1 /* 2 * Copyright (C) 2020 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 package com.android.settings.network.telephony; 17 18 import android.app.settings.SettingsEnums; 19 import android.content.Context; 20 import android.os.PersistableBundle; 21 import android.telephony.CarrierConfigManager; 22 import android.telephony.SubscriptionInfo; 23 import android.telephony.SubscriptionManager; 24 import android.telephony.TelephonyManager; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import androidx.preference.Preference; 29 import androidx.preference.PreferenceScreen; 30 31 import com.android.settings.R; 32 import com.android.settings.network.CarrierConfigCache; 33 import com.android.settings.network.SubscriptionUtil; 34 import com.android.settings.overlay.FeatureFactory; 35 import com.android.settingslib.RestrictedSwitchPreference; 36 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 37 38 /** 39 * Preference controller for "Enable 2G" 40 * 41 * <p> 42 * This preference controller is invoked per subscription id, which means toggling 2g is a per-sim 43 * operation. The requested 2g preference is delegated to 44 * {@link TelephonyManager#setAllowedNetworkTypesForReason(int reason, long allowedNetworkTypes)} 45 * with: 46 * <ul> 47 * <li>{@code reason} {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}.</li> 48 * <li>{@code allowedNetworkTypes} with set or cleared 2g-related bits, depending on the 49 * requested preference state. </li> 50 * </ul> 51 */ 52 public class Enable2gPreferenceController extends TelephonyTogglePreferenceController { 53 54 private static final String LOG_TAG = "Enable2gPreferenceController"; 55 private static final long BITMASK_2G = TelephonyManager.NETWORK_TYPE_BITMASK_GSM 56 | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS 57 | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE 58 | TelephonyManager.NETWORK_TYPE_BITMASK_CDMA 59 | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT; 60 61 private final MetricsFeatureProvider mMetricsFeatureProvider; 62 63 private CarrierConfigCache mCarrierConfigCache; 64 private SubscriptionManager mSubscriptionManager; 65 private TelephonyManager mTelephonyManager; 66 private RestrictedSwitchPreference mRestrictedPreference; 67 68 /** 69 * Class constructor of "Enable 2G" toggle. 70 * 71 * @param context of settings 72 * @param key assigned within UI entry of XML file 73 */ Enable2gPreferenceController(Context context, String key)74 public Enable2gPreferenceController(Context context, String key) { 75 super(context, key); 76 mCarrierConfigCache = CarrierConfigCache.getInstance(context); 77 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); 78 mSubscriptionManager = context.getSystemService(SubscriptionManager.class); 79 mRestrictedPreference = null; 80 } 81 82 /** 83 * Initialization based on a given subscription id. 84 * 85 * @param subId is the subscription id 86 * @return this instance after initialization 87 */ init(int subId)88 public Enable2gPreferenceController init(int subId) { 89 mSubId = subId; 90 mTelephonyManager = mContext.getSystemService(TelephonyManager.class) 91 .createForSubscriptionId(mSubId); 92 return this; 93 } 94 95 @Override displayPreference(PreferenceScreen screen)96 public void displayPreference(PreferenceScreen screen) { 97 super.displayPreference(screen); 98 mRestrictedPreference = screen.findPreference(getPreferenceKey()); 99 } 100 101 @Override updateState(Preference preference)102 public void updateState(Preference preference) { 103 super.updateState(preference); 104 105 // The device admin decision overrides any carrier preferences 106 if (isDisabledByAdmin()) { 107 return; 108 } 109 110 if (preference == null || !SubscriptionManager.isUsableSubscriptionId(mSubId)) { 111 return; 112 } 113 114 final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(mSubId); 115 boolean isDisabledByCarrier = 116 carrierConfig != null 117 && carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENABLE_2G); 118 preference.setEnabled(!isDisabledByCarrier); 119 String summary; 120 if (isDisabledByCarrier) { 121 summary = mContext.getString(R.string.enable_2g_summary_disabled_carrier, 122 getSimCardName()); 123 } else { 124 summary = mContext.getString(R.string.enable_2g_summary); 125 } 126 preference.setSummary(summary); 127 } 128 getSimCardName()129 private String getSimCardName() { 130 SubscriptionInfo subInfo = SubscriptionUtil.getSubById(mSubscriptionManager, mSubId); 131 if (subInfo == null) { 132 return ""; 133 } 134 // It is the sim card name, and it should be the same name as the sim page. 135 CharSequence simCardName = subInfo.getDisplayName(); 136 return TextUtils.isEmpty(simCardName) ? "" : simCardName.toString(); 137 } 138 139 /** 140 * Get the {@link com.android.settings.core.BasePreferenceController.AvailabilityStatus} for 141 * this preference given a {@code subId}. 142 * <p> 143 * A return value of {@link #AVAILABLE} denotes that the 2g status can be updated for this 144 * particular subscription. 145 * We return {@link #AVAILABLE} if the following conditions are met and {@link 146 * #CONDITIONALLY_UNAVAILABLE} otherwise. 147 * <ul> 148 * <li>The subscription is usable {@link SubscriptionManager#isUsableSubscriptionId}</li> 149 * <li>The carrier has not opted to disable this preference 150 * {@link CarrierConfigManager#KEY_HIDE_ENABLE_2G}</li> 151 * <li>The device supports 152 * <a href="https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/radio/1.6/IRadio.hal">Radio HAL version 1.6 or greater</a> </li> 153 * </ul> 154 */ 155 @Override getAvailabilityStatus(int subId)156 public int getAvailabilityStatus(int subId) { 157 final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId); 158 if (mTelephonyManager == null) { 159 Log.w(LOG_TAG, "Telephony manager not yet initialized"); 160 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 161 } 162 boolean visible = 163 SubscriptionManager.isUsableSubscriptionId(subId) 164 && carrierConfig != null 165 && mTelephonyManager.isRadioInterfaceCapabilitySupported( 166 mTelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK); 167 return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; 168 } 169 170 /** 171 * Return {@code true} if 2g is currently enabled. 172 * 173 * <p><b>NOTE:</b> This method returns the active state of the preference controller and is not 174 * the parameter passed into {@link #setChecked(boolean)}, which is instead the requested future 175 * state.</p> 176 */ 177 @Override isChecked()178 public boolean isChecked() { 179 // If an enterprise admin has disabled 2g, we show the toggle as not checked to avoid 180 // user confusion of seeing a checked toggle, but having 2g actually disabled. 181 // The RestrictedSwitchPreference will take care of transparently informing the user that 182 // the setting was disabled by their admin 183 if (isDisabledByAdmin()) { 184 return false; 185 } 186 187 long currentlyAllowedNetworkTypes = mTelephonyManager.getAllowedNetworkTypesForReason( 188 mTelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G); 189 return (currentlyAllowedNetworkTypes & BITMASK_2G) != 0; 190 } 191 192 /** 193 * Ensure that the modem's allowed network types are configured according to the user's 194 * preference. 195 * <p> 196 * See {@link com.android.settings.core.TogglePreferenceController#setChecked(boolean)} for 197 * details. 198 * 199 * @param isChecked The toggle value that we're being requested to enforce. A value of {@code 200 * false} denotes that 2g will be disabled by the modem after this function 201 * completes, if it is not already. 202 */ 203 @Override setChecked(boolean isChecked)204 public boolean setChecked(boolean isChecked) { 205 if (isDisabledByAdmin()) { 206 return false; 207 } 208 209 if (!SubscriptionManager.isUsableSubscriptionId(mSubId)) { 210 return false; 211 } 212 long currentlyAllowedNetworkTypes = mTelephonyManager.getAllowedNetworkTypesForReason( 213 mTelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G); 214 boolean enabled = (currentlyAllowedNetworkTypes & BITMASK_2G) != 0; 215 if (enabled == isChecked) { 216 return false; 217 } 218 long newAllowedNetworkTypes = currentlyAllowedNetworkTypes; 219 if (isChecked) { 220 newAllowedNetworkTypes = currentlyAllowedNetworkTypes | BITMASK_2G; 221 Log.i(LOG_TAG, "Enabling 2g. Allowed network types: " + newAllowedNetworkTypes); 222 } else { 223 newAllowedNetworkTypes = currentlyAllowedNetworkTypes & ~BITMASK_2G; 224 Log.i(LOG_TAG, "Disabling 2g. Allowed network types: " + newAllowedNetworkTypes); 225 } 226 mTelephonyManager.setAllowedNetworkTypesForReason( 227 mTelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, newAllowedNetworkTypes); 228 mMetricsFeatureProvider.action( 229 mContext, SettingsEnums.ACTION_2G_ENABLED, isChecked); 230 return true; 231 } 232 isDisabledByAdmin()233 private boolean isDisabledByAdmin() { 234 return (mRestrictedPreference != null && mRestrictedPreference.isDisabledByAdmin()); 235 } 236 } 237