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