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