Honor DISALLOW_CELLULAR_2G User Restriction in Enable2gPreferenceController
When 2g is disallowed by a device admin the 2g toggle in the preference screen will implement the following behaviors as a result of being changed to a RestrictedSwitchPreference: 1. become disabled (greyed out) 2. show a summary message explaining that the preference was disabled by an admin 3 show a pop up when a user tries to click on the preference informing them that the setting is unusable because it was disabled by an admin. Additionally, the toggle will show as unchecked (off) when admins disable 2g. When 2g is re-enabled by a device admin, the preference screen will go back to its previous state. Test: atest Enable2gPreferenceControllerTest Bug: b/248250240 Change-Id: I7af901f2d9f62ebfe884e01724d8eff845c2968e
This commit is contained in:
@@ -241,11 +241,13 @@
|
|||||||
settings:controller="com.android.settings.network.telephony.CarrierPreferenceController">
|
settings:controller="com.android.settings.network.telephony.CarrierPreferenceController">
|
||||||
</Preference>
|
</Preference>
|
||||||
|
|
||||||
<SwitchPreference
|
<com.android.settingslib.RestrictedSwitchPreference
|
||||||
android:key="enable_2g"
|
android:key="enable_2g"
|
||||||
android:title="@string/enable_2g_title"
|
android:title="@string/enable_2g_title"
|
||||||
android:summary="@string/enable_2g_summary"
|
android:summary="@string/enable_2g_summary"
|
||||||
settings:controller="com.android.settings.network.telephony.Enable2gPreferenceController" />
|
settings:controller="com.android.settings.network.telephony.Enable2gPreferenceController"
|
||||||
|
settings:useAdminDisabledSummary="true"
|
||||||
|
settings:userRestriction="no_cellular_2g"/>
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="nr_advanced_calling"
|
android:key="nr_advanced_calling"
|
||||||
|
@@ -26,11 +26,13 @@ import android.text.TextUtils;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.network.CarrierConfigCache;
|
import com.android.settings.network.CarrierConfigCache;
|
||||||
import com.android.settings.network.SubscriptionUtil;
|
import com.android.settings.network.SubscriptionUtil;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,29 +52,31 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
|||||||
public class Enable2gPreferenceController extends TelephonyTogglePreferenceController {
|
public class Enable2gPreferenceController extends TelephonyTogglePreferenceController {
|
||||||
|
|
||||||
private static final String LOG_TAG = "Enable2gPreferenceController";
|
private static final String LOG_TAG = "Enable2gPreferenceController";
|
||||||
private static final long BITMASK_2G = TelephonyManager.NETWORK_TYPE_BITMASK_GSM
|
private static final long BITMASK_2G = TelephonyManager.NETWORK_TYPE_BITMASK_GSM
|
||||||
| TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
|
| TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
|
||||||
| TelephonyManager.NETWORK_TYPE_BITMASK_EDGE
|
| TelephonyManager.NETWORK_TYPE_BITMASK_EDGE
|
||||||
| TelephonyManager.NETWORK_TYPE_BITMASK_CDMA
|
| TelephonyManager.NETWORK_TYPE_BITMASK_CDMA
|
||||||
| TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT;
|
| TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT;
|
||||||
|
|
||||||
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
private final MetricsFeatureProvider mMetricsFeatureProvider;
|
||||||
|
|
||||||
private CarrierConfigCache mCarrierConfigCache;
|
private CarrierConfigCache mCarrierConfigCache;
|
||||||
private SubscriptionManager mSubscriptionManager;
|
private SubscriptionManager mSubscriptionManager;
|
||||||
private TelephonyManager mTelephonyManager;
|
private TelephonyManager mTelephonyManager;
|
||||||
|
private RestrictedSwitchPreference mRestrictedPreference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class constructor of "Enable 2G" toggle.
|
* Class constructor of "Enable 2G" toggle.
|
||||||
*
|
*
|
||||||
* @param context of settings
|
* @param context of settings
|
||||||
* @param key assigned within UI entry of XML file
|
* @param key assigned within UI entry of XML file
|
||||||
*/
|
*/
|
||||||
public Enable2gPreferenceController(Context context, String key) {
|
public Enable2gPreferenceController(Context context, String key) {
|
||||||
super(context, key);
|
super(context, key);
|
||||||
mCarrierConfigCache = CarrierConfigCache.getInstance(context);
|
mCarrierConfigCache = CarrierConfigCache.getInstance(context);
|
||||||
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
|
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
|
||||||
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
|
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
|
||||||
|
mRestrictedPreference = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,10 +88,53 @@ public class Enable2gPreferenceController extends TelephonyTogglePreferenceContr
|
|||||||
public Enable2gPreferenceController init(int subId) {
|
public Enable2gPreferenceController init(int subId) {
|
||||||
mSubId = subId;
|
mSubId = subId;
|
||||||
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
|
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
|
||||||
.createForSubscriptionId(mSubId);
|
.createForSubscriptionId(mSubId);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
mRestrictedPreference = screen.findPreference(getPreferenceKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(Preference preference) {
|
||||||
|
super.updateState(preference);
|
||||||
|
|
||||||
|
// The device admin decision overrides any carrier preferences
|
||||||
|
if (isDisabledByAdmin()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preference == null || !SubscriptionManager.isUsableSubscriptionId(mSubId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(mSubId);
|
||||||
|
boolean isDisabledByCarrier =
|
||||||
|
carrierConfig != null
|
||||||
|
&& carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENABLE_2G);
|
||||||
|
preference.setEnabled(!isDisabledByCarrier);
|
||||||
|
String summary;
|
||||||
|
if (isDisabledByCarrier) {
|
||||||
|
summary = mContext.getString(R.string.enable_2g_summary_disabled_carrier,
|
||||||
|
getCarrierName());
|
||||||
|
} else {
|
||||||
|
summary = mContext.getString(R.string.enable_2g_summary);
|
||||||
|
}
|
||||||
|
preference.setSummary(summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCarrierName() {
|
||||||
|
SubscriptionInfo subInfo = SubscriptionUtil.getSubById(mSubscriptionManager, mSubId);
|
||||||
|
if (subInfo == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
CharSequence carrierName = subInfo.getCarrierName();
|
||||||
|
return TextUtils.isEmpty(carrierName) ? "" : carrierName.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the {@link com.android.settings.core.BasePreferenceController.AvailabilityStatus} for
|
* Get the {@link com.android.settings.core.BasePreferenceController.AvailabilityStatus} for
|
||||||
* this preference given a {@code subId}.
|
* this preference given a {@code subId}.
|
||||||
@@ -104,36 +151,6 @@ public class Enable2gPreferenceController extends TelephonyTogglePreferenceContr
|
|||||||
* <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>
|
* <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>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
public void updateState(Preference preference) {
|
|
||||||
super.updateState(preference);
|
|
||||||
if (preference == null || !SubscriptionManager.isUsableSubscriptionId(mSubId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(mSubId);
|
|
||||||
boolean isDisabledByCarrier =
|
|
||||||
carrierConfig != null
|
|
||||||
&& carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENABLE_2G);
|
|
||||||
preference.setEnabled(!isDisabledByCarrier);
|
|
||||||
String summary;
|
|
||||||
if (isDisabledByCarrier) {
|
|
||||||
summary = mContext.getString(R.string.enable_2g_summary_disabled_carrier,
|
|
||||||
getCarrierName());
|
|
||||||
} else {
|
|
||||||
summary = mContext.getString(R.string.enable_2g_summary);
|
|
||||||
}
|
|
||||||
preference.setSummary(summary);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getCarrierName() {
|
|
||||||
SubscriptionInfo subInfo = SubscriptionUtil.getSubById(mSubscriptionManager, mSubId);
|
|
||||||
if (subInfo == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
CharSequence carrierName = subInfo.getCarrierName();
|
|
||||||
return TextUtils.isEmpty(carrierName) ? "" : carrierName.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getAvailabilityStatus(int subId) {
|
public int getAvailabilityStatus(int subId) {
|
||||||
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId);
|
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(subId);
|
||||||
@@ -143,9 +160,9 @@ public class Enable2gPreferenceController extends TelephonyTogglePreferenceContr
|
|||||||
}
|
}
|
||||||
boolean visible =
|
boolean visible =
|
||||||
SubscriptionManager.isUsableSubscriptionId(subId)
|
SubscriptionManager.isUsableSubscriptionId(subId)
|
||||||
&& carrierConfig != null
|
&& carrierConfig != null
|
||||||
&& mTelephonyManager.isRadioInterfaceCapabilitySupported(
|
&& mTelephonyManager.isRadioInterfaceCapabilitySupported(
|
||||||
mTelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK);
|
mTelephonyManager.CAPABILITY_USES_ALLOWED_NETWORK_TYPES_BITMASK);
|
||||||
return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
|
return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +175,14 @@ public class Enable2gPreferenceController extends TelephonyTogglePreferenceContr
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isChecked() {
|
public boolean isChecked() {
|
||||||
|
// If an enterprise admin has disabled 2g, we show the toggle as not checked to avoid
|
||||||
|
// user confusion of seeing a checked toggle, but having 2g actually disabled.
|
||||||
|
// The RestrictedSwitchPreference will take care of transparently informing the user that
|
||||||
|
// the setting was disabled by their admin
|
||||||
|
if (isDisabledByAdmin()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
long currentlyAllowedNetworkTypes = mTelephonyManager.getAllowedNetworkTypesForReason(
|
long currentlyAllowedNetworkTypes = mTelephonyManager.getAllowedNetworkTypesForReason(
|
||||||
mTelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G);
|
mTelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G);
|
||||||
return (currentlyAllowedNetworkTypes & BITMASK_2G) != 0;
|
return (currentlyAllowedNetworkTypes & BITMASK_2G) != 0;
|
||||||
@@ -176,6 +201,10 @@ public class Enable2gPreferenceController extends TelephonyTogglePreferenceContr
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean setChecked(boolean isChecked) {
|
public boolean setChecked(boolean isChecked) {
|
||||||
|
if (isDisabledByAdmin()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!SubscriptionManager.isUsableSubscriptionId(mSubId)) {
|
if (!SubscriptionManager.isUsableSubscriptionId(mSubId)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -199,4 +228,8 @@ public class Enable2gPreferenceController extends TelephonyTogglePreferenceContr
|
|||||||
mContext, SettingsEnums.ACTION_2G_ENABLED, isChecked);
|
mContext, SettingsEnums.ACTION_2G_ENABLED, isChecked);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isDisabledByAdmin() {
|
||||||
|
return (mRestrictedPreference != null && mRestrictedPreference.isDisabledByAdmin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,15 +27,19 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Looper;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
import android.telephony.CarrierConfigManager;
|
import android.telephony.CarrierConfigManager;
|
||||||
import android.telephony.SubscriptionManager;
|
import android.telephony.SubscriptionManager;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import com.android.settings.network.CarrierConfigCache;
|
import com.android.settings.network.CarrierConfigCache;
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -46,6 +50,7 @@ import org.mockito.MockitoAnnotations;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public final class Enable2gPreferenceControllerTest {
|
public final class Enable2gPreferenceControllerTest {
|
||||||
private static final int SUB_ID = 2;
|
private static final int SUB_ID = 2;
|
||||||
|
private static final String PREFERENCE_KEY = "TEST_2G_PREFERENCE";
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private CarrierConfigCache mCarrierConfigCache;
|
private CarrierConfigCache mCarrierConfigCache;
|
||||||
@@ -54,12 +59,18 @@ public final class Enable2gPreferenceControllerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private TelephonyManager mInvalidTelephonyManager;
|
private TelephonyManager mInvalidTelephonyManager;
|
||||||
|
|
||||||
|
private RestrictedSwitchPreference mPreference;
|
||||||
|
private PreferenceScreen mPreferenceScreen;
|
||||||
private PersistableBundle mPersistableBundle;
|
private PersistableBundle mPersistableBundle;
|
||||||
private Enable2gPreferenceController mController;
|
private Enable2gPreferenceController mController;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
if (Looper.myLooper() == null) {
|
||||||
|
Looper.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
mContext = spy(ApplicationProvider.getApplicationContext());
|
mContext = spy(ApplicationProvider.getApplicationContext());
|
||||||
@@ -75,7 +86,12 @@ public final class Enable2gPreferenceControllerTest {
|
|||||||
doReturn(mPersistableBundle).when(mCarrierConfigCache).getConfigForSubId(SUB_ID);
|
doReturn(mPersistableBundle).when(mCarrierConfigCache).getConfigForSubId(SUB_ID);
|
||||||
doReturn(mPersistableBundle).when(mCarrierConfigCache).getConfigForSubId(
|
doReturn(mPersistableBundle).when(mCarrierConfigCache).getConfigForSubId(
|
||||||
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
|
||||||
mController = new Enable2gPreferenceController(mContext, "mobile_data");
|
mController = new Enable2gPreferenceController(mContext, PREFERENCE_KEY);
|
||||||
|
|
||||||
|
mPreference = spy(new RestrictedSwitchPreference(mContext));
|
||||||
|
mPreference.setKey(PREFERENCE_KEY);
|
||||||
|
mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
|
||||||
|
mPreferenceScreen.addPreference(mPreference);
|
||||||
mController.init(SUB_ID);
|
mController.init(SUB_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,13 +153,15 @@ public final class Enable2gPreferenceControllerTest {
|
|||||||
assertThat(mController.setChecked(false)).isFalse();
|
assertThat(mController.setChecked(false)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setChecked_disabledByAdmin_returnFalse() {
|
||||||
|
when2gIsDisabledByAdmin(true);
|
||||||
|
assertThat(mController.setChecked(false)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onPreferenceChange_update() {
|
public void onPreferenceChange_update() {
|
||||||
// Set "Enable 2G" flag to "on"
|
when2gIsEnabledForReasonEnable2g();
|
||||||
when(mTelephonyManager.getAllowedNetworkTypesForReason(
|
|
||||||
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G)).thenReturn(
|
|
||||||
(long) (TelephonyManager.NETWORK_TYPE_BITMASK_GSM
|
|
||||||
| TelephonyManager.NETWORK_TYPE_BITMASK_LTE));
|
|
||||||
|
|
||||||
// Setup state to allow disabling
|
// Setup state to allow disabling
|
||||||
doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported(
|
doReturn(true).when(mTelephonyManager).isRadioInterfaceCapabilitySupported(
|
||||||
@@ -159,4 +177,42 @@ public final class Enable2gPreferenceControllerTest {
|
|||||||
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G,
|
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G,
|
||||||
TelephonyManager.NETWORK_TYPE_BITMASK_LTE);
|
TelephonyManager.NETWORK_TYPE_BITMASK_LTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disabledByAdmin_toggleUnchecked() {
|
||||||
|
when2gIsEnabledForReasonEnable2g();
|
||||||
|
when2gIsDisabledByAdmin(true);
|
||||||
|
assertThat(mController.isChecked()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void userRestrictionInactivated_userToggleMaintainsState() {
|
||||||
|
// Initially, 2g is enabled
|
||||||
|
when2gIsEnabledForReasonEnable2g();
|
||||||
|
when2gIsDisabledByAdmin(false);
|
||||||
|
assertThat(mController.isChecked()).isTrue();
|
||||||
|
|
||||||
|
// When we disable the preference by an admin, the preference should be unchecked
|
||||||
|
when2gIsDisabledByAdmin(true);
|
||||||
|
assertThat(mController.isChecked()).isFalse();
|
||||||
|
|
||||||
|
// If the preference is re-enabled by an admin, former state should hold
|
||||||
|
when2gIsDisabledByAdmin(false);
|
||||||
|
assertThat(mController.isChecked()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void when2gIsEnabledForReasonEnable2g() {
|
||||||
|
when(mTelephonyManager.getAllowedNetworkTypesForReason(
|
||||||
|
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G)).thenReturn(
|
||||||
|
(long) (TelephonyManager.NETWORK_TYPE_BITMASK_GSM
|
||||||
|
| TelephonyManager.NETWORK_TYPE_BITMASK_LTE));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void when2gIsDisabledByAdmin(boolean is2gDisabledByAdmin) {
|
||||||
|
// Our controller depends on state being initialized when the associated preference is
|
||||||
|
// displayed because the admin disablement functionality flows from the association of a
|
||||||
|
// Preference with the PreferenceScreen
|
||||||
|
when(mPreference.isDisabledByAdmin()).thenReturn(is2gDisabledByAdmin);
|
||||||
|
mController.displayPreference(mPreferenceScreen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user