aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-04-16 23:06:56 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-04-16 23:06:56 +0000
commit84adc0d13c9704606408b464bcbbb4514b9ce5b1 (patch)
treec9dbedc4226ddfcd242b516d47dbe1eda739c331
parent39f4ab8734683e0120245edc60bcb894dc8280d7 (diff)
parent2cedb0bb4826265431a258a166a9ab05ccc4d191 (diff)
downloadmobly-bundled-snippets-sdk-release.tar.gz
Snap for 11724015 from 2cedb0bb4826265431a258a166a9ab05ccc4d191 to sdk-releasesdk-release
Change-Id: I87d815e1aa31c9cc6e4b9630e194d5f5e11e335c
-rw-r--r--METADATA27
-rw-r--r--build.gradle6
-rw-r--r--src/main/AndroidManifest.xml8
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java16
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/TelephonySnippet.java62
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/WifiManagerSnippet.java2
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/BluetoothAdapterSnippet.java2
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/PairingBroadcastReceiver.java1
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/profiles/BluetoothHeadsetSnippet.java163
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonDeserializer.java3
10 files changed, 258 insertions, 32 deletions
diff --git a/METADATA b/METADATA
index d606bbe..c09220a 100644
--- a/METADATA
+++ b/METADATA
@@ -1,19 +1,20 @@
-name: "mobly-bundled-snippets"
-description:
- "Mobly Bundled Snippets is a set of Snippets to allow Mobly tests to "
- "control Android devices by exposing a simplified version of the public "
- "Android API suitable for testing."
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/mobly-bundled-snippets
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+name: "mobly-bundled-snippets"
+description: "Mobly Bundled Snippets is a set of Snippets to allow Mobly tests to control Android devices by exposing a simplified version of the public Android API suitable for testing."
third_party {
- url {
- type: HOMEPAGE
- value: "https://github.com/google/mobly-bundled-snippets"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2024
+ month: 4
+ day: 9
}
- url {
- type: GIT
+ homepage: "https://github.com/google/mobly-bundled-snippets"
+ identifier {
+ type: "Git"
value: "https://github.com/google/mobly-bundled-snippets"
+ version: "4c30f2e6d835ac95b47e0fdfdfaffe5e9e63e4f6"
}
- version: "363a22ae26a277dfbf6c7a0c6596d1a7c08a39f1"
- last_upgrade_date { year: 2023 month: 7 day: 26 }
- license_type: NOTICE
}
diff --git a/build.gradle b/build.gradle
index 99839ee..c88f93c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,12 +29,12 @@ allprojects {
apply plugin: 'com.android.application'
android {
- compileSdkVersion 31
+ compileSdk 33
defaultConfig {
applicationId "com.google.android.mobly.snippet.bundled"
- minSdkVersion 26
- targetSdkVersion 31
+ minSdk 26
+ targetSdk 33
versionCode 1
versionName "0.0.1"
setProperty("archivesBaseName", "mobly-bundled-snippets")
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 8c13914..211104d 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -11,8 +11,11 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
- <uses-permission android:name="android.permission.BLUETOOTH" />
- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+
+ <!-- Request legacy Bluetooth permissions on older devices. -->
+ <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
+
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
@@ -47,6 +50,7 @@
com.google.android.mobly.snippet.bundled.bluetooth.BluetoothGattServerSnippet,
com.google.android.mobly.snippet.bundled.bluetooth.profiles.BluetoothA2dpSnippet,
com.google.android.mobly.snippet.bundled.bluetooth.profiles.BluetoothHearingAidSnippet,
+ com.google.android.mobly.snippet.bundled.bluetooth.profiles.BluetoothHeadsetSnippet,
com.google.android.mobly.snippet.bundled.BluetoothLeAdvertiserSnippet,
com.google.android.mobly.snippet.bundled.BluetoothLeScannerSnippet,
com.google.android.mobly.snippet.bundled.LogSnippet,
diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java
index e8a84c9..362a1b7 100644
--- a/src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java
+++ b/src/main/java/com/google/android/mobly/snippet/bundled/SmsSnippet.java
@@ -84,7 +84,13 @@ public class SmsSnippet implements Snippet {
if (message.length() > MAX_CHAR_COUNT_PER_SMS) {
ArrayList<String> parts = mSmsManager.divideMessage(message);
receiver.setExpectedMessageCount(parts.size());
- mContext.registerReceiver(receiver, new IntentFilter(SMS_SENT_ACTION));
+ if (Build.VERSION.SDK_INT >= 33) {
+ mContext.registerReceiver(receiver, new IntentFilter(SMS_SENT_ACTION), null,
+ null,
+ Context.RECEIVER_EXPORTED);
+ } else {
+ mContext.registerReceiver(receiver, new IntentFilter(SMS_SENT_ACTION));
+ }
mSmsManager.sendMultipartTextMessage(
/* destinationAddress= */ phoneNumber,
/* scAddress= */ null,
@@ -107,7 +113,13 @@ public class SmsSnippet implements Snippet {
/* intent= */ new Intent(SMS_SENT_ACTION),
/* flags= */ PendingIntent.FLAG_IMMUTABLE);
receiver.setExpectedMessageCount(1);
- mContext.registerReceiver(receiver, new IntentFilter(SMS_SENT_ACTION));
+ if (Build.VERSION.SDK_INT >= 33) {
+ mContext.registerReceiver(receiver, new IntentFilter(SMS_SENT_ACTION), null,
+ null,
+ Context.RECEIVER_EXPORTED);
+ } else {
+ mContext.registerReceiver(receiver, new IntentFilter(SMS_SENT_ACTION));
+ }
mSmsManager.sendTextMessage(
/* destinationAddress= */ phoneNumber,
/* scAddress= */ null,
diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/TelephonySnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/TelephonySnippet.java
index 21c5d1e..e4d33ec 100644
--- a/src/main/java/com/google/android/mobly/snippet/bundled/TelephonySnippet.java
+++ b/src/main/java/com/google/android/mobly/snippet/bundled/TelephonySnippet.java
@@ -17,24 +17,49 @@
package com.google.android.mobly.snippet.bundled;
import android.content.Context;
+import android.os.Build;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.test.platform.app.InstrumentationRegistry;
import com.google.android.mobly.snippet.Snippet;
import com.google.android.mobly.snippet.rpc.Rpc;
+import com.google.android.mobly.snippet.rpc.RpcDefault;
/** Snippet class for telephony RPCs. */
public class TelephonySnippet implements Snippet {
private final TelephonyManager mTelephonyManager;
+ private final SubscriptionManager mSubscriptionManager;
public TelephonySnippet() {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ mSubscriptionManager =
+ (SubscriptionManager)
+ context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
}
- @Rpc(description = "Gets the line 1 phone number.")
- public String getLine1Number() {
- return mTelephonyManager.getLine1Number();
+ @Rpc(
+ description =
+ "Gets the line 1 phone number, or optionally get phone number for the "
+ + "simSlot (slot# start from 0, only valid for API level > 32)")
+ public String getLine1Number(@RpcDefault("0") Integer simSlot) {
+ String thisNumber = "";
+
+ if (Build.VERSION.SDK_INT < 33) {
+ thisNumber = mTelephonyManager.getLine1Number();
+ } else {
+ SubscriptionInfo mSubscriptionInfo =
+ mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
+ simSlot.intValue());
+ if (mSubscriptionInfo != null) {
+ thisNumber =
+ mSubscriptionManager.getPhoneNumber(mSubscriptionInfo.getSubscriptionId());
+ }
+ }
+
+ return thisNumber;
}
@Rpc(description = "Returns the unique subscriber ID, for example, the IMSI for a GSM phone.")
@@ -44,10 +69,27 @@ public class TelephonySnippet implements Snippet {
@Rpc(
description =
- "Gets the call state for the default subscription. Call state values are"
- + "0: IDLE, 1: RINGING, 2: OFFHOOK")
- public int getTelephonyCallState() {
- return mTelephonyManager.getCallState();
+ "Gets the call state for the default subscription or optionally get the call"
+ + " state for the simSlot (slot# start from 0, only valid for API"
+ + " level > 30). Call state values are 0: IDLE, 1: RINGING, 2: OFFHOOK")
+ public int getTelephonyCallState(@RpcDefault("0") Integer simSlot) {
+ int thisState = -1;
+
+ if (Build.VERSION.SDK_INT < 31) {
+ return mTelephonyManager.getCallState();
+ } else {
+ SubscriptionInfo mSubscriptionInfo =
+ mSubscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(
+ simSlot.intValue());
+ if (mSubscriptionInfo != null) {
+ thisState =
+ mTelephonyManager
+ .createForSubscriptionId(mSubscriptionInfo.getSubscriptionId())
+ .getCallStateForSubscription();
+ }
+ }
+
+ return thisState;
}
@Rpc(
@@ -55,7 +97,11 @@ public class TelephonySnippet implements Snippet {
"Returns a constant indicating the radio technology (network type) currently"
+ "in use on the device for data transmission.")
public int getDataNetworkType() {
- return mTelephonyManager.getDataNetworkType();
+ if (Build.VERSION.SDK_INT < 30) {
+ return mTelephonyManager.getNetworkType();
+ } else {
+ return mTelephonyManager.getDataNetworkType();
+ }
}
@Rpc(
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 89a65d2..e457dc3 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
@@ -35,8 +35,6 @@ import com.google.android.mobly.snippet.bundled.utils.Utils;
import com.google.android.mobly.snippet.rpc.Rpc;
import com.google.android.mobly.snippet.rpc.RpcMinSdk;
import com.google.android.mobly.snippet.util.Log;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
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 71061fe..07f51e2 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
@@ -343,7 +343,7 @@ public class BluetoothAdapterSnippet implements Snippet {
throws BluetoothAdapterSnippetException, InterruptedException, JSONException {
ArrayList<Bundle> pairedDevices = new ArrayList<>();
for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices()) {
- pairedDevices.add(mJsonSerializer.serializeBluetoothDevice(device));
+ pairedDevices.add(JsonSerializer.serializeBluetoothDevice(device));
}
return pairedDevices;
}
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 69ae433..f704897 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
@@ -20,6 +20,7 @@ public class PairingBroadcastReceiver extends BroadcastReceiver {
Utils.adaptShellPermissionIfRequired(mContext);
}
+ @Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/profiles/BluetoothHeadsetSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/profiles/BluetoothHeadsetSnippet.java
new file mode 100644
index 0000000..71cb81d
--- /dev/null
+++ b/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/profiles/BluetoothHeadsetSnippet.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2024 Google Inc.
+ *
+ * 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.google.android.mobly.snippet.bundled.bluetooth.profiles;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.os.Bundle;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.google.android.mobly.snippet.Snippet;
+import com.google.android.mobly.snippet.bundled.bluetooth.PairingBroadcastReceiver;
+import com.google.android.mobly.snippet.bundled.utils.JsonSerializer;
+import com.google.android.mobly.snippet.bundled.utils.Utils;
+import com.google.android.mobly.snippet.rpc.Rpc;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * Custom exception class for handling exceptions within the BluetoothHeadsetSnippet.
+ * This exception is meant to encapsulate and convey specific error information related to
+ * BluetoothHeadsetSnippet operations.
+ */
+public class BluetoothHeadsetSnippet implements Snippet {
+
+ private final JsonSerializer mJsonSerializer = new JsonSerializer();
+ private static final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ private final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ private static class BluetoothHeadsetSnippetException extends Exception {
+ private static final long serialVersionUID = 1;
+
+ /**
+ * Constructs a BluetoothHeadsetSnippetException with the specified detail message.
+ *
+ * @param msg The detail message providing information about the exception.
+ */
+ BluetoothHeadsetSnippetException(String msg) {
+ super(msg);
+ }
+ }
+
+ private BluetoothHeadset mBluetoothHeadset;
+ private static final int HEADSET = 1;
+
+ private final BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
+ @Override
+ public void onServiceConnected(int var1, BluetoothProfile profile) {
+ if (var1 == HEADSET) {
+ mBluetoothHeadset = (BluetoothHeadset)profile;
+ }
+ }
+ @Override
+ public void onServiceDisconnected(int var1) {
+ if (var1 == HEADSET) {
+ mBluetoothHeadset = null;
+ }
+ }
+ };
+
+ public BluetoothHeadsetSnippet() throws Throwable {
+ IntentFilter filter = new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+ filter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
+ mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEADSET);
+ Utils.waitUntil(() -> mBluetoothHeadset != null, 60);
+ mContext.registerReceiver(new PairingBroadcastReceiver(mContext), filter);
+ }
+
+
+ /**
+ * Returns the connection state for a Bluetooth device with the specified name.
+ *
+ * @param deviceAddress The address of the Bluetooth device.
+ * @return The connection state for the specified device.
+ * @throws BluetoothHeadsetSnippetException If no device with the specified name is connected via HEADSET.
+ */
+ @Rpc(description = "Returns connection state.")
+ public int btHfpGetConnectionState(String deviceAddress) throws BluetoothHeadsetSnippetException {
+ Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
+ for (BluetoothDevice device : pairedDevices) {
+ if (device.getAddress().equalsIgnoreCase(deviceAddress)) {
+ return mBluetoothHeadset.getConnectionState(device);
+ }
+ }
+ throw new BluetoothHeadsetSnippetException("No device with name " + deviceAddress +" is connected via HEADSET.");
+ }
+
+ /**
+ * Starts voice recognition for the Bluetooth device with the specified name.
+ *
+ * @param deviceAddress The address of the Bluetooth device.
+ * @return True if voice recognition is successfully started; false otherwise.
+ * @throws BluetoothHeadsetSnippetException If no device with the specified name is found or if an error
+ * occurs during the startVoiceRecognition operation.
+ */
+ @Rpc(description = "Starts voice recognition.")
+ public boolean btHfpStartVoiceRecognition(String deviceAddress) throws BluetoothHeadsetSnippetException{
+ Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
+ for (BluetoothDevice device : pairedDevices) {
+ if (device.getAddress().equalsIgnoreCase(deviceAddress)) {
+ return mBluetoothHeadset.startVoiceRecognition(device);
+ }
+ }
+ throw new BluetoothHeadsetSnippetException("No device with name " + deviceAddress +" is connected via HEADSET.");
+ }
+
+
+ /**
+ * Stops voice recognition for the Bluetooth device with the specified name.
+ *
+ * @param deviceAddress The address of the Bluetooth device.
+ * @return True if voice recognition is successfully started; false otherwise.
+ * @throws BluetoothHeadsetSnippetException If no device with the specified name is found or if an error
+ * occurs during the startVoiceRecognition operation.
+ */
+ @Rpc(description = "Stops voice recognition.")
+ public boolean btHfpStopVoiceRecognition(String deviceAddress) throws BluetoothHeadsetSnippetException {
+ Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
+ for (BluetoothDevice device : pairedDevices) {
+ if (device.getAddress().equalsIgnoreCase(deviceAddress)) {
+ return mBluetoothHeadset.stopVoiceRecognition(device);
+ }
+ }
+ throw new BluetoothHeadsetSnippetException("No device with name " + deviceAddress +" is connected via HEADSET.");
+ }
+
+ @Rpc(description = "Checks whether the headset supports voice recognition;")
+ public boolean btHfpIsVoiceRecognitionSupported(String deviceAddress) throws BluetoothHeadsetSnippetException {
+ Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
+ for (BluetoothDevice device : pairedDevices) {
+ if (device.getAddress().equalsIgnoreCase(deviceAddress)) {
+ return mBluetoothHeadset.isVoiceRecognitionSupported(device);
+ }
+ }
+ throw new BluetoothHeadsetSnippetException("No device with name " + deviceAddress +" is connected via HEADSET.");
+ }
+ @Rpc(description = "Gets all the devices currently connected via HFP profile.")
+ public ArrayList<Bundle> btHfpGetConnectedDevices() {
+ return mJsonSerializer.serializeBluetoothDeviceList(mBluetoothHeadset.getConnectedDevices());
+ }
+
+ @Override
+ public void shutdown() { }
+}
diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonDeserializer.java b/src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonDeserializer.java
index a3d5325..c7d5a91 100644
--- a/src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonDeserializer.java
+++ b/src/main/java/com/google/android/mobly/snippet/bundled/utils/JsonDeserializer.java
@@ -101,7 +101,8 @@ public class JsonDeserializer {
JSONObject manufacturerData = jsonObject.getJSONObject("ManufacturerData");
int manufacturerId = manufacturerData.getInt("ManufacturerId");
byte[] manufacturerSpecificData =
- Base64.decode(jsonObject.getString("ManufacturerSpecificData"), Base64.DEFAULT);
+ Base64.decode(
+ manufacturerData.getString("ManufacturerSpecificData"), Base64.DEFAULT);
builder.addManufacturerData(manufacturerId, manufacturerSpecificData);
}
return builder.build();