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