/*
* 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 java.util.HashMap;
import java.util.List;
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.content.res.Resources;
import android.net.ConnectivityManager;
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.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.MsmsConstants;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.gsm.NetworkInfo;
/**
* "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 = true;
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, NetworkInfo> 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 TelephonyManager mTelephonyManager; //add by liguxiang 11-14-11 for NEWMS00139542
private ConnectivityManager cm;
private static final String CHINA_MOBILE = "CHINA MOBILE";
private static final String CHN_CUGSM = "CHN-CUGSM";
private static final String CHINA_MOBILE_IC = "46000";
private static final String CHN_CUGSM_IC = "46001";
private int mSubId = 0;
ProgressDialog dialogLoaded;
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_NETWORK_SCAN_COMPLETED:
networksListLoaded ((List<NetworkInfo>) msg.obj, msg.arg1);
break;
case EVENT_NETWORK_SELECTION_DONE:
if (DBG) log("hideProgressPanel");
removeDialog(DIALOG_NETWORK_SELECTION);
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");
removeDialog(DIALOG_NETWORK_AUTO_SELECT);
/*
if (mIsForeground) {
dismissDialog(DIALOG_NETWORK_AUTO_SELECT);
}*/
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<NetworkInfo> 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) {
if(cm.getMobileDataEnabledByPhoneId(mSubId)){
handled=false;
Toast.makeText(NetworkSetting.this, R.string.toast_message_data_business_on, Toast.LENGTH_LONG).show();
}else{
loadNetworksList();
handled = true;
}
} else if (preference == mAutoSelect) {
getPreferenceScreen().setEnabled(false);
selectNetworkAutomatic();
handled = true;
} else {
if(cm.getMobileDataEnabledByPhoneId(mSubId)){
handled=false;
Toast.makeText(NetworkSetting.this, R.string.toast_message_data_business_on, Toast.LENGTH_LONG).show();
}else{
getPreferenceScreen().setEnabled(false);
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();
}
private String getDisplayStringFromAct(int act) {
if (act == NetworkInfo.ACT_UTRAN) {
return "3G";
} else {
return "2G";
}
}
public String getNormalizedCarrierName(NetworkInfo ni) {
if (ni != null) {
Resources res = getResources();
String state = getNetworkState(ni.getState());
if (TextUtils.isEmpty(ni.getOperatorAlphaLong())) {
String numberIC = ni.getOperatorNumeric().trim();
if(CHINA_MOBILE_IC.equals(numberIC)) {
return res.getText(R.string.china_mobile_provider) + " "
+ getDisplayStringFromAct(ni.getAct()) + state;
}
else if (CHN_CUGSM_IC.equals(numberIC)) {
return res.getText(R.string.chn_cugsm_provider) + " "
+ getDisplayStringFromAct(ni.getAct()) + state;
}
else{
return numberIC + " " + getDisplayStringFromAct(ni.getAct()) + state;
}
} else {
String alphaLong = ni.getOperatorAlphaLong().trim();
if(CHINA_MOBILE.equals(alphaLong)) {
return res.getText(R.string.china_mobile_provider) + " "
+ getDisplayStringFromAct(ni.getAct()) + state;
}
else if(CHN_CUGSM.equals(alphaLong)) {
return res.getText(R.string.chn_cugsm_provider) + " "
+ getDisplayStringFromAct(ni.getAct()) + state;
}
else {
return alphaLong + " " + getDisplayStringFromAct(ni.getAct()) + state;
}
}
}
return null;
}
public String getNetworkState(NetworkInfo.State state) {
Resources res = getResources();
if(state == null) {
return "";
}
else if(state == NetworkInfo.State.FORBIDDEN) {
return ""+" (" + res.getText(R.string.network_inhibit) + ")";
}
else if(state == NetworkInfo.State.UNKNOWN) {
return ""+" (" + res.getText(R.string.network_unknown) + ")";
}
else {
return "";
}
}
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.carrier_select);
mSubId = getIntent().getIntExtra(MobileNetworkSettings.SUB_ID, 0);
if (TelephonyManager.getPhoneCount() > 1) {
if (mSubId == 0) {
setTitle(getResources().getString(R.string.sim1)
+ getResources().getString(R.string.label_available));
} else if (mSubId == 1) {
setTitle(getResources().getString(R.string.sim2)
+ getResources().getString(R.string.label_available));
}
}
mPhone = PhoneApp.getInstance().getPhone(mSubId);
cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
mNetworkList = (PreferenceGroup) getPreferenceScreen().findPreference(LIST_NETWORKS_KEY);
mNetworkMap = new HashMap<Preference, NetworkInfo>();
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.
//add by liguxiang 11-14-11 for NEWMS00139542 begin
mTelephonyManager = (TelephonyManager)getSystemService(PhoneFactory.getServiceName(Context.TELEPHONY_SERVICE, mSubId));
Log.d("ligx","*************** has Icc Card :" + mTelephonyManager.hasIccCard());
if (mTelephonyManager.hasIccCard()) {
Intent intent = new Intent(this, NetworkQueryService.class);
intent.putExtra(MsmsConstants.SUBSCRIPTION_KEY, mSubId);
startService(intent);
bindService(new Intent(this, NetworkQueryService.class),
mNetworkQueryServiceConnection, Context.BIND_AUTO_CREATE);
} else {
mSearchButton.setEnabled(false);
mAutoSelect.setEnabled(false);
}
//add by liguxiang 11-14-11 for NEWMS00139542 end
dialogLoaded = new ProgressDialog(this);
}
@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.
//add by liguxiang 11-14-11 for NEWMS00139542 begin
if (mTelephonyManager.hasIccCard()) {
unbindService(mNetworkQueryServiceConnection);
}
if ((dialogLoaded != null) && (dialogLoaded.isShowing())) {
dialogLoaded.dismiss();
}
//add by liguxiang 11-14-11 for NEWMS00139542 end
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;
default:
}
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);
PhoneApp.getInstance().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);
}
PhoneApp.getInstance().notificationMgr.postTransientNotification(
NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
getPreferenceScreen().setEnabled(true);
}
private void displayNetworkSelectionSucceeded() {
String status = getResources().getString(R.string.registration_done);
PhoneApp.getInstance().notificationMgr.postTransientNotification(
NotificationMgr.NETWORK_SELECTION_NOTIFICATION, status);
mHandler.postDelayed(new Runnable() {
public void run() {
finish();
}
}, 1000);
}
public void creatDialog() {
dialogLoaded.setMessage(getResources().getString(R.string.load_networks_progress));
dialogLoaded.setCancelable(true);
dialogLoaded.setOnCancelListener(this);
}
private void loadNetworksList() {
if (DBG) log("load networks list...");
creatDialog();
if (mIsForeground) {
dialogLoaded.show();
getPreferenceScreen().setEnabled(false);
}
// delegate query request to the service.
try {
mNetworkQueryService.startNetworkQuery(mCallback);
} catch (RemoteException e) {
}
displayEmptyNetworkList(false);
}
/**
* networksListLoaded has been rewritten to take an array of
* NetworkInfo objects and a status field, instead of an
* AsyncResult. Otherwise, the functionality which takes the
* NetworkInfo array and creates a list of preferences from it,
* remains unchanged.
*/
private void networksListLoaded(List<NetworkInfo> result, int status) {
if (DBG) log("networks list loaded");
// update the state of the preferences.
if (DBG) log("hideProgressPanel");
if (dialogLoaded != null) {
log("dialog is showing " + dialogLoaded.isShowing());
dialogLoaded.dismiss();
}
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 (NetworkInfo ni : result) {
Preference carrier = new Preference(this, null);
//carrier.setTitle(ni.getOperatorAlphaLong());
carrier.setTitle(getNormalizedCarrierName(ni));
carrier.setPersistent(false);
mNetworkList.addPreference(carrier);
mNetworkMap.put(carrier, ni);
if (DBG) log(" " + ni);
}
} else {
displayEmptyNetworkList(true);
}
}
}
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);
}
}