• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.BluetoothHeadset;
23 import android.bluetooth.BluetoothProfile;
24 import android.bluetooth.BluetoothStatusCodes;
25 import android.bluetooth.BluetoothUuid;
26 import android.os.ParcelUuid;
27 
28 import com.googlecode.android_scripting.Log;
29 import com.googlecode.android_scripting.facade.FacadeManager;
30 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
31 import com.googlecode.android_scripting.rpc.Rpc;
32 import com.googlecode.android_scripting.rpc.RpcParameter;
33 
34 import java.util.List;
35 
36 public class BluetoothHspFacade extends RpcReceiver {
37     static final ParcelUuid[] UUIDS = {
38             BluetoothUuid.HSP, BluetoothUuid.HFP
39     };
40 
41     private final Service mService;
42     private final BluetoothAdapter mBluetoothAdapter;
43 
44     private static boolean sIsHspReady = false;
45     private static BluetoothHeadset sHspProfile = null;
46 
BluetoothHspFacade(FacadeManager manager)47     public BluetoothHspFacade(FacadeManager manager) {
48         super(manager);
49         mService = manager.getService();
50         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
51         mBluetoothAdapter.getProfileProxy(mService, new HspServiceListener(),
52                 BluetoothProfile.HEADSET);
53     }
54 
55     class HspServiceListener implements BluetoothProfile.ServiceListener {
56         @Override
onServiceConnected(int profile, BluetoothProfile proxy)57         public void onServiceConnected(int profile, BluetoothProfile proxy) {
58             sHspProfile = (BluetoothHeadset) proxy;
59             sIsHspReady = true;
60         }
61 
62         @Override
onServiceDisconnected(int profile)63         public void onServiceDisconnected(int profile) {
64             sIsHspReady = false;
65         }
66     }
67 
68     /**
69      * Connect to Hsp Profile
70      * @param device - the BluetoothDevice object to connect to.
71      * @return if the connection was successfull or not.
72      */
hspConnect(BluetoothDevice device)73     public Boolean hspConnect(BluetoothDevice device) {
74         if (sHspProfile == null) return false;
75         return sHspProfile.connect(device);
76     }
77 
78     /**
79      * Disconnect to Hsp Profile.
80      * @param device - the Bluetooth Device object to disconnect from.
81      * @return if the disconnection was successfull or not.
82      */
hspDisconnect(BluetoothDevice device)83     public Boolean hspDisconnect(BluetoothDevice device) {
84         if (sHspProfile == null) return false;
85         return sHspProfile.disconnect(device);
86     }
87 
88     /**
89      * Wait Hsp Profile ready until timeout.
90      * @param timeout - Timeout second.
91      * @return true if Hsp Profile is ready else false.
92      */
waitHspReady(long timeout)93     public Boolean waitHspReady(long timeout) {
94         long startTime = System.currentTimeMillis();
95         while (System.currentTimeMillis() < startTime + timeout * 1000) {
96             if (sIsHspReady) return true;
97         }
98         Log.d("Hsp profile is not ready");
99         return false;
100     }
101 
102     /**
103      * Is Hsp profile ready.
104      * @return if Hsp profile is ready or not.
105      */
106     @Rpc(description = "Is Hsp profile ready.")
bluetoothHspIsReady()107     public Boolean bluetoothHspIsReady() {
108         return sIsHspReady;
109     }
110 
111     /**
112      * Set connection policy of the profile.
113      * @param deviceStr - name or MAC address of a Bluetooth device.
114      * @param connectionPolicy - Connection policy that needs to be set.
115      */
116     @Rpc(description = "Set priority of the profile.")
bluetoothHspSetConnectionPolicy( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr, @RpcParameter(name = "connectionPolicy", description = "Connection policy that needs to be set.") Integer connectionPolicy)117     public void bluetoothHspSetConnectionPolicy(
118             @RpcParameter(name = "device", description = "Mac address of a BT device.")
119                 String deviceStr,
120             @RpcParameter(name = "connectionPolicy",
121               description = "Connection policy that needs to be set.")
122                 Integer connectionPolicy) throws Exception {
123         if (!waitHspReady(10)) return;
124         BluetoothDevice device = BluetoothFacade.getDevice(
125                 mBluetoothAdapter.getBondedDevices(), deviceStr);
126         Log.d("Changing connection policy of device " + device.getAlias() + " cp: "
127                 + connectionPolicy);
128         sHspProfile.setConnectionPolicy(device, connectionPolicy);
129     }
130 
131     /**
132      * Connect to an HSP device.
133      * @param device - Name or MAC address of a bluetooth device.
134      * @return True if the connection was successful; otherwise False.
135      */
136     @Rpc(description = "Connect to an HSP device.")
bluetoothHspConnect( @pcParametername = "device", description = "Name or MAC address of a bluetooth device.") String device)137     public Boolean bluetoothHspConnect(
138             @RpcParameter(name = "device", description =
139                 "Name or MAC address of a bluetooth device.")
140                 String device) throws Exception {
141         if (!waitHspReady(10)) return false;
142         BluetoothDevice mDevice = BluetoothFacade.getDevice(
143                 mBluetoothAdapter.getBondedDevices(), device);
144         Log.d("Connecting to device " + mDevice.getAlias());
145         return hspConnect(mDevice);
146     }
147 
148     /**
149      * Disconnect an HSP device.
150      * @param device - Name or MAC address of a bluetooth device.
151      * @return True if the disconnection was successful; otherwise False.
152      */
153     @Rpc(description = "Disconnect an HSP device.")
bluetoothHspDisconnect( @pcParametername = "device", description = "Name or MAC address of a device.") String device)154     public Boolean bluetoothHspDisconnect(
155             @RpcParameter(name = "device", description = "Name or MAC address of a device.")
156                 String device) throws Exception {
157         if (!waitHspReady(10)) return false;
158         Log.d("Connected devices: " + sHspProfile.getConnectedDevices());
159         BluetoothDevice mDevice = BluetoothFacade.getDevice(
160                 sHspProfile.getConnectedDevices(), device);
161         return hspDisconnect(mDevice);
162     }
163 
164      /**
165      * Get all the devices connected through HSP.
166      * @return List of all the devices connected through HSP.
167      */
168     @Rpc(description = "Get all the devices connected through HSP.")
bluetoothHspGetConnectedDevices()169     public List<BluetoothDevice> bluetoothHspGetConnectedDevices() {
170         if (!waitHspReady(10)) return null;
171         return sHspProfile.getConnectedDevices();
172     }
173 
174     /**
175      * Get the connection status of a device.
176      * @param deviceID - Name or MAC address of a bluetooth device.
177      * @return connection status of a device.
178      */
179     @Rpc(description = "Get the connection status of a device.")
bluetoothHspGetConnectionStatus( @pcParametername = "deviceID", description = "Name or MAC address of a bluetooth device.") String deviceID)180     public Integer bluetoothHspGetConnectionStatus(
181             @RpcParameter(name = "deviceID",
182                 description = "Name or MAC address of a bluetooth device.")
183                     String deviceID) {
184         if (!waitHspReady(10)) {
185             return BluetoothProfile.STATE_DISCONNECTED;
186         }
187         List<BluetoothDevice> deviceList = sHspProfile.getConnectedDevices();
188         BluetoothDevice device;
189         try {
190             device = BluetoothFacade.getDevice(deviceList, deviceID);
191         } catch (Exception e) {
192             return BluetoothProfile.STATE_DISCONNECTED;
193         }
194         return sHspProfile.getConnectionState(device);
195     }
196 
197     /**
198      * Force SCO audio on DUT, ignore all other restrictions
199      *
200      * @param force True to force SCO audio, False to resume normal
201      * @return True if the setup is successful
202      */
203     @Rpc(description = "Force SCO audio connection on DUT.")
bluetoothHspForceScoAudio( @pcParametername = "force", description = "whether to force SCO audio") Boolean force)204     public Boolean bluetoothHspForceScoAudio(
205             @RpcParameter(name = "force", description = "whether to force SCO audio")
206                 Boolean force) {
207         if (!waitHspReady(10)) {
208             return false;
209         }
210         sHspProfile.setForceScoAudio(force);
211         return true;
212     }
213 
214     /**
215      * Connect SCO audio to a remote device
216      *
217      * @param deviceAddress the Bluetooth MAC address of remote device
218      * @return True if connection is successful, False otherwise
219      */
220     @Rpc(description = "Connect SCO audio for a remote device.")
bluetoothHspConnectAudio( @pcParametername = "deviceAddress", description = "MAC address of a bluetooth device.") String deviceAddress)221     public Boolean bluetoothHspConnectAudio(
222             @RpcParameter(name = "deviceAddress",
223                 description = "MAC address of a bluetooth device.")
224                     String deviceAddress) {
225         if (!waitHspReady(10)) {
226             return false;
227         }
228         Log.d("Connected devices: " + sHspProfile.getConnectedDevices());
229         BluetoothDevice device = null;
230         if (sHspProfile.getConnectedDevices().size() > 1) {
231             Log.d("More than one device available");
232         }
233         try {
234             device = BluetoothFacade.getDevice(
235                     sHspProfile.getConnectedDevices(), deviceAddress);
236         } catch (Exception e) {
237             Log.d("Cannot find device " + deviceAddress);
238             return false;
239         }
240         return sHspProfile.connectAudio() == BluetoothStatusCodes.SUCCESS;
241     }
242 
243     /**
244      * Disconnect SCO audio for a remote device
245      *
246      * @param deviceAddress the Bluetooth MAC address of remote device
247      * @return True if disconnection is successful, False otherwise
248      */
249     @Rpc(description = "Disconnect SCO audio for a remote device")
bluetoothHspDisconnectAudio( @pcParametername = "deviceAddress", description = "MAC address of a bluetooth device.") String deviceAddress)250     public Boolean bluetoothHspDisconnectAudio(
251             @RpcParameter(name = "deviceAddress",
252                 description = "MAC address of a bluetooth device.")
253                     String deviceAddress) {
254         if (!waitHspReady(10)) {
255             return false;
256         }
257         Log.d("Connected devices: " + sHspProfile.getConnectedDevices());
258         BluetoothDevice device = null;
259         if (sHspProfile.getConnectedDevices().size() > 1) {
260             Log.d("More than one device available");
261         }
262         try {
263             device = BluetoothFacade.getDevice(
264                     sHspProfile.getConnectedDevices(), deviceAddress);
265         } catch (Exception e) {
266             Log.d("Cannot find device " + deviceAddress);
267             return false;
268         }
269         if (!sHspProfile.isAudioConnected(device)) {
270             Log.d("SCO audio is not connected for device " + deviceAddress);
271             return false;
272         }
273         return sHspProfile.disconnectAudio() == BluetoothStatusCodes.SUCCESS;
274     }
275 
276     /**
277      * Check if SCO audio is connected for a remote device
278      *
279      * @param deviceAddress the Bluetooth MAC address of remote device
280      * @return True if device is connected to us via SCO audio, False otherwise
281      */
282     @Rpc(description = "Check if SCO audio is connected for a remote device")
bluetoothHspIsAudioConnected( @pcParametername = "deviceAddress", description = "MAC address of a bluetooth device.") String deviceAddress)283     public Boolean bluetoothHspIsAudioConnected(
284             @RpcParameter(name = "deviceAddress",
285                 description = "MAC address of a bluetooth device.")
286                     String deviceAddress) {
287         if (!waitHspReady(10)) {
288             return false;
289         }
290         Log.d("Connected devices: " + sHspProfile.getConnectedDevices());
291         BluetoothDevice device = null;
292         if (sHspProfile.getConnectedDevices().size() > 1) {
293             Log.d("More than one device available");
294         }
295         try {
296             device = BluetoothFacade.getDevice(
297                     sHspProfile.getConnectedDevices(), deviceAddress);
298         } catch (Exception e) {
299             Log.d("Cannot find device " + deviceAddress);
300             return false;
301         }
302         return sHspProfile.isAudioConnected(device);
303     }
304 
305     /**
306      * Start voice recognition. Send BVRA command.
307      *
308      * @param deviceAddress the Bluetooth MAC address of remote device
309      * @return True if started successfully, False otherwise.
310      */
311     @Rpc(description = "Start Voice Recognition.")
bluetoothHspStartVoiceRecognition( @pcParametername = "deviceAddress", description = "MAC address of a bluetooth device.") String deviceAddress)312     public Boolean bluetoothHspStartVoiceRecognition(
313             @RpcParameter(name = "deviceAddress",
314                     description = "MAC address of a bluetooth device.")
315                         String deviceAddress) throws Exception {
316         BluetoothDevice device = BluetoothFacade.getDevice(
317                 sHspProfile.getConnectedDevices(), deviceAddress);
318         return sHspProfile.startVoiceRecognition(device);
319     }
320 
321     /**
322      * Stop voice recognition. Send BVRA command.
323      *
324      * @param deviceAddress the Bluetooth MAC address of remote device
325      * @return True if stopped successfully, False otherwise.
326      */
327     @Rpc(description = "Stop Voice Recognition.")
bluetoothHspStopVoiceRecognition( @pcParametername = "deviceAddress", description = "MAC address of a bluetooth device.") String deviceAddress)328     public Boolean bluetoothHspStopVoiceRecognition(
329             @RpcParameter(name = "deviceAddress",
330                 description = "MAC address of a bluetooth device.")
331                     String deviceAddress) throws Exception {
332         BluetoothDevice device = BluetoothFacade.getDevice(
333                 sHspProfile.getConnectedDevices(), deviceAddress);
334         return sHspProfile.stopVoiceRecognition(device);
335     }
336 
337     /**
338      * Determine whether in-band ringtone is enabled or not.
339      *
340      * @return True if enabled, False otherwise.
341      */
342     @Rpc(description = "In-band ringtone enabled check.")
bluetoothHspIsInbandRingingEnabled()343     public Boolean bluetoothHspIsInbandRingingEnabled() {
344         return sHspProfile.isInbandRingingEnabled();
345     }
346 
347     /**
348      * Send a CLCC response from Sl4a (experimental).
349      *
350      * @param index the index of the call
351      * @param direction the direction of the call
352      * @param status the status of the call
353      * @param mode the mode
354      * @param mpty the mpty value
355      * @param number the phone number
356      * @param type the type
357      */
358     @Rpc(description = "Send generic clcc response.")
bluetoothHspClccResponse( @pcParametername = "index", description = "") Integer index, @RpcParameter(name = "direction", description = "") Integer direction, @RpcParameter(name = "status", description = "") Integer status, @RpcParameter(name = "mode", description = "") Integer mode, @RpcParameter(name = "mpty", description = "") Boolean mpty, @RpcParameter(name = "number", description = "") String number, @RpcParameter(name = "type", description = "") Integer type )359     public void bluetoothHspClccResponse(
360             @RpcParameter(name = "index", description = "") Integer index,
361             @RpcParameter(name = "direction", description = "") Integer direction,
362             @RpcParameter(name = "status", description = "") Integer status,
363             @RpcParameter(name = "mode", description = "") Integer mode,
364             @RpcParameter(name = "mpty", description = "") Boolean mpty,
365             @RpcParameter(name = "number", description = "") String number,
366             @RpcParameter(name = "type", description = "") Integer type
367                   ) {
368         sHspProfile.clccResponse(index, direction, status, mode, mpty, number, type);
369     }
370 
371     @Override
shutdown()372     public void shutdown() {
373     }
374 }
375