blob: 6692e137fa0a3e4fb7fe99babe127a61bfe75a08 [file] [log] [blame]
Hemant Guptae88fd4b2014-04-18 11:22:45 +05301/*
2 * Copyright (C) 2016 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
17package android.bluetooth;
18
Ivan Podogov0afe1902016-12-23 11:52:21 +000019import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
Hemant Guptae88fd4b2014-04-18 11:22:45 +053021import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
25import android.os.IBinder;
26import android.os.RemoteException;
27import android.util.Log;
28
Ivan Podogovdd87cd32016-12-30 14:43:29 +000029import java.util.ArrayList;
Jack Hea355e5e2017-08-22 16:06:54 -070030import java.util.Arrays;
Hemant Guptae88fd4b2014-04-18 11:22:45 +053031import java.util.List;
32
33/**
Hansong Zhangfa377b42017-09-27 14:17:20 -070034 * Provides the public APIs to control the Bluetooth HID Device
35 * profile.
36 *
37 * BluetoothHidDevice is a proxy object for controlling the Bluetooth HID
38 * Device Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
39 * the BluetoothHidDevice proxy object.
40 *
41 * {@hide}
Hemant Guptae88fd4b2014-04-18 11:22:45 +053042 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -070043public final class BluetoothHidDevice implements BluetoothProfile {
Hemant Guptae88fd4b2014-04-18 11:22:45 +053044
Hansong Zhangc26c76c2017-10-20 15:55:59 -070045 private static final String TAG = BluetoothHidDevice.class.getSimpleName();
Hemant Guptae88fd4b2014-04-18 11:22:45 +053046
Ivan Podogov0afe1902016-12-23 11:52:21 +000047 /**
48 * Intent used to broadcast the change in connection state of the Input
49 * Host profile.
50 *
51 * <p>This intent will have 3 extras:
52 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070053 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
54 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
55 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Ivan Podogov0afe1902016-12-23 11:52:21 +000056 * </ul>
57 *
58 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
59 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
60 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
61 *
62 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
63 * receive.
64 */
65 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Hemant Guptae88fd4b2014-04-18 11:22:45 +053066 public static final String ACTION_CONNECTION_STATE_CHANGED =
Hansong Zhangc26c76c2017-10-20 15:55:59 -070067 "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
Hemant Guptae88fd4b2014-04-18 11:22:45 +053068
69 /**
70 * Constants representing device subclass.
71 *
Hansong Zhangfa377b42017-09-27 14:17:20 -070072 * @see #registerApp
73 * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
74 * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
Hemant Guptae88fd4b2014-04-18 11:22:45 +053075 */
76 public static final byte SUBCLASS1_NONE = (byte) 0x00;
77 public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
78 public static final byte SUBCLASS1_MOUSE = (byte) 0x80;
79 public static final byte SUBCLASS1_COMBO = (byte) 0xC0;
80
81 public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00;
82 public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01;
83 public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
84 public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
85 public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
Hansong Zhang9eb138b2017-09-29 09:26:09 -070086 public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05;
Hemant Guptae88fd4b2014-04-18 11:22:45 +053087 public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
88
89 /**
90 * Constants representing report types.
91 *
Hansong Zhangfa377b42017-09-27 14:17:20 -070092 * @see BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)
93 * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
94 * @see BluetoothHidDeviceCallback#onIntrData(BluetoothDevice, byte, byte[])
Hemant Guptae88fd4b2014-04-18 11:22:45 +053095 */
96 public static final byte REPORT_TYPE_INPUT = (byte) 1;
97 public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
98 public static final byte REPORT_TYPE_FEATURE = (byte) 3;
99
100 /**
101 * Constants representing error response for Set Report.
102 *
Hansong Zhangfa377b42017-09-27 14:17:20 -0700103 * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530104 */
105 public static final byte ERROR_RSP_SUCCESS = (byte) 0;
106 public static final byte ERROR_RSP_NOT_READY = (byte) 1;
107 public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2;
108 public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3;
109 public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4;
110 public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
111
112 /**
113 * Constants representing protocol mode used set by host. Default is always
114 * {@link #PROTOCOL_REPORT_MODE} unless notified otherwise.
115 *
Hansong Zhangfa377b42017-09-27 14:17:20 -0700116 * @see BluetoothHidDeviceCallback#onSetProtocol(BluetoothDevice, byte)
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530117 */
118 public static final byte PROTOCOL_BOOT_MODE = (byte) 0;
119 public static final byte PROTOCOL_REPORT_MODE = (byte) 1;
120
121 private Context mContext;
122
123 private ServiceListener mServiceListener;
124
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700125 private volatile IBluetoothHidDevice mService;
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530126
127 private BluetoothAdapter mAdapter;
128
Jack Hea355e5e2017-08-22 16:06:54 -0700129 private static class BluetoothHidDeviceCallbackWrapper extends
130 IBluetoothHidDeviceCallback.Stub {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530131
132 private BluetoothHidDeviceCallback mCallback;
133
134 public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) {
135 mCallback = callback;
136 }
137
138 @Override
139 public void onAppStatusChanged(BluetoothDevice pluggedDevice,
140 BluetoothHidDeviceAppConfiguration config, boolean registered) {
141 mCallback.onAppStatusChanged(pluggedDevice, config, registered);
142 }
143
144 @Override
145 public void onConnectionStateChanged(BluetoothDevice device, int state) {
146 mCallback.onConnectionStateChanged(device, state);
147 }
148
149 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000150 public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
151 mCallback.onGetReport(device, type, id, bufferSize);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530152 }
153
154 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000155 public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
156 mCallback.onSetReport(device, type, id, data);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530157 }
158
159 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000160 public void onSetProtocol(BluetoothDevice device, byte protocol) {
161 mCallback.onSetProtocol(device, protocol);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530162 }
163
164 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000165 public void onIntrData(BluetoothDevice device, byte reportId, byte[] data) {
166 mCallback.onIntrData(device, reportId, data);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530167 }
168
169 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000170 public void onVirtualCableUnplug(BluetoothDevice device) {
171 mCallback.onVirtualCableUnplug(device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530172 }
173 }
174
Jack He2992cd02017-08-22 21:21:23 -0700175 private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
Jack Hea355e5e2017-08-22 16:06:54 -0700176 new IBluetoothStateChangeCallback.Stub() {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530177
Jack Hea355e5e2017-08-22 16:06:54 -0700178 public void onBluetoothStateChange(boolean up) {
179 Log.d(TAG, "onBluetoothStateChange: up=" + up);
180 synchronized (mConnection) {
Hansong Zhangfa377b42017-09-27 14:17:20 -0700181 if (up) {
Jack Hea355e5e2017-08-22 16:06:54 -0700182 try {
183 if (mService == null) {
184 Log.d(TAG, "Binding HID Device service...");
185 doBind();
186 }
187 } catch (IllegalStateException e) {
188 Log.e(TAG,
189 "onBluetoothStateChange: could not bind to HID Dev "
Hansong Zhangfa377b42017-09-27 14:17:20 -0700190 + "service: ", e);
Jack Hea355e5e2017-08-22 16:06:54 -0700191 } catch (SecurityException e) {
192 Log.e(TAG,
193 "onBluetoothStateChange: could not bind to HID Dev "
Hansong Zhangfa377b42017-09-27 14:17:20 -0700194 + "service: ", e);
Jack Hea355e5e2017-08-22 16:06:54 -0700195 }
Hansong Zhangfa377b42017-09-27 14:17:20 -0700196 } else {
197 Log.d(TAG, "Unbinding service...");
198 doUnbind();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530199 }
200 }
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530201 }
Jack Hea355e5e2017-08-22 16:06:54 -0700202 };
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530203
Jack He16eeac32017-08-17 12:11:18 -0700204 private final ServiceConnection mConnection = new ServiceConnection() {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530205 public void onServiceConnected(ComponentName className, IBinder service) {
206 Log.d(TAG, "onServiceConnected()");
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700207 mService = IBluetoothHidDevice.Stub.asInterface(service);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530208 if (mServiceListener != null) {
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700209 mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE,
210 BluetoothHidDevice.this);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530211 }
212 }
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530213 public void onServiceDisconnected(ComponentName className) {
214 Log.d(TAG, "onServiceDisconnected()");
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530215 mService = null;
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530216 if (mServiceListener != null) {
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700217 mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530218 }
219 }
220 };
221
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700222 BluetoothHidDevice(Context context, ServiceListener listener) {
223 Log.v(TAG, "BluetoothHidDevice");
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530224
225 mContext = context;
226 mServiceListener = listener;
227 mAdapter = BluetoothAdapter.getDefaultAdapter();
228
229 IBluetoothManager mgr = mAdapter.getBluetoothManager();
230 if (mgr != null) {
231 try {
232 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
233 } catch (RemoteException e) {
234 e.printStackTrace();
235 }
236 }
237
238 doBind();
239 }
240
241 boolean doBind() {
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700242 Intent intent = new Intent(IBluetoothHidDevice.class.getName());
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530243 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
244 intent.setComponent(comp);
245 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
246 android.os.Process.myUserHandle())) {
247 Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent);
248 return false;
249 }
250 Log.d(TAG, "Bound to HID Device Service");
251 return true;
252 }
253
Hansong Zhangfa377b42017-09-27 14:17:20 -0700254 void doUnbind() {
255 Log.d(TAG, "Unbinding HidDevService");
256 if (mService != null) {
257 mService = null;
258 try {
259 mContext.unbindService(mConnection);
260 } catch (IllegalArgumentException e) {
261 Log.e(TAG, "Unable to unbind HidDevService", e);
262 }
263 }
264 }
265
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530266 void close() {
267 Log.v(TAG, "close()");
268
269 IBluetoothManager mgr = mAdapter.getBluetoothManager();
270 if (mgr != null) {
271 try {
272 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
273 } catch (RemoteException e) {
274 e.printStackTrace();
275 }
276 }
277
278 synchronized (mConnection) {
Hansong Zhangfa377b42017-09-27 14:17:20 -0700279 doUnbind();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530280 }
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530281 mServiceListener = null;
282 }
283
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000284 /**
285 * {@inheritDoc}
286 */
Jack He2992cd02017-08-22 21:21:23 -0700287 @Override
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530288 public List<BluetoothDevice> getConnectedDevices() {
289 Log.v(TAG, "getConnectedDevices()");
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000290
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700291 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700292 if (service != null) {
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000293 try {
Jack He16eeac32017-08-17 12:11:18 -0700294 return service.getConnectedDevices();
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000295 } catch (RemoteException e) {
296 Log.e(TAG, e.toString());
297 }
298 } else {
299 Log.w(TAG, "Proxy not attached to service");
300 }
301
302 return new ArrayList<BluetoothDevice>();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530303 }
304
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000305 /**
306 * {@inheritDoc}
307 */
Jack He2992cd02017-08-22 21:21:23 -0700308 @Override
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530309 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
310 Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000311
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700312 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700313 if (service != null) {
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000314 try {
Jack He16eeac32017-08-17 12:11:18 -0700315 return service.getDevicesMatchingConnectionStates(states);
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000316 } catch (RemoteException e) {
317 Log.e(TAG, e.toString());
318 }
319 } else {
320 Log.w(TAG, "Proxy not attached to service");
321 }
322
323 return new ArrayList<BluetoothDevice>();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530324 }
325
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000326 /**
327 * {@inheritDoc}
328 */
Jack He2992cd02017-08-22 21:21:23 -0700329 @Override
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530330 public int getConnectionState(BluetoothDevice device) {
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000331 Log.v(TAG, "getConnectionState(): device=" + device);
332
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700333 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700334 if (service != null) {
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000335 try {
Jack He16eeac32017-08-17 12:11:18 -0700336 return service.getConnectionState(device);
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000337 } catch (RemoteException e) {
338 Log.e(TAG, e.toString());
339 }
340 } else {
341 Log.w(TAG, "Proxy not attached to service");
342 }
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530343
344 return STATE_DISCONNECTED;
345 }
346
347 /**
348 * Registers application to be used for HID device. Connections to HID
349 * Device are only possible when application is registered. Only one
350 * application can be registered at time. When no longer used, application
351 * should be unregistered using
352 * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800353 * The registration status should be tracked by the application by handling callback from
354 * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
355 * to the return value of this method.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530356 *
Jack Hea355e5e2017-08-22 16:06:54 -0700357 * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800358 * The HID Device SDP record is required.
Jack Hea355e5e2017-08-22 16:06:54 -0700359 * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800360 * The Incoming QoS Settings is not required. Use null or default
361 * BluetoothHidDeviceAppQosSettings.Builder for default values.
Jack Hea355e5e2017-08-22 16:06:54 -0700362 * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800363 * The Outgoing QoS Settings is not required. Use null or default
364 * BluetoothHidDeviceAppQosSettings.Builder for default values.
Jack Hea355e5e2017-08-22 16:06:54 -0700365 * @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be
366 * sent.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800367 * The BluetoothHidDeviceCallback object is required.
368 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530369 */
370 public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
371 BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
372 BluetoothHidDeviceCallback callback) {
373 Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
374 + " callback=" + callback);
375
376 boolean result = false;
377
378 if (sdp == null || callback == null) {
379 return false;
380 }
381
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700382 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700383 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530384 try {
385 BluetoothHidDeviceAppConfiguration config =
Jack Hea355e5e2017-08-22 16:06:54 -0700386 new BluetoothHidDeviceAppConfiguration();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530387 BluetoothHidDeviceCallbackWrapper cbw =
Jack Hea355e5e2017-08-22 16:06:54 -0700388 new BluetoothHidDeviceCallbackWrapper(callback);
Jack He16eeac32017-08-17 12:11:18 -0700389 result = service.registerApp(config, sdp, inQos, outQos, cbw);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530390 } catch (RemoteException e) {
391 Log.e(TAG, e.toString());
392 }
393 } else {
394 Log.w(TAG, "Proxy not attached to service");
395 }
396
397 return result;
398 }
399
400 /**
401 * Unregisters application. Active connection will be disconnected and no
402 * new connections will be allowed until registered again using
Hansong Zhangfa377b42017-09-27 14:17:20 -0700403 * {@link #registerApp
404 * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
405 * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)}
Hansong Zhangceb84db2017-11-08 09:57:12 -0800406 * The registration status should be tracked by the application by handling callback from
407 * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
408 * to the return value of this method.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530409 *
Jack Hea355e5e2017-08-22 16:06:54 -0700410 * @param config {@link BluetoothHidDeviceAppConfiguration} object as obtained from {@link
411 * BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
412 * BluetoothHidDeviceAppConfiguration,
413 * boolean)}
Hansong Zhangceb84db2017-11-08 09:57:12 -0800414 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530415 */
416 public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
417 Log.v(TAG, "unregisterApp()");
418
419 boolean result = false;
420
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700421 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700422 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530423 try {
Jack He16eeac32017-08-17 12:11:18 -0700424 result = service.unregisterApp(config);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530425 } catch (RemoteException e) {
426 Log.e(TAG, e.toString());
427 }
428 } else {
429 Log.w(TAG, "Proxy not attached to service");
430 }
431
432 return result;
433 }
434
435 /**
436 * Sends report to remote host using interrupt channel.
437 *
Jack Hea355e5e2017-08-22 16:06:54 -0700438 * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
439 * descriptor.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530440 * @param data Report data, not including Report Id.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800441 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530442 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000443 public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530444 boolean result = false;
445
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700446 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700447 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530448 try {
Jack He16eeac32017-08-17 12:11:18 -0700449 result = service.sendReport(device, id, data);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530450 } catch (RemoteException e) {
451 Log.e(TAG, e.toString());
452 }
453 } else {
454 Log.w(TAG, "Proxy not attached to service");
455 }
456
457 return result;
458 }
459
460 /**
461 * Sends report to remote host as reply for GET_REPORT request from
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000462 * {@link BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530463 *
464 * @param type Report Type, as in request.
465 * @param id Report Id, as in request.
466 * @param data Report data, not including Report Id.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800467 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530468 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000469 public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
470 Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530471
472 boolean result = false;
473
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700474 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700475 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530476 try {
Jack He16eeac32017-08-17 12:11:18 -0700477 result = service.replyReport(device, type, id, data);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530478 } catch (RemoteException e) {
479 Log.e(TAG, e.toString());
480 }
481 } else {
482 Log.w(TAG, "Proxy not attached to service");
483 }
484
485 return result;
486 }
487
488 /**
489 * Sends error handshake message as reply for invalid SET_REPORT request
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000490 * from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530491 *
492 * @param error Error to be sent for SET_REPORT via HANDSHAKE.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800493 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530494 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000495 public boolean reportError(BluetoothDevice device, byte error) {
496 Log.v(TAG, "reportError(): device=" + device + " error=" + error);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530497
498 boolean result = false;
499
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700500 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700501 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530502 try {
Jack He16eeac32017-08-17 12:11:18 -0700503 result = service.reportError(device, error);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530504 } catch (RemoteException e) {
505 Log.e(TAG, e.toString());
506 }
507 } else {
508 Log.w(TAG, "Proxy not attached to service");
509 }
510
511 return result;
512 }
513
514 /**
515 * Sends Virtual Cable Unplug to currently connected host.
516 *
517 * @return
518 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000519 public boolean unplug(BluetoothDevice device) {
520 Log.v(TAG, "unplug(): device=" + device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530521
522 boolean result = false;
523
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700524 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700525 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530526 try {
Jack He16eeac32017-08-17 12:11:18 -0700527 result = service.unplug(device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530528 } catch (RemoteException e) {
529 Log.e(TAG, e.toString());
530 }
531 } else {
532 Log.w(TAG, "Proxy not attached to service");
533 }
534
535 return result;
536 }
537
538 /**
Hansong Zhangceb84db2017-11-08 09:57:12 -0800539 * Initiates connection to host which is currently paired with this device.
540 * If the application is not registered, #connect(BluetoothDevice) will fail.
541 * The connection state should be tracked by the application by handling callback from
542 * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
543 * to the return value of this method.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530544 *
Hansong Zhangceb84db2017-11-08 09:57:12 -0800545 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530546 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000547 public boolean connect(BluetoothDevice device) {
548 Log.v(TAG, "connect(): device=" + device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530549
550 boolean result = false;
551
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700552 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700553 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530554 try {
Jack He16eeac32017-08-17 12:11:18 -0700555 result = service.connect(device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530556 } catch (RemoteException e) {
557 Log.e(TAG, e.toString());
558 }
559 } else {
560 Log.w(TAG, "Proxy not attached to service");
561 }
562
563 return result;
564 }
565
566 /**
567 * Disconnects from currently connected host.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800568 * The connection state should be tracked by the application by handling callback from
569 * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
570 * to the return value of this method.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530571 *
Hansong Zhangceb84db2017-11-08 09:57:12 -0800572 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530573 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000574 public boolean disconnect(BluetoothDevice device) {
575 Log.v(TAG, "disconnect(): device=" + device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530576
577 boolean result = false;
578
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700579 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700580 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530581 try {
Jack He16eeac32017-08-17 12:11:18 -0700582 result = service.disconnect(device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530583 } catch (RemoteException e) {
584 Log.e(TAG, e.toString());
585 }
586 } else {
587 Log.w(TAG, "Proxy not attached to service");
588 }
589
590 return result;
591 }
592}