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