1 /* 2 * Copyright (C) 2017 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.bluetooth; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyBoolean; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.never; 24 import static org.mockito.Mockito.spy; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.bluetooth.BluetoothAdapter; 29 import android.content.BroadcastReceiver; 30 import android.content.ComponentName; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.IntentFilter; 34 import android.os.UserHandle; 35 import android.os.UserManager; 36 import android.view.View; 37 38 import androidx.preference.PreferenceViewHolder; 39 40 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; 41 import com.android.settings.widget.SwitchBar; 42 import com.android.settings.widget.SwitchBarController; 43 import com.android.settings.widget.SwitchWidgetController; 44 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 45 import com.android.settingslib.RestrictedSwitchPreference; 46 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 47 48 import org.junit.Before; 49 import org.junit.BeforeClass; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.ArgumentCaptor; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 import org.robolectric.RobolectricTestRunner; 56 import org.robolectric.RuntimeEnvironment; 57 import org.robolectric.annotation.Config; 58 import org.robolectric.shadow.api.Shadow; 59 60 @RunWith(RobolectricTestRunner.class) 61 @Config(shadows = ShadowBluetoothAdapter.class) 62 public class BluetoothEnablerTest { 63 64 private static EnforcedAdmin sFakeEnforcedAdmin; 65 private PreferenceViewHolder mHolder; 66 private RestrictedSwitchPreference mRestrictedSwitchPreference; 67 68 @BeforeClass beforeClass()69 public static void beforeClass() { 70 sFakeEnforcedAdmin = new EnforcedAdmin(new ComponentName("test.package", "test.Class"), 71 UserHandle.of(10)); 72 } 73 74 @Mock 75 private MetricsFeatureProvider mMetricsFeatureProvider; 76 @Mock 77 private RestrictionUtils mRestrictionUtils; 78 @Mock 79 private SwitchWidgetController.OnSwitchChangeListener mCallback; 80 81 private Context mContext; 82 private SwitchWidgetController mSwitchController; 83 private BluetoothEnabler mBluetoothEnabler; 84 private ShadowBluetoothAdapter mShadowBluetoothAdapter; 85 86 @Before setUp()87 public void setUp() { 88 MockitoAnnotations.initMocks(this); 89 mContext = spy(RuntimeEnvironment.application); 90 91 mRestrictedSwitchPreference = new RestrictedSwitchPreference(mContext); 92 mSwitchController = spy(new SwitchBarController(new SwitchBar(mContext))); 93 mBluetoothEnabler = new BluetoothEnabler( 94 mContext, 95 mSwitchController, 96 mMetricsFeatureProvider, 97 123, 98 mRestrictionUtils); 99 mHolder = PreferenceViewHolder.createInstanceForTests(mock(View.class)); 100 mRestrictedSwitchPreference.onBindViewHolder(mHolder); 101 mBluetoothEnabler.setToggleCallback(mCallback); 102 mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); 103 } 104 105 @Test onSwitchToggled_shouldLogActionWithSuppliedEvent()106 public void onSwitchToggled_shouldLogActionWithSuppliedEvent() { 107 // WHEN the switch is toggled... 108 mBluetoothEnabler.onSwitchToggled(false); 109 110 // THEN the corresponding metrics action is logged. 111 verify(mMetricsFeatureProvider).action(mContext, 123, false); 112 } 113 114 @Test onSwitchToggled_shouldTriggerCallback()115 public void onSwitchToggled_shouldTriggerCallback() { 116 // WHEN the switch is toggled... 117 mBluetoothEnabler.onSwitchToggled(false); 118 119 // THEN the callback is triggered 120 verify(mCallback).onSwitchToggled(false); 121 } 122 123 @Test maybeEnforceRestrictions_noRestrictions()124 public void maybeEnforceRestrictions_noRestrictions() { 125 // GIVEN there are no restrictions set... 126 when(mRestrictionUtils.checkIfRestrictionEnforced(any(Context.class), any(String.class))) 127 .thenReturn(null); 128 129 // WHEN the maybeEnforceRestrictions is called... 130 // THEN false is returned to indicate there was no restriction to enforce 131 assertThat(mBluetoothEnabler.maybeEnforceRestrictions()).isFalse(); 132 133 // THEN a null EnfoceAdmin is set. 134 verify(mSwitchController).setDisabledByAdmin(null); 135 // THEN the state of the switch isn't changed. 136 verify(mSwitchController, never()).setChecked(anyBoolean()); 137 } 138 139 @Test maybeEnforceRestrictions_disallowBluetoothRestrictionSet()140 public void maybeEnforceRestrictions_disallowBluetoothRestrictionSet() { 141 // GIVEN Bluetooth has been disallowed... 142 when(mRestrictionUtils.checkIfRestrictionEnforced( 143 mContext, UserManager.DISALLOW_BLUETOOTH)).thenReturn(sFakeEnforcedAdmin); 144 when(mRestrictionUtils.checkIfRestrictionEnforced( 145 mContext, UserManager.DISALLOW_CONFIG_BLUETOOTH)).thenReturn(null); 146 147 // WHEN the maybeEnforceRestrictions is called... 148 // THEN true is returned to indicate there was a restriction to enforce. 149 assertThat(mBluetoothEnabler.maybeEnforceRestrictions()).isTrue(); 150 151 // THEN the expected EnfoceAdmin is set. 152 verify(mSwitchController).setDisabledByAdmin(sFakeEnforcedAdmin); 153 154 // THEN the switch is unchecked. 155 verify(mSwitchController).setChecked(false); 156 } 157 158 @Test maybeEnforceRestrictions_disallowConfigBluetoothRestrictionSet()159 public void maybeEnforceRestrictions_disallowConfigBluetoothRestrictionSet() { 160 // GIVEN configuring Bluetooth has been disallowed... 161 when(mRestrictionUtils.checkIfRestrictionEnforced( 162 mContext, UserManager.DISALLOW_BLUETOOTH)).thenReturn(null); 163 when(mRestrictionUtils.checkIfRestrictionEnforced( 164 mContext, UserManager.DISALLOW_CONFIG_BLUETOOTH)).thenReturn(sFakeEnforcedAdmin); 165 166 // WHEN the maybeEnforceRestrictions is called... 167 // THEN true is returned to indicate there was a restriction to enforce. 168 assertThat(mBluetoothEnabler.maybeEnforceRestrictions()).isTrue(); 169 170 // THEN the expected EnfoceAdmin is set. 171 verify(mSwitchController).setDisabledByAdmin(sFakeEnforcedAdmin); 172 173 // THEN the switch is unchecked. 174 verify(mSwitchController).setChecked(false); 175 } 176 177 @Test maybeEnforceRestrictions_disallowBluetoothNotOverriden()178 public void maybeEnforceRestrictions_disallowBluetoothNotOverriden() { 179 // GIVEN Bluetooth has been disallowed... 180 when(mRestrictionUtils.checkIfRestrictionEnforced( 181 mContext, UserManager.DISALLOW_BLUETOOTH)).thenReturn(sFakeEnforcedAdmin); 182 when(mRestrictionUtils.checkIfRestrictionEnforced( 183 mContext, UserManager.DISALLOW_CONFIG_BLUETOOTH)).thenReturn(null); 184 185 mBluetoothEnabler.resume(mContext); 186 187 verify(mSwitchController, never()).setEnabled(true); 188 } 189 190 @Test startWithBluetoothOff_switchIsOff()191 public void startWithBluetoothOff_switchIsOff() { 192 mShadowBluetoothAdapter.setState(BluetoothAdapter.STATE_OFF); 193 verify(mSwitchController, never()).setChecked(anyBoolean()); 194 mBluetoothEnabler.resume(mContext); 195 verify(mSwitchController, never()).setChecked(true); 196 } 197 198 @Test startWithBluetoothOn_switchIsOn()199 public void startWithBluetoothOn_switchIsOn() { 200 mShadowBluetoothAdapter.setState(BluetoothAdapter.STATE_ON); 201 verify(mSwitchController, never()).setChecked(anyBoolean()); 202 mBluetoothEnabler.resume(mContext); 203 verify(mSwitchController, never()).setChecked(false); 204 verify(mSwitchController).setChecked(true); 205 } 206 207 @Test bluetoothTurnsOff_switchTurnsOff()208 public void bluetoothTurnsOff_switchTurnsOff() { 209 // Start up with bluetooth turned on. The switch should get turned on. 210 ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class); 211 when(mContext.registerReceiver(captor.capture(), any(IntentFilter.class))).thenReturn(null); 212 mShadowBluetoothAdapter.setState(BluetoothAdapter.STATE_ON); 213 verify(mSwitchController, never()).setChecked(anyBoolean()); 214 mBluetoothEnabler.resume(mContext); 215 verify(mSwitchController, never()).setChecked(false); 216 verify(mSwitchController).setChecked(true); 217 218 // Now simulate bluetooth being turned off via an event. 219 BroadcastReceiver receiver = captor.getValue(); 220 Intent turningOff = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 221 turningOff.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_TURNING_OFF); 222 receiver.onReceive(mContext, turningOff); 223 Intent off = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 224 off.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF); 225 receiver.onReceive(mContext, off); 226 227 // Make sure the switch was turned off. 228 verify(mSwitchController).setChecked(false); 229 } 230 231 @Test bluetoothTurnsOn_switchTurnsOn()232 public void bluetoothTurnsOn_switchTurnsOn() { 233 // Start up with bluetooth turned on. The switch should be left off. 234 ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class); 235 when(mContext.registerReceiver(captor.capture(), any(IntentFilter.class))).thenReturn(null); 236 mShadowBluetoothAdapter.setState(BluetoothAdapter.STATE_OFF); 237 verify(mSwitchController, never()).setChecked(anyBoolean()); 238 mBluetoothEnabler.resume(mContext); 239 verify(mSwitchController, never()).setChecked(anyBoolean()); 240 241 // Now simulate bluetooth being turned on via an event. 242 BroadcastReceiver receiver = captor.getValue(); 243 Intent turningOn = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 244 turningOn.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_TURNING_ON); 245 receiver.onReceive(mContext, turningOn); 246 Intent on = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED); 247 on.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_ON); 248 receiver.onReceive(mContext, on); 249 250 // Make sure the switch was turned on. 251 verify(mSwitchController).setChecked(true); 252 } 253 } 254