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