1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.googlecode.android_scripting.facade.bluetooth;
18 
19 import java.util.List;
20 
21 import android.app.Service;
22 import android.bluetooth.BluetoothA2dp;
23 import android.bluetooth.BluetoothAdapter;
24 import android.bluetooth.BluetoothDevice;
25 import android.bluetooth.BluetoothProfile;
26 import android.bluetooth.BluetoothUuid;
27 import android.os.ParcelUuid;
28 
29 import com.googlecode.android_scripting.Log;
30 import com.googlecode.android_scripting.facade.FacadeManager;
31 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
32 import com.googlecode.android_scripting.rpc.Rpc;
33 import com.googlecode.android_scripting.rpc.RpcParameter;
34 
35 public class BluetoothA2dpFacade extends RpcReceiver {
36   static final ParcelUuid[] SINK_UUIDS = {
37     BluetoothUuid.AudioSink, BluetoothUuid.AdvAudioDist,
38   };
39   private final Service mService;
40   private final BluetoothAdapter mBluetoothAdapter;
41 
42   private static boolean sIsA2dpReady = false;
43   private static BluetoothA2dp sA2dpProfile = null;
44 
BluetoothA2dpFacade(FacadeManager manager)45   public BluetoothA2dpFacade(FacadeManager manager) {
46     super(manager);
47     mService = manager.getService();
48     mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
49     mBluetoothAdapter.getProfileProxy(mService, new A2dpServiceListener(),
50         BluetoothProfile.A2DP);
51   }
52 
53   class A2dpServiceListener implements BluetoothProfile.ServiceListener {
54     @Override
onServiceConnected(int profile, BluetoothProfile proxy)55     public void onServiceConnected(int profile, BluetoothProfile proxy) {
56       sA2dpProfile = (BluetoothA2dp) proxy;
57       sIsA2dpReady = true;
58     }
59 
60     @Override
onServiceDisconnected(int profile)61     public void onServiceDisconnected(int profile) {
62       sIsA2dpReady = false;
63     }
64   }
65 
a2dpConnect(BluetoothDevice device)66   public Boolean a2dpConnect(BluetoothDevice device) {
67     List<BluetoothDevice> sinks = sA2dpProfile.getConnectedDevices();
68     if (sinks != null) {
69       for (BluetoothDevice sink : sinks) {
70         sA2dpProfile.disconnect(sink);
71       }
72     }
73     return sA2dpProfile.connect(device);
74   }
75 
a2dpDisconnect(BluetoothDevice device)76   public Boolean a2dpDisconnect(BluetoothDevice device) {
77     if (sA2dpProfile == null) return false;
78     if (sA2dpProfile.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
79       sA2dpProfile.setPriority(device, BluetoothProfile.PRIORITY_ON);
80     }
81     return sA2dpProfile.disconnect(device);
82   }
83 
84   /**
85    * Checks to see if the A2DP profile is ready for use.
86    *
87    * @return Returns true if the A2DP Profile is ready.
88    */
89   @Rpc(description = "Is A2dp profile ready.")
bluetoothA2dpIsReady()90   public Boolean bluetoothA2dpIsReady() {
91     return sIsA2dpReady;
92   }
93 
94   /**
95    * Connect to remote device using the A2DP profile.
96    *
97    * @param deviceId the name or mac address of the remote Bluetooth device.
98    * @return True if connected successfully.
99    * @throws Exception
100    */
101   @Rpc(description = "Connect to an A2DP device.")
bluetoothA2dpConnect( @pcParametername = "deviceID", description = "Name or MAC address of a bluetooth device.") String deviceID)102   public Boolean bluetoothA2dpConnect(
103       @RpcParameter(name = "deviceID", description = "Name or MAC address of a bluetooth device.")
104       String deviceID)
105       throws Exception {
106     if (sA2dpProfile == null)
107       return false;
108     BluetoothDevice mDevice = BluetoothFacade.getDevice(
109         BluetoothFacade.DiscoveredDevices, deviceID);
110     Log.d("Connecting to device " + mDevice.getAliasName());
111     return a2dpConnect(mDevice);
112   }
113 
114   /**
115    * Disconnect a remote device using the A2DP profile.
116    *
117    * @param deviceId the name or mac address of the remote Bluetooth device.
118    * @return True if connected successfully.
119    * @throws Exception
120    */
121   @Rpc(description = "Disconnect an A2DP device.")
bluetoothA2dpDisconnect( @pcParametername = "deviceID", description = "Name or MAC address of a device.") String deviceID)122   public Boolean bluetoothA2dpDisconnect(
123       @RpcParameter(name = "deviceID", description = "Name or MAC address of a device.")
124       String deviceID)
125       throws Exception {
126     if (sA2dpProfile == null)
127       return false;
128     List<BluetoothDevice> connectedA2dpDevices = sA2dpProfile.getConnectedDevices();
129     Log.d("Connected a2dp devices " + connectedA2dpDevices);
130     BluetoothDevice mDevice = BluetoothFacade.getDevice(connectedA2dpDevices, deviceID);
131     return a2dpDisconnect(mDevice);
132   }
133 
134   /**
135    * Get the list of devices connected through the A2DP profile.
136    *
137    * @return List of bluetooth devices that are in one of the following states:
138    *   connected, connecting, and disconnecting.
139    */
140   @Rpc(description = "Get all the devices connected through A2DP.")
bluetoothA2dpGetConnectedDevices()141   public List<BluetoothDevice> bluetoothA2dpGetConnectedDevices() {
142     while (!sIsA2dpReady);
143     return sA2dpProfile.getDevicesMatchingConnectionStates(
144           new int[] {BluetoothProfile.STATE_CONNECTED,
145                      BluetoothProfile.STATE_CONNECTING,
146                      BluetoothProfile.STATE_DISCONNECTING});
147   }
148 
149   @Override
shutdown()150   public void shutdown() {
151   }
152 }
153