1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.googlecode.android_scripting.facade.bluetooth;
18 
19 import android.app.Service;
20 import android.bluetooth.BluetoothAdapter;
21 import android.bluetooth.BluetoothDevice;
22 import android.bluetooth.BluetoothHeadsetClient;
23 import android.bluetooth.BluetoothProfile;
24 import android.bluetooth.BluetoothUuid;
25 import android.os.ParcelUuid;
26 
27 import com.googlecode.android_scripting.Log;
28 import com.googlecode.android_scripting.facade.FacadeManager;
29 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
30 import com.googlecode.android_scripting.rpc.Rpc;
31 import com.googlecode.android_scripting.rpc.RpcParameter;
32 
33 import java.util.ArrayList;
34 import java.util.List;
35 
36 public class BluetoothHfpClientFacade extends RpcReceiver {
37     static final ParcelUuid[] UUIDS = {
38         BluetoothUuid.Handsfree_AG,
39     };
40 
41     private final Service mService;
42     private final BluetoothAdapter mBluetoothAdapter;
43 
44     private static boolean sIsHfpClientReady = false;
45     private static BluetoothHeadsetClient sHfpClientProfile = null;
46 
BluetoothHfpClientFacade(FacadeManager manager)47     public BluetoothHfpClientFacade(FacadeManager manager) {
48         super(manager);
49         mService = manager.getService();
50         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
51         mBluetoothAdapter.getProfileProxy(mService,
52                 new HfpClientServiceListener(),
53                 BluetoothProfile.HEADSET_CLIENT);
54     }
55 
56     class HfpClientServiceListener implements BluetoothProfile.ServiceListener {
57         @Override
onServiceConnected(int profile, BluetoothProfile proxy)58         public void onServiceConnected(int profile, BluetoothProfile proxy) {
59             sHfpClientProfile = (BluetoothHeadsetClient) proxy;
60             sIsHfpClientReady = true;
61         }
62 
63         @Override
onServiceDisconnected(int profile)64         public void onServiceDisconnected(int profile) {
65             sIsHfpClientReady = false;
66         }
67     }
68 
69     /**
70      * Connect to HfpClient.
71      * @param device - the BluetoothDevice object to connect Hfp client.
72      * @return if the connection was successfull or not.
73      */
hfpClientConnect(BluetoothDevice device)74     public Boolean hfpClientConnect(BluetoothDevice device) {
75         if (sHfpClientProfile == null) return false;
76         return sHfpClientProfile.connect(device);
77     }
78 
79     /**
80      * Disconnect from HfpClient.
81      * @param device - the BluetoothDevice object to disconnect from Hfp client.
82      * @return if the disconnection was successfull or not.
83      */
hfpClientDisconnect(BluetoothDevice device)84     public Boolean hfpClientDisconnect(BluetoothDevice device) {
85         if (sHfpClientProfile == null) return false;
86         return sHfpClientProfile.disconnect(device);
87     }
88 
89     /**
90      * Is Hfp Client profile ready.
91      * @return Hfp Client profile is ready or not.
92      */
93     @Rpc(description = "Is HfpClient profile ready.")
bluetoothHfpClientIsReady()94     public Boolean bluetoothHfpClientIsReady() {
95         return sIsHfpClientReady;
96     }
97 
98     /**
99      * Set priority of the profile.
100      * @param deviceStr - Mac address of a BT device.
101      * @param priority - Priority that needs to be set.
102      */
103     @Rpc(description = "Set priority of the profile")
bluetoothHfpClientSetPriority( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr, @RpcParameter(name = "priority", description = "Priority that needs to be set.") Integer priority)104     public void bluetoothHfpClientSetPriority(
105             @RpcParameter(name = "device",
106                 description = "Mac address of a BT device.") String deviceStr,
107             @RpcParameter(name = "priority",
108                 description = "Priority that needs to be set.")
109                     Integer priority) throws Exception {
110         if (sHfpClientProfile == null) return;
111         BluetoothDevice device =
112                 BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
113                     deviceStr);
114         Log.d("Changing priority of device " + device.getAliasName()
115                 + " p: " + priority);
116         sHfpClientProfile.setPriority(device, priority);
117     }
118 
119     /**
120      * Get priority of the profile.
121      * @param deviceStr - Mac address of a BT device.
122      * @return Priority of the device.
123      */
124     @Rpc(description = "Get priority of the profile")
bluetoothHfpClientGetPriority( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr)125     public Integer bluetoothHfpClientGetPriority(
126             @RpcParameter(name = "device", description =
127                     "Mac address of a BT device.") String deviceStr)
128                     throws Exception {
129         if (sHfpClientProfile == null) return BluetoothProfile.PRIORITY_UNDEFINED;
130         BluetoothDevice device = BluetoothFacade.getDevice(
131                 mBluetoothAdapter.getBondedDevices(), deviceStr);
132         return sHfpClientProfile.getPriority(device);
133     }
134 
135     /**
136      * Connect to an HFP Client device.
137      * @param deviceStr - Name or MAC address of a bluetooth device.
138      * @return Hfp Client was connected or not.
139      */
140     @Rpc(description = "Connect to an HFP Client device.")
bluetoothHfpClientConnect( @pcParametername = "device", description = "Name or MAC address of a bluetooth device.") String deviceStr)141     public Boolean bluetoothHfpClientConnect(
142             @RpcParameter(name = "device",
143                 description = "Name or MAC address of a bluetooth device.")
144                     String deviceStr)
145                         throws Exception {
146         if (sHfpClientProfile == null) return false;
147         try {
148             BluetoothDevice device = BluetoothFacade.getDevice(
149                     BluetoothFacade.DiscoveredDevices, deviceStr);
150             Log.d("Connecting to device " + device.getAliasName());
151             return hfpClientConnect(device);
152         } catch (Exception e) {
153             Log.e("bluetoothHfpClientConnect failed on getDevice "
154                     + deviceStr + " with " + e);
155             return false;
156         }
157     }
158 
159     /**
160      * Disconnect an HFP Client device.
161      * @param deviceStr - Name or MAC address of a bluetooth device.
162      * @return Hfp Client was disconnected or not.
163      */
164     @Rpc(description = "Disconnect an HFP Client device.")
bluetoothHfpClientDisconnect( @pcParametername = "device", description = "Name or MAC address of a device.") String deviceStr)165     public Boolean bluetoothHfpClientDisconnect(
166             @RpcParameter(name = "device",
167                 description = "Name or MAC address of a device.")
168                     String deviceStr) {
169         if (sHfpClientProfile == null) return false;
170         Log.d("Connected devices: " + sHfpClientProfile.getConnectedDevices());
171         try {
172             BluetoothDevice device = BluetoothFacade.getDevice(
173                     sHfpClientProfile.getConnectedDevices(), deviceStr);
174             return hfpClientDisconnect(device);
175         } catch (Exception e) {
176             // Do nothing since it is disconnect and this
177             // function should force disconnect.
178             Log.e("bluetoothHfpClientConnect getDevice failed " + e);
179         }
180         return false;
181     }
182 
183     /**
184      * Get all the devices connected through HFP Client.
185      * @return List of all the devices connected through HFP Client.
186      */
187     @Rpc(description = "Get all the devices connected through HFP Client.")
bluetoothHfpClientGetConnectedDevices()188     public List<BluetoothDevice> bluetoothHfpClientGetConnectedDevices() {
189         if (sHfpClientProfile == null) return new ArrayList<BluetoothDevice>();
190         return sHfpClientProfile.getConnectedDevices();
191     }
192 
193     /**
194      * Get the connection status of a device.
195      * @param deviceID - Name or MAC address of a bluetooth device.
196      * @return connection status of the device.
197      */
198     @Rpc(description = "Get the connection status of a device.")
bluetoothHfpClientGetConnectionStatus( @pcParametername = "deviceID", description = "Name or MAC address of a bluetooth device.") String deviceID)199     public Integer bluetoothHfpClientGetConnectionStatus(
200             @RpcParameter(name = "deviceID",
201                 description = "Name or MAC address of a bluetooth device.")
202                     String deviceID) {
203         if (sHfpClientProfile == null) {
204             return BluetoothProfile.STATE_DISCONNECTED;
205         }
206         List<BluetoothDevice> deviceList =
207                 sHfpClientProfile.getConnectedDevices();
208         BluetoothDevice device;
209         try {
210             device = BluetoothFacade.getDevice(deviceList, deviceID);
211         } catch (Exception e) {
212             Log.e(e);
213             return BluetoothProfile.STATE_DISCONNECTED;
214         }
215         return sHfpClientProfile.getConnectionState(device);
216     }
217 
218     /**
219      * Get the audio routing state of specified device.
220      * @param deviceStr the Bluetooth MAC address of remote device
221      * @return Audio State of the device.
222      */
223     @Rpc(description = "Get all the devices connected through HFP Client.")
bluetoothHfpClientGetAudioState( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)224     public Integer bluetoothHfpClientGetAudioState(
225             @RpcParameter(name = "device",
226                 description = "MAC address of a bluetooth device.")
227                 String deviceStr) {
228         if (sHfpClientProfile == null) return -1;
229         BluetoothDevice device;
230         try {
231             device =  BluetoothFacade.getDevice(sHfpClientProfile.getConnectedDevices(), deviceStr);
232         } catch (Exception e) {
233             // Do nothing since it is disconnect and this function should force disconnect.
234             Log.e("bluetoothHfpClientConnect getDevice failed " + e);
235             return -1;
236         }
237         return sHfpClientProfile.getAudioState(device);
238     }
239 
240     /**
241      * Start Voice Recognition on remote device
242      *
243      * @param deviceStr the Bluetooth MAC address of remote device
244      * @return True if command was sent
245      */
246     @Rpc(description = "Start Remote device Voice Recognition through HFP Client.")
bluetoothHfpClientStartVoiceRecognition( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)247     public boolean bluetoothHfpClientStartVoiceRecognition(
248             @RpcParameter(name = "device",
249                 description = "MAC address of a bluetooth device.")
250                     String deviceStr) {
251         if (sHfpClientProfile == null) return false;
252         BluetoothDevice device;
253         try {
254             device = BluetoothFacade.getDevice(
255                     sHfpClientProfile.getConnectedDevices(), deviceStr);
256         } catch (Exception e) {
257             // Do nothing since it is disconnect and this function should force disconnect.
258             Log.e("bluetoothHfpClientConnect getDevice failed " + e);
259             return false;
260         }
261         return sHfpClientProfile.startVoiceRecognition(device);
262     }
263 
264     /**
265      * Stop Voice Recognition on remote device
266      *
267      * @param deviceStr the Bluetooth MAC address of remote device
268      * @return True if command was sent
269      */
270     @Rpc(description = "Stop Remote device Voice Recognition through HFP Client.")
bluetoothHfpClientStopVoiceRecognition( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)271     public boolean bluetoothHfpClientStopVoiceRecognition(
272             @RpcParameter(name = "device",
273                 description = "MAC address of a bluetooth device.")
274                     String deviceStr) {
275         if (sHfpClientProfile == null) return false;
276         BluetoothDevice device;
277         try {
278             device = BluetoothFacade.getDevice(
279                     sHfpClientProfile.getConnectedDevices(), deviceStr);
280         } catch (Exception e) {
281             // Do nothing since it is disconnect
282             // and this function should force disconnect.
283             Log.e("bluetoothHfpClientConnect getDevice failed " + e);
284             return false;
285         }
286         return sHfpClientProfile.stopVoiceRecognition(device);
287     }
288 
289     @Override
shutdown()290     public void shutdown() {
291     }
292 }
293