NetworkSetting.java revision abc47110c17fa8e8cb6161bc045e87f31eeb7a1c
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 17package com.android.phone; 18 19import com.android.internal.telephony.Phone; 20import com.android.internal.telephony.gsm.NetworkInfo; 21 22import android.app.Dialog; 23import android.app.ProgressDialog; 24import android.content.ComponentName; 25import android.content.Context; 26import android.content.DialogInterface; 27import android.content.Intent; 28import android.content.ServiceConnection; 29import android.os.AsyncResult; 30import android.os.Bundle; 31import android.os.Handler; 32import android.os.IBinder; 33import android.os.Message; 34import android.os.RemoteException; 35import android.preference.Preference; 36import android.preference.PreferenceActivity; 37import android.preference.PreferenceCategory; 38import android.preference.PreferenceScreen; 39import android.util.Log; 40 41import java.util.HashMap; 42import java.util.List; 43 44/** 45 * "Networks" settings UI for the Phone app. 46 */ 47public 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 PreferenceCategory 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 = (PreferenceCategory) 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