1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.content.ContentResolver; 22 import android.content.Intent; 23 import android.net.Proxy; 24 import android.os.Bundle; 25 import android.provider.Settings; 26 import android.text.Selection; 27 import android.text.Spannable; 28 import android.text.TextUtils; 29 import android.util.Log; 30 import android.view.View; 31 import android.view.View.OnClickListener; 32 import android.view.View.OnFocusChangeListener; 33 import android.widget.Button; 34 import android.widget.EditText; 35 import android.widget.TextView; 36 37 import java.util.regex.Matcher; 38 import java.util.regex.Pattern; 39 40 /** 41 * To start the Proxy Selector activity, create the following intent. 42 * 43 * <code> 44 * Intent intent = new Intent(); 45 * intent.setClassName("com.android.browser.ProxySelector"); 46 * startActivity(intent); 47 * </code> 48 * 49 * you can add extra options to the intent by using 50 * 51 * <code> 52 * intent.putExtra(key, value); 53 * </code> 54 * 55 * the extra options are: 56 * 57 * button-label: a string label to display for the okay button 58 * title: the title of the window 59 * error-text: If not null, will be used as the label of the error message. 60 */ 61 public class ProxySelector extends Activity 62 { 63 private final static String LOGTAG = "Settings"; 64 65 EditText mHostnameField; 66 EditText mPortField; 67 Button mOKButton; 68 69 // Matches blank input, ips, and domain names 70 private static final String HOSTNAME_REGEXP = "^$|^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*$"; 71 private static final Pattern HOSTNAME_PATTERN; 72 static { 73 HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP); 74 } 75 76 77 public void onCreate(Bundle icicle) { 78 super.onCreate(icicle); 79 80 if (android.util.Config.LOGV) Log.v(LOGTAG, "[ProxySelector] onStart"); 81 82 setContentView(R.layout.proxy); 83 initView(); 84 populateFields(false); 85 } 86 87 protected void showError(int error) { 88 89 new AlertDialog.Builder(this) 90 .setTitle(R.string.proxy_error) 91 .setMessage(error) 92 .setPositiveButton(R.string.proxy_error_dismiss, null) 93 .show(); 94 } 95 96 void initView() { 97 98 mHostnameField = (EditText)findViewById(R.id.hostname); 99 mHostnameField.setOnFocusChangeListener(mOnFocusChangeHandler); 100 101 mPortField = (EditText)findViewById(R.id.port); 102 mPortField.setOnClickListener(mOKHandler); 103 mPortField.setOnFocusChangeListener(mOnFocusChangeHandler); 104 105 mOKButton = (Button)findViewById(R.id.action); 106 mOKButton.setOnClickListener(mOKHandler); 107 108 Button b = (Button)findViewById(R.id.clear); 109 b.setOnClickListener(mClearHandler); 110 111 b = (Button)findViewById(R.id.defaultView); 112 b.setOnClickListener(mDefaultHandler); 113 } 114 115 void populateFields(boolean useDefault) { 116 String hostname = null; 117 int port = -1; 118 if (useDefault) { 119 // Use the default proxy settings provided by the carrier 120 hostname = Proxy.getDefaultHost(); 121 port = Proxy.getDefaultPort(); 122 } else { 123 // Use the last setting given by the user 124 hostname = Proxy.getHost(this); 125 port = Proxy.getPort(this); 126 } 127 128 if (hostname == null) { 129 hostname = ""; 130 } 131 132 mHostnameField.setText(hostname); 133 134 String portStr = port == -1 ? "" : Integer.toString(port); 135 mPortField.setText(portStr); 136 137 Intent intent = getIntent(); 138 139 String buttonLabel = intent.getStringExtra("button-label"); 140 if (!TextUtils.isEmpty(buttonLabel)) { 141 mOKButton.setText(buttonLabel); 142 } 143 144 String title = intent.getStringExtra("title"); 145 if (!TextUtils.isEmpty(title)) { 146 setTitle(title); 147 } 148 } 149 150 /** 151 * validate syntax of hostname and port entries 152 * @return 0 on success, string resource ID on failure 153 */ 154 int validate(String hostname, String port) { 155 Matcher match = HOSTNAME_PATTERN.matcher(hostname); 156 157 if (!match.matches()) return R.string.proxy_error_invalid_host; 158 159 if (hostname.length() > 0 && port.length() == 0) { 160 return R.string.proxy_error_empty_port; 161 } 162 163 if (port.length() > 0) { 164 if (hostname.length() == 0) { 165 return R.string.proxy_error_empty_host_set_port; 166 } 167 int portVal = -1; 168 try { 169 portVal = Integer.parseInt(port); 170 } catch (NumberFormatException ex) { 171 return R.string.proxy_error_invalid_port; 172 } 173 if (portVal <= 0 || portVal > 0xFFFF) { 174 return R.string.proxy_error_invalid_port; 175 } 176 } 177 return 0; 178 } 179 180 /** 181 * returns true on success, false if the user must correct something 182 */ 183 boolean saveToDb() { 184 185 String hostname = mHostnameField.getText().toString().trim(); 186 String portStr = mPortField.getText().toString().trim(); 187 int port = -1; 188 189 int result = validate(hostname, portStr); 190 if (result > 0) { 191 showError(result); 192 return false; 193 } 194 195 if (portStr.length() > 0) { 196 try { 197 port = Integer.parseInt(portStr); 198 } catch (NumberFormatException ex) { 199 return false; 200 } 201 } 202 203 // FIXME: The best solution would be to make a better UI that would 204 // disable editing of the text boxes if the user chooses to use the 205 // default settings. i.e. checking a box to always use the default 206 // carrier. http:/b/issue?id=756480 207 // FIXME: This currently will not work if the default host is blank and 208 // the user has cleared the input boxes in order to not use a proxy. 209 // This is a UI problem and can be solved with some better form 210 // controls. 211 // FIXME: If the user types in a proxy that matches the default, should 212 // we keep that setting? Can be fixed with a new UI. 213 ContentResolver res = getContentResolver(); 214 if (hostname.equals(Proxy.getDefaultHost()) 215 && port == Proxy.getDefaultPort()) { 216 // If the user hit the default button and didn't change any of 217 // the input boxes, treat it as if the user has not specified a 218 // proxy. 219 hostname = null; 220 } 221 222 if (!TextUtils.isEmpty(hostname)) { 223 hostname += ':' + portStr; 224 } 225 Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY, hostname); 226 sendBroadcast(new Intent(Proxy.PROXY_CHANGE_ACTION)); 227 228 return true; 229 } 230 231 OnClickListener mOKHandler = new OnClickListener() { 232 public void onClick(View v) { 233 if (saveToDb()) { 234 finish(); 235 } 236 } 237 }; 238 239 OnClickListener mClearHandler = new OnClickListener() { 240 public void onClick(View v) { 241 mHostnameField.setText(""); 242 mPortField.setText(""); 243 } 244 }; 245 246 OnClickListener mDefaultHandler = new OnClickListener() { 247 public void onClick(View v) { 248 populateFields(true); 249 } 250 }; 251 252 OnFocusChangeListener mOnFocusChangeHandler = new OnFocusChangeListener() { 253 public void onFocusChange(View v, boolean hasFocus) { 254 if (hasFocus) { 255 TextView textView = (TextView) v; 256 Selection.selectAll((Spannable) textView.getText()); 257 } 258 } 259 }; 260 } 261