2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
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.ComponentName;
26 import android.content.Context;
27 import android.content.DialogInterface;
28 import android.content.Intent;
29 import android.content.pm.PackageManager;
30 import android.content.res.Resources;
31 import android.net.ConnectivityManager;
32 import android.net.NetworkInfo;
33 import android.net.Uri;
34 import android.nfc.NfcAdapter;
35 import android.nfc.NfcManager;
36 import android.os.Bundle;
37 import android.os.SystemProperties;
38 import android.os.UserHandle;
39 import android.os.UserManager;
40 import android.preference.Preference;
41 import android.preference.Preference.OnPreferenceChangeListener;
42 import android.preference.PreferenceScreen;
43 import android.preference.SwitchPreference;
44 import android.provider.SearchIndexableResource;
45 import android.provider.Settings;
46 import android.telephony.TelephonyManager;
47 import android.text.TextUtils;
48 import android.util.Log;
50 import com.android.internal.telephony.SmsApplication;
51 import com.android.internal.telephony.SmsApplication.SmsApplicationData;
52 import com.android.internal.telephony.TelephonyIntents;
53 import com.android.internal.telephony.TelephonyProperties;
54 import com.android.settings.nfc.NfcEnabler;
55 import com.android.settings.search.BaseSearchIndexProvider;
56 import com.android.settings.search.Indexable;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Collection;
61 import java.util.List;
63 public class WirelessSettings extends SettingsPreferenceFragment
64 implements OnPreferenceChangeListener, Indexable {
65 private static final String TAG = "WirelessSettings";
67 private static final String KEY_TOGGLE_AIRPLANE = "toggle_airplane";
68 private static final String KEY_TOGGLE_NFC = "toggle_nfc";
69 private static final String KEY_WIMAX_SETTINGS = "wimax_settings";
70 private static final String KEY_ANDROID_BEAM_SETTINGS = "android_beam_settings";
71 private static final String KEY_VPN_SETTINGS = "vpn_settings";
72 private static final String KEY_TETHER_SETTINGS = "tether_settings";
73 private static final String KEY_PROXY_SETTINGS = "proxy_settings";
74 private static final String KEY_MOBILE_NETWORK_SETTINGS = "mobile_network_settings";
75 private static final String KEY_MANAGE_MOBILE_PLAN = "manage_mobile_plan";
76 private static final String KEY_SMS_APPLICATION = "sms_application";
77 private static final String KEY_TOGGLE_NSD = "toggle_nsd"; //network service discovery
78 private static final String KEY_CELL_BROADCAST_SETTINGS = "cell_broadcast_settings";
80 public static final String EXIT_ECM_RESULT = "exit_ecm_result";
81 public static final int REQUEST_CODE_EXIT_ECM = 1;
83 private AirplaneModeEnabler mAirplaneModeEnabler;
84 private SwitchPreference mAirplaneModePreference;
85 private NfcEnabler mNfcEnabler;
86 private NfcAdapter mNfcAdapter;
87 private NsdEnabler mNsdEnabler;
89 private ConnectivityManager mCm;
90 private TelephonyManager mTm;
91 private PackageManager mPm;
92 private UserManager mUm;
94 private static final int MANAGE_MOBILE_PLAN_DIALOG_ID = 1;
95 private static final String SAVED_MANAGE_MOBILE_PLAN_MSG = "mManageMobilePlanMessage";
97 private AppListPreference mSmsApplicationPreference;
100 * Invoked on each preference click in this hierarchy, overrides
101 * PreferenceFragment's implementation. Used to make sure we track the
102 * preference click events.
105 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
106 log("onPreferenceTreeClick: preference=" + preference);
107 if (preference == mAirplaneModePreference && Boolean.parseBoolean(
108 SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
109 // In ECM mode launch ECM app dialog
110 startActivityForResult(
111 new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
112 REQUEST_CODE_EXIT_ECM);
114 } else if (preference == findPreference(KEY_MANAGE_MOBILE_PLAN)) {
115 onManageMobilePlanClick();
117 // Let the intents be launched by the Preference manager
118 return super.onPreferenceTreeClick(preferenceScreen, preference);
121 private String mManageMobilePlanMessage;
122 public void onManageMobilePlanClick() {
123 log("onManageMobilePlanClick:");
124 mManageMobilePlanMessage = null;
125 Resources resources = getActivity().getResources();
127 NetworkInfo ni = mCm.getProvisioningOrActiveNetworkInfo();
128 if (mTm.hasIccCard() && (ni != null)) {
129 // Check for carrier apps that can handle provisioning first
130 Intent provisioningIntent = new Intent(TelephonyIntents.ACTION_CARRIER_SETUP);
131 List<String> carrierPackages =
132 mTm.getCarrierPackageNamesForIntent(provisioningIntent);
133 if (carrierPackages != null && !carrierPackages.isEmpty()) {
134 if (carrierPackages.size() != 1) {
135 Log.w(TAG, "Multiple matching carrier apps found, launching the first.");
137 provisioningIntent.setPackage(carrierPackages.get(0));
138 startActivity(provisioningIntent);
142 // Get provisioning URL
143 String url = mCm.getMobileProvisioningUrl();
144 if (!TextUtils.isEmpty(url)) {
145 Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
146 Intent.CATEGORY_APP_BROWSER);
147 intent.setData(Uri.parse(url));
148 intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
149 Intent.FLAG_ACTIVITY_NEW_TASK);
151 startActivity(intent);
152 } catch (ActivityNotFoundException e) {
153 Log.w(TAG, "onManageMobilePlanClick: startActivity failed" + e);
156 // No provisioning URL
157 String operatorName = mTm.getSimOperatorName();
158 if (TextUtils.isEmpty(operatorName)) {
159 // Use NetworkOperatorName as second choice in case there is no
160 // SPN (Service Provider Name on the SIM). Such as with T-mobile.
161 operatorName = mTm.getNetworkOperatorName();
162 if (TextUtils.isEmpty(operatorName)) {
163 mManageMobilePlanMessage = resources.getString(
164 R.string.mobile_unknown_sim_operator);
166 mManageMobilePlanMessage = resources.getString(
167 R.string.mobile_no_provisioning_url, operatorName);
170 mManageMobilePlanMessage = resources.getString(
171 R.string.mobile_no_provisioning_url, operatorName);
174 } else if (mTm.hasIccCard() == false) {
176 mManageMobilePlanMessage = resources.getString(R.string.mobile_insert_sim_card);
178 // NetworkInfo is null, there is no connection
179 mManageMobilePlanMessage = resources.getString(R.string.mobile_connect_to_internet);
181 if (!TextUtils.isEmpty(mManageMobilePlanMessage)) {
182 log("onManageMobilePlanClick: message=" + mManageMobilePlanMessage);
183 showDialog(MANAGE_MOBILE_PLAN_DIALOG_ID);
187 private void initSmsApplicationSetting() {
188 log("initSmsApplicationSetting:");
189 Collection<SmsApplicationData> smsApplications =
190 SmsApplication.getApplicationCollection(getActivity());
192 // If the list is empty the dialog will be empty, but we will not crash.
193 int count = smsApplications.size();
194 String[] packageNames = new String[count];
196 for (SmsApplicationData smsApplicationData : smsApplications) {
197 packageNames[i] = smsApplicationData.mPackageName;
200 String defaultPackageName = null;
201 ComponentName appName = SmsApplication.getDefaultSmsApplication(getActivity(), true);
202 if (appName != null) {
203 defaultPackageName = appName.getPackageName();
205 mSmsApplicationPreference.setPackageNames(packageNames, defaultPackageName);
209 public Dialog onCreateDialog(int dialogId) {
210 log("onCreateDialog: dialogId=" + dialogId);
212 case MANAGE_MOBILE_PLAN_DIALOG_ID:
213 return new AlertDialog.Builder(getActivity())
214 .setMessage(mManageMobilePlanMessage)
215 .setCancelable(false)
216 .setPositiveButton(com.android.internal.R.string.ok,
217 new DialogInterface.OnClickListener() {
219 public void onClick(DialogInterface dialog, int id) {
220 log("MANAGE_MOBILE_PLAN_DIALOG.onClickListener id=" + id);
221 mManageMobilePlanMessage = null;
226 return super.onCreateDialog(dialogId);
229 private void log(String s) {
233 public static boolean isRadioAllowed(Context context, String type) {
234 if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
237 // Here we use the same logic in onCreate().
238 String toggleable = Settings.Global.getString(context.getContentResolver(),
239 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
240 return toggleable != null && toggleable.contains(type);
243 private boolean isSmsSupported() {
244 // Some tablet has sim card but could not do telephony operations. Skip those.
245 return mTm.isSmsCapable();
249 public void onCreate(Bundle savedInstanceState) {
250 super.onCreate(savedInstanceState);
251 if (savedInstanceState != null) {
252 mManageMobilePlanMessage = savedInstanceState.getString(SAVED_MANAGE_MOBILE_PLAN_MSG);
254 log("onCreate: mManageMobilePlanMessage=" + mManageMobilePlanMessage);
256 mCm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
257 mTm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
258 mPm = getPackageManager();
259 mUm = (UserManager) getSystemService(Context.USER_SERVICE);
261 addPreferencesFromResource(R.xml.wireless_settings);
263 final int myUserId = UserHandle.myUserId();
264 final boolean isSecondaryUser = myUserId != UserHandle.USER_OWNER;
265 final boolean isRestrictedUser = mUm.getUserInfo(myUserId).isRestricted();
267 final Activity activity = getActivity();
268 mAirplaneModePreference = (SwitchPreference) findPreference(KEY_TOGGLE_AIRPLANE);
269 SwitchPreference nfc = (SwitchPreference) findPreference(KEY_TOGGLE_NFC);
270 PreferenceScreen androidBeam = (PreferenceScreen) findPreference(KEY_ANDROID_BEAM_SETTINGS);
271 SwitchPreference nsd = (SwitchPreference) findPreference(KEY_TOGGLE_NSD);
273 mAirplaneModeEnabler = new AirplaneModeEnabler(activity, mAirplaneModePreference);
274 mNfcEnabler = new NfcEnabler(activity, nfc, androidBeam);
276 mSmsApplicationPreference = (AppListPreference) findPreference(KEY_SMS_APPLICATION);
277 // Restricted users cannot currently read/write SMS.
278 if (isRestrictedUser) {
279 removePreference(KEY_SMS_APPLICATION);
281 mSmsApplicationPreference.setOnPreferenceChangeListener(this);
282 initSmsApplicationSetting();
285 // Remove NSD checkbox by default
286 getPreferenceScreen().removePreference(nsd);
287 //mNsdEnabler = new NsdEnabler(activity, nsd);
289 String toggleable = Settings.Global.getString(activity.getContentResolver(),
290 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
292 //enable/disable wimax depending on the value in config.xml
293 final boolean isWimaxEnabled = !isSecondaryUser && this.getResources().getBoolean(
294 com.android.internal.R.bool.config_wimaxEnabled);
296 || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
297 PreferenceScreen root = getPreferenceScreen();
298 Preference ps = (Preference) findPreference(KEY_WIMAX_SETTINGS);
299 if (ps != null) root.removePreference(ps);
301 if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_WIMAX )
303 Preference ps = (Preference) findPreference(KEY_WIMAX_SETTINGS);
304 ps.setDependency(KEY_TOGGLE_AIRPLANE);
308 // Manually set dependencies for Wifi when not toggleable.
309 if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_WIFI)) {
310 findPreference(KEY_VPN_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
313 if (isSecondaryUser || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
314 removePreference(KEY_VPN_SETTINGS);
317 // Manually set dependencies for Bluetooth when not toggleable.
318 if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_BLUETOOTH)) {
319 // No bluetooth-dependent items in the list. Code kept in case one is added later.
322 // Manually set dependencies for NFC when not toggleable.
323 if (toggleable == null || !toggleable.contains(Settings.Global.RADIO_NFC)) {
324 findPreference(KEY_TOGGLE_NFC).setDependency(KEY_TOGGLE_AIRPLANE);
325 findPreference(KEY_ANDROID_BEAM_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
328 // Remove NFC if not available
329 mNfcAdapter = NfcAdapter.getDefaultAdapter(activity);
330 if (mNfcAdapter == null) {
331 getPreferenceScreen().removePreference(nfc);
332 getPreferenceScreen().removePreference(androidBeam);
336 // Remove Mobile Network Settings and Manage Mobile Plan for secondary users,
337 // if it's a wifi-only device, or if the settings are restricted.
338 if (isSecondaryUser || Utils.isWifiOnly(getActivity())
339 || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
340 removePreference(KEY_MOBILE_NETWORK_SETTINGS);
341 removePreference(KEY_MANAGE_MOBILE_PLAN);
343 // Remove Mobile Network Settings and Manage Mobile Plan
344 // if config_show_mobile_plan sets false.
345 final boolean isMobilePlanEnabled = this.getResources().getBoolean(
346 R.bool.config_show_mobile_plan);
347 if (!isMobilePlanEnabled) {
348 Preference pref = findPreference(KEY_MANAGE_MOBILE_PLAN);
350 removePreference(KEY_MANAGE_MOBILE_PLAN);
354 // Remove SMS Application if the device does not support SMS
355 if (!isSmsSupported()) {
356 removePreference(KEY_SMS_APPLICATION);
359 // Remove Airplane Mode settings if it's a stationary device such as a TV.
360 if (mPm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
361 removePreference(KEY_TOGGLE_AIRPLANE);
364 // Enable Proxy selector settings if allowed.
365 Preference mGlobalProxy = findPreference(KEY_PROXY_SETTINGS);
366 final DevicePolicyManager mDPM = (DevicePolicyManager)
367 activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
368 // proxy UI disabled until we have better app support
369 getPreferenceScreen().removePreference(mGlobalProxy);
370 mGlobalProxy.setEnabled(mDPM.getGlobalProxyAdmin() == null);
372 // Disable Tethering if it's not allowed or if it's a wifi-only device
373 final ConnectivityManager cm =
374 (ConnectivityManager) activity.getSystemService(Context.CONNECTIVITY_SERVICE);
375 if (isSecondaryUser || !cm.isTetheringSupported()
376 || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
377 getPreferenceScreen().removePreference(findPreference(KEY_TETHER_SETTINGS));
379 Preference p = findPreference(KEY_TETHER_SETTINGS);
380 p.setTitle(Utils.getTetheringLabel(cm));
382 // Grey out if provisioning is not available.
383 p.setEnabled(!TetherSettings
384 .isProvisioningNeededButUnavailable(getActivity()));
387 // Enable link to CMAS app settings depending on the value in config.xml.
388 boolean isCellBroadcastAppLinkEnabled = this.getResources().getBoolean(
389 com.android.internal.R.bool.config_cellBroadcastAppLinks);
391 if (isCellBroadcastAppLinkEnabled) {
392 if (mPm.getApplicationEnabledSetting("com.android.cellbroadcastreceiver")
393 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
394 isCellBroadcastAppLinkEnabled = false; // CMAS app disabled
397 } catch (IllegalArgumentException ignored) {
398 isCellBroadcastAppLinkEnabled = false; // CMAS app not installed
400 if (isSecondaryUser || !isCellBroadcastAppLinkEnabled
401 || mUm.hasUserRestriction(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS)) {
402 PreferenceScreen root = getPreferenceScreen();
403 Preference ps = findPreference(KEY_CELL_BROADCAST_SETTINGS);
404 if (ps != null) root.removePreference(ps);
409 public void onStart() {
412 initSmsApplicationSetting();
416 public void onResume() {
419 mAirplaneModeEnabler.resume();
420 if (mNfcEnabler != null) {
421 mNfcEnabler.resume();
423 if (mNsdEnabler != null) {
424 mNsdEnabler.resume();
429 public void onSaveInstanceState(Bundle outState) {
430 super.onSaveInstanceState(outState);
432 if (!TextUtils.isEmpty(mManageMobilePlanMessage)) {
433 outState.putString(SAVED_MANAGE_MOBILE_PLAN_MSG, mManageMobilePlanMessage);
438 public void onPause() {
441 mAirplaneModeEnabler.pause();
442 if (mNfcEnabler != null) {
445 if (mNsdEnabler != null) {
451 public void onActivityResult(int requestCode, int resultCode, Intent data) {
452 if (requestCode == REQUEST_CODE_EXIT_ECM) {
453 Boolean isChoiceYes = data.getBooleanExtra(EXIT_ECM_RESULT, false);
454 // Set Airplane mode based on the return value and checkbox state
455 mAirplaneModeEnabler.setAirplaneModeInECM(isChoiceYes,
456 mAirplaneModePreference.isChecked());
458 super.onActivityResult(requestCode, resultCode, data);
462 protected int getHelpResource() {
463 return R.string.help_url_more_networks;
467 public boolean onPreferenceChange(Preference preference, Object newValue) {
468 if (preference == mSmsApplicationPreference && newValue != null) {
469 SmsApplication.setDefaultApplication(newValue.toString(), getActivity());
478 public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
479 new BaseSearchIndexProvider() {
481 public List<SearchIndexableResource> getXmlResourcesToIndex(
482 Context context, boolean enabled) {
483 SearchIndexableResource sir = new SearchIndexableResource(context);
484 sir.xmlResId = R.xml.wireless_settings;
485 return Arrays.asList(sir);
489 public List<String> getNonIndexableKeys(Context context) {
490 final ArrayList<String> result = new ArrayList<String>();
492 result.add(KEY_TOGGLE_NSD);
494 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
495 final int myUserId = UserHandle.myUserId();
496 final boolean isSecondaryUser = myUserId != UserHandle.USER_OWNER;
497 final boolean isRestrictedUser = um.getUserInfo(myUserId).isRestricted();
498 final boolean isWimaxEnabled = !isSecondaryUser
499 && context.getResources().getBoolean(
500 com.android.internal.R.bool.config_wimaxEnabled);
502 || um.hasUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)) {
503 result.add(KEY_WIMAX_SETTINGS);
506 if (isSecondaryUser) { // Disable VPN
507 result.add(KEY_VPN_SETTINGS);
510 // Remove NFC if not available
511 final NfcManager manager = (NfcManager)
512 context.getSystemService(Context.NFC_SERVICE);
513 if (manager != null) {
514 NfcAdapter adapter = manager.getDefaultAdapter();
515 if (adapter == null) {
516 result.add(KEY_TOGGLE_NFC);
517 result.add(KEY_ANDROID_BEAM_SETTINGS);
521 // Remove Mobile Network Settings and Manage Mobile Plan if it's a wifi-only device.
522 if (isSecondaryUser || Utils.isWifiOnly(context)) {
523 result.add(KEY_MOBILE_NETWORK_SETTINGS);
524 result.add(KEY_MANAGE_MOBILE_PLAN);
527 // Remove Mobile Network Settings and Manage Mobile Plan
528 // if config_show_mobile_plan sets false.
529 final boolean isMobilePlanEnabled = context.getResources().getBoolean(
530 R.bool.config_show_mobile_plan);
531 if (!isMobilePlanEnabled) {
532 result.add(KEY_MANAGE_MOBILE_PLAN);
535 // Remove SMS Application if the device does not support SMS
536 TelephonyManager tm =
537 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
538 if (!tm.isSmsCapable() || isRestrictedUser) {
539 result.add(KEY_SMS_APPLICATION);
542 final PackageManager pm = context.getPackageManager();
544 // Remove Airplane Mode settings if it's a stationary device such as a TV.
545 if (pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)) {
546 result.add(KEY_TOGGLE_AIRPLANE);
549 // proxy UI disabled until we have better app support
550 result.add(KEY_PROXY_SETTINGS);
552 // Disable Tethering if it's not allowed or if it's a wifi-only device
553 ConnectivityManager cm = (ConnectivityManager)
554 context.getSystemService(Context.CONNECTIVITY_SERVICE);
555 if (isSecondaryUser || !cm.isTetheringSupported()) {
556 result.add(KEY_TETHER_SETTINGS);
559 // Enable link to CMAS app settings depending on the value in config.xml.
560 boolean isCellBroadcastAppLinkEnabled = context.getResources().getBoolean(
561 com.android.internal.R.bool.config_cellBroadcastAppLinks);
563 if (isCellBroadcastAppLinkEnabled) {
564 if (pm.getApplicationEnabledSetting("com.android.cellbroadcastreceiver")
565 == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
566 isCellBroadcastAppLinkEnabled = false; // CMAS app disabled
569 } catch (IllegalArgumentException ignored) {
570 isCellBroadcastAppLinkEnabled = false; // CMAS app not installed
572 if (isSecondaryUser || !isCellBroadcastAppLinkEnabled) {
573 result.add(KEY_CELL_BROADCAST_SETTINGS);