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.app.Dialog;
22 import android.app.admin.DevicePolicyManager;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.net.ConnectivityManager;
26 import android.net.Proxy;
27 import android.net.ProxyInfo;
28 import android.os.Bundle;
29 import android.text.Selection;
30 import android.text.Spannable;
31 import android.text.TextUtils;
32 import android.util.Log;
33 import android.view.LayoutInflater;
34 import android.view.View;
35 import android.view.View.OnClickListener;
36 import android.view.View.OnFocusChangeListener;
37 import android.view.ViewGroup;
38 import android.widget.Button;
39 import android.widget.EditText;
40 import android.widget.TextView;
41 
42 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
43 import com.android.settings.SettingsPreferenceFragment.SettingsDialogFragment;
44 import com.android.settings.core.InstrumentedPreferenceFragment;
45 
46 public class ProxySelector extends InstrumentedPreferenceFragment implements DialogCreatable {
47     private static final String TAG = "ProxySelector";
48 
49     EditText    mHostnameField;
50     EditText    mPortField;
51     EditText    mExclusionListField;
52     Button      mOKButton;
53     Button      mClearButton;
54     Button      mDefaultButton;
55 
56     private static final int ERROR_DIALOG_ID = 0;
57 
58     private SettingsDialogFragment mDialogFragment;
59     private View mView;
60 
61     @Override
onCreate(Bundle icicle)62     public void onCreate(Bundle icicle) {
63         super.onCreate(icicle);
64     }
65 
66     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)67     public View onCreateView(LayoutInflater inflater, ViewGroup container,
68             Bundle savedInstanceState) {
69         mView = inflater.inflate(R.layout.proxy, container, false);
70         initView(mView);
71         // TODO: Populate based on connection status
72         populateFields();
73         return mView;
74     }
75 
76     @Override
onActivityCreated(Bundle savedInstanceState)77     public void onActivityCreated(Bundle savedInstanceState) {
78         super.onActivityCreated(savedInstanceState);
79         final DevicePolicyManager dpm =
80                 (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
81 
82         final boolean userSetGlobalProxy = (dpm.getGlobalProxyAdmin() == null);
83         // Disable UI if the Global Proxy is being controlled by a Device Admin
84         mHostnameField.setEnabled(userSetGlobalProxy);
85         mPortField.setEnabled(userSetGlobalProxy);
86         mExclusionListField.setEnabled(userSetGlobalProxy);
87         mOKButton.setEnabled(userSetGlobalProxy);
88         mClearButton.setEnabled(userSetGlobalProxy);
89         mDefaultButton.setEnabled(userSetGlobalProxy);
90     }
91 
92     // Dialog management
93 
94     @Override
onCreateDialog(int id)95     public Dialog onCreateDialog(int id) {
96         if (id == ERROR_DIALOG_ID) {
97             String hostname = mHostnameField.getText().toString().trim();
98             String portStr = mPortField.getText().toString().trim();
99             String exclList = mExclusionListField.getText().toString().trim();
100             String msg = getActivity().getString(validate(hostname, portStr, exclList));
101 
102             return new AlertDialog.Builder(getActivity())
103                     .setTitle(R.string.proxy_error)
104                     .setPositiveButton(R.string.proxy_error_dismiss, null)
105                     .setMessage(msg)
106                     .create();
107         }
108         return null;
109     }
110 
111     @Override
getDialogMetricsCategory(int dialogId)112     public int getDialogMetricsCategory(int dialogId) {
113         return MetricsEvent.DIALOG_PROXY_SELECTOR_ERROR;
114     }
115 
showDialog(int dialogId)116     private void showDialog(int dialogId) {
117         if (mDialogFragment != null) {
118             Log.e(TAG, "Old dialog fragment not null!");
119         }
120         mDialogFragment = new SettingsDialogFragment(this, dialogId);
121         mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId));
122     }
123 
initView(View view)124     private void initView(View view) {
125         mHostnameField = (EditText)view.findViewById(R.id.hostname);
126         mHostnameField.setOnFocusChangeListener(mOnFocusChangeHandler);
127 
128         mPortField = (EditText)view.findViewById(R.id.port);
129         mPortField.setOnClickListener(mOKHandler);
130         mPortField.setOnFocusChangeListener(mOnFocusChangeHandler);
131 
132         mExclusionListField = (EditText)view.findViewById(R.id.exclusionlist);
133         mExclusionListField.setOnFocusChangeListener(mOnFocusChangeHandler);
134 
135         mOKButton = (Button)view.findViewById(R.id.action);
136         mOKButton.setOnClickListener(mOKHandler);
137 
138         mClearButton = (Button)view.findViewById(R.id.clear);
139         mClearButton.setOnClickListener(mClearHandler);
140 
141         mDefaultButton = (Button)view.findViewById(R.id.defaultView);
142         mDefaultButton.setOnClickListener(mDefaultHandler);
143     }
144 
populateFields()145     void populateFields() {
146         final Activity activity = getActivity();
147         String hostname = "";
148         int port = -1;
149         String exclList = "";
150         // Use the last setting given by the user
151         ConnectivityManager cm =
152                 (ConnectivityManager)getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
153 
154         ProxyInfo proxy = cm.getGlobalProxy();
155         if (proxy != null) {
156             hostname = proxy.getHost();
157             port = proxy.getPort();
158             exclList = proxy.getExclusionListAsString();
159         }
160 
161         if (hostname == null) {
162             hostname = "";
163         }
164 
165         mHostnameField.setText(hostname);
166 
167         String portStr = port == -1 ? "" : Integer.toString(port);
168         mPortField.setText(portStr);
169 
170         mExclusionListField.setText(exclList);
171 
172         final Intent intent = activity.getIntent();
173 
174         String buttonLabel = intent.getStringExtra("button-label");
175         if (!TextUtils.isEmpty(buttonLabel)) {
176             mOKButton.setText(buttonLabel);
177         }
178 
179         String title = intent.getStringExtra("title");
180         if (!TextUtils.isEmpty(title)) {
181             activity.setTitle(title);
182         }
183     }
184 
185     /**
186      * validate syntax of hostname and port entries
187      * @return 0 on success, string resource ID on failure
188      */
validate(String hostname, String port, String exclList)189     public static int validate(String hostname, String port, String exclList) {
190         switch (Proxy.validate(hostname, port, exclList)) {
191             case Proxy.PROXY_VALID:
192                 return 0;
193             case Proxy.PROXY_HOSTNAME_EMPTY:
194                 return R.string.proxy_error_empty_host_set_port;
195             case Proxy.PROXY_HOSTNAME_INVALID:
196                 return R.string.proxy_error_invalid_host;
197             case Proxy.PROXY_PORT_EMPTY:
198                 return R.string.proxy_error_empty_port;
199             case Proxy.PROXY_PORT_INVALID:
200                 return R.string.proxy_error_invalid_port;
201             case Proxy.PROXY_EXCLLIST_INVALID:
202                 return R.string.proxy_error_invalid_exclusion_list;
203             default:
204                 // should neven happen
205                 Log.e(TAG, "Unknown proxy settings error");
206                 return -1;
207         }
208     }
209 
210     /**
211      * returns true on success, false if the user must correct something
212      */
saveToDb()213     boolean saveToDb() {
214 
215         String hostname = mHostnameField.getText().toString().trim();
216         String portStr = mPortField.getText().toString().trim();
217         String exclList = mExclusionListField.getText().toString().trim();
218         int port = 0;
219 
220         int result = validate(hostname, portStr, exclList);
221         if (result != 0) {
222             showDialog(ERROR_DIALOG_ID);
223             return false;
224         }
225 
226         if (portStr.length() > 0) {
227             try {
228                 port = Integer.parseInt(portStr);
229             } catch (NumberFormatException ex) {
230                 // should never happen - caught by validate above
231                 return false;
232             }
233         }
234         ProxyInfo p = new ProxyInfo(hostname, port, exclList);
235         // FIXME: The best solution would be to make a better UI that would
236         // disable editing of the text boxes if the user chooses to use the
237         // default settings. i.e. checking a box to always use the default
238         // carrier. http:/b/issue?id=756480
239         // FIXME: If the user types in a proxy that matches the default, should
240         // we keep that setting? Can be fixed with a new UI.
241         ConnectivityManager cm =
242                 (ConnectivityManager)getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
243 
244         cm.setGlobalProxy(p);
245         return true;
246     }
247 
248     OnClickListener mOKHandler = new OnClickListener() {
249             public void onClick(View v) {
250                 if (saveToDb()) {
251                     getActivity().onBackPressed();
252                 }
253             }
254         };
255 
256     OnClickListener mClearHandler = new OnClickListener() {
257             public void onClick(View v) {
258                 mHostnameField.setText("");
259                 mPortField.setText("");
260                 mExclusionListField.setText("");
261             }
262         };
263 
264     OnClickListener mDefaultHandler = new OnClickListener() {
265             public void onClick(View v) {
266                 // TODO: populate based on connection status
267                 populateFields();
268             }
269         };
270 
271     OnFocusChangeListener mOnFocusChangeHandler = new OnFocusChangeListener() {
272             public void onFocusChange(View v, boolean hasFocus) {
273                 if (hasFocus) {
274                     TextView textView = (TextView) v;
275                     Selection.selectAll((Spannable) textView.getText());
276                 }
277             }
278         };
279 
280     @Override
getMetricsCategory()281     public int getMetricsCategory() {
282         return MetricsEvent.PROXY_SELECTOR;
283     }
284 }
285