package com.google.android.mobly.snippet.bundled.bluetooth.profiles; import android.annotation.TargetApi; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.IntentFilter; import android.os.Build; 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.BluetoothAdapterSnippet; 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 com.google.android.mobly.snippet.rpc.RpcMinSdk; import java.util.ArrayList; public class BluetoothA2dpSnippet implements Snippet { private static class BluetoothA2dpSnippetException extends Exception { private static final long serialVersionUID = 1; BluetoothA2dpSnippetException(String msg) { super(msg); } } private Context mContext; private static boolean sIsA2dpProfileReady = false; private static BluetoothA2dp sA2dpProfile; private final JsonSerializer mJsonSerializer = new JsonSerializer(); public BluetoothA2dpSnippet() { mContext = InstrumentationRegistry.getInstrumentation().getContext(); BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); bluetoothAdapter.getProfileProxy( mContext, new A2dpServiceListener(), BluetoothProfile.A2DP); Utils.waitUntil(() -> sIsA2dpProfileReady, 60); } private static class A2dpServiceListener implements BluetoothProfile.ServiceListener { public void onServiceConnected(int var1, BluetoothProfile profile) { sA2dpProfile = (BluetoothA2dp) profile; sIsA2dpProfileReady = true; } public void onServiceDisconnected(int var1) { sIsA2dpProfileReady = false; } } @TargetApi(Build.VERSION_CODES.KITKAT) @RpcMinSdk(Build.VERSION_CODES.KITKAT) @Rpc( description = "Connects to a paired or discovered device with A2DP profile." + "If a device has been discovered but not paired, this will pair it.") public void btA2dpConnect(String deviceAddress) throws Throwable { BluetoothDevice device = BluetoothAdapterSnippet.getKnownDeviceByAddress(deviceAddress); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST); mContext.registerReceiver(new PairingBroadcastReceiver(mContext), filter); Utils.invokeByReflection(sA2dpProfile, "connect", device); if (!Utils.waitUntil( () -> sA2dpProfile.getConnectionState(device) == BluetoothA2dp.STATE_CONNECTED, 120)) { throw new BluetoothA2dpSnippetException( "Failed to connect to device " + device.getName() + "|" + device.getAddress() + " with A2DP profile within 2min."); } } @Rpc(description = "Disconnects a device from A2DP profile.") public void btA2dpDisconnect(String deviceAddress) throws Throwable { BluetoothDevice device = getConnectedBluetoothDevice(deviceAddress); Utils.invokeByReflection(sA2dpProfile, "disconnect", device); if (!Utils.waitUntil( () -> sA2dpProfile.getConnectionState(device) == BluetoothA2dp.STATE_DISCONNECTED, 120)) { throw new BluetoothA2dpSnippetException( "Failed to disconnect device " + device.getName() + "|" + device.getAddress() + " from A2DP profile within 2min."); } } @Rpc(description = "Gets all the devices currently connected via A2DP profile.") public ArrayList<Bundle> btA2dpGetConnectedDevices() { return mJsonSerializer.serializeBluetoothDeviceList(sA2dpProfile.getConnectedDevices()); } @Rpc(description = "Checks if a device is streaming audio via A2DP profile.") public boolean btIsA2dpPlaying(String deviceAddress) throws Throwable { BluetoothDevice device = getConnectedBluetoothDevice(deviceAddress); return sA2dpProfile.isA2dpPlaying(device); } private BluetoothDevice getConnectedBluetoothDevice(String deviceAddress) throws BluetoothA2dpSnippetException { for (BluetoothDevice device : sA2dpProfile.getConnectedDevices()) { if (device.getAddress().equalsIgnoreCase(deviceAddress)) { return device; } } throw new BluetoothA2dpSnippetException( "No device with address " + deviceAddress + " is connected via A2DP."); } @Override public void shutdown() {} }