blob: 4a0048673c282dc8f7c776875ee6ccac4e3adc72 [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 Zhang53f54122017-12-04 10:31:30 -080034 * Provides the public APIs to control the Bluetooth HID Device profile.
Hansong Zhangfa377b42017-09-27 14:17:20 -070035 *
Hansong Zhang53f54122017-12-04 10:31:30 -080036 * <p>BluetoothHidDevice is a proxy object for controlling the Bluetooth HID Device Service via IPC.
37 * Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object.
Hansong Zhangfa377b42017-09-27 14:17:20 -070038 *
Hansong Zhang53f54122017-12-04 10:31:30 -080039 * <p>{@hide}
Hemant Guptae88fd4b2014-04-18 11:22:45 +053040 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -070041public final class BluetoothHidDevice implements BluetoothProfile {
Hemant Guptae88fd4b2014-04-18 11:22:45 +053042
Hansong Zhangc26c76c2017-10-20 15:55:59 -070043 private static final String TAG = BluetoothHidDevice.class.getSimpleName();
Hemant Guptae88fd4b2014-04-18 11:22:45 +053044
Ivan Podogov0afe1902016-12-23 11:52:21 +000045 /**
Hansong Zhang53f54122017-12-04 10:31:30 -080046 * Intent used to broadcast the change in connection state of the Input Host profile.
Ivan Podogov0afe1902016-12-23 11:52:21 +000047 *
48 * <p>This intent will have 3 extras:
Hansong Zhang53f54122017-12-04 10:31:30 -080049 *
Ivan Podogov0afe1902016-12-23 11:52:21 +000050 * <ul>
Hansong Zhang53f54122017-12-04 10:31:30 -080051 * <li>{@link #EXTRA_STATE} - The current state of the profile.
52 * <li>{@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
53 * <li>{@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
Ivan Podogov0afe1902016-12-23 11:52:21 +000054 * </ul>
55 *
Hansong Zhang53f54122017-12-04 10:31:30 -080056 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link
57 * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link
58 * #STATE_DISCONNECTING}.
Ivan Podogov0afe1902016-12-23 11:52:21 +000059 *
Hansong Zhang53f54122017-12-04 10:31:30 -080060 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to receive.
Ivan Podogov0afe1902016-12-23 11:52:21 +000061 */
62 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Hemant Guptae88fd4b2014-04-18 11:22:45 +053063 public static final String ACTION_CONNECTION_STATE_CHANGED =
Hansong Zhangc26c76c2017-10-20 15:55:59 -070064 "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
Hemant Guptae88fd4b2014-04-18 11:22:45 +053065
66 /**
67 * Constants representing device subclass.
68 *
Hansong Zhang53f54122017-12-04 10:31:30 -080069 * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
70 * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
Hemant Guptae88fd4b2014-04-18 11:22:45 +053071 */
72 public static final byte SUBCLASS1_NONE = (byte) 0x00;
73 public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
74 public static final byte SUBCLASS1_MOUSE = (byte) 0x80;
75 public static final byte SUBCLASS1_COMBO = (byte) 0xC0;
76
77 public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00;
78 public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01;
79 public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
80 public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
81 public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
Hansong Zhang9eb138b2017-09-29 09:26:09 -070082 public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05;
Hemant Guptae88fd4b2014-04-18 11:22:45 +053083 public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
84
85 /**
86 * Constants representing report types.
87 *
Hansong Zhangfa377b42017-09-27 14:17:20 -070088 * @see BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)
89 * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
90 * @see BluetoothHidDeviceCallback#onIntrData(BluetoothDevice, byte, byte[])
Hemant Guptae88fd4b2014-04-18 11:22:45 +053091 */
92 public static final byte REPORT_TYPE_INPUT = (byte) 1;
93 public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
94 public static final byte REPORT_TYPE_FEATURE = (byte) 3;
95
96 /**
97 * Constants representing error response for Set Report.
98 *
Hansong Zhangfa377b42017-09-27 14:17:20 -070099 * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530100 */
101 public static final byte ERROR_RSP_SUCCESS = (byte) 0;
102 public static final byte ERROR_RSP_NOT_READY = (byte) 1;
103 public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2;
104 public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3;
105 public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4;
106 public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
107
108 /**
Hansong Zhang53f54122017-12-04 10:31:30 -0800109 * Constants representing protocol mode used set by host. Default is always {@link
110 * #PROTOCOL_REPORT_MODE} unless notified otherwise.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530111 *
Hansong Zhangfa377b42017-09-27 14:17:20 -0700112 * @see BluetoothHidDeviceCallback#onSetProtocol(BluetoothDevice, byte)
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530113 */
114 public static final byte PROTOCOL_BOOT_MODE = (byte) 0;
115 public static final byte PROTOCOL_REPORT_MODE = (byte) 1;
116
117 private Context mContext;
118
119 private ServiceListener mServiceListener;
120
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700121 private volatile IBluetoothHidDevice mService;
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530122
123 private BluetoothAdapter mAdapter;
124
Hansong Zhang53f54122017-12-04 10:31:30 -0800125 private static class BluetoothHidDeviceCallbackWrapper
126 extends IBluetoothHidDeviceCallback.Stub {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530127
128 private BluetoothHidDeviceCallback mCallback;
129
130 public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) {
131 mCallback = callback;
132 }
133
134 @Override
Hansong Zhang7e527b72017-11-30 16:37:05 -0800135 public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
136 mCallback.onAppStatusChanged(pluggedDevice, registered);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530137 }
138
139 @Override
140 public void onConnectionStateChanged(BluetoothDevice device, int state) {
141 mCallback.onConnectionStateChanged(device, state);
142 }
143
144 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000145 public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
146 mCallback.onGetReport(device, type, id, bufferSize);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530147 }
148
149 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000150 public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
151 mCallback.onSetReport(device, type, id, data);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530152 }
153
154 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000155 public void onSetProtocol(BluetoothDevice device, byte protocol) {
156 mCallback.onSetProtocol(device, protocol);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530157 }
158
159 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000160 public void onIntrData(BluetoothDevice device, byte reportId, byte[] data) {
161 mCallback.onIntrData(device, reportId, data);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530162 }
163
164 @Override
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000165 public void onVirtualCableUnplug(BluetoothDevice device) {
166 mCallback.onVirtualCableUnplug(device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530167 }
168 }
169
Jack He2992cd02017-08-22 21:21:23 -0700170 private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
Jack Hea355e5e2017-08-22 16:06:54 -0700171 new IBluetoothStateChangeCallback.Stub() {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530172
Jack Hea355e5e2017-08-22 16:06:54 -0700173 public void onBluetoothStateChange(boolean up) {
174 Log.d(TAG, "onBluetoothStateChange: up=" + up);
175 synchronized (mConnection) {
Hansong Zhangfa377b42017-09-27 14:17:20 -0700176 if (up) {
Jack Hea355e5e2017-08-22 16:06:54 -0700177 try {
178 if (mService == null) {
179 Log.d(TAG, "Binding HID Device service...");
180 doBind();
181 }
182 } catch (IllegalStateException e) {
Hansong Zhang53f54122017-12-04 10:31:30 -0800183 Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
184 + "service: ", e);
Jack Hea355e5e2017-08-22 16:06:54 -0700185 } catch (SecurityException e) {
Hansong Zhang53f54122017-12-04 10:31:30 -0800186 Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
187 + "service: ", e);
Jack Hea355e5e2017-08-22 16:06:54 -0700188 }
Hansong Zhangfa377b42017-09-27 14:17:20 -0700189 } else {
190 Log.d(TAG, "Unbinding service...");
191 doUnbind();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530192 }
193 }
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530194 }
Jack Hea355e5e2017-08-22 16:06:54 -0700195 };
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530196
Hansong Zhang53f54122017-12-04 10:31:30 -0800197 private final ServiceConnection mConnection =
198 new ServiceConnection() {
199 public void onServiceConnected(ComponentName className, IBinder service) {
200 Log.d(TAG, "onServiceConnected()");
201 mService = IBluetoothHidDevice.Stub.asInterface(service);
202 if (mServiceListener != null) {
203 mServiceListener.onServiceConnected(
204 BluetoothProfile.HID_DEVICE, BluetoothHidDevice.this);
205 }
206 }
207
208 public void onServiceDisconnected(ComponentName className) {
209 Log.d(TAG, "onServiceDisconnected()");
210 mService = null;
211 if (mServiceListener != null) {
212 mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
213 }
214 }
215 };
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530216
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700217 BluetoothHidDevice(Context context, ServiceListener listener) {
218 Log.v(TAG, "BluetoothHidDevice");
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530219
220 mContext = context;
221 mServiceListener = listener;
222 mAdapter = BluetoothAdapter.getDefaultAdapter();
223
224 IBluetoothManager mgr = mAdapter.getBluetoothManager();
225 if (mgr != null) {
226 try {
227 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
228 } catch (RemoteException e) {
229 e.printStackTrace();
230 }
231 }
232
233 doBind();
234 }
235
236 boolean doBind() {
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700237 Intent intent = new Intent(IBluetoothHidDevice.class.getName());
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530238 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
239 intent.setComponent(comp);
240 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
241 android.os.Process.myUserHandle())) {
242 Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent);
243 return false;
244 }
245 Log.d(TAG, "Bound to HID Device Service");
246 return true;
247 }
248
Hansong Zhangfa377b42017-09-27 14:17:20 -0700249 void doUnbind() {
250 Log.d(TAG, "Unbinding HidDevService");
251 if (mService != null) {
252 mService = null;
253 try {
254 mContext.unbindService(mConnection);
255 } catch (IllegalArgumentException e) {
256 Log.e(TAG, "Unable to unbind HidDevService", e);
257 }
258 }
259 }
260
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530261 void close() {
262 Log.v(TAG, "close()");
263
264 IBluetoothManager mgr = mAdapter.getBluetoothManager();
265 if (mgr != null) {
266 try {
267 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
268 } catch (RemoteException e) {
269 e.printStackTrace();
270 }
271 }
272
273 synchronized (mConnection) {
Hansong Zhangfa377b42017-09-27 14:17:20 -0700274 doUnbind();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530275 }
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530276 mServiceListener = null;
277 }
278
Hansong Zhang53f54122017-12-04 10:31:30 -0800279 /** {@inheritDoc} */
Jack He2992cd02017-08-22 21:21:23 -0700280 @Override
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530281 public List<BluetoothDevice> getConnectedDevices() {
282 Log.v(TAG, "getConnectedDevices()");
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000283
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700284 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700285 if (service != null) {
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000286 try {
Jack He16eeac32017-08-17 12:11:18 -0700287 return service.getConnectedDevices();
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000288 } catch (RemoteException e) {
289 Log.e(TAG, e.toString());
290 }
291 } else {
292 Log.w(TAG, "Proxy not attached to service");
293 }
294
295 return new ArrayList<BluetoothDevice>();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530296 }
297
Hansong Zhang53f54122017-12-04 10:31:30 -0800298 /** {@inheritDoc} */
Jack He2992cd02017-08-22 21:21:23 -0700299 @Override
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530300 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
301 Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000302
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700303 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700304 if (service != null) {
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000305 try {
Jack He16eeac32017-08-17 12:11:18 -0700306 return service.getDevicesMatchingConnectionStates(states);
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000307 } catch (RemoteException e) {
308 Log.e(TAG, e.toString());
309 }
310 } else {
311 Log.w(TAG, "Proxy not attached to service");
312 }
313
314 return new ArrayList<BluetoothDevice>();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530315 }
316
Hansong Zhang53f54122017-12-04 10:31:30 -0800317 /** {@inheritDoc} */
Jack He2992cd02017-08-22 21:21:23 -0700318 @Override
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530319 public int getConnectionState(BluetoothDevice device) {
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000320 Log.v(TAG, "getConnectionState(): device=" + device);
321
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700322 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700323 if (service != null) {
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000324 try {
Jack He16eeac32017-08-17 12:11:18 -0700325 return service.getConnectionState(device);
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000326 } catch (RemoteException e) {
327 Log.e(TAG, e.toString());
328 }
329 } else {
330 Log.w(TAG, "Proxy not attached to service");
331 }
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530332
333 return STATE_DISCONNECTED;
334 }
335
336 /**
Hansong Zhang53f54122017-12-04 10:31:30 -0800337 * Registers application to be used for HID device. Connections to HID Device are only possible
338 * when application is registered. Only one application can be registered at one time. When an
339 * application is registered, the HID Host service will be disabled until it is unregistered.
340 * When no longer used, application should be unregistered using {@link #unregisterApp()}. The
341 * registration status should be tracked by the application by handling callback from
342 * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
343 * the return value of this method.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530344 *
Hansong Zhang53f54122017-12-04 10:31:30 -0800345 * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID
346 * Device SDP record is required.
347 * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings. The
348 * Incoming QoS Settings is not required. Use null or default
349 * BluetoothHidDeviceAppQosSettings.Builder for default values.
350 * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings. The
351 * Outgoing QoS Settings is not required. Use null or default
352 * BluetoothHidDeviceAppQosSettings.Builder for default values.
Jack Hea355e5e2017-08-22 16:06:54 -0700353 * @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be
Hansong Zhang53f54122017-12-04 10:31:30 -0800354 * sent. The BluetoothHidDeviceCallback object is required.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800355 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530356 */
357 public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
358 BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
359 BluetoothHidDeviceCallback callback) {
360 Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
Hansong Zhang53f54122017-12-04 10:31:30 -0800361 + " callback=" + callback);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530362
363 boolean result = false;
364
365 if (sdp == null || callback == null) {
366 return false;
367 }
368
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700369 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700370 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530371 try {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530372 BluetoothHidDeviceCallbackWrapper cbw =
Jack Hea355e5e2017-08-22 16:06:54 -0700373 new BluetoothHidDeviceCallbackWrapper(callback);
Hansong Zhang7e527b72017-11-30 16:37:05 -0800374 result = service.registerApp(sdp, inQos, outQos, cbw);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530375 } catch (RemoteException e) {
376 Log.e(TAG, e.toString());
377 }
378 } else {
379 Log.w(TAG, "Proxy not attached to service");
380 }
381
382 return result;
383 }
384
385 /**
Hansong Zhang53f54122017-12-04 10:31:30 -0800386 * Unregisters application. Active connection will be disconnected and no new connections will
387 * be allowed until registered again using {@link #registerApp
Hansong Zhangfa377b42017-09-27 14:17:20 -0700388 * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
Hansong Zhang53f54122017-12-04 10:31:30 -0800389 * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)} The registration status should
390 * be tracked by the application by handling callback from
391 * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
392 * the return value of this method.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530393 *
Hansong Zhangceb84db2017-11-08 09:57:12 -0800394 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530395 */
Hansong Zhang7e527b72017-11-30 16:37:05 -0800396 public boolean unregisterApp() {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530397 Log.v(TAG, "unregisterApp()");
398
399 boolean result = false;
400
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700401 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700402 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530403 try {
Hansong Zhang7e527b72017-11-30 16:37:05 -0800404 result = service.unregisterApp();
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530405 } catch (RemoteException e) {
406 Log.e(TAG, e.toString());
407 }
408 } else {
409 Log.w(TAG, "Proxy not attached to service");
410 }
411
412 return result;
413 }
414
415 /**
416 * Sends report to remote host using interrupt channel.
417 *
Jack Hea355e5e2017-08-22 16:06:54 -0700418 * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
Hansong Zhang53f54122017-12-04 10:31:30 -0800419 * descriptor.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530420 * @param data Report data, not including Report Id.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800421 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530422 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000423 public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530424 boolean result = false;
425
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700426 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700427 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530428 try {
Jack He16eeac32017-08-17 12:11:18 -0700429 result = service.sendReport(device, id, data);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530430 } catch (RemoteException e) {
431 Log.e(TAG, e.toString());
432 }
433 } else {
434 Log.w(TAG, "Proxy not attached to service");
435 }
436
437 return result;
438 }
439
440 /**
Hansong Zhang53f54122017-12-04 10:31:30 -0800441 * Sends report to remote host as reply for GET_REPORT request from {@link
442 * BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530443 *
444 * @param type Report Type, as in request.
445 * @param id Report Id, as in request.
446 * @param data Report data, not including Report Id.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800447 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530448 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000449 public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
450 Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530451
452 boolean result = false;
453
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700454 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700455 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530456 try {
Jack He16eeac32017-08-17 12:11:18 -0700457 result = service.replyReport(device, type, id, data);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530458 } catch (RemoteException e) {
459 Log.e(TAG, e.toString());
460 }
461 } else {
462 Log.w(TAG, "Proxy not attached to service");
463 }
464
465 return result;
466 }
467
468 /**
Hansong Zhang53f54122017-12-04 10:31:30 -0800469 * Sends error handshake message as reply for invalid SET_REPORT request from {@link
470 * BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530471 *
472 * @param error Error to be sent for SET_REPORT via HANDSHAKE.
Hansong Zhangceb84db2017-11-08 09:57:12 -0800473 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530474 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000475 public boolean reportError(BluetoothDevice device, byte error) {
476 Log.v(TAG, "reportError(): device=" + device + " error=" + error);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530477
478 boolean result = false;
479
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700480 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700481 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530482 try {
Jack He16eeac32017-08-17 12:11:18 -0700483 result = service.reportError(device, error);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530484 } catch (RemoteException e) {
485 Log.e(TAG, e.toString());
486 }
487 } else {
488 Log.w(TAG, "Proxy not attached to service");
489 }
490
491 return result;
492 }
493
494 /**
495 * Sends Virtual Cable Unplug to currently connected host.
496 *
497 * @return
Hansong Zhang53f54122017-12-04 10:31:30 -0800498 * {@hide}
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530499 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000500 public boolean unplug(BluetoothDevice device) {
501 Log.v(TAG, "unplug(): device=" + device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530502
503 boolean result = false;
504
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700505 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700506 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530507 try {
Jack He16eeac32017-08-17 12:11:18 -0700508 result = service.unplug(device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530509 } catch (RemoteException e) {
510 Log.e(TAG, e.toString());
511 }
512 } else {
513 Log.w(TAG, "Proxy not attached to service");
514 }
515
516 return result;
517 }
518
519 /**
Hansong Zhang53f54122017-12-04 10:31:30 -0800520 * Initiates connection to host which is currently paired with this device. If the application
521 * is not registered, #connect(BluetoothDevice) will fail. The connection state should be
522 * tracked by the application by handling callback from
523 * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related to
524 * the return value of this method.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530525 *
Hansong Zhangceb84db2017-11-08 09:57:12 -0800526 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530527 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000528 public boolean connect(BluetoothDevice device) {
529 Log.v(TAG, "connect(): device=" + device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530530
531 boolean result = false;
532
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700533 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700534 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530535 try {
Jack He16eeac32017-08-17 12:11:18 -0700536 result = service.connect(device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530537 } catch (RemoteException e) {
538 Log.e(TAG, e.toString());
539 }
540 } else {
541 Log.w(TAG, "Proxy not attached to service");
542 }
543
544 return result;
545 }
546
547 /**
Hansong Zhang53f54122017-12-04 10:31:30 -0800548 * Disconnects from currently connected host. The connection state should be tracked by the
549 * application by handling callback from BluetoothHidDeviceCallback#onConnectionStateChanged.
550 * The connection state is not related to the return value of this method.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530551 *
Hansong Zhangceb84db2017-11-08 09:57:12 -0800552 * @return true if the command is successfully sent; otherwise false.
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530553 */
Ivan Podogovdd87cd32016-12-30 14:43:29 +0000554 public boolean disconnect(BluetoothDevice device) {
555 Log.v(TAG, "disconnect(): device=" + device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530556
557 boolean result = false;
558
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700559 final IBluetoothHidDevice service = mService;
Jack He16eeac32017-08-17 12:11:18 -0700560 if (service != null) {
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530561 try {
Jack He16eeac32017-08-17 12:11:18 -0700562 result = service.disconnect(device);
Hemant Guptae88fd4b2014-04-18 11:22:45 +0530563 } catch (RemoteException e) {
564 Log.e(TAG, e.toString());
565 }
566 } else {
567 Log.w(TAG, "Proxy not attached to service");
568 }
569
570 return result;
571 }
572}