/* * 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 com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import android.app.ActionBar; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.ConnectivityManager; import android.net.ThrottleManager; import android.net.Uri; import android.os.AsyncResult; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; import android.preference.CheckBoxPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceScreen; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import android.view.MenuItem; /** * "Mobile network settings" screen. This preference screen lets you * enable/disable mobile data, and control data roaming and other * network-specific mobile data features. It's used on non-voice-capable * tablets as well as regular phone devices. * * Note that this PreferenceActivity is part of the phone app, even though * you reach it from the "Wireless & Networks" section of the main * Settings app. It's not part of the "Call settings" hierarchy that's * available from the Phone app (see CallFeaturesSetting for that.) * * TODO: Rename this to be "NetworkSettings.java" to be more clear. * (But be careful in case the Settings app has any hardwired references * to this class name...) */ public class Settings extends PreferenceActivity implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener, Preference.OnPreferenceChangeListener{ // debug data private static final String LOG_TAG = "NetworkSettings"; private static final boolean DBG = true; public static final int REQUEST_CODE_EXIT_ECM = 17; //String keys for preference lookup private static final String BUTTON_DATA_ENABLED_KEY = "button_data_enabled_key"; private static final String BUTTON_DATA_USAGE_KEY = "button_data_usage_key"; private static final String BUTTON_PREFERED_NETWORK_MODE = "preferred_network_mode_key"; private static final String BUTTON_ROAMING_KEY = "button_roaming_key"; private static final String BUTTON_CDMA_LTE_DATA_SERVICE_KEY = "cdma_lte_data_service_key"; static final int preferredNetworkMode = Phone.PREFERRED_NT_MODE; //Information about logical "up" Activity private static final String UP_ACTIVITY_PACKAGE = "com.android.settings"; private static final String UP_ACTIVITY_CLASS = "com.android.settings.Settings$WirelessSettingsActivity"; //UI objects private ListPreference mButtonPreferredNetworkMode; private CheckBoxPreference mButtonDataRoam; private CheckBoxPreference mButtonDataEnabled; private Preference mLteDataServicePref; private Preference mButtonDataUsage; private DataUsageListener mDataUsageListener; private static final String iface = "rmnet0"; //TODO: this will go away private Phone mPhone; private MyHandler mHandler; private boolean mOkClicked; //GsmUmts options and Cdma options GsmUmtsOptions mGsmUmtsOptions; CdmaOptions mCdmaOptions; private Preference mClickedPreference; //This is a method implemented for DialogInterface.OnClickListener. // Used to dismiss the dialogs when they come up. public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { mPhone.setDataRoamingEnabled(true); mOkClicked = true; } else { // Reset the toggle mButtonDataRoam.setChecked(false); } } public void onDismiss(DialogInterface dialog) { // Assuming that onClick gets called first if (!mOkClicked) { mButtonDataRoam.setChecked(false); } } /** * Invoked on each preference click in this hierarchy, overrides * PreferenceActivity's implementation. Used to make sure we track the * preference click events. */ @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { /** TODO: Refactor and get rid of the if's using subclasses */ if (mGsmUmtsOptions != null && mGsmUmtsOptions.preferenceTreeClick(preference) == true) { return true; } else if (mCdmaOptions != null && mCdmaOptions.preferenceTreeClick(preference) == true) { if (Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { mClickedPreference = preference; // In ECM mode launch ECM app dialog startActivityForResult( new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null), REQUEST_CODE_EXIT_ECM); } return true; } else if (preference == mButtonPreferredNetworkMode) { //displays the value taken from the Settings.System int settingsNetworkMode = android.provider.Settings.Secure.getInt(mPhone.getContext(). getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode)); return true; } else if (preference == mButtonDataRoam) { if (DBG) log("onPreferenceTreeClick: preference == mButtonDataRoam."); //normally called on the toggle click if (mButtonDataRoam.isChecked()) { // First confirm with a warning dialog about charges mOkClicked = false; new AlertDialog.Builder(this).setMessage( getResources().getString(R.string.roaming_warning)) .setTitle(android.R.string.dialog_alert_title) .setIcon(android.R.drawable.ic_dialog_alert) .setPositiveButton(android.R.string.yes, this) .setNegativeButton(android.R.string.no, this) .show() .setOnDismissListener(this); } else { mPhone.setDataRoamingEnabled(false); } return true; } else if (preference == mButtonDataEnabled) { if (DBG) log("onPreferenceTreeClick: preference == mButtonDataEnabled."); ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); cm.setMobileDataEnabled(mButtonDataEnabled.isChecked()); return true; } else if (preference == mLteDataServicePref) { String tmpl = android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.SETUP_PREPAID_DATA_SERVICE_URL); if (!TextUtils.isEmpty(tmpl)) { TelephonyManager tm = (TelephonyManager) getSystemService( Context.TELEPHONY_SERVICE); String imsi = tm.getSubscriberId(); if (imsi == null) { imsi = ""; } final String url = TextUtils.isEmpty(tmpl) ? null : TextUtils.expandTemplate(tmpl, imsi).toString(); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); } else { android.util.Log.e(LOG_TAG, "Missing SETUP_PREPAID_DATA_SERVICE_URL"); } return true; } else { // if the button is anything but the simple toggle preference, // we'll need to disable all preferences to reject all click // events until the sub-activity's UI comes up. preferenceScreen.setEnabled(false); // Let the intents be launched by the Preference manager return false; } } @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.network_setting); mPhone = PhoneApp.getPhone(); mHandler = new MyHandler(); //get UI object references PreferenceScreen prefSet = getPreferenceScreen(); mButtonDataEnabled = (CheckBoxPreference) prefSet.findPreference(BUTTON_DATA_ENABLED_KEY); mButtonDataRoam = (CheckBoxPreference) prefSet.findPreference(BUTTON_ROAMING_KEY); mButtonPreferredNetworkMode = (ListPreference) prefSet.findPreference( BUTTON_PREFERED_NETWORK_MODE); mButtonDataUsage = prefSet.findPreference(BUTTON_DATA_USAGE_KEY); mLteDataServicePref = prefSet.findPreference(BUTTON_CDMA_LTE_DATA_SERVICE_KEY); boolean isLteOnCdma = mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE; if (getResources().getBoolean(R.bool.world_phone) == true) { // set the listener for the mButtonPreferredNetworkMode list preference so we can issue // change Preferred Network Mode. mButtonPreferredNetworkMode.setOnPreferenceChangeListener(this); //Get the networkMode from Settings.System and displays it int settingsNetworkMode = android.provider.Settings.Secure.getInt(mPhone.getContext(). getContentResolver(),android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); mButtonPreferredNetworkMode.setValue(Integer.toString(settingsNetworkMode)); mCdmaOptions = new CdmaOptions(this, prefSet, mPhone); mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet); } else { if (!isLteOnCdma) { prefSet.removePreference(mButtonPreferredNetworkMode); } int phoneType = mPhone.getPhoneType(); if (phoneType == Phone.PHONE_TYPE_CDMA) { mCdmaOptions = new CdmaOptions(this, prefSet, mPhone); if (isLteOnCdma) { mButtonPreferredNetworkMode.setOnPreferenceChangeListener(this); mButtonPreferredNetworkMode.setEntries( R.array.preferred_network_mode_choices_lte); mButtonPreferredNetworkMode.setEntryValues( R.array.preferred_network_mode_values_lte); int settingsNetworkMode = android.provider.Settings.Secure.getInt( mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); mButtonPreferredNetworkMode.setValue( Integer.toString(settingsNetworkMode)); } } else if (phoneType == Phone.PHONE_TYPE_GSM) { mGsmUmtsOptions = new GsmUmtsOptions(this, prefSet); } else { throw new IllegalStateException("Unexpected phone type: " + phoneType); } } final boolean missingDataServiceUrl = TextUtils.isEmpty( android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.SETUP_PREPAID_DATA_SERVICE_URL)); if (!isLteOnCdma || missingDataServiceUrl) { prefSet.removePreference(mLteDataServicePref); } else { android.util.Log.d(LOG_TAG, "keep ltePref"); } ThrottleManager tm = (ThrottleManager) getSystemService(Context.THROTTLE_SERVICE); mDataUsageListener = new DataUsageListener(this, mButtonDataUsage, prefSet); ActionBar actionBar = getActionBar(); if (actionBar != null) { // android.R.id.home will be triggered in onOptionsItemSelected() actionBar.setDisplayHomeAsUpEnabled(true); } } @Override protected void onResume() { super.onResume(); // upon resumption from the sub-activity, make sure we re-enable the // preferences. getPreferenceScreen().setEnabled(true); ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE); mButtonDataEnabled.setChecked(cm.getMobileDataEnabled()); // Set UI state in onResume because a user could go home, launch some // app to change this setting's backend, and re-launch this settings app // and the UI state would be inconsistent with actual state mButtonDataRoam.setChecked(mPhone.getDataRoamingEnabled()); if (getPreferenceScreen().findPreference(BUTTON_PREFERED_NETWORK_MODE) != null) { mPhone.getPreferredNetworkType(mHandler.obtainMessage( MyHandler.MESSAGE_GET_PREFERRED_NETWORK_TYPE)); } mDataUsageListener.resume(); } @Override protected void onPause() { super.onPause(); mDataUsageListener.pause(); } /** * Implemented to support onPreferenceChangeListener to look for preference * changes specifically on CLIR. * * @param preference is the preference to be changed, should be mButtonCLIR. * @param objValue should be the value of the selection, NOT its localized * display value. */ public boolean onPreferenceChange(Preference preference, Object objValue) { if (preference == mButtonPreferredNetworkMode) { //NOTE onPreferenceChange seems to be called even if there is no change //Check if the button value is changed from the System.Setting mButtonPreferredNetworkMode.setValue((String) objValue); int buttonNetworkMode; buttonNetworkMode = Integer.valueOf((String) objValue).intValue(); int settingsNetworkMode = android.provider.Settings.Secure.getInt( mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); if (buttonNetworkMode != settingsNetworkMode) { int modemNetworkMode; switch(buttonNetworkMode) { case Phone.NT_MODE_GLOBAL: modemNetworkMode = Phone.NT_MODE_GLOBAL; break; case Phone.NT_MODE_EVDO_NO_CDMA: modemNetworkMode = Phone.NT_MODE_EVDO_NO_CDMA; break; case Phone.NT_MODE_CDMA_NO_EVDO: modemNetworkMode = Phone.NT_MODE_CDMA_NO_EVDO; break; case Phone.NT_MODE_CDMA: modemNetworkMode = Phone.NT_MODE_CDMA; break; case Phone.NT_MODE_GSM_UMTS: modemNetworkMode = Phone.NT_MODE_GSM_UMTS; break; case Phone.NT_MODE_WCDMA_ONLY: modemNetworkMode = Phone.NT_MODE_WCDMA_ONLY; break; case Phone.NT_MODE_GSM_ONLY: modemNetworkMode = Phone.NT_MODE_GSM_ONLY; break; case Phone.NT_MODE_WCDMA_PREF: modemNetworkMode = Phone.NT_MODE_WCDMA_PREF; break; default: modemNetworkMode = Phone.PREFERRED_NT_MODE; } // If button has no valid selection && setting is LTE ONLY // mode, let the setting stay in LTE ONLY mode. UI is not // supported but LTE ONLY mode could be used in testing. if ((modemNetworkMode == Phone.PREFERRED_NT_MODE) && (settingsNetworkMode == Phone.NT_MODE_LTE_ONLY)) { return true; } UpdatePreferredNetworkModeSummary(buttonNetworkMode); android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, buttonNetworkMode ); //Set the modem network mode mPhone.setPreferredNetworkType(modemNetworkMode, mHandler .obtainMessage(MyHandler.MESSAGE_SET_PREFERRED_NETWORK_TYPE)); } } // always let the preference setting proceed. return true; } private class MyHandler extends Handler { private static final int MESSAGE_GET_PREFERRED_NETWORK_TYPE = 0; private static final int MESSAGE_SET_PREFERRED_NETWORK_TYPE = 1; @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_GET_PREFERRED_NETWORK_TYPE: handleGetPreferredNetworkTypeResponse(msg); break; case MESSAGE_SET_PREFERRED_NETWORK_TYPE: handleSetPreferredNetworkTypeResponse(msg); break; } } private void handleGetPreferredNetworkTypeResponse(Message msg) { AsyncResult ar = (AsyncResult) msg.obj; if (ar.exception == null) { int modemNetworkMode = ((int[])ar.result)[0]; if (DBG) { log ("handleGetPreferredNetworkTypeResponse: modemNetworkMode = " + modemNetworkMode); } int settingsNetworkMode = android.provider.Settings.Secure.getInt( mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode); if (DBG) { log("handleGetPreferredNetworkTypeReponse: settingsNetworkMode = " + settingsNetworkMode); } //check that modemNetworkMode is from an accepted value if (modemNetworkMode == Phone.NT_MODE_WCDMA_PREF || modemNetworkMode == Phone.NT_MODE_GSM_ONLY || modemNetworkMode == Phone.NT_MODE_WCDMA_ONLY || modemNetworkMode == Phone.NT_MODE_GSM_UMTS || modemNetworkMode == Phone.NT_MODE_CDMA || modemNetworkMode == Phone.NT_MODE_CDMA_NO_EVDO || modemNetworkMode == Phone.NT_MODE_EVDO_NO_CDMA || modemNetworkMode == Phone.NT_MODE_GLOBAL ) { if (DBG) { log("handleGetPreferredNetworkTypeResponse: if 1: modemNetworkMode = " + modemNetworkMode); } //check changes in modemNetworkMode and updates settingsNetworkMode if (modemNetworkMode != settingsNetworkMode) { if (DBG) { log("handleGetPreferredNetworkTypeResponse: if 2: " + "modemNetworkMode != settingsNetworkMode"); } settingsNetworkMode = modemNetworkMode; if (DBG) { log("handleGetPreferredNetworkTypeResponse: if 2: " + "settingsNetworkMode = " + settingsNetworkMode); } //changes the Settings.System accordingly to modemNetworkMode android.provider.Settings.Secure.putInt( mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, settingsNetworkMode ); } UpdatePreferredNetworkModeSummary(modemNetworkMode); // changes the mButtonPreferredNetworkMode accordingly to modemNetworkMode mButtonPreferredNetworkMode.setValue(Integer.toString(modemNetworkMode)); } else if (modemNetworkMode == Phone.NT_MODE_LTE_ONLY) { // LTE Only mode not yet supported on UI, but could be used for testing if (DBG) log("handleGetPreferredNetworkTypeResponse: lte only: no action"); } else { if (DBG) log("handleGetPreferredNetworkTypeResponse: else: reset to default"); resetNetworkModeToDefault(); } } } private void handleSetPreferredNetworkTypeResponse(Message msg) { AsyncResult ar = (AsyncResult) msg.obj; if (ar.exception == null) { int networkMode = Integer.valueOf( mButtonPreferredNetworkMode.getValue()).intValue(); android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, networkMode ); } else { mPhone.getPreferredNetworkType(obtainMessage(MESSAGE_GET_PREFERRED_NETWORK_TYPE)); } } private void resetNetworkModeToDefault() { //set the mButtonPreferredNetworkMode mButtonPreferredNetworkMode.setValue(Integer.toString(preferredNetworkMode)); //set the Settings.System android.provider.Settings.Secure.putInt(mPhone.getContext().getContentResolver(), android.provider.Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode ); //Set the Modem mPhone.setPreferredNetworkType(preferredNetworkMode, this.obtainMessage(MyHandler.MESSAGE_SET_PREFERRED_NETWORK_TYPE)); } } private void UpdatePreferredNetworkModeSummary(int NetworkMode) { switch(NetworkMode) { case Phone.NT_MODE_WCDMA_PREF: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_wcdma_perf_summary); break; case Phone.NT_MODE_GSM_ONLY: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_gsm_only_summary); break; case Phone.NT_MODE_WCDMA_ONLY: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_wcdma_only_summary); break; case Phone.NT_MODE_GSM_UMTS: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_gsm_wcdma_summary); break; case Phone.NT_MODE_CDMA: switch (mPhone.getLteOnCdmaMode()) { case Phone.LTE_ON_CDMA_TRUE: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_cdma_summary); break; case Phone.LTE_ON_CDMA_FALSE: default: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_cdma_evdo_summary); break; } break; case Phone.NT_MODE_CDMA_NO_EVDO: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_cdma_only_summary); break; case Phone.NT_MODE_EVDO_NO_CDMA: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_evdo_only_summary); break; case Phone.NT_MODE_GLOBAL: default: mButtonPreferredNetworkMode.setSummary( R.string.preferred_network_mode_lte_cdma_summary); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch(requestCode) { case REQUEST_CODE_EXIT_ECM: Boolean isChoiceYes = data.getBooleanExtra(EmergencyCallbackModeExitDialog.EXTRA_EXIT_ECM_RESULT, false); if (isChoiceYes) { // If the phone exits from ECM mode, show the CDMA Options mCdmaOptions.showDialog(mClickedPreference); } else { // do nothing } break; default: break; } } private static void log(String msg) { Log.d(LOG_TAG, msg); } @Override public boolean onOptionsItemSelected(MenuItem item) { final int itemId = item.getItemId(); if (itemId == android.R.id.home) { // See ActionBar#setDisplayHomeAsUpEnabled() // Commenting out "logical up" capability. This is a workaround for issue 5278083. // // Settings app may not launch this activity via UP_ACTIVITY_CLASS but the other // Activity that looks exactly same as UP_ACTIVITY_CLASS ("SubSettings" Activity). // At that moment, this Activity launches UP_ACTIVITY_CLASS on top of the Activity. // which confuses users. // TODO: introduce better mechanism for "up" capability here. /*Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(UP_ACTIVITY_PACKAGE, UP_ACTIVITY_CLASS); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent);*/ finish(); return true; } return super.onOptionsItemSelected(item); } }