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
17package com.googlecode.android_scripting.facade.bluetooth;
18
19import java.util.List;
20
21import android.app.Service;
22import android.bluetooth.BluetoothInputDevice;
23import android.bluetooth.BluetoothAdapter;
24import android.bluetooth.BluetoothDevice;
25import android.bluetooth.BluetoothProfile;
26import android.bluetooth.BluetoothUuid;
27import android.os.ParcelUuid;
28
29import com.googlecode.android_scripting.Log;
30import com.googlecode.android_scripting.facade.FacadeManager;
31import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
32import com.googlecode.android_scripting.rpc.Rpc;
33import com.googlecode.android_scripting.rpc.RpcDefault;
34import com.googlecode.android_scripting.rpc.RpcParameter;
35
36public class BluetoothHidFacade extends RpcReceiver {
37  public final static ParcelUuid[] UUIDS = { BluetoothUuid.Hid };
38
39  private final Service mService;
40  private final BluetoothAdapter mBluetoothAdapter;
41
42  private static boolean sIsHidReady = false;
43  private static BluetoothInputDevice sHidProfile = null;
44
45  public BluetoothHidFacade(FacadeManager manager) {
46    super(manager);
47    mService = manager.getService();
48    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
49    mBluetoothAdapter.getProfileProxy(mService, new HidServiceListener(),
50        BluetoothProfile.INPUT_DEVICE);
51  }
52
53  class HidServiceListener implements BluetoothProfile.ServiceListener {
54    @Override
55    public void onServiceConnected(int profile, BluetoothProfile proxy) {
56      sHidProfile = (BluetoothInputDevice) proxy;
57      sIsHidReady = true;
58    }
59
60    @Override
61    public void onServiceDisconnected(int profile) {
62      sIsHidReady = false;
63    }
64  }
65
66  public Boolean hidConnect(BluetoothDevice device) {
67    if (sHidProfile == null) return false;
68    return sHidProfile.connect(device);
69  }
70
71  public Boolean hidDisconnect(BluetoothDevice device) {
72    if (sHidProfile == null) return false;
73    return sHidProfile.disconnect(device);
74  }
75
76  @Rpc(description = "Is Hid profile ready.")
77  public Boolean bluetoothHidIsReady() {
78    return sIsHidReady;
79  }
80
81  @Rpc(description = "Connect to an HID device.")
82  public Boolean bluetoothHidConnect(
83      @RpcParameter(name = "device", description = "Name or MAC address of a bluetooth device.")
84      String device)
85      throws Exception {
86    if (sHidProfile == null)
87      return false;
88    BluetoothDevice mDevice = BluetoothFacade.getDevice(BluetoothFacade.DiscoveredDevices, device);
89    Log.d("Connecting to device " + mDevice.getAliasName());
90    return hidConnect(mDevice);
91  }
92
93  @Rpc(description = "Disconnect an HID device.")
94  public Boolean bluetoothHidDisconnect(
95      @RpcParameter(name = "device", description = "Name or MAC address of a device.")
96      String device)
97      throws Exception {
98    if (sHidProfile == null)
99      return false;
100    Log.d("Connected devices: " + sHidProfile.getConnectedDevices());
101    BluetoothDevice mDevice = BluetoothFacade.getDevice(sHidProfile.getConnectedDevices(),
102                                                        device);
103    return hidDisconnect(mDevice);
104  }
105
106  @Rpc(description = "Get all the devices connected through HID.")
107  public List<BluetoothDevice> bluetoothHidGetConnectedDevices() {
108    while (!sIsHidReady);
109    return sHidProfile.getConnectedDevices();
110  }
111
112  @Rpc(description = "Get the connection status of a device.")
113  public Integer bluetoothHidGetConnectionStatus(
114          @RpcParameter(name = "deviceID",
115                        description = "Name or MAC address of a bluetooth device.")
116          String deviceID) {
117      if (sHidProfile == null) {
118          return BluetoothProfile.STATE_DISCONNECTED;
119      }
120      List<BluetoothDevice> deviceList = sHidProfile.getConnectedDevices();
121      BluetoothDevice device;
122      try {
123          device = BluetoothFacade.getDevice(deviceList, deviceID);
124      } catch (Exception e) {
125          return BluetoothProfile.STATE_DISCONNECTED;
126      }
127      return sHidProfile.getConnectionState(device);
128  }
129
130  @Rpc(description = "Send Set_Report command to the connected HID input device.")
131  public Boolean bluetoothHidSetReport(
132          @RpcParameter(name = "deviceID",
133          description = "Name or MAC address of a bluetooth device.")
134          String deviceID,
135          @RpcParameter(name = "type")
136          @RpcDefault(value = "1")
137          String type,
138          @RpcParameter(name = "report")
139          String report) throws Exception {
140      BluetoothDevice device = BluetoothFacade.getDevice(sHidProfile.getConnectedDevices(),
141              deviceID);
142      Log.d("type " + type.getBytes()[0]);
143      return sHidProfile.setReport(device, type.getBytes()[0], report);
144  }
145
146  @Rpc(description = "Send Get_Report command to the connected HID input device.")
147  public Boolean bluetoothHidGetReport(
148          @RpcParameter(name = "deviceID",
149          description = "Name or MAC address of a bluetooth device.")
150          String deviceID,
151          @RpcParameter(name = "type")
152          @RpcDefault(value = "1")
153          String type,
154          @RpcParameter(name = "reportId")
155          String reportId,
156          @RpcParameter(name = "buffSize")
157          Integer buffSize) throws Exception {
158      BluetoothDevice device = BluetoothFacade.getDevice(sHidProfile.getConnectedDevices(),
159              deviceID);
160      Log.d("type " + type.getBytes()[0] + "reportId " + reportId.getBytes()[0]);
161      return sHidProfile.getReport(device, type.getBytes()[0], reportId.getBytes()[0], buffSize);
162  }
163
164  @Rpc(description = "Send data to a connected HID device.")
165  public Boolean bluetoothHidSendData(
166          @RpcParameter(name = "deviceID",
167          description = "Name or MAC address of a bluetooth device.")
168          String deviceID,
169          @RpcParameter(name = "report")
170          String report) throws Exception {
171      BluetoothDevice device = BluetoothFacade.getDevice(sHidProfile.getConnectedDevices(),
172              deviceID);
173      return sHidProfile.sendData(device, report);
174  }
175
176  @Rpc(description = "Send virtual unplug to a connected HID device.")
177  public Boolean bluetoothHidVirtualUnplug(
178          @RpcParameter(name = "deviceID",
179          description = "Name or MAC address of a bluetooth device.")
180          String deviceID) throws Exception {
181      BluetoothDevice device = BluetoothFacade.getDevice(sHidProfile.getConnectedDevices(),
182              deviceID);
183      return sHidProfile.virtualUnplug(device);
184  }
185
186  @Rpc(description = "Test byte transfer.")
187  public byte[] testByte() {
188      byte[] bts = {0b01,0b10,0b11,0b100};
189      return bts;
190  }
191
192  @Override
193  public void shutdown() {
194  }
195}
196