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