diff options
author | Kolin Lu <kolinlu@google.com> | 2023-07-20 10:00:48 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-20 10:00:48 -0700 |
commit | 363a22ae26a277dfbf6c7a0c6596d1a7c08a39f1 (patch) | |
tree | fccb6a72a9c459a7bb9fa4eb0f359592313c24d7 | |
parent | d56020d155e315bab4e1877a917dc83dabedef86 (diff) | |
parent | af75836bb4622ce286f480b55e6a070fc7a5b105 (diff) | |
download | mobly-bundled-snippets-363a22ae26a277dfbf6c7a0c6596d1a7c08a39f1.tar.gz |
Merge pull request #169 from stplaydog/btfix
Solve permission issues when performing btDiscoverAndGetResults
5 files changed, 61 insertions, 36 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 075fbe8..bcf52b2 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> + <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> @@ -39,6 +40,7 @@ android:name="androidx.multidex.MultiDexApplication"> <meta-data android:name="mobly-snippets" + android:testOnly="true" android:value="com.google.android.mobly.snippet.bundled.AccountSnippet, com.google.android.mobly.snippet.bundled.AudioSnippet, com.google.android.mobly.snippet.bundled.bluetooth.BluetoothAdapterSnippet, diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java index 7e1a416..89a65d2 100644 --- a/src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java +++ b/src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java @@ -16,7 +16,6 @@ package com.google.android.mobly.snippet.bundled; -import android.app.UiAutomation; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -44,6 +43,9 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.net.wifi.SupplicantState; + +import com.google.android.mobly.snippet.bundled.utils.Utils; + /** Snippet class exposing Android APIs in WifiManager. */ public class WifiManagerSnippet implements Snippet { private static class WifiManagerSnippetException extends Exception { @@ -52,10 +54,6 @@ public class WifiManagerSnippet implements Snippet { public WifiManagerSnippetException(String msg) { super(msg); } - - public WifiManagerSnippetException(String msg, Throwable err) { - super(msg, err); - } } private static final int TIMEOUT_TOGGLE_STATE = 30; @@ -69,7 +67,7 @@ public class WifiManagerSnippet implements Snippet { mWifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE); - adaptShellPermissionIfRequired(); + Utils.adaptShellPermissionIfRequired(mContext); } @Rpc( @@ -403,33 +401,6 @@ public class WifiManagerSnippet implements Snippet { @Override public void shutdown() {} - /** - * Elevates permission as require for proper wifi controls. - * - * Starting in Android Q (29), additional restrictions are added for wifi operation. See - * below Android Q privacy changes for additional details. - * https://developer.android.com/preview/privacy/camera-connectivity - * - * @throws Throwable if failed to cleanup connection with UiAutomation - */ - private void adaptShellPermissionIfRequired() throws Throwable { - if (mContext.getApplicationContext().getApplicationInfo().targetSdkVersion >= 29 - && Build.VERSION.SDK_INT >= 29) { - Log.d("Elevating permission require to enable support for wifi operation in Android Q+"); - UiAutomation uia = InstrumentationRegistry.getInstrumentation().getUiAutomation(); - uia.adoptShellPermissionIdentity(); - try { - Class<?> cls = Class.forName("android.app.UiAutomation"); - Method destroyMethod = cls.getDeclaredMethod("destroy"); - destroyMethod.invoke(uia); - } catch (NoSuchMethodException - | IllegalAccessException - | ClassNotFoundException - | InvocationTargetException e) { - throw new WifiManagerSnippetException("Failed to cleaup Ui Automation", e); - } - } - } private class WifiScanReceiver extends BroadcastReceiver { diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java index 2fd836b..71061fe 100644 --- a/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java +++ b/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java @@ -36,7 +36,10 @@ import com.google.android.mobly.snippet.bundled.utils.Utils; import com.google.android.mobly.snippet.rpc.Rpc; import com.google.android.mobly.snippet.util.Log; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.HashMap; +import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Pattern; @@ -69,9 +72,13 @@ public class BluetoothAdapterSnippet implements Snippet { private static final ConcurrentHashMap<String, BluetoothDevice> mDiscoveryResults = new ConcurrentHashMap<>(); private volatile boolean mIsDiscoveryFinished = false; + private final Map<String, BroadcastReceiver> mReceivers; - public BluetoothAdapterSnippet() { + public BluetoothAdapterSnippet() throws Throwable { mContext = InstrumentationRegistry.getInstrumentation().getContext(); + // Use a synchronized map to avoid racing problems + mReceivers = Collections.synchronizedMap(new HashMap<String, BroadcastReceiver>()); + Utils.adaptShellPermissionIfRequired(mContext); mPackageManager = mContext.getPackageManager(); } @@ -193,6 +200,20 @@ public class BluetoothAdapterSnippet implements Snippet { return mBluetoothAdapter.getName(); } + @Rpc(description = "Automatically confirm the incoming BT pairing request.") + public void btStartAutoAcceptIncomingPairRequest() throws Throwable { + BroadcastReceiver receiver = new PairingBroadcastReceiver(mContext); + mContext.registerReceiver( + receiver, PairingBroadcastReceiver.filter); + mReceivers.put("AutoAcceptIncomingPairReceiver", receiver); + } + + @Rpc(description = "Stop the incoming BT pairing request.") + public void btStopAutoAcceptIncomingPairRequest() throws Throwable { + BroadcastReceiver receiver = mReceivers.remove("AutoAcceptIncomingPairReceiver"); + mContext.unregisterReceiver(receiver); + } + @Rpc(description = "Returns the hardware address of the local Bluetooth adapter.") public String btGetAddress() { return mBluetoothAdapter.getAddress(); @@ -369,7 +390,12 @@ public class BluetoothAdapterSnippet implements Snippet { } @Override - public void shutdown() {} + public void shutdown() { + for (Map.Entry<String, BroadcastReceiver> entry : mReceivers.entrySet()) { + mContext.unregisterReceiver(entry.getValue()); + } + mReceivers.clear(); + } private class BluetoothScanReceiver extends BroadcastReceiver { diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/PairingBroadcastReceiver.java b/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/PairingBroadcastReceiver.java index 0cfd362..69ae433 100644 --- a/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/PairingBroadcastReceiver.java +++ b/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/PairingBroadcastReceiver.java @@ -8,14 +8,16 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Build; import com.google.android.mobly.snippet.util.Log; +import com.google.android.mobly.snippet.bundled.utils.Utils; @TargetApi(Build.VERSION_CODES.KITKAT) public class PairingBroadcastReceiver extends BroadcastReceiver { private final Context mContext; public static IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST); - public PairingBroadcastReceiver(Context context) { + public PairingBroadcastReceiver(Context context) throws Throwable { mContext = context; + Utils.adaptShellPermissionIfRequired(mContext); } public void onReceive(Context context, Intent intent) { diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java b/src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java index 376bcb5..bd9a76f 100644 --- a/src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java +++ b/src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java @@ -16,9 +16,14 @@ package com.google.android.mobly.snippet.bundled.utils; +import android.app.UiAutomation; +import android.os.Build; +import android.content.Context; +import androidx.test.platform.app.InstrumentationRegistry; import com.google.android.mobly.snippet.bundled.SmsSnippet; import com.google.android.mobly.snippet.event.EventCache; import com.google.android.mobly.snippet.event.SnippetEvent; +import com.google.android.mobly.snippet.util.Log; import com.google.common.primitives.Primitives; import com.google.common.reflect.TypeToken; import java.lang.reflect.InvocationTargetException; @@ -210,4 +215,23 @@ public final class Utils { } return new String(hexChars); } + + public static void adaptShellPermissionIfRequired(Context context) throws Throwable { + if (context.getApplicationContext().getApplicationInfo().targetSdkVersion >= 29 + && Build.VERSION.SDK_INT >= 29) { + Log.d("Elevating permission require to enable support for privileged operation in Android Q+"); + UiAutomation uia = InstrumentationRegistry.getInstrumentation().getUiAutomation(); + uia.adoptShellPermissionIdentity(); + try { + Class<?> cls = Class.forName("android.app.UiAutomation"); + Method destroyMethod = cls.getDeclaredMethod("destroy"); + destroyMethod.invoke(uia); + } catch (NoSuchMethodException + | IllegalAccessException + | ClassNotFoundException + | InvocationTargetException e) { + throw new RuntimeException("Failed to cleaup Ui Automation", e); + } + } + } } |