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 17 package android.bluetooth.cts; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.le.ScanRecord; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.content.pm.PackageManager; 26 import android.provider.Settings; 27 import android.util.Log; 28 29 import junit.framework.Assert; 30 31 import java.lang.reflect.InvocationTargetException; 32 import java.lang.reflect.Method; 33 import java.util.Arrays; 34 import java.util.concurrent.TimeUnit; 35 import java.util.concurrent.locks.Condition; 36 import java.util.concurrent.locks.ReentrantLock; 37 38 /** 39 * Utility for controlling the Bluetooth adapter from CTS test. 40 */ 41 public class BTAdapterUtils { 42 private static final String TAG = "BTAdapterUtils"; 43 44 // ADAPTER_ENABLE_TIMEOUT_MS = AdapterState.BLE_START_TIMEOUT_DELAY + 45 // AdapterState.BREDR_START_TIMEOUT_DELAY 46 private static final int ADAPTER_ENABLE_TIMEOUT_MS = 8000; 47 // ADAPTER_DISABLE_TIMEOUT_MS = AdapterState.BLE_STOP_TIMEOUT_DELAY + 48 // AdapterState.BREDR_STOP_TIMEOUT_DELAY 49 private static final int ADAPTER_DISABLE_TIMEOUT_MS = 5000; 50 51 private static BroadcastReceiver mAdapterIntentReceiver; 52 53 private static Condition mConditionAdapterIsEnabled; 54 private static ReentrantLock mAdapterStateEnablinglock; 55 56 private static Condition mConditionAdapterIsDisabled; 57 private static ReentrantLock mAdapterStateDisablinglock; 58 private static boolean mAdapterVarsInitialized; 59 60 private static class AdapterIntentReceiver extends BroadcastReceiver { 61 @Override onReceive(Context context, Intent intent)62 public void onReceive(Context context, Intent intent) { 63 if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) { 64 int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1); 65 int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); 66 Log.d(TAG, "Previous state: " + previousState + " New state: " + newState); 67 68 if (newState == BluetoothAdapter.STATE_ON) { 69 mAdapterStateEnablinglock.lock(); 70 try { 71 Log.d(TAG, "Signaling to mConditionAdapterIsEnabled"); 72 mConditionAdapterIsEnabled.signal(); 73 } finally { 74 mAdapterStateEnablinglock.unlock(); 75 } 76 } else if (newState == BluetoothAdapter.STATE_OFF) { 77 mAdapterStateDisablinglock.lock(); 78 try { 79 Log.d(TAG, "Signaling to mConditionAdapterIsDisabled"); 80 mConditionAdapterIsDisabled.signal(); 81 } finally { 82 mAdapterStateDisablinglock.unlock(); 83 } 84 } 85 } 86 } 87 } 88 89 /** Enables the Bluetooth Adapter. Return true if it is already enabled or is enabled. */ enableAdapter(BluetoothAdapter bluetoothAdapter, Context context)90 public static boolean enableAdapter(BluetoothAdapter bluetoothAdapter, Context context) { 91 if (!mAdapterVarsInitialized) { 92 initAdapterStateVariables(context); 93 } 94 95 if (bluetoothAdapter.isEnabled()) return true; 96 97 Log.d(TAG, "Enabling bluetooth adapter"); 98 bluetoothAdapter.enable(); 99 mAdapterStateEnablinglock.lock(); 100 try { 101 // Wait for the Adapter to be enabled 102 while (!bluetoothAdapter.isEnabled()) { 103 if (!mConditionAdapterIsEnabled.await( 104 ADAPTER_ENABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 105 // Timeout 106 Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter enable"); 107 break; 108 } // else spurious wakeups 109 } 110 } catch(InterruptedException e) { 111 Log.e(TAG, "enableAdapter: interrrupted"); 112 } finally { 113 mAdapterStateEnablinglock.unlock(); 114 } 115 return bluetoothAdapter.isEnabled(); 116 } 117 118 /** Disable the Bluetooth Adapter. Return true if it is already disabled or is disabled. */ disableAdapter(BluetoothAdapter bluetoothAdapter, Context context)119 public static boolean disableAdapter(BluetoothAdapter bluetoothAdapter, Context context) { 120 if (!mAdapterVarsInitialized) { 121 initAdapterStateVariables(context); 122 } 123 124 if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) return true; 125 126 Log.d(TAG, "Disabling bluetooth adapter"); 127 bluetoothAdapter.disable(); 128 mAdapterStateDisablinglock.lock(); 129 try { 130 // Wait for the Adapter to be disabled 131 while (bluetoothAdapter.getState() != BluetoothAdapter.STATE_OFF) { 132 if (!mConditionAdapterIsDisabled.await( 133 ADAPTER_DISABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 134 // Timeout 135 Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter disable"); 136 break; 137 } // else spurious wakeups 138 } 139 } catch(InterruptedException e) { 140 Log.e(TAG, "enableAdapter: interrrupted"); 141 } finally { 142 mAdapterStateDisablinglock.unlock(); 143 } 144 return bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF; 145 } 146 147 // Initialize variables required for TestUtils#enableAdapter and TestUtils#disableAdapter initAdapterStateVariables(Context context)148 private static void initAdapterStateVariables(Context context) { 149 Log.d(TAG, "Initializing adapter state variables"); 150 mAdapterIntentReceiver = new AdapterIntentReceiver(); 151 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 152 context.registerReceiver(mAdapterIntentReceiver, filter); 153 154 mAdapterStateEnablinglock = new ReentrantLock(); 155 mConditionAdapterIsEnabled = mAdapterStateEnablinglock.newCondition(); 156 mAdapterStateDisablinglock = new ReentrantLock(); 157 mConditionAdapterIsDisabled = mAdapterStateDisablinglock.newCondition(); 158 159 mAdapterVarsInitialized = true; 160 } 161 }