Check for user restrictions disallowing BT in BluetoothEnabler.

Test: make RunSettingsRoboTests -j40
Test: manual

BUG: 35596982
BUG: 32895313

Change-Id: Ie8f53b665a4aad4e6b17b20602cbe5502998d7a2
This commit is contained in:
Lenka Trochtova
2017-04-11 20:29:21 +02:00
parent c7b2bc65cb
commit 479d197196
5 changed files with 192 additions and 12 deletions

View File

@@ -21,13 +21,16 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.os.UserManager;
import android.provider.Settings; import android.provider.Settings;
import android.widget.Switch; import android.widget.Switch;
import android.widget.Toast; import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.SwitchWidgetController; import com.android.settings.widget.SwitchWidgetController;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.WirelessUtils; import com.android.settingslib.WirelessUtils;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter; import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -45,6 +48,7 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh
private boolean mValidListener; private boolean mValidListener;
private final LocalBluetoothAdapter mLocalAdapter; private final LocalBluetoothAdapter mLocalAdapter;
private final IntentFilter mIntentFilter; private final IntentFilter mIntentFilter;
private final RestrictionUtils mRestrictionUtils;
private static final String EVENT_DATA_IS_BT_ON = "is_bluetooth_on"; private static final String EVENT_DATA_IS_BT_ON = "is_bluetooth_on";
private static final int EVENT_UPDATE_INDEX = 0; private static final int EVENT_UPDATE_INDEX = 0;
@@ -63,6 +67,13 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh
public BluetoothEnabler(Context context, SwitchWidgetController switchWidget, public BluetoothEnabler(Context context, SwitchWidgetController switchWidget,
MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager, MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager,
int metricsEvent) { int metricsEvent) {
this(context, switchWidget, metricsFeatureProvider, manager, metricsEvent,
new RestrictionUtils());
}
public BluetoothEnabler(Context context, SwitchWidgetController switchWidget,
MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager,
int metricsEvent, RestrictionUtils restrictionUtils) {
mContext = context; mContext = context;
mMetricsFeatureProvider = metricsFeatureProvider; mMetricsFeatureProvider = metricsFeatureProvider;
mSwitchWidget = switchWidget; mSwitchWidget = switchWidget;
@@ -79,6 +90,7 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh
mLocalAdapter = manager.getBluetoothAdapter(); mLocalAdapter = manager.getBluetoothAdapter();
} }
mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
mRestrictionUtils = restrictionUtils;
} }
public void setupSwitchController() { public void setupSwitchController() {
@@ -90,15 +102,17 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh
} }
public void resume(Context context) { public void resume(Context context) {
if (mContext != context) {
mContext = context;
}
maybeEnforceRestrictions();
if (mLocalAdapter == null) { if (mLocalAdapter == null) {
mSwitchWidget.setEnabled(false); mSwitchWidget.setEnabled(false);
return; return;
} }
if (mContext != context) {
mContext = context;
}
// Bluetooth state is not sticky, so set it manually // Bluetooth state is not sticky, so set it manually
handleStateChanged(mLocalAdapter.getBluetoothState()); handleStateChanged(mLocalAdapter.getBluetoothState());
@@ -156,6 +170,10 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh
@Override @Override
public boolean onSwitchToggled(boolean isChecked) { public boolean onSwitchToggled(boolean isChecked) {
if (maybeEnforceRestrictions()) {
return true;
}
// Show toast message if Bluetooth is not allowed in airplane mode // Show toast message if Bluetooth is not allowed in airplane mode
if (isChecked && if (isChecked &&
!WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) { !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
@@ -182,4 +200,29 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh
mSwitchWidget.setEnabled(false); mSwitchWidget.setEnabled(false);
return true; return true;
} }
/**
* Enforces user restrictions disallowing Bluetooth (or its configuration) if there are any.
*
* @return if there was any user restriction to enforce.
*/
@VisibleForTesting
boolean maybeEnforceRestrictions() {
EnforcedAdmin admin = mRestrictionUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_BLUETOOTH);
if (admin == null) {
admin = mRestrictionUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_CONFIG_BLUETOOTH);
}
mSwitchWidget.setDisabledByAdmin(admin);
if (admin != null) {
mSwitchWidget.setChecked(false);
if (mSwitch != null) {
mSwitch.setEnabled(false);
mSwitch.setChecked(false);
}
}
return admin != null;
}
} }

