1 /* 2 * Copyright (C) 2016 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 17 package com.android.cts.deviceowner; 18 19 import static com.google.common.truth.Truth.assertWithMessage; 20 21 import android.bluetooth.BluetoothAdapter; 22 import android.content.ComponentName; 23 import android.content.pm.PackageManager; 24 import android.os.SystemClock; 25 import android.os.UserManager; 26 import android.util.DebugUtils; 27 import android.util.Log; 28 29 import com.android.bedstead.nene.TestApis; 30 import com.android.internal.util.ArrayUtils; 31 32 /** 33 * Test interaction between {@link UserManager#DISALLOW_BLUETOOTH} user restriction and the state 34 * of Bluetooth. 35 */ 36 public class BluetoothRestrictionTest extends BaseDeviceOwnerTest { 37 38 private static final String TAG = BluetoothRestrictionTest.class.getSimpleName(); 39 private static final boolean VERBOSE = false; 40 41 private static final int DISABLE_TIMEOUT_MS = 8000; // ms timeout for BT disable 42 private static final int ENABLE_TIMEOUT_MS = 20_000; // ms timeout for BT enable 43 private static final int POLL_TIME_MS = 400; // ms to poll BT state 44 private static final int CHECK_WAIT_TIME_MS = 1_000; // ms to wait before enable/disable 45 private static final int COMPONENT_STATE_TIMEOUT_MS = 10_000; 46 private static final String OPP_LAUNCHER_CLASS = 47 "com.android.bluetooth.opp.BluetoothOppLauncherActivity"; 48 private BluetoothAdapter mBluetoothAdapter; 49 private PackageManager mPackageManager; 50 51 @Override setUp()52 protected void setUp() throws Exception { 53 super.setUp(); 54 55 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 56 if (mBluetoothAdapter == null) { 57 Log.w(TAG, "No Bluetooth adapter"); 58 } else { 59 int state = mBluetoothAdapter.getConnectionState(); 60 Log.d(TAG, "BluetoothAdapter: " + mBluetoothAdapter 61 + " enabled: " + mBluetoothAdapter.isEnabled() 62 + " state: " + state + " (" + btStateToString(state) + ")"); 63 } 64 mPackageManager = mContext.getPackageManager(); 65 } 66 67 @Override tearDown()68 protected void tearDown() throws Exception { 69 super.tearDown(); 70 71 clearBluetoothRestriction(); 72 enable(); 73 } 74 testEnableBluetoothFailsWhenDisallowed()75 public void testEnableBluetoothFailsWhenDisallowed() throws Exception { 76 if (mBluetoothAdapter == null) { 77 return; 78 } 79 80 // Make sure Bluetooth is initially disabled. 81 disable(); 82 83 // Add the user restriction disallowing Bluetooth. 84 addBluetoothRestriction(); 85 86 // Check that enabling Bluetooth fails. 87 assertBluetoothAdapterDisabled(); 88 } 89 testBluetoothGetsDisabledAfterRestrictionSet()90 public void testBluetoothGetsDisabledAfterRestrictionSet() throws Exception { 91 if (mBluetoothAdapter == null) { 92 return; 93 } 94 95 // Make sure Bluetooth is enabled first. 96 enable(); 97 98 // Add the user restriction to disallow Bluetooth. 99 addBluetoothRestriction(); 100 101 // Check that Bluetooth gets disabled as a result. 102 assertDisabledAfterTimeout(); 103 } 104 testEnableBluetoothSucceedsAfterRestrictionRemoved()105 public void testEnableBluetoothSucceedsAfterRestrictionRemoved() throws Exception { 106 if (mBluetoothAdapter == null) { 107 return; 108 } 109 110 // Add the user restriction. 111 addBluetoothRestriction(); 112 113 // Make sure Bluetooth is disabled. 114 assertDisabledAfterTimeout(); 115 116 // Remove the user restriction. 117 clearBluetoothRestriction(); 118 119 // Check that it is possible to enable Bluetooth again once the restriction has been 120 // removed. 121 enable(); 122 } 123 124 /** 125 * Tests that BluetoothOppLauncherActivity gets disabled when Bluetooth itself or Bluetooth 126 * sharing is disallowed. 127 * 128 * <p> It also checks the state of the activity is set back to default if Bluetooth is not 129 * disallowed anymore. 130 */ testOppDisabledWhenRestrictionSet()131 public void testOppDisabledWhenRestrictionSet() throws Exception { 132 if (mBluetoothAdapter == null || UserManager.isHeadlessSystemUserMode()) { 133 return; 134 } 135 136 ComponentName oppLauncherComponent = 137 new ComponentName(TestApis.bluetooth().findPackageName(), OPP_LAUNCHER_CLASS); 138 139 // First verify DISALLOW_BLUETOOTH. 140 testOppDisabledWhenRestrictionSet(UserManager.DISALLOW_BLUETOOTH, 141 oppLauncherComponent); 142 143 // Verify DISALLOW_BLUETOOTH_SHARING which leaves bluetooth workable but the sharing 144 // component should be disabled. 145 testOppDisabledWhenRestrictionSet( 146 UserManager.DISALLOW_BLUETOOTH_SHARING, oppLauncherComponent); 147 } 148 149 /** Verifies that a given restriction disables the bluetooth sharing component. */ testOppDisabledWhenRestrictionSet(String restriction, ComponentName oppLauncherComponent)150 private void testOppDisabledWhenRestrictionSet(String restriction, 151 ComponentName oppLauncherComponent) { 152 // Add the user restriction. 153 addUserRestriction(restriction); 154 155 // The BluetoothOppLauncherActivity's component should be disabled. 156 assertComponentStateAfterTimeout( 157 oppLauncherComponent, new int[] {PackageManager.COMPONENT_ENABLED_STATE_DISABLED}); 158 159 // Remove the user restriction. 160 clearUserRestriction(restriction); 161 162 // The BluetoothOppLauncherActivity's component should be enabled or default. 163 assertComponentStateAfterTimeout( 164 oppLauncherComponent, new int[] {PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 165 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT}); 166 } 167 168 /** Helper to turn BT off. 169 * This method will either fail on an assert, or return with BT turned off. 170 * Behavior of getState() and isEnabled() are validated along the way. 171 */ disable()172 private void disable() { 173 // Can't disable a bluetooth adapter that does not exist. 174 if (mBluetoothAdapter == null) { 175 Log.v(TAG, "disable(): ignoring as there is no BT adapter"); 176 return; 177 } 178 179 sleep(CHECK_WAIT_TIME_MS); 180 int state = mBluetoothAdapter.getState(); 181 Log.v(TAG, "disable(): Current state: " + btStateToString(state)); 182 if (state == BluetoothAdapter.STATE_OFF) { 183 assertBluetoothAdapterDisabled(); 184 return; 185 } 186 187 assertBluetoothAdapterState(BluetoothAdapter.STATE_ON); 188 assertBluetoothAdapterEnabled(); 189 Log.i(TAG, "Disabling BT"); 190 boolean result = mBluetoothAdapter.disable(); 191 Log.v(TAG, "Result: " + result); 192 assertDisabledAfterTimeout(); 193 } 194 195 /** 196 * Helper method which waits for Bluetooth to be disabled. Fails if it doesn't happen in a 197 * given time. 198 */ assertDisabledAfterTimeout()199 private void assertDisabledAfterTimeout() { 200 boolean turningOff = false; 201 long timeout = SystemClock.elapsedRealtime() + DISABLE_TIMEOUT_MS; 202 Log.d(TAG, "Waiting up to " + timeout + " ms for STATE_OFF and disabled"); 203 int state = Integer.MIN_VALUE; 204 while (SystemClock.elapsedRealtime() < timeout) { 205 state = mBluetoothAdapter.getState(); 206 Log.v(TAG, "State: " + btStateToString(state) + " turningOff: " + turningOff); 207 switch (state) { 208 case BluetoothAdapter.STATE_OFF: 209 Log.d(TAG, "STATE_OFF received, check that adapter is disabled"); 210 assertBluetoothAdapterDisabled(); 211 return; 212 default: 213 if (state != BluetoothAdapter.STATE_ON || turningOff) { 214 assertBluetoothAdapterState(BluetoothAdapter.STATE_TURNING_OFF); 215 turningOff = true; 216 } 217 break; 218 } 219 sleep(POLL_TIME_MS); 220 } 221 fail("disable() timeout - BT adapter state is " + btStateToString(state) 222 + " instead of STATE_OFF"); 223 } 224 assertComponentStateAfterTimeout(ComponentName component, int[] expectedState)225 private void assertComponentStateAfterTimeout(ComponentName component, int[] expectedState) { 226 final long timeout = SystemClock.elapsedRealtime() + COMPONENT_STATE_TIMEOUT_MS; 227 int state = -1; 228 while (SystemClock.elapsedRealtime() < timeout) { 229 state = mPackageManager.getComponentEnabledSetting(component); 230 if (ArrayUtils.contains(expectedState, state)) { 231 // Success, waiting for component to be fully turned on/off 232 sleep(CHECK_WAIT_TIME_MS); 233 return; 234 } 235 sleep(POLL_TIME_MS); 236 } 237 fail("The state of " + component + " should have been " 238 + ArrayUtils.deepToString(expectedState) + ", it but was " 239 + state + " after timeout."); 240 } 241 242 /** Helper to turn BT on. 243 * This method will either fail on an assert, or return with BT turned on. 244 * Behavior of getState() and isEnabled() are validated along the way. 245 */ enable()246 private void enable() { 247 // Can't enable a bluetooth adapter that does not exist. 248 if (mBluetoothAdapter == null) { 249 Log.v(TAG, "enable(): ignoring as there is no BT adapter"); 250 return; 251 } 252 253 sleep(CHECK_WAIT_TIME_MS); 254 int state = mBluetoothAdapter.getState(); 255 Log.v(TAG, "enable(): Current state: " + btStateToString(state)); 256 257 if (state == BluetoothAdapter.STATE_ON) { 258 assertBluetoothAdapterEnabled(); 259 return; 260 } 261 262 assertBluetoothAdapterState(BluetoothAdapter.STATE_OFF); 263 assertBluetoothAdapterDisabled(); 264 Log.i(TAG, "Enabling BT"); 265 boolean result = mBluetoothAdapter.enable(); 266 Log.v(TAG, "Result: " + result); 267 assertEnabledAfterTimeout(); 268 } 269 270 /** 271 * Helper method which waits for Bluetooth to be enabled. Fails if it doesn't happen in a given 272 * time. 273 */ assertEnabledAfterTimeout()274 private void assertEnabledAfterTimeout() { 275 boolean turningOn = false; 276 long timeout = SystemClock.elapsedRealtime() + ENABLE_TIMEOUT_MS; 277 Log.d(TAG, "Waiting up to " + timeout + " ms for STATE_ON and enabled"); 278 int state = Integer.MIN_VALUE; 279 while (SystemClock.elapsedRealtime() < timeout) { 280 state = mBluetoothAdapter.getState(); 281 Log.v(TAG, "State: " + btStateToString(state) + " turningOn: " + turningOn); 282 switch (state) { 283 case BluetoothAdapter.STATE_ON: 284 Log.d(TAG, "STATE_ON received, check that adapter is enabled"); 285 assertBluetoothAdapterEnabled(); 286 return; 287 default: 288 if (state != BluetoothAdapter.STATE_OFF || turningOn) { 289 assertBluetoothAdapterState(BluetoothAdapter.STATE_TURNING_ON); 290 turningOn = true; 291 } 292 break; 293 } 294 sleep(POLL_TIME_MS); 295 } 296 fail("enable() timeout - BT adapter state is " + btStateToString(state) 297 + " instead of STATE_ON"); 298 } 299 assertBluetoothAdapterEnabled()300 private void assertBluetoothAdapterEnabled() { 301 assertWithMessage("mBluetoothAdapter.isEnabled()").that(mBluetoothAdapter.isEnabled()) 302 .isTrue(); 303 } 304 assertBluetoothAdapterDisabled()305 private void assertBluetoothAdapterDisabled() { 306 assertWithMessage("mBluetoothAdapter.isEnabled()").that(mBluetoothAdapter.isEnabled()) 307 .isFalse(); 308 } 309 assertBluetoothAdapterState(int expectedState)310 private void assertBluetoothAdapterState(int expectedState) { 311 int actualState = mBluetoothAdapter.getState(); 312 assertWithMessage("mBluetoothAdapter.getState() (where %s is %s and %s is %s)", 313 expectedState, btStateToString(expectedState), 314 actualState, btStateToString(actualState)) 315 .that(actualState).isEqualTo(expectedState); 316 } 317 addBluetoothRestriction()318 private void addBluetoothRestriction() { 319 addUserRestriction(UserManager.DISALLOW_BLUETOOTH); 320 } 321 clearBluetoothRestriction()322 private void clearBluetoothRestriction() { 323 clearUserRestriction(UserManager.DISALLOW_BLUETOOTH); 324 } 325 addUserRestriction(String restriction)326 private void addUserRestriction(String restriction) { 327 Log.d(TAG, "Adding " + restriction + " using " + mDevicePolicyManager); 328 mDevicePolicyManager.addUserRestriction(getWho(), restriction); 329 } 330 clearUserRestriction(String restriction)331 private void clearUserRestriction(String restriction) { 332 Log.d(TAG, "Clearing " + restriction + " using " + mDevicePolicyManager); 333 mDevicePolicyManager.clearUserRestriction(getWho(), restriction); 334 } 335 btStateToString(int state)336 private static String btStateToString(int state) { 337 return DebugUtils.constantToString(BluetoothAdapter.class, "STATE_", state); 338 } 339 sleep(long t)340 private static void sleep(long t) { 341 if (VERBOSE) { 342 Log.v(TAG, "Sleeping for " + t + "ms"); 343 } 344 SystemClock.sleep(t); 345 } 346 } 347