• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.phone;
18 
19 import android.app.Dialog;
20 import android.app.ProgressDialog;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.os.AsyncResult;
27 import android.os.Bundle;
28 import android.os.Handler;
29 import android.os.IBinder;
30 import android.os.Message;
31 import android.os.RemoteException;
32 import android.os.UserManager;
33 import android.preference.Preference;
34 import android.preference.PreferenceActivity;
35 import android.preference.PreferenceGroup;
36 import android.preference.PreferenceScreen;
37 import android.text.TextUtils;
38 import android.util.Log;
39 
40 import com.android.internal.telephony.CommandException;
41 import com.android.internal.telephony.Phone;
42 import com.android.internal.telephony.OperatorInfo;
43 
44 import java.util.HashMap;
45 import java.util.List;
46 
47 /**
48  * "Networks" settings UI for the Phone app.
49  */
50 public class NetworkSetting extends PreferenceActivity
51         implements DialogInterface.OnCancelListener {
52 
53     private static final String LOG_TAG = "phone";
54     private static final boolean DBG = false;
55 
56     private static final int EVENT_NETWORK_SCAN_COMPLETED = 100;
57     private static final int EVENT_NETWORK_SELECTION_DONE = 200;
58     private static final int EVENT_AUTO_SELECT_DONE = 300;
59 
60     //dialog ids
61     private static final int DIALOG_NETWORK_SELECTION = 100;
62     private static final int DIALOG_NETWORK_LIST_LOAD = 200;
63     private static final int DIALOG_NETWORK_AUTO_SELECT = 300;
64 
65     //String keys for preference lookup
66     private static final String LIST_NETWORKS_KEY = "list_networks_key";
67     private static final String BUTTON_SRCH_NETWRKS_KEY = "button_srch_netwrks_key";
68     private static final String BUTTON_AUTO_SELECT_KEY = "button_auto_select_key";
69 
70     //map of network controls to the network data.
71     private HashMap<Preference, OperatorInfo> mNetworkMap;
72 
73     Phone mPhone;
74     protected boolean mIsForeground = false;
75 
76     private UserManager mUm;
77     private boolean mUnavailable;
78 
79     /** message for network selection */
80     String mNetworkSelectMsg;
81 
82     //preference objects
83     private PreferenceGroup mNetworkList;
84     private Preference mSearchButton;
85     private Preference mAutoSelect;
86 
87     private final Handler mHandler = new Handler() {
88         @Override
89         public void handleMessage(Message msg) {
90             AsyncResult ar;
91             switch (msg.what) {
92                 case EVENT_NETWORK_SCAN_COMPLETED:
93                     networksListLoaded ((List<OperatorInfo>) msg.obj, msg.arg1);
94                     break;
95 
96                 case EVENT_NETWORK_SELECTION_DONE:
97                     if (DBG) log("hideProgressPanel");
98                     removeDialog(DIALOG_NETWORK_SELECTION);
99                     getPreferenceScreen().setEnabled(true);
100 
101                     ar = (AsyncResult) msg.obj;
102                     if (ar.exception != null) {
103                         if (DBG) log("manual network selection: failed!");
104                         displayNetworkSelectionFailed(ar.exception);
105                     } else {
106                         if (DBG) log("manual network selection: succeeded!");
107                         displayNetworkSelectionSucceeded();
108                     }
109                     break;
110                 case EVENT_AUTO_SELECT_DONE:
111                     if (DBG) log("hideProgressPanel");
112 
113                     // Always try to dismiss the dialog because activity may
114                     // be moved to background after dialog is shown.
115                     try {
116                         dismissDialog(DIALOG_NETWORK_AUTO_SELECT);
117                     } catch (IllegalArgumentException e) {
118                         // "auto select" is always trigged in foreground, so "auto select" dialog
119                         //  should be shown when "auto select" is trigged. Should NOT get
120                         // this exception, and Log it.
121                         Log.w(LOG_TAG, "[NetworksList] Fail to dismiss auto select dialog", e);
122                     }
123                     getPreferenceScreen().setEnabled(true);
124 
125                     ar = (AsyncResult) msg.obj;
126                     if (ar.exception != null) {
127                         if (DBG) log("automatic network selection: failed!");
128                         displayNetworkSelectionFailed(ar.exception);
129                     } else {
130                         if (DBG) log("automatic network selection: succeeded!");
131                         displayNetworkSelectionSucceeded();
132                     }
133                     break;
134             }
135 
136             return;
137         }
138     };
139 
140     /**
141      * Service connection code for the NetworkQueryService.
142      * Handles the work of binding to a local object so that we can make
143      * the appropriate service calls.
144      */
145 
146     /** Local service interface */
147     private INetworkQueryService mNetworkQueryService = null;
148 
149     /** Service connection */
150     private final ServiceConnection mNetworkQueryServiceConnection = new ServiceConnection() {
151 
152         /** Handle the task of binding the local object to the service */
153         public void onServiceConnected(ComponentName className, IBinder service) {
154             if (DBG) log("connection created, binding local service.");
155             mNetworkQueryService = ((NetworkQueryService.LocalBinder) service).getService();
156             // as soon as it is bound, run a query.
157             loadNetworksList();
158         }
159 
160         /** Handle the task of cleaning up the local binding */
161         public void onServiceDisconnected(ComponentName className) {
162             if (DBG) log("connection disconnected, cleaning local binding.");
163             mNetworkQueryService = null;
164         }
165     };
166 
167     /**
168      * This implementation of INetworkQueryServiceCallback is used to receive
169      * callback notifications from the network query service.
170      */
171     private final INetworkQueryServiceCallback mCallback = new INetworkQueryServiceCallback.Stub() {
172 
173         /** place the message on the looper queue upon query completion. */
174         public void onQueryComplete(List<OperatorInfo> networkInfoArray, int status) {
175             if (DBG) log("notifying message loop of query completion.");
176             Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_COMPLETED,
177                     status, 0, networkInfoArray);
178             msg.sendToTarget();
179         }
180     };
181 
182     @Override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)183     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
184         boolean handled = false;
185 
186         if (preference == mSearchButton) {
187             loadNetworksList();
188             handled = true;
189         } else if (preference == mAutoSelect) {
190             selectNetworkAutomatic();
191             handled = true;
192         } else {
193             Preference selectedCarrier = preference;
194 
195             String networkStr = selectedCarrier.getTitle().toString();
196             if (DBG) log("selected network: " + networkStr);
197 
198             Message msg = mHandler.obtainMessage(EVENT_NETWORK_SELECTION_DONE);
199             mPhone.selectNetworkManually(mNetworkMap.get(selectedCarrier), msg);
200 
201             displayNetworkSeletionInProgress(networkStr);
202 
203             handled = true;
204         }
205 
206         return handled;
207     }
208 
209     //implemented for DialogInterface.OnCancelListener
onCancel(DialogInterface dialog)210     public void onCancel(DialogInterface dialog) {
211         // request that the service stop the query with this callback object.
212         try {
213             mNetworkQueryService.stopNetworkQuery(mCallback);
214         } catch (RemoteException e) {
215             throw new RuntimeException(e);
216         }
217         finish();
218     }
219 
getNormalizedCarrierName(OperatorInfo ni)220     public String getNormalizedCarrierName(OperatorInfo ni) {
221         if (ni != null) {
222             return ni.getOperatorAlphaLong() + " (" + ni.getOperatorNumeric() + ")";
223         }
224         return null;
225     }
226 
227     @Override
onCreate(Bundle icicle)228     protected void onCreate(Bundle icicle) {
229         super.onCreate(icicle);
230 
231         mUm = (UserManager) getSystemService(Context.USER_SERVICE);
232 
233         if (mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
234             setContentView(R.layout.telephony_disallowed_preference_screen);
235             mUnavailable = true;
236             return;
237         }
238 
239         addPreferencesFromResource(R.xml.carrier_select);
240 
241         mPhone = PhoneGlobals.getPhone();
242 
243         mNetworkList = (PreferenceGroup) getPreferenceScreen().findPreference(LIST_NETWORKS_KEY);
244         mNetworkMap = new HashMap<Preference, OperatorInfo>();
245 
246         mSearchButton = getPreferenceScreen().findPreference(BUTTON_SRCH_NETWRKS_KEY);
247         mAutoSelect = getPreferenceScreen().findPreference(BUTTON_AUTO_SELECT_KEY);
248 
249         // Start the Network Query service, and bind it.
250         // The OS knows to start he service only once and keep the instance around (so
251         // long as startService is called) until a stopservice request is made.  Since
252         // we want this service to just stay in the background until it is killed, we
253         // don't bother stopping it from our end.
254         startService (new Intent(this, NetworkQueryService.class));
255         bindService (new Intent(this, NetworkQueryService.class), mNetworkQueryServiceConnection,
256                 Context.BIND_AUTO_CREATE);
257     }
258 
259     @Override
onResume()260     public void onResume() {
261         super.onResume();
262         mIsForeground = true;
263     }
264 
265     @Override
onPause()266     public void onPause() {
267         super.onPause();
268         mIsForeground = false;
269     }
270 
271     /**
272      * Override onDestroy() to unbind the query service, avoiding service
273      * leak exceptions.
274      */
275     @Override
onDestroy()276     protected void onDestroy() {
277         if (!mUnavailable) {
278             // unbind the service.
279             unbindService(mNetworkQueryServiceConnection);
280         }
281         super.onDestroy();
282     }
283 
284     @Override
onCreateDialog(int id)285     protected Dialog onCreateDialog(int id) {
286 
287         if ((id == DIALOG_NETWORK_SELECTION) || (id == DIALOG_NETWORK_LIST_LOAD) ||
288                 (id == DIALOG_NETWORK_AUTO_SELECT)) {
289             ProgressDialog dialog = new ProgressDialog(this);
290             switch (id) {
291                 case DIALOG_NETWORK_SELECTION:
292                     // It would be more efficient to reuse this dialog by moving
293                     // this setMessage() into onPreparedDialog() and NOT use
294                     // removeDialog().  However, this is not possible since the
295                     // message is rendered only 2 times in the ProgressDialog -
296                     // after show() and before onCreate.
297                     dialog.setMessage(mNetworkSelectMsg);
298                     dialog.setCancelable(false);
299                     dialog.setIndeterminate(true);
300                     break;
301                 case DIALOG_NETWORK_AUTO_SELECT:
302                     dialog.setMessage(getResources().getString(R.string.register_automatically));
303                     dialog.setCancelable(false);
304                     dialog.setIndeterminate(true);
305                     break;
306                 case DIALOG_NETWORK_LIST_LOAD:
307                 default:
308                     // reinstate the cancelablity of the dialog.
309                     dialog.setMessage(getResources().getString(R.string.load_networks_progress));
310                     dialog.setCanceledOnTouchOutside(false);
311                     dialog.setOnCancelListener(this);
312                     break;
313             }
314             return dialog;
315         }
316         return null;
317     }
318 
319     @Override
onPrepareDialog(int id, Dialog dialog)320     protected void onPrepareDialog(int id, Dialog dialog) {
321         if ((id == DIALOG_NETWORK_SELECTION) || (id == DIALOG_NETWORK_LIST_LOAD) ||
322                 (id == DIALOG_NETWORK_AUTO_SELECT)) {
323             // when the dialogs come up, we'll need to indicate that
324             // we're in a busy state to dissallow further input.
325             getPreferenceScreen().setEnabled(false);
326         }
327     }
328 
displayEmptyNetworkList(boolean flag)329     private void displayEmptyNetworkList(boolean flag) {
330         mNetworkList.setTitle(flag ? R.string.empty_networks_list : R.string.label_available);
331     }
332 
displayNetworkSeletionInProgress(String networkStr)333     private void displayNetworkSeletionInProgress(String networkStr) {
334         // TODO: use notification manager?
335         mNetworkSelectMsg = getResources().getString(R.string.register_on_network, networkStr);
336 
337         if (mIsForeground) {
338             showDialog(DIALOG_NETWORK_SELECTION);
339         }
340     }
341 
displayNetworkQueryFailed(int error)342     private void displayNetworkQueryFailed(int error) {
343         String status = getResources().getString(R.string.network_query_error);
344 
345         final PhoneGlobals app = PhoneGlobals.getInstance();
346         app.notificationMgr.postTransientNotification(
347                 NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
348     }
349 
displayNetworkSelectionFailed(Throwable ex)350     private void displayNetworkSelectionFailed(Throwable ex) {
351         String status;
352 
353         if ((ex != null && ex instanceof CommandException) &&
354                 ((CommandException)ex).getCommandError()
355                   == CommandException.Error.ILLEGAL_SIM_OR_ME)
356         {
357             status = getResources().getString(R.string.not_allowed);
358         } else {
359             status = getResources().getString(R.string.connect_later);
360         }
361 
362         final PhoneGlobals app = PhoneGlobals.getInstance();
363         app.notificationMgr.postTransientNotification(
364                 NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
365     }
366 
displayNetworkSelectionSucceeded()367     private void displayNetworkSelectionSucceeded() {
368         String status = getResources().getString(R.string.registration_done);
369 
370         final PhoneGlobals app = PhoneGlobals.getInstance();
371         app.notificationMgr.postTransientNotification(
372                 NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
373 
374         mHandler.postDelayed(new Runnable() {
375             public void run() {
376                 finish();
377             }
378         }, 3000);
379     }
380 
loadNetworksList()381     private void loadNetworksList() {
382         if (DBG) log("load networks list...");
383 
384         if (mIsForeground) {
385             showDialog(DIALOG_NETWORK_LIST_LOAD);
386         }
387 
388         // delegate query request to the service.
389         try {
390             mNetworkQueryService.startNetworkQuery(mCallback);
391         } catch (RemoteException e) {
392         }
393 
394         displayEmptyNetworkList(false);
395     }
396 
397     /**
398      * networksListLoaded has been rewritten to take an array of
399      * OperatorInfo objects and a status field, instead of an
400      * AsyncResult.  Otherwise, the functionality which takes the
401      * OperatorInfo array and creates a list of preferences from it,
402      * remains unchanged.
403      */
networksListLoaded(List<OperatorInfo> result, int status)404     private void networksListLoaded(List<OperatorInfo> result, int status) {
405         if (DBG) log("networks list loaded");
406 
407         // update the state of the preferences.
408         if (DBG) log("hideProgressPanel");
409 
410 
411         // Always try to dismiss the dialog because activity may
412         // be moved to background after dialog is shown.
413         try {
414             dismissDialog(DIALOG_NETWORK_LIST_LOAD);
415         } catch (IllegalArgumentException e) {
416             // It's not a error in following scenario, we just ignore it.
417             // "Load list" dialog will not show, if NetworkQueryService is
418             // connected after this activity is moved to background.
419             if (DBG) log("Fail to dismiss network load list dialog");
420         }
421 
422         getPreferenceScreen().setEnabled(true);
423         clearList();
424 
425         if (status != NetworkQueryService.QUERY_OK) {
426             if (DBG) log("error while querying available networks");
427             displayNetworkQueryFailed(status);
428             displayEmptyNetworkList(true);
429         } else {
430             if (result != null){
431                 displayEmptyNetworkList(false);
432 
433                 // create a preference for each item in the list.
434                 // just use the operator name instead of the mildly
435                 // confusing mcc/mnc.
436                 for (OperatorInfo ni : result) {
437                     Preference carrier = new Preference(this, null);
438                     carrier.setTitle(getNetworkTitle(ni));
439                     carrier.setPersistent(false);
440                     mNetworkList.addPreference(carrier);
441                     mNetworkMap.put(carrier, ni);
442 
443                     if (DBG) log("  " + ni);
444                 }
445 
446             } else {
447                 displayEmptyNetworkList(true);
448             }
449         }
450     }
451 
452     /**
453      * Returns the title of the network obtained in the manual search.
454      *
455      * @param OperatorInfo contains the information of the network.
456      *
457      * @return Long Name if not null/empty, otherwise Short Name if not null/empty,
458      * else MCCMNC string.
459      */
460 
getNetworkTitle(OperatorInfo ni)461     private String getNetworkTitle(OperatorInfo ni) {
462         if (!TextUtils.isEmpty(ni.getOperatorAlphaLong())) {
463             return ni.getOperatorAlphaLong();
464         } else if (!TextUtils.isEmpty(ni.getOperatorAlphaShort())) {
465             return ni.getOperatorAlphaShort();
466         } else {
467             return ni.getOperatorNumeric();
468         }
469     }
470 
clearList()471     private void clearList() {
472         for (Preference p : mNetworkMap.keySet()) {
473             mNetworkList.removePreference(p);
474         }
475         mNetworkMap.clear();
476     }
477 
selectNetworkAutomatic()478     private void selectNetworkAutomatic() {
479         if (DBG) log("select network automatically...");
480         if (mIsForeground) {
481             showDialog(DIALOG_NETWORK_AUTO_SELECT);
482         }
483 
484         Message msg = mHandler.obtainMessage(EVENT_AUTO_SELECT_DONE);
485         mPhone.setNetworkSelectionModeAutomatic(msg);
486     }
487 
log(String msg)488     private void log(String msg) {
489         Log.d(LOG_TAG, "[NetworksList] " + msg);
490     }
491 }
492