summaryrefslogtreecommitdiff
path: root/src/com/android/phone/NetworkSetting.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/phone/NetworkSetting.java')
-rw-r--r--src/com/android/phone/NetworkSetting.java478
1 files changed, 478 insertions, 0 deletions
diff --git a/src/com/android/phone/NetworkSetting.java b/src/com/android/phone/NetworkSetting.java
new file mode 100644
index 00000000..59177957
--- /dev/null
+++ b/src/com/android/phone/NetworkSetting.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.AsyncResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.OperatorInfo;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * "Networks" settings UI for the Phone app.
+ */
+public class NetworkSetting extends PreferenceActivity
+ implements DialogInterface.OnCancelListener {
+
+ private static final String LOG_TAG = "phone";
+ private static final boolean DBG = false;
+
+ private static final int EVENT_NETWORK_SCAN_COMPLETED = 100;
+ private static final int EVENT_NETWORK_SELECTION_DONE = 200;
+ private static final int EVENT_AUTO_SELECT_DONE = 300;
+
+ //dialog ids
+ private static final int DIALOG_NETWORK_SELECTION = 100;
+ private static final int DIALOG_NETWORK_LIST_LOAD = 200;
+ private static final int DIALOG_NETWORK_AUTO_SELECT = 300;
+
+ //String keys for preference lookup
+ private static final String LIST_NETWORKS_KEY = "list_networks_key";
+ private static final String BUTTON_SRCH_NETWRKS_KEY = "button_srch_netwrks_key";
+ private static final String BUTTON_AUTO_SELECT_KEY = "button_auto_select_key";
+
+ //map of network controls to the network data.
+ private HashMap<Preference, OperatorInfo> mNetworkMap;
+
+ Phone mPhone;
+ protected boolean mIsForeground = false;
+
+ /** message for network selection */
+ String mNetworkSelectMsg;
+
+ //preference objects
+ private PreferenceGroup mNetworkList;
+ private Preference mSearchButton;
+ private Preference mAutoSelect;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+ switch (msg.what) {
+ case EVENT_NETWORK_SCAN_COMPLETED:
+ networksListLoaded ((List<OperatorInfo>) msg.obj, msg.arg1);
+ break;
+
+ case EVENT_NETWORK_SELECTION_DONE:
+ if (DBG) log("hideProgressPanel");
+ removeDialog(DIALOG_NETWORK_SELECTION);
+ getPreferenceScreen().setEnabled(true);
+
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception != null) {
+ if (DBG) log("manual network selection: failed!");
+ displayNetworkSelectionFailed(ar.exception);
+ } else {
+ if (DBG) log("manual network selection: succeeded!");
+ displayNetworkSelectionSucceeded();
+ }
+ break;
+ case EVENT_AUTO_SELECT_DONE:
+ if (DBG) log("hideProgressPanel");
+
+ // Always try to dismiss the dialog because activity may
+ // be moved to background after dialog is shown.
+ try {
+ dismissDialog(DIALOG_NETWORK_AUTO_SELECT);
+ } catch (IllegalArgumentException e) {
+ // "auto select" is always trigged in foreground, so "auto select" dialog
+ // should be shown when "auto select" is trigged. Should NOT get
+ // this exception, and Log it.
+ Log.w(LOG_TAG, "[NetworksList] Fail to dismiss auto select dialog", e);
+ }
+ getPreferenceScreen().setEnabled(true);
+
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception != null) {
+ if (DBG) log("automatic network selection: failed!");
+ displayNetworkSelectionFailed(ar.exception);
+ } else {
+ if (DBG) log("automatic network selection: succeeded!");
+ displayNetworkSelectionSucceeded();
+ }
+ break;
+ }
+
+ return;
+ }
+ };
+
+ /**
+ * Service connection code for the NetworkQueryService.
+ * Handles the work of binding to a local object so that we can make
+ * the appropriate service calls.
+ */
+
+ /** Local service interface */
+ private INetworkQueryService mNetworkQueryService = null;
+
+ /** Service connection */
+ private final ServiceConnection mNetworkQueryServiceConnection = new ServiceConnection() {
+
+ /** Handle the task of binding the local object to the service */
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) log("connection created, binding local service.");
+ mNetworkQueryService = ((NetworkQueryService.LocalBinder) service).getService();
+ // as soon as it is bound, run a query.
+ loadNetworksList();
+ }
+
+ /** Handle the task of cleaning up the local binding */
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) log("connection disconnected, cleaning local binding.");
+ mNetworkQueryService = null;
+ }
+ };
+
+ /**
+ * This implementation of INetworkQueryServiceCallback is used to receive
+ * callback notifications from the network query service.
+ */
+ private final INetworkQueryServiceCallback mCallback = new INetworkQueryServiceCallback.Stub() {
+
+ /** place the message on the looper queue upon query completion. */
+ public void onQueryComplete(List<OperatorInfo> networkInfoArray, int status) {
+ if (DBG) log("notifying message loop of query completion.");
+ Message msg = mHandler.obtainMessage(EVENT_NETWORK_SCAN_COMPLETED,
+ status, 0, networkInfoArray);
+ msg.sendToTarget();
+ }
+ };
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+ boolean handled = false;
+
+ if (preference == mSearchButton) {
+ loadNetworksList();
+ handled = true;
+ } else if (preference == mAutoSelect) {
+ selectNetworkAutomatic();
+ handled = true;
+ } else {
+ Preference selectedCarrier = preference;
+
+ String networkStr = selectedCarrier.getTitle().toString();
+ if (DBG) log("selected network: " + networkStr);
+
+ Message msg = mHandler.obtainMessage(EVENT_NETWORK_SELECTION_DONE);
+ mPhone.selectNetworkManually(mNetworkMap.get(selectedCarrier), msg);
+
+ displayNetworkSeletionInProgress(networkStr);
+
+ handled = true;
+ }
+
+ return handled;
+ }
+
+ //implemented for DialogInterface.OnCancelListener
+ public void onCancel(DialogInterface dialog) {
+ // request that the service stop the query with this callback object.
+ try {
+ mNetworkQueryService.stopNetworkQuery(mCallback);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ finish();
+ }
+
+ public String getNormalizedCarrierName(OperatorInfo ni) {
+ if (ni != null) {
+ return ni.getOperatorAlphaLong() + " (" + ni.getOperatorNumeric() + ")";
+ }
+ return null;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ addPreferencesFromResource(R.xml.carrier_select);
+
+ mPhone = PhoneGlobals.getPhone();
+
+ mNetworkList = (PreferenceGroup) getPreferenceScreen().findPreference(LIST_NETWORKS_KEY);
+ mNetworkMap = new HashMap<Preference, OperatorInfo>();
+
+ mSearchButton = getPreferenceScreen().findPreference(BUTTON_SRCH_NETWRKS_KEY);
+ mAutoSelect = getPreferenceScreen().findPreference(BUTTON_AUTO_SELECT_KEY);
+
+ // Start the Network Query service, and bind it.
+ // The OS knows to start he service only once and keep the instance around (so
+ // long as startService is called) until a stopservice request is made. Since
+ // we want this service to just stay in the background until it is killed, we
+ // don't bother stopping it from our end.
+ startService (new Intent(this, NetworkQueryService.class));
+ bindService (new Intent(this, NetworkQueryService.class), mNetworkQueryServiceConnection,
+ Context.BIND_AUTO_CREATE);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mIsForeground = true;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mIsForeground = false;
+ }
+
+ /**
+ * Override onDestroy() to unbind the query service, avoiding service
+ * leak exceptions.
+ */
+ @Override
+ protected void onDestroy() {
+ // unbind the service.
+ unbindService(mNetworkQueryServiceConnection);
+
+ super.onDestroy();
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+
+ if ((id == DIALOG_NETWORK_SELECTION) || (id == DIALOG_NETWORK_LIST_LOAD) ||
+ (id == DIALOG_NETWORK_AUTO_SELECT)) {
+ ProgressDialog dialog = new ProgressDialog(this);
+ switch (id) {
+ case DIALOG_NETWORK_SELECTION:
+ // It would be more efficient to reuse this dialog by moving
+ // this setMessage() into onPreparedDialog() and NOT use
+ // removeDialog(). However, this is not possible since the
+ // message is rendered only 2 times in the ProgressDialog -
+ // after show() and before onCreate.
+ dialog.setMessage(mNetworkSelectMsg);
+ dialog.setCancelable(false);
+ dialog.setIndeterminate(true);
+ break;
+ case DIALOG_NETWORK_AUTO_SELECT:
+ dialog.setMessage(getResources().getString(R.string.register_automatically));
+ dialog.setCancelable(false);
+ dialog.setIndeterminate(true);
+ break;
+ case DIALOG_NETWORK_LIST_LOAD:
+ default:
+ // reinstate the cancelablity of the dialog.
+ dialog.setMessage(getResources().getString(R.string.load_networks_progress));
+ dialog.setCanceledOnTouchOutside(false);
+ dialog.setOnCancelListener(this);
+ break;
+ }
+ return dialog;
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPrepareDialog(int id, Dialog dialog) {
+ if ((id == DIALOG_NETWORK_SELECTION) || (id == DIALOG_NETWORK_LIST_LOAD) ||
+ (id == DIALOG_NETWORK_AUTO_SELECT)) {
+ // when the dialogs come up, we'll need to indicate that
+ // we're in a busy state to dissallow further input.
+ getPreferenceScreen().setEnabled(false);
+ }
+ }
+
+ private void displayEmptyNetworkList(boolean flag) {
+ mNetworkList.setTitle(flag ? R.string.empty_networks_list : R.string.label_available);
+ }
+
+ private void displayNetworkSeletionInProgress(String networkStr) {
+ // TODO: use notification manager?
+ mNetworkSelectMsg = getResources().getString(R.string.register_on_network, networkStr);
+
+ if (mIsForeground) {
+ showDialog(DIALOG_NETWORK_SELECTION);
+ }
+ }
+
+ private void displayNetworkQueryFailed(int error) {
+ String status = getResources().getString(R.string.network_query_error);
+
+ final PhoneGlobals app = PhoneGlobals.getInstance();
+ app.notificationMgr.postTransientNotification(
+ NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
+ }
+
+ private void displayNetworkSelectionFailed(Throwable ex) {
+ String status;
+
+ if ((ex != null && ex instanceof CommandException) &&
+ ((CommandException)ex).getCommandError()
+ == CommandException.Error.ILLEGAL_SIM_OR_ME)
+ {
+ status = getResources().getString(R.string.not_allowed);
+ } else {
+ status = getResources().getString(R.string.connect_later);
+ }
+
+ final PhoneGlobals app = PhoneGlobals.getInstance();
+ app.notificationMgr.postTransientNotification(
+ NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
+ }
+
+ private void displayNetworkSelectionSucceeded() {
+ String status = getResources().getString(R.string.registration_done);
+
+ final PhoneGlobals app = PhoneGlobals.getInstance();
+ app.notificationMgr.postTransientNotification(
+ NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
+
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ finish();
+ }
+ }, 3000);
+ }
+
+ private void loadNetworksList() {
+ if (DBG) log("load networks list...");
+
+ if (mIsForeground) {
+ showDialog(DIALOG_NETWORK_LIST_LOAD);
+ }
+
+ // delegate query request to the service.
+ try {
+ mNetworkQueryService.startNetworkQuery(mCallback);
+ } catch (RemoteException e) {
+ }
+
+ displayEmptyNetworkList(false);
+ }
+
+ /**
+ * networksListLoaded has been rewritten to take an array of
+ * OperatorInfo objects and a status field, instead of an
+ * AsyncResult. Otherwise, the functionality which takes the
+ * OperatorInfo array and creates a list of preferences from it,
+ * remains unchanged.
+ */
+ private void networksListLoaded(List<OperatorInfo> result, int status) {
+ if (DBG) log("networks list loaded");
+
+ // update the state of the preferences.
+ if (DBG) log("hideProgressPanel");
+
+
+ // Always try to dismiss the dialog because activity may
+ // be moved to background after dialog is shown.
+ try {
+ dismissDialog(DIALOG_NETWORK_LIST_LOAD);
+ } catch (IllegalArgumentException e) {
+ // It's not a error in following scenario, we just ignore it.
+ // "Load list" dialog will not show, if NetworkQueryService is
+ // connected after this activity is moved to background.
+ if (DBG) log("Fail to dismiss network load list dialog");
+ }
+
+ getPreferenceScreen().setEnabled(true);
+ clearList();
+
+ if (status != NetworkQueryService.QUERY_OK) {
+ if (DBG) log("error while querying available networks");
+ displayNetworkQueryFailed(status);
+ displayEmptyNetworkList(true);
+ } else {
+ if (result != null){
+ displayEmptyNetworkList(false);
+
+ // create a preference for each item in the list.
+ // just use the operator name instead of the mildly
+ // confusing mcc/mnc.
+ for (OperatorInfo ni : result) {
+ Preference carrier = new Preference(this, null);
+ carrier.setTitle(getNetworkTitle(ni));
+ carrier.setPersistent(false);
+ mNetworkList.addPreference(carrier);
+ mNetworkMap.put(carrier, ni);
+
+ if (DBG) log(" " + ni);
+ }
+
+ } else {
+ displayEmptyNetworkList(true);
+ }
+ }
+ }
+
+ /**
+ * Returns the title of the network obtained in the manual search.
+ *
+ * @param OperatorInfo contains the information of the network.
+ *
+ * @return Long Name if not null/empty, otherwise Short Name if not null/empty,
+ * else MCCMNC string.
+ */
+
+ private String getNetworkTitle(OperatorInfo ni) {
+ if (!TextUtils.isEmpty(ni.getOperatorAlphaLong())) {
+ return ni.getOperatorAlphaLong();
+ } else if (!TextUtils.isEmpty(ni.getOperatorAlphaShort())) {
+ return ni.getOperatorAlphaShort();
+ } else {
+ return ni.getOperatorNumeric();
+ }
+ }
+
+ private void clearList() {
+ for (Preference p : mNetworkMap.keySet()) {
+ mNetworkList.removePreference(p);
+ }
+ mNetworkMap.clear();
+ }
+
+ private void selectNetworkAutomatic() {
+ if (DBG) log("select network automatically...");
+ if (mIsForeground) {
+ showDialog(DIALOG_NETWORK_AUTO_SELECT);
+ }
+
+ Message msg = mHandler.obtainMessage(EVENT_AUTO_SELECT_DONE);
+ mPhone.setNetworkSelectionModeAutomatic(msg);
+ }
+
+ private void log(String msg) {
+ Log.d(LOG_TAG, "[NetworksList] " + msg);
+ }
+}