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