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 java.util.List;
20 import java.util.ArrayList;
21 
22 import android.app.Service;
23 import android.bluetooth.BluetoothA2dpSink;
24 import android.bluetooth.BluetoothAdapter;
25 import android.bluetooth.BluetoothDevice;
26 import android.bluetooth.BluetoothProfile;
27 import android.bluetooth.BluetoothUuid;
28 import android.os.ParcelUuid;
29 
30 import com.googlecode.android_scripting.Log;
31 import com.googlecode.android_scripting.facade.FacadeManager;
32 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
33 import com.googlecode.android_scripting.rpc.Rpc;
34 import com.googlecode.android_scripting.rpc.RpcParameter;
35 
36 public class BluetoothA2dpSinkFacade extends RpcReceiver {
37   static final ParcelUuid[] SOURCE_UUIDS = {
38     BluetoothUuid.AudioSource,
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 
a2dpSinkConnect(BluetoothDevice device)66   public Boolean a2dpSinkConnect(BluetoothDevice device) {
67     if (sA2dpSinkProfile == null) return false;
68     return sA2dpSinkProfile.connect(device);
69   }
70 
a2dpSinkDisconnect(BluetoothDevice device)71   public Boolean a2dpSinkDisconnect(BluetoothDevice device) {
72     if (sA2dpSinkProfile == null) return false;
73     return sA2dpSinkProfile.disconnect(device);
74   }
75 
76   @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)77   public void bluetoothA2dpSinkSetPriority(
78       @RpcParameter(name = "device", description = "Mac address of a BT device.")
79       String deviceStr,
80       @RpcParameter(name = "priority", description = "Priority that needs to be set.")
81       Integer priority)
82       throws Exception {
83     if (sA2dpSinkProfile == null) return;
84     BluetoothDevice device =
85         BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(), deviceStr);
86     Log.d("Changing priority of device " + device.getAliasName() + " p: " + priority);
87     sA2dpSinkProfile.setPriority(device, priority);
88   }
89 
90   @Rpc(description = "get priority of the profile")
bluetoothA2dpSinkGetPriority( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr)91   public Integer bluetoothA2dpSinkGetPriority(
92       @RpcParameter(name = "device", description = "Mac address of a BT device.")
93       String deviceStr)
94       throws Exception {
95     if (sA2dpSinkProfile == null) return BluetoothProfile.PRIORITY_UNDEFINED;
96     BluetoothDevice device =
97         BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(), deviceStr);
98     return sA2dpSinkProfile.getPriority(device);
99   }
100 
101   @Rpc(description = "Is A2dpSink profile ready.")
bluetoothA2dpSinkIsReady()102   public Boolean bluetoothA2dpSinkIsReady() {
103     return (sA2dpSinkProfile != null);
104   }
105 
106   @Rpc(description = "Connect to an A2DP Sink device.")
bluetoothA2dpSinkConnect( @pcParametername = "device", description = "Name or MAC address of a bluetooth device.") String deviceStr)107   public Boolean bluetoothA2dpSinkConnect(
108       @RpcParameter(name = "device", description = "Name or MAC address of a bluetooth device.")
109       String deviceStr)
110       throws Exception {
111     if (sA2dpSinkProfile == null) return false;
112     BluetoothDevice device =
113         BluetoothFacade.getDevice(BluetoothFacade.DiscoveredDevices, deviceStr);
114     Log.d("Connecting to device " + device.getAliasName());
115     return a2dpSinkConnect(device);
116   }
117 
118   @Rpc(description = "Disconnect an A2DP Sink device.")
bluetoothA2dpSinkDisconnect( @pcParametername = "device", description = "Name or MAC address of a device.") String deviceStr)119   public Boolean bluetoothA2dpSinkDisconnect(
120       @RpcParameter(name = "device", description = "Name or MAC address of a device.")
121       String deviceStr) {
122     if (sA2dpSinkProfile == null) return false;
123     Log.d("Connected devices: " + sA2dpSinkProfile.getConnectedDevices());
124     BluetoothDevice device = null;
125     try {
126       device = BluetoothFacade.getDevice(sA2dpSinkProfile.getConnectedDevices(), deviceStr);
127       return a2dpSinkDisconnect(device);
128     } catch (Exception e) {
129         // Do nothing here. Since it is disconnect this function should force shutdown anyways.
130         Log.d("bluetoothA2dpSinkDisconnect error while getDevice " + e);
131     }
132     return false;
133   }
134 
135   @Rpc(description = "Get all the devices connected through A2DP Sink.")
bluetoothA2dpSinkGetConnectedDevices()136   public List<BluetoothDevice> bluetoothA2dpSinkGetConnectedDevices() {
137     if (sA2dpSinkProfile == null) return new ArrayList<BluetoothDevice>();
138     return sA2dpSinkProfile.getConnectedDevices();
139   }
140 
141   @Rpc(description = "Get the connection status of a device.")
bluetoothA2dpSinkGetConnectionStatus( @pcParametername = "deviceID", description = "Name or MAC address of a bluetooth device.") String deviceID)142   public Integer bluetoothA2dpSinkGetConnectionStatus(
143       @RpcParameter(name = "deviceID",
144                     description = "Name or MAC address of a bluetooth device.")
145         String deviceID) {
146     if (sA2dpSinkProfile == null) {
147       return BluetoothProfile.STATE_DISCONNECTED;
148     }
149     List<BluetoothDevice> deviceList = sA2dpSinkProfile.getConnectedDevices();
150     BluetoothDevice device;
151     try {
152       device = BluetoothFacade.getDevice(deviceList, deviceID);
153     } catch (Exception e) {
154       Log.e(e);
155       return BluetoothProfile.STATE_DISCONNECTED;
156     }
157     return sA2dpSinkProfile.getConnectionState(device);
158   }
159 
160   @Override
shutdown()161   public void shutdown() {
162   }
163 }
164