• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.google.android.mobly.snippet.bundled.bluetooth.profiles;
2 
3 import android.annotation.TargetApi;
4 import android.bluetooth.BluetoothAdapter;
5 import android.bluetooth.BluetoothDevice;
6 import android.bluetooth.BluetoothHearingAid;
7 import android.bluetooth.BluetoothProfile;
8 import android.content.Context;
9 import android.content.IntentFilter;
10 import android.os.Build;
11 import android.os.Bundle;
12 import androidx.test.platform.app.InstrumentationRegistry;
13 import com.google.android.mobly.snippet.Snippet;
14 import com.google.android.mobly.snippet.bundled.bluetooth.BluetoothAdapterSnippet;
15 import com.google.android.mobly.snippet.bundled.bluetooth.PairingBroadcastReceiver;
16 import com.google.android.mobly.snippet.bundled.utils.JsonSerializer;
17 import com.google.android.mobly.snippet.bundled.utils.Utils;
18 import com.google.android.mobly.snippet.rpc.Rpc;
19 import com.google.android.mobly.snippet.rpc.RpcMinSdk;
20 import com.google.common.base.Ascii;
21 import java.util.ArrayList;
22 
23 public class BluetoothHearingAidSnippet implements Snippet {
24     private static class BluetoothHearingAidSnippetException extends Exception {
25         private static final long serialVersionUID = 1;
26 
BluetoothHearingAidSnippetException(String msg)27         BluetoothHearingAidSnippetException(String msg) {
28             super(msg);
29         }
30     }
31 
32     private static final int TIMEOUT_SEC = 60;
33 
34     private final Context context;
35     private static boolean isHearingAidProfileReady = false;
36     private static BluetoothHearingAid hearingAidProfile;
37     private final JsonSerializer jsonSerializer = new JsonSerializer();
38 
39     @TargetApi(Build.VERSION_CODES.Q)
BluetoothHearingAidSnippet()40     public BluetoothHearingAidSnippet() {
41         context = InstrumentationRegistry.getInstrumentation().getContext();
42         BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
43         bluetoothAdapter.getProfileProxy(
44                 context, new HearingAidServiceListener(), BluetoothProfile.HEARING_AID);
45         Utils.waitUntil(() -> isHearingAidProfileReady, TIMEOUT_SEC);
46     }
47 
48     @TargetApi(Build.VERSION_CODES.Q)
49     private static class HearingAidServiceListener implements BluetoothProfile.ServiceListener {
50         @Override
onServiceConnected(int var1, BluetoothProfile profile)51         public void onServiceConnected(int var1, BluetoothProfile profile) {
52             hearingAidProfile = (BluetoothHearingAid) profile;
53             isHearingAidProfileReady = true;
54         }
55 
56         @Override
onServiceDisconnected(int var1)57         public void onServiceDisconnected(int var1) {
58             isHearingAidProfileReady = false;
59         }
60     }
61 
62     @TargetApi(Build.VERSION_CODES.Q)
63     @RpcMinSdk(Build.VERSION_CODES.Q)
64     @Rpc(description = "Connects to a paired or discovered device with HA profile.")
btHearingAidConnect(String deviceAddress)65     public void btHearingAidConnect(String deviceAddress) throws Throwable {
66         BluetoothDevice device = BluetoothAdapterSnippet.getKnownDeviceByAddress(deviceAddress);
67         IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
68         context.registerReceiver(new PairingBroadcastReceiver(context), filter);
69         Utils.invokeByReflection(hearingAidProfile, "connect", device);
70         if (!Utils.waitUntil(
71                 () ->
72                         hearingAidProfile.getConnectionState(device)
73                                 == BluetoothHearingAid.STATE_CONNECTED,
74                 TIMEOUT_SEC)) {
75             throw new BluetoothHearingAidSnippetException(
76                     String.format(
77                             "Failed to connect to device %s|%s with HA profile within %d sec.",
78                             device.getName(), device.getAddress(), TIMEOUT_SEC));
79         }
80     }
81 
82     @Rpc(description = "Disconnects a device from HA profile.")
btHearingAidDisconnect(String deviceAddress)83     public void btHearingAidDisconnect(String deviceAddress) throws Throwable {
84         BluetoothDevice device = getConnectedBluetoothDevice(deviceAddress);
85         Utils.invokeByReflection(hearingAidProfile, "disconnect", device);
86         if (!Utils.waitUntil(
87                 () ->
88                         hearingAidProfile.getConnectionState(device)
89                                 == BluetoothHearingAid.STATE_DISCONNECTED,
90                 TIMEOUT_SEC)) {
91             throw new BluetoothHearingAidSnippetException(
92                     String.format(
93                             "Failed to disconnect to device %s|%s with HA profile within %d sec.",
94                             device.getName(), device.getAddress(), TIMEOUT_SEC));
95         }
96     }
97 
98     @Rpc(description = "Gets all the devices currently connected via HA profile.")
btHearingAidGetConnectedDevices()99     public ArrayList<Bundle> btHearingAidGetConnectedDevices() {
100         return jsonSerializer.serializeBluetoothDeviceList(hearingAidProfile.getConnectedDevices());
101     }
102 
getConnectedBluetoothDevice(String deviceAddress)103     private static BluetoothDevice getConnectedBluetoothDevice(String deviceAddress)
104             throws BluetoothHearingAidSnippetException {
105         for (BluetoothDevice device : hearingAidProfile.getConnectedDevices()) {
106             if (Ascii.equalsIgnoreCase(device.getAddress(), deviceAddress)) {
107                 return device;
108             }
109         }
110         throw new BluetoothHearingAidSnippetException(String.format(
111                 "No device with address %s is connected via HA Profile.", deviceAddress));
112     }
113 
114     @Override
shutdown()115     public void shutdown() {}
116 }
117