diff options
Diffstat (limited to 'src/com/android/phone/NetworkSetting.java')
-rw-r--r-- | src/com/android/phone/NetworkSetting.java | 478 |
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); + } +} |