aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/google/android/mobly/snippet/bundled/bluetooth/profiles/BluetoothHeadsetSnippet.java
blob: 71cb81d577e30f20e90dd12870cde21b3db172f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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() { }
}