View File

@@ -18,6 +18,7 @@ package com.android.settings.bluetooth;
import android.content.Context; import android.content.Context;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.core.PreferenceController; import com.android.settings.core.PreferenceController;
import com.android.settings.core.lifecycle.LifecycleObserver; import com.android.settings.core.lifecycle.LifecycleObserver;
@@ -26,9 +27,9 @@ import com.android.settings.core.lifecycle.events.OnResume;
import com.android.settings.core.lifecycle.events.OnStart; import com.android.settings.core.lifecycle.events.OnStart;
import com.android.settings.core.lifecycle.events.OnStop; import com.android.settings.core.lifecycle.events.OnStop;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.SummaryUpdater.OnSummaryChangeListener;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settings.widget.MasterSwitchController; import com.android.settings.widget.MasterSwitchController;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settings.widget.SummaryUpdater.OnSummaryChangeListener;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
public class BluetoothMasterSwitchPreferenceController extends PreferenceController public class BluetoothMasterSwitchPreferenceController extends PreferenceController
@@ -41,12 +42,20 @@ public class BluetoothMasterSwitchPreferenceController extends PreferenceControl
private MasterSwitchPreference mBtPreference; private MasterSwitchPreference mBtPreference;
private BluetoothEnabler mBluetoothEnabler; private BluetoothEnabler mBluetoothEnabler;
private BluetoothSummaryUpdater mSummaryUpdater; private BluetoothSummaryUpdater mSummaryUpdater;
private RestrictionUtils mRestrictionUtils;
public BluetoothMasterSwitchPreferenceController(Context context, public BluetoothMasterSwitchPreferenceController(Context context,
LocalBluetoothManager bluetoothManager) { LocalBluetoothManager bluetoothManager) {
this(context, bluetoothManager, new RestrictionUtils());
}
@VisibleForTesting
public BluetoothMasterSwitchPreferenceController(Context context,
LocalBluetoothManager bluetoothManager, RestrictionUtils restrictionUtils) {
super(context); super(context);
mBluetoothManager = bluetoothManager; mBluetoothManager = bluetoothManager;
mSummaryUpdater = new BluetoothSummaryUpdater(mContext, this, mBluetoothManager); mSummaryUpdater = new BluetoothSummaryUpdater(mContext, this, mBluetoothManager);
mRestrictionUtils = restrictionUtils;
} }
@Override @Override
@@ -56,7 +65,8 @@ public class BluetoothMasterSwitchPreferenceController extends PreferenceControl
mBluetoothEnabler = new BluetoothEnabler(mContext, mBluetoothEnabler = new BluetoothEnabler(mContext,
new MasterSwitchController(mBtPreference), new MasterSwitchController(mBtPreference),
FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(), mBluetoothManager, FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(), mBluetoothManager,
MetricsEvent.ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE); MetricsEvent.ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE,
mRestrictionUtils);
} }
@Override @Override

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.bluetooth;
import android.content.Context;
import android.os.UserHandle;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
/**
* A utility class to aid testing.
*/
public class RestrictionUtils {
public RestrictionUtils() {}
/**
* Utility method to check if user restriction is enforced on the current user.
*
* <p> It helps with testing - override it to avoid calling static method which calls system
* API.
*/
public EnforcedAdmin checkIfRestrictionEnforced(Context context, String restriction) {
return RestrictedLockUtils.checkIfRestrictionEnforced(
context, restriction, UserHandle.myUserId());
}
}

View File

