Home | History | Annotate | Download | only in settings
      1 /*
      2  * Copyright (C) 2009 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 
     17 package com.android.settings;
     18 
     19 
     20 import android.app.Activity;
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.app.admin.DevicePolicyManager;
     24 import android.content.ActivityNotFoundException;
     25 import android.content.Context;
     26 import android.content.DialogInterface;
     27 import android.content.Intent;
     28 import android.content.pm.PackageManager;
     29 import android.content.res.Resources;
     30 import android.net.ConnectivityManager;
     31 import android.net.NetworkInfo;
     32 import android.net.Uri;
     33 import android.nfc.NfcAdapter;
     34 import android.nfc.NfcManager;
     35 import android.os.Bundle;
     36 import android.os.SystemProperties;
     37 import android.os.UserHandle;
     38 import android.os.UserManager;
     39 import android.provider.SearchIndexableResource;
     40 import android.provider.Settings;
     41 import android.support.v14.preference.SwitchPreference;
     42 import android.support.v7.preference.Preference;
     43 import android.support.v7.preference.PreferenceScreen;
     44 import android.telephony.TelephonyManager;
     45 import android.text.TextUtils;
     46 import android.util.Log;
     47 
     48 import com.android.ims.ImsManager;
     49 import com.android.internal.logging.MetricsProto.MetricsEvent;
     50 import com.android.internal.telephony.TelephonyIntents;
     51 import com.android.internal.telephony.TelephonyProperties;
     52 import com.android.settings.nfc.NfcEnabler;
     53 import com.android.settings.search.BaseSearchIndexProvider;
     54 import com.android.settings.search.Indexable;
     55 import com.android.settingslib.RestrictedLockUtils;
     56 import com.android.settingslib.RestrictedPreference;
     57 
     58 import java.util.ArrayList;
     59 import java.util.Arrays;
     60 import java.util.List;
     61 
     62 public class WirelessSettings extends SettingsPreferenceFragment implements Indexable {
     63     private static final String TAG = "WirelessSettings";
     64 
     65     private static final String KEY_TOGGLE_AIRPLANE = "toggle_airplane";
     66     private static final String KEY_TOGGLE_NFC = "toggle_nfc";
     67     private static final String KEY_WIMAX_SETTINGS = "wimax_settings";
     68     private static final String KEY_ANDROID_BEAM_SETTINGS = "android_beam_settings";
     69     private static final String KEY_VPN_SETTINGS = "vpn_settings";
     70     private static final String KEY_TETHER_SETTINGS = "tether_settings";
     71     private static final String KEY_PROXY_SETTINGS = "proxy_settings";
     72     private static final String KEY_MOBILE_NETWORK_SETTINGS = "mobile_network_settings";
     73     private static final String KEY_MANAGE_MOBILE_PLAN = "manage_mobile_plan";
     74     private static final String KEY_WFC_SETTINGS = "wifi_calling_settings";
     75 
     76     public static final String EXIT_ECM_RESULT = "exit_ecm_result";
     77     public static final int REQUEST_CODE_EXIT_ECM = 1;
     78 
     79     private AirplaneModeEnabler mAirplaneModeEnabler;
     80     private SwitchPreference mAirplaneModePreference;
     81     private NfcEnabler mNfcEnabler;
     82     private NfcAdapter mNfcAdapter;
     83 
     84     private ConnectivityManager mCm;
     85     private TelephonyManager mTm;
     86     private PackageManager mPm;
     87     private UserManager mUm;
     88 
     89     private static final int MANAGE_MOBILE_PLAN_DIALOG_ID = 1;
     90     private static final String SAVED_MANAGE_MOBILE_PLAN_MSG = "mManageMobilePlanMessage";
     91 
     92     private PreferenceScreen mButtonWfc;
     93 
     94     /**
     95      * Invoked on each preference click in this hierarchy, overrides
     96      * PreferenceFragment's implementation.  Used to make sure we track the
     97      * preference click events.
     98      */
     99     @Override
    100     public boolean onPreferenceTreeClick(Preference preference) {
    101         log("onPreferenceTreeClick: preference=" + preference);
    102         if (preference == mAirplaneModePreference && Boolean.parseBoolean(
    103                 SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
    104             // In ECM mode launch ECM app dialog
    105             startActivityForResult(
    106                 new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
    107                 REQUEST_CODE_EXIT_ECM);
    108             return true;
    109         } else if (preference == findPreference(KEY_MANAGE_MOBILE_PLAN)) {
    110             onManageMobilePlanClick();
    111         }
    112         // Let the intents be launched by the Preference manager
    113         return super.onPreferenceTreeClick(preference);
    114     }
    115 
    116     private String mManageMobilePlanMessage;
    117     public void onManageMobilePlanClick() {
    118         log("onManageMobilePlanClick:");
    119         mManageMobilePlanMessage = null;
    120         Resources resources = getActivity().getResources();
    121 
    122         NetworkInfo ni = mCm.getActiveNetworkInfo();
    123         if (mTm.hasIccCard() && (ni != null)) {
    124             // Check for carrier apps that can handle provisioning first
    125             Intent provisioningIntent = new Intent(TelephonyIntents.ACTION_CARRIER_SETUP);
    126             List<String> carrierPackages =
    127                     mTm.getCarrierPackageNamesForIntent(provisioningIntent);
    128             if (carrierPackages != null && !carrierPackages.isEmpty()) {
    129                 if (carrierPackages.size() != 1) {
    130                     Log.w(TAG, "Multiple matching carrier apps found, launching the first.");
    131                 }
    132                 provisioningIntent.setPackage(carrierPackages.get(0));
    133                 startActivity(provisioningIntent);
    134                 return;
    135             }
    136 
    137             // Get provisioning URL
    138             String url = mCm.getMobileProvisioningUrl();
    139             if (!TextUtils.isEmpty(url)) {
    140                 Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
    141                         Intent.CATEGORY_APP_BROWSER);
    142                 intent.setData(Uri.parse(url));
    143                 intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
    144                         Intent.FLAG_ACTIVITY_NEW_TASK);
    145                 try {
    146                     startActivity(intent);
    147                 } catch (ActivityNotFoundException e) {
    148                     Log.w(TAG, "onManageMobilePlanClick: startActivity failed" + e);
    149                 }
    150             } else {
    151                 // No provisioning URL
    152                 String operatorName = mTm.getSimOperatorName();
    153                 if (TextUtils.isEmpty(operatorName)) {
    154                     // Use NetworkOperatorName as second choice in case there is no
    155                     // SPN (Service Provider Name on the SIM). Such as with T-mobile.
    156                     operatorName = mTm.getNetworkOperatorName();
    157                     if (TextUtils.isEmpty(operatorName)) {
    158                         mManageMobilePlanMessage = resources.getString(
    159                                 R.string.mobile_unknown_sim_operator);
    160                     } else {
    161                         mManageMobilePlanMessage = resources.getString(
    162                                 R.string.mobile_no_provisioning_url, operatorName);
    163                     }
    164                 } else {
    165                     mManageMobilePlanMessage = resources.getString(
    166                             R.string.mobile_no_provisioning_url, operatorName);
    167                 }
    168             }
    169         } else if (mTm.hasIccCard() == false) {
    170             // No sim card
    171             mManageMobilePlanMessage = resources.getString(R.string.mobile_insert_sim_card);
    172         } else {
    173             // NetworkInfo is null, there is no connection
    174             mManageMobilePlanMessage = resources.getString(R.string.mobile_connect_to_internet);
    175         }
    176         if (!TextUtils.isEmpty(mManageMobilePlanMessage)) {
    177             log("onManageMobilePlanClick: message=" + mManageMobilePlanMessage);
    178             showDialog(MANAGE_MOBILE_PLAN_DIALOG_ID);
    179         }
    180     }
    181 
    182     @Override
    183     public Dialog onCreateDialog(int dialogId) {
    184         log("onCreateDialog: dialogId=" + dialogId);
    185         switch (dialogId) {
    186             case MANAGE_MOBILE_PLAN_DIALOG_ID:
    187                 return new AlertDialog.Builder(getActivity())
    188                             .setMessage(mManageMobilePlanMessage)
    189                             .setCancelable(false)
    190                             .setPositiveButton(com.android.internal.R.string.ok,
    191                                     new DialogInterface.OnClickListener() {
    192                                 @Override
    193                                 public void onClick(DialogInterface dialog, int id) {
    194                                     log("MANAGE_MOBILE_PLAN_DIALOG.onClickListener id=" + id);
    195                                     mManageMobilePlanMessage = null;
    196                                 }
    197                             })
    198                             .create();
    199         }
    200         return super.onCreateDialog(dialogId);
    201     }
    202 
    203     private void log(String s) {
    204         Log.d(TAG, s);
    205     }
    206 
    207     @Override
    208     protected int getMetricsCategory() {
    209         return MetricsEvent.WIRELESS;
    210     }
    211 
    212     @Override
    213     public void onCreate(Bundle savedInstanceState) {
    214         super.onCreate(savedInstanceState);
    215         if (savedInstanceState != null) {
    216             mManageMobilePlanMessage = savedInstanceState.getString(SAVED_MANAGE_MOBILE_PLAN_MSG);
    217         }
    218         log("onCreate: mManageMobilePlanMessage=" + mManageMobilePlanMessage);
    219 
    220         mCm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    221         mTm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    222         mPm = getPackageManager();
    223         mUm = (UserManager) getSystemService(Context.USER_SERVICE);
    224 
    225         addPreferencesFromResource(R.xml.wireless_settings);
    226 
    227         final boolean isAdmin = mUm.isAdminUser();
    228 
    229         final Activity activity = getActivity();
    230         mAirplaneModePreference = (SwitchPreference) findPreference(KEY_TOGGLE_AIRPLANE);
    231         SwitchPreference nfc = (SwitchPreference) findPreference(KEY_TOGGLE_NFC);
    232         RestrictedPreference androidBeam = (RestrictedPreference) findPreference(
    233                 KEY_ANDROID_BEAM_SETTINGS);
    234 
    235         mAirplaneModeEnabler = new AirplaneModeEnabler(activity, mAirplaneModePreference);
    236         mNfcEnabler = new NfcEnabler(activity, nfc, androidBeam);
    237 
    238         mButtonWfc = (PreferenceScreen) findPreference(KEY_WFC_SETTINGS);
    239 
    240         String toggleable = Settings.Global.getString(activity.getContentResolver(),
    241                 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
    242 
    243         //enable/disable wimax depending on the value in config.xml
    244         final boolean isWimaxEnabled = isAdmin && this.getResources().getBoolean(
    245                 com.android.internal.R.bool.config_wimaxEnabled);
    246         if (!isWimaxEnabled || RestrictedLockUtils.hasBaseUserRestriction(activity,
    247                 UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, UserHandle.myUserId())) {
    248             PreferenceScreen root = getPreferenceScreen();
    249             Preference ps = findPreference(KEY_WIMAX_SETTINGS);
    250             if (ps != null) root.removePreference(ps);
    251         } else {
    252             if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_WIMAX )
    253                     && isWimaxEnabled) {
    254                 Preference ps = findPreference(KEY_WIMAX_SETTINGS);
    255                 ps.setDependency(KEY_TOGGLE_AIRPLANE);
    256             }
    257         }
    258 
    259         // Manually set dependencies for Wifi when not toggleable.
    260         if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_WIFI)) {
    261             findPreference(KEY_VPN_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
    262         }
    263         // Disable VPN.
    264         // TODO: http://b/23693383
    265         if (!isAdmin || RestrictedLockUtils.hasBaseUserRestriction(activity,
    266                 UserManager.DISALLOW_CONFIG_VPN, UserHandle.myUserId())) {
    267             removePreference(KEY_VPN_SETTINGS);
    268         }
    269 
    270         // Manually set dependencies for Bluetooth when not toggleable.
    271         if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_BLUETOOTH)) {
    272             // No bluetooth-dependent items in the list. Code kept in case one is added later.
    273         }
    274 
    275         // Manually set dependencies for NFC when not toggleable.
    276         if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_NFC)) {
    277             findPreference(KEY_TOGGLE_NFC).setDependency(KEY_TOGGLE_AIRPLANE);
    278             findPreference(KEY_ANDROID_BEAM_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
    279         }
    280 
    281         // Remove NFC if not available
    282         mNfcAdapter = NfcAdapter.getDefaultAdapter(activity);
    283         if (mNfcAdapter == null) {
    284             getPreferenceScreen().removePreference(nfc);
    285             getPreferenceScreen().removePreference(androidBeam);
    286             mNfcEnabler = null;
    287         }
    288 
    289         // Remove Mobile Network Settings and Manage Mobile Plan for secondary users,
    290         // if it's a wifi-only device.
    291         if (!isAdmin || Utils.isWifiOnly(getActivity()) ||
    292                 RestrictedLockUtils.hasBaseUserRestriction(activity,
    293                         UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, UserHandle.myUserId())) {
    294             removePreference(KEY_MOBILE_NETWORK_SETTINGS);
    295             removePreference(KEY_MANAGE_MOBILE_PLAN);
    296         }
    297         // Remove Mobile Network Settings and Manage Mobile Plan
    298         // if config_show_mobile_plan sets false.
    299         final boolean isMobilePlanEnabled = this.getResources().getBoolean(
    300                 R.bool.config_show_mobile_plan);
    301         if (!isMobilePlanEnabled) {
    302             Preference pref = findPreference(KEY_MANAGE_MOBILE_PLAN);
    303             if (pref != null) {
    304                 removePreference(KEY_MANAGE_MOBILE_PLAN);
    305             }
    306         }
    307 
    308         // Remove Airplane Mode settings if it's a stationary device such as a TV.
    309         if (mPm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
    310             removePreference(KEY_TOGGLE_AIRPLANE);
    311         }
    312 
    313         // Enable Proxy selector settings if allowed.
    314         Preference mGlobalProxy = findPreference(KEY_PROXY_SETTINGS);
    315         final DevicePolicyManager mDPM = (DevicePolicyManager)
    316                 activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
    317         // proxy UI disabled until we have better app support
    318         getPreferenceScreen().removePreference(mGlobalProxy);
    319         mGlobalProxy.setEnabled(mDPM.getGlobalProxyAdmin() == null);
    320 
    321         // Disable Tethering if it's not allowed or if it's a wifi-only device
    322         final ConnectivityManager cm =
    323                 (ConnectivityManager) activity.getSystemService(Context.CONNECTIVITY_SERVICE);
    324 
    325         final boolean adminDisallowedTetherConfig = RestrictedLockUtils.checkIfRestrictionEnforced(
    326                 activity, UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId()) != null;
    327         if ((!cm.isTetheringSupported() && !adminDisallowedTetherConfig) ||
    328                 RestrictedLockUtils.hasBaseUserRestriction(activity,
    329                         UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.myUserId())) {
    330             getPreferenceScreen().removePreference(findPreference(KEY_TETHER_SETTINGS));
    331         } else if (!adminDisallowedTetherConfig) {
    332             Preference p = findPreference(KEY_TETHER_SETTINGS);
    333             p.setTitle(com.android.settingslib.Utils.getTetheringLabel(cm));
    334 
    335             // Grey out if provisioning is not available.
    336             p.setEnabled(!TetherSettings
    337                     .isProvisioningNeededButUnavailable(getActivity()));
    338         }
    339     }
    340 
    341     @Override
    342     public void onResume() {
    343         super.onResume();
    344 
    345         mAirplaneModeEnabler.resume();
    346         if (mNfcEnabler != null) {
    347             mNfcEnabler.resume();
    348         }
    349 
    350         // update WFC setting
    351         final Context context = getActivity();
    352         if (ImsManager.isWfcEnabledByPlatform(context)) {
    353             getPreferenceScreen().addPreference(mButtonWfc);
    354 
    355             mButtonWfc.setSummary(WifiCallingSettings.getWfcModeSummary(
    356                     context, ImsManager.getWfcMode(context)));
    357         } else {
    358             removePreference(KEY_WFC_SETTINGS);
    359         }
    360     }
    361 
    362     @Override
    363     public void onSaveInstanceState(Bundle outState) {
    364         super.onSaveInstanceState(outState);
    365 
    366         if (!TextUtils.isEmpty(mManageMobilePlanMessage)) {
    367             outState.putString(SAVED_MANAGE_MOBILE_PLAN_MSG, mManageMobilePlanMessage);
    368         }
    369     }
    370 
    371     @Override
    372     public void onPause() {
    373         super.onPause();
    374 
    375         mAirplaneModeEnabler.pause();
    376         if (mNfcEnabler != null) {
    377             mNfcEnabler.pause();
    378         }
    379     }
    380 
    381     @Override
    382     public void onActivityResult(int requestCode, int resultCode, Intent data) {
    383         if (requestCode == REQUEST_CODE_EXIT_ECM) {
    384             Boolean isChoiceYes = data.getBooleanExtra(EXIT_ECM_RESULT, false);
    385             // Set Airplane mode based on the return value and checkbox state
    386             mAirplaneModeEnabler.setAirplaneModeInECM(isChoiceYes,
    387                     mAirplaneModePreference.isChecked());
    388         }
    389         super.onActivityResult(requestCode, resultCode, data);
    390     }
    391 
    392     @Override
    393     protected int getHelpResource() {
    394         return R.string.help_url_more_networks;
    395     }
    396 
    397     /**
    398      * For Search.
    399      */
    400     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
    401         new BaseSearchIndexProvider() {
    402             @Override
    403             public List<SearchIndexableResource> getXmlResourcesToIndex(
    404                     Context context, boolean enabled) {
    405                 SearchIndexableResource sir = new SearchIndexableResource(context);
    406                 sir.xmlResId = R.xml.wireless_settings;
    407                 return Arrays.asList(sir);
    408             }
    409 
    410             @Override
    411             public List<String> getNonIndexableKeys(Context context) {
    412                 final ArrayList<String> result = new ArrayList<String>();
    413 
    414                 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    415                 final boolean isSecondaryUser = !um.isAdminUser();
    416                 final boolean isWimaxEnabled = !isSecondaryUser
    417                         && context.getResources().getBoolean(
    418                         com.android.internal.R.bool.config_wimaxEnabled);
    419                 if (!isWimaxEnabled) {
    420                     result.add(KEY_WIMAX_SETTINGS);
    421                 }
    422 
    423                 if (isSecondaryUser) { // Disable VPN
    424                     result.add(KEY_VPN_SETTINGS);
    425                 }
    426 
    427                 // Remove NFC if not available
    428                 final NfcManager manager = (NfcManager)
    429                         context.getSystemService(Context.NFC_SERVICE);
    430                 if (manager != null) {
    431                     NfcAdapter adapter = manager.getDefaultAdapter();
    432                     if (adapter == null) {
    433                         result.add(KEY_TOGGLE_NFC);
    434                         result.add(KEY_ANDROID_BEAM_SETTINGS);
    435                     }
    436                 }
    437 
    438                 // Remove Mobile Network Settings and Manage Mobile Plan if it's a wifi-only device.
    439                 if (isSecondaryUser || Utils.isWifiOnly(context)) {
    440                     result.add(KEY_MOBILE_NETWORK_SETTINGS);
    441                     result.add(KEY_MANAGE_MOBILE_PLAN);
    442                 }
    443 
    444                 // Remove Mobile Network Settings and Manage Mobile Plan
    445                 // if config_show_mobile_plan sets false.
    446                 final boolean isMobilePlanEnabled = context.getResources().getBoolean(
    447                         R.bool.config_show_mobile_plan);
    448                 if (!isMobilePlanEnabled) {
    449                     result.add(KEY_MANAGE_MOBILE_PLAN);
    450                 }
    451 
    452                 final PackageManager pm = context.getPackageManager();
    453 
    454                 // Remove Airplane Mode settings if it's a stationary device such as a TV.
    455                 if (pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
    456                     result.add(KEY_TOGGLE_AIRPLANE);
    457                 }
    458 
    459                 // proxy UI disabled until we have better app support
    460                 result.add(KEY_PROXY_SETTINGS);
    461 
    462                 // Disable Tethering if it's not allowed or if it's a wifi-only device
    463                 ConnectivityManager cm = (ConnectivityManager)
    464                         context.getSystemService(Context.CONNECTIVITY_SERVICE);
    465                 if (isSecondaryUser || !cm.isTetheringSupported()) {
    466                     result.add(KEY_TETHER_SETTINGS);
    467                 }
    468 
    469                 if (!ImsManager.isWfcEnabledByPlatform(context)) {
    470                     result.add(KEY_WFC_SETTINGS);
    471                 }
    472 
    473                 return result;
    474             }
    475         };
    476 }
    477