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.BluetoothA2dpSink;
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.BluetoothDevice;
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 BluetoothA2dpSinkFacade extends RpcReceiver {
37     static final ParcelUuid[] SOURCE_UUIDS = {
38         BluetoothUuid.A2DP_SOURCE,
39     };
40 
41     private final Service mService;
42     private final BluetoothAdapter mBluetoothAdapter;
43 
44     private static BluetoothA2dpSink sA2dpSinkProfile = null;
45 
BluetoothA2dpSinkFacade(FacadeManager manager)46     public BluetoothA2dpSinkFacade(FacadeManager manager) {
47         super(manager);
48         mService = manager.getService();
49         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
50         mBluetoothAdapter.getProfileProxy(mService, new A2dpSinkServiceListener(),
51         BluetoothProfile.A2DP_SINK);
52     }
53 
54     class A2dpSinkServiceListener implements BluetoothProfile.ServiceListener {
55         @Override
onServiceConnected(int profile, BluetoothProfile proxy)56         public void onServiceConnected(int profile, BluetoothProfile proxy) {
57             sA2dpSinkProfile = (BluetoothA2dpSink) proxy;
58         }
59 
60         @Override
onServiceDisconnected(int profile)61         public void onServiceDisconnected(int profile) {
62             sA2dpSinkProfile = null;
63         }
64     }
65 
66     /**
67      * Connect A2dp Sink profile.
68      * @param device - the Bluetooth Device object to connect.
69      * @return if the A2dp Sink Profile connection was successful or not.
70      */
a2dpSinkConnect(BluetoothDevice device)71     public Boolean a2dpSinkConnect(BluetoothDevice device) {
72         if (sA2dpSinkProfile == null) return false;
73         return sA2dpSinkProfile.connect(device);
74     }
75 
76     /**
77      * Disconnect A2dp Sink profile.
78      * @param device - the Bluetooth Device object to connect.
79      * @return if the A2dp Sink Profile disconnection was successful or not.
80      */
a2dpSinkDisconnect(BluetoothDevice device)81     public Boolean a2dpSinkDisconnect(BluetoothDevice device) {
82         if (sA2dpSinkProfile == null) return false;
83         return sA2dpSinkProfile.disconnect(device);
84     }
85 
86     /**
87      * Set priority of the profile.
88      * @param deviceStr - Mac address of a Bluetooth device.
89      * @param priority - Priority that needs to be set.
90      */
91     @Rpc(description = "Set priority of the profile")
bluetoothA2dpSinkSetPriority( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr, @RpcParameter(name = "priority", description = "Priority that needs to be set.") Integer priority)92     public void bluetoothA2dpSinkSetPriority(
93             @RpcParameter(name = "device", description = "Mac address of a BT device.")
94             String deviceStr,
95             @RpcParameter(name = "priority", description = "Priority that needs to be set.")
96             Integer priority)
97             throws Exception {
98         if (sA2dpSinkProfile == null) return;
99         BluetoothDevice device =
100                 BluetoothFacade.getDevice(
101                         mBluetoothAdapter.getBondedDevices(), deviceStr);
102         Log.d("Changing priority of device "
103                 + device.getAlias() + " p: " + priority);
104         sA2dpSinkProfile.setPriority(device, priority);
105     }
106 
107     /**
108      * Get priority of the profile.
109       * @param deviceStr - Mac address of a Bluetooth device.
110       * @return priority of the device.
111      */
112     @Rpc(description = "get priority of the profile")
bluetoothA2dpSinkGetPriority( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr)113     public Integer bluetoothA2dpSinkGetPriority(
114             @RpcParameter(name = "device", description = "Mac address of a BT device.")
115                 String deviceStr)
116             throws Exception {
117         if (sA2dpSinkProfile == null) return BluetoothProfile.PRIORITY_UNDEFINED;
118         BluetoothDevice device =
119                 BluetoothFacade.getDevice(
120                 mBluetoothAdapter.getBondedDevices(), deviceStr);
121         return sA2dpSinkProfile.getPriority(device);
122     }
123 
124     /**
125      * Is A2dpSink profile ready.
126      * @return if the Profile is ready or not.
127      */
128     @Rpc(description = "Is A2dpSink profile ready.")
bluetoothA2dpSinkIsReady()129     public Boolean bluetoothA2dpSinkIsReady() {
130         return sA2dpSinkProfile != null;
131     }
132 
133     /**
134      * Connect to an A2DP Sink device.
135      * @param deviceStr - Name or MAC address of a bluetooth device.
136      * @return connection to A2DP was successful.
137      */
138     @Rpc(description = "Connect to an A2DP Sink device.")
bluetoothA2dpSinkConnect( @pcParametername = "device", description = "Name or MAC address of a bluetooth device.") String deviceStr)139     public Boolean bluetoothA2dpSinkConnect(
140             @RpcParameter(name = "device", description =
141                 "Name or MAC address of a bluetooth device.") String deviceStr)
142             throws Exception {
143         if (sA2dpSinkProfile == null) return false;
144         BluetoothDevice device =
145                 BluetoothFacade.getDevice(
146                 BluetoothFacade.DiscoveredDevices, deviceStr);
147         Log.d("Connecting to device " + device.getAlias());
148         return a2dpSinkConnect(device);
149     }
150 
151     /**
152      * Disconnect to an A2DP Sink device.
153      * @param deviceStr - Name or MAC address of a bluetooth device.
154      * @return disconnection to A2DP was successful or not.
155      */
156     @Rpc(description = "Disconnect an A2DP Sink device.")
bluetoothA2dpSinkDisconnect( @pcParametername = "device", description = "Name or MAC address of a device.") String deviceStr)157     public Boolean bluetoothA2dpSinkDisconnect(
158             @RpcParameter(name = "device", description = "Name or MAC address of a device.")
159                 String deviceStr) {
160         if (sA2dpSinkProfile == null) return false;
161         Log.d("Connected devices: " + sA2dpSinkProfile.getConnectedDevices());
162         BluetoothDevice device = null;
163         try {
164             device = BluetoothFacade.getDevice(
165                     sA2dpSinkProfile.getConnectedDevices(), deviceStr);
166             return a2dpSinkDisconnect(device);
167         } catch (Exception e) {
168             // Do nothing here. Since it is disconnect this function should force shutdown anyways.
169             Log.d("bluetoothA2dpSinkDisconnect error while getDevice " + e);
170         }
171         return false;
172     }
173 
174     /**
175      * Get all the devices connected through A2DP Sink.
176      * @return List of all the devices connected through A2dp Sink.
177      */
178     @Rpc(description = "Get all the devices connected through A2DP Sink.")
bluetoothA2dpSinkGetConnectedDevices()179     public List<BluetoothDevice> bluetoothA2dpSinkGetConnectedDevices() {
180         if (sA2dpSinkProfile == null) return new ArrayList<BluetoothDevice>();
181         return sA2dpSinkProfile.getConnectedDevices();
182     }
183 
184     /**
185      * Get the connection status of a device.
186      * @param deviceID - Name or MAC address of a bluetooth device.
187      * @return connection status of the device.
188      */
189     @Rpc(description = "Get the connection status of a device.")
bluetoothA2dpSinkGetConnectionStatus( @pcParametername = "deviceID", description = "Name or MAC address of a bluetooth device.") String deviceID)190     public Integer bluetoothA2dpSinkGetConnectionStatus(
191             @RpcParameter(name = "deviceID",
192                 description = "Name or MAC address of a bluetooth device.")
193                 String deviceID) {
194         if (sA2dpSinkProfile == null) {
195             return BluetoothProfile.STATE_DISCONNECTED;
196         }
197         List<BluetoothDevice> deviceList = sA2dpSinkProfile.getConnectedDevices();
198         BluetoothDevice device;
199         try {
200             device = BluetoothFacade.getDevice(deviceList, deviceID);
201         } catch (Exception e) {
202             Log.e(e);
203             return BluetoothProfile.STATE_DISCONNECTED;
204         }
205         return sA2dpSinkProfile.getConnectionState(device);
206     }
207 
208     @Override
shutdown()209     public void shutdown() {
210     }
211 }
212