@@ -15,12 +15,15 @@
*/ */
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.os.UserManager;
import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.widget.MasterSwitchController; import com.android.settings.widget.MasterSwitchController;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before; import org.junit.Before;
@@ -30,30 +33,108 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertEquals;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class BluetoothEnablerTest { public class BluetoothEnablerTest {
private static final EnforcedAdmin FAKE_ENFORCED_ADMIN =
new EnforcedAdmin(new ComponentName("test.package", "test.Class"), 10);
@Mock @Mock
private MetricsFeatureProvider mMetricsFeatureProvider; private MetricsFeatureProvider mMetricsFeatureProvider;
@Mock @Mock
private Context mContext; private Context mContext;
@Mock
private MasterSwitchController mMasterSwitchController;
@Mock
private RestrictionUtils mRestrictionUtils;
private BluetoothEnabler mBluetoothEnabler;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mBluetoothEnabler = new BluetoothEnabler(
mContext,
mMasterSwitchController,
mMetricsFeatureProvider,
mock(LocalBluetoothManager.class),
123,
mRestrictionUtils);
} }
@Test @Test
public void onSwitchToggled_shouldLogActionWithSuppliedEvent() { public void onSwitchToggled_shouldLogActionWithSuppliedEvent() {
BluetoothEnabler bluetoothEnabler = new BluetoothEnabler(mContext, // WHEN the switch is toggled...
mock(MasterSwitchController.class), mMetricsFeatureProvider, mBluetoothEnabler.onSwitchToggled(false);
mock(LocalBluetoothManager.class), 123);
bluetoothEnabler.onSwitchToggled(false);
// THEN the corresponding metrics action is logged.
verify(mMetricsFeatureProvider).action(mContext, 123, false); verify(mMetricsFeatureProvider).action(mContext, 123, false);
} }
@Test
public void maybeEnforceRestrictions_noRestrictions() {
// GIVEN there are no restrictions set...
when(mRestrictionUtils.checkIfRestrictionEnforced(any(Context.class), any(String.class)))
.thenReturn(null);
// WHEN the maybeEnforceRestrictions is called...
// THEN false is returned to indicate there was no restriction to enforce
assertThat(mBluetoothEnabler.maybeEnforceRestrictions()).isFalse();
// THEN a null EnfoceAdmin is set.
verify(mMasterSwitchController).setDisabledByAdmin(null);
// THEN the state of the switch isn't changed.
verify(mMasterSwitchController, never()).setChecked(anyBoolean());
}
@Test
public void maybeEnforceRestrictions_disallowBluetoothRestrictionSet() {
// GIVEN Bluetooth has been disallowed...
when(mRestrictionUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_BLUETOOTH)).thenReturn(FAKE_ENFORCED_ADMIN);
when(mRestrictionUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_CONFIG_BLUETOOTH)).thenReturn(null);
// WHEN the maybeEnforceRestrictions is called...
// THEN true is returned to indicate there was a restriction to enforce.
assertThat(mBluetoothEnabler.maybeEnforceRestrictions()).isTrue();
// THEN the expected EnfoceAdmin is set.
verify(mMasterSwitchController).setDisabledByAdmin(FAKE_ENFORCED_ADMIN);
// THEN the switch is unchecked.
verify(mMasterSwitchController).setChecked(false);
}
@Test
public void maybeEnforceRestrictions_disallowConfigBluetoothRestrictionSet() {
// GIVEN configuring Bluetooth has been disallowed...
when(mRestrictionUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_BLUETOOTH)).thenReturn(null);
when(mRestrictionUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_CONFIG_BLUETOOTH)).thenReturn(FAKE_ENFORCED_ADMIN);
// WHEN the maybeEnforceRestrictions is called...
// THEN true is returned to indicate there was a restriction to enforce.
assertThat(mBluetoothEnabler.maybeEnforceRestrictions()).isTrue();
// THEN the expected EnfoceAdmin is set.
verify(mMasterSwitchController).setDisabledByAdmin(FAKE_ENFORCED_ADMIN);
// THEN the switch is unchecked.
verify(mMasterSwitchController).setChecked(false);
}
} }

View File

@@ -52,6 +52,8 @@ public class BluetoothMasterSwitchPreferenceControllerTest {
private PreferenceScreen mScreen; private PreferenceScreen mScreen;
@Mock @Mock
private MasterSwitchPreference mPreference; private MasterSwitchPreference mPreference;
@Mock
private RestrictionUtils mRestrictionUtils;
private Context mContext; private Context mContext;
private BluetoothMasterSwitchPreferenceController mController; private BluetoothMasterSwitchPreferenceController mController;
@@ -60,7 +62,8 @@ public class BluetoothMasterSwitchPreferenceControllerTest {
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application.getApplicationContext(); mContext = RuntimeEnvironment.application.getApplicationContext();
mController = new BluetoothMasterSwitchPreferenceController(mContext, mBluetoothManager); mController = new BluetoothMasterSwitchPreferenceController(
mContext, mBluetoothManager, mRestrictionUtils);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
} }