blob: 4afb382c066050fb13df414a74f81bc206b86514 [file] [log] [blame]
Jaikumar Ganesh545e6702010-06-04 10:23:03 -07001/*
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -08002 * Copyright (C) 2011 The Android Open Source Project
Jaikumar Ganesh545e6702010-06-04 10:23:03 -07003 *
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
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.content.Context;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060022import android.os.Binder;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070023import android.os.IBinder;
24import android.os.RemoteException;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070025import android.util.Log;
26
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070027import java.util.ArrayList;
28import java.util.List;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070029
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080030
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070031/**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080032 * This class provides the public APIs to control the Bluetooth Input
33 * Device Profile.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070034 *
Hansong Zhangc26c76c2017-10-20 15:55:59 -070035 * <p>BluetoothHidHost is a proxy object for controlling the Bluetooth
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080036 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
Hansong Zhangc26c76c2017-10-20 15:55:59 -070037 * the BluetoothHidHost proxy object.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070038 *
Jack Hea355e5e2017-08-22 16:06:54 -070039 * <p>Each method is protected with its appropriate permission.
40 *
41 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070042 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -070043public final class BluetoothHidHost implements BluetoothProfile {
44 private static final String TAG = "BluetoothHidHost";
fredc0f420372012-04-12 00:02:00 -070045 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070046 private static final boolean VDBG = false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070047
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080048 /**
49 * Intent used to broadcast the change in connection state of the Input
50 * Device profile.
51 *
52 * <p>This intent will have 3 extras:
53 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070054 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
55 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
56 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080057 * </ul>
58 *
59 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
60 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
61 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
62 *
63 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
64 * receive.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070065 */
66 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080067 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070068 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070069
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080070 /**
Priti Aghera349e62f2012-04-09 12:13:17 -070071 * @hide
72 */
73 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
74 public static final String ACTION_PROTOCOL_MODE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070075 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -070076
Mike J. Chend96d5cf2014-01-27 17:55:40 -080077 /**
78 * @hide
79 */
80 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chen8faffa42014-03-04 17:27:16 -080081 public static final String ACTION_HANDSHAKE =
Jack Hea355e5e2017-08-22 16:06:54 -070082 "android.bluetooth.input.profile.action.HANDSHAKE";
Mike J. Chen8faffa42014-03-04 17:27:16 -080083
84 /**
85 * @hide
86 */
87 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chend96d5cf2014-01-27 17:55:40 -080088 public static final String ACTION_REPORT =
Jack Hea355e5e2017-08-22 16:06:54 -070089 "android.bluetooth.input.profile.action.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -070090
91 /**
92 * @hide
93 */
94 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
95 public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
Jack Hea355e5e2017-08-22 16:06:54 -070096 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -070097
Hemant Guptacef9ce32013-07-30 16:09:20 +053098 /**
99 * @hide
100 */
101 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
102 public static final String ACTION_IDLE_TIME_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700103 "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -0700104
105 /**
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800106 * Return codes for the connect and disconnect Bluez / Dbus calls.
Jack Hea355e5e2017-08-22 16:06:54 -0700107 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800108 * @hide
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800109 */
110 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
111
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800112 /**
113 * @hide
114 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800115 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
116
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800117 /**
118 * @hide
119 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800120 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
121
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800122 /**
123 * @hide
124 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800125 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
126
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800127 /**
128 * @hide
129 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800130 public static final int INPUT_OPERATION_SUCCESS = 5004;
131
Priti Aghera349e62f2012-04-09 12:13:17 -0700132 /**
133 * @hide
134 */
135 public static final int PROTOCOL_REPORT_MODE = 0;
136
137 /**
138 * @hide
139 */
140 public static final int PROTOCOL_BOOT_MODE = 1;
141
142 /**
143 * @hide
144 */
145 public static final int PROTOCOL_UNSUPPORTED_MODE = 255;
146
147 /* int reportType, int reportType, int bufferSize */
148 /**
149 * @hide
150 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800151 public static final byte REPORT_TYPE_INPUT = 1;
Priti Aghera349e62f2012-04-09 12:13:17 -0700152
153 /**
154 * @hide
155 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800156 public static final byte REPORT_TYPE_OUTPUT = 2;
Priti Aghera349e62f2012-04-09 12:13:17 -0700157
158 /**
159 * @hide
160 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800161 public static final byte REPORT_TYPE_FEATURE = 3;
Priti Aghera349e62f2012-04-09 12:13:17 -0700162
163 /**
164 * @hide
165 */
166 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;
167
168 /**
169 * @hide
170 */
171 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;
172
173 /**
174 * @hide
175 */
Jack Hea355e5e2017-08-22 16:06:54 -0700176 public static final String EXTRA_PROTOCOL_MODE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700177 "android.bluetooth.BluetoothHidHost.extra.PROTOCOL_MODE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700178
179 /**
180 * @hide
181 */
Jack Hea355e5e2017-08-22 16:06:54 -0700182 public static final String EXTRA_REPORT_TYPE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700183 "android.bluetooth.BluetoothHidHost.extra.REPORT_TYPE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700184
185 /**
186 * @hide
187 */
Jack Hea355e5e2017-08-22 16:06:54 -0700188 public static final String EXTRA_REPORT_ID =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700189 "android.bluetooth.BluetoothHidHost.extra.REPORT_ID";
Priti Aghera349e62f2012-04-09 12:13:17 -0700190
191 /**
192 * @hide
193 */
Jack Hea355e5e2017-08-22 16:06:54 -0700194 public static final String EXTRA_REPORT_BUFFER_SIZE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700195 "android.bluetooth.BluetoothHidHost.extra.REPORT_BUFFER_SIZE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700196
197 /**
198 * @hide
199 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700200 public static final String EXTRA_REPORT = "android.bluetooth.BluetoothHidHost.extra.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -0700201
202 /**
203 * @hide
204 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700205 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothHidHost.extra.STATUS";
Mike J. Chen8faffa42014-03-04 17:27:16 -0800206
207 /**
208 * @hide
209 */
Jack Hea355e5e2017-08-22 16:06:54 -0700210 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700211 "android.bluetooth.BluetoothHidHost.extra.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700212
Hemant Guptacef9ce32013-07-30 16:09:20 +0530213 /**
214 * @hide
215 */
Jack Hea355e5e2017-08-22 16:06:54 -0700216 public static final String EXTRA_IDLE_TIME =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700217 "android.bluetooth.BluetoothHidHost.extra.IDLE_TIME";
Hemant Guptacef9ce32013-07-30 16:09:20 +0530218
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800219 private BluetoothAdapter mAdapter;
Ugo Yud0115462019-03-26 21:38:08 +0800220 private final BluetoothProfileConnector<IBluetoothHidHost> mProfileConnector =
221 new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST,
222 "BluetoothHidHost", IBluetoothHidHost.class.getName()) {
223 @Override
224 public IBluetoothHidHost getServiceInterface(IBinder service) {
225 return IBluetoothHidHost.Stub.asInterface(Binder.allowBlocking(service));
fredc0f420372012-04-12 00:02:00 -0700226 }
Ugo Yud0115462019-03-26 21:38:08 +0800227 };
fredc0f420372012-04-12 00:02:00 -0700228
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700229 /**
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700230 * Create a BluetoothHidHost proxy object for interacting with the local
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800231 * Bluetooth Service which handles the InputDevice profile
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700232 */
Ugo Yud0115462019-03-26 21:38:08 +0800233 /*package*/ BluetoothHidHost(Context context, ServiceListener listener) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800234 mAdapter = BluetoothAdapter.getDefaultAdapter();
Ugo Yud0115462019-03-26 21:38:08 +0800235 mProfileConnector.connect(context, listener);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700236 }
237
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800238 /*package*/ void close() {
Matthew Xie563e4142012-10-09 22:10:37 -0700239 if (VDBG) log("close()");
Ugo Yud0115462019-03-26 21:38:08 +0800240 mProfileConnector.disconnect();
241 }
fredc0f420372012-04-12 00:02:00 -0700242
Ugo Yud0115462019-03-26 21:38:08 +0800243 private IBluetoothHidHost getService() {
244 return mProfileConnector.getService();
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800245 }
246
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800247 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700248 * Initiate connection to a profile of the remote bluetooth device.
249 *
250 * <p> The system supports connection to multiple input devices.
251 *
252 * <p> This API returns false in scenarios like the profile on the
253 * device is already connected or Bluetooth is not turned on.
254 * When this API returns true, it is guaranteed that
255 * connection state intent for the profile will be broadcasted with
256 * the state. Users can get the connection state of the profile
257 * from this intent.
258 *
259 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
260 * permission.
261 *
262 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700263 * @return false on immediate error, true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800264 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700265 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800266 public boolean connect(BluetoothDevice device) {
267 if (DBG) log("connect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800268 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700269 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800270 try {
Jack He16eeac32017-08-17 12:11:18 -0700271 return service.connect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800272 } catch (RemoteException e) {
273 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
274 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700275 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700276 }
Jack He16eeac32017-08-17 12:11:18 -0700277 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700278 return false;
279 }
280
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800281 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700282 * Initiate disconnection from a profile
283 *
284 * <p> This API will return false in scenarios like the profile on the
285 * Bluetooth device is not in connected state etc. When this API returns,
286 * true, it is guaranteed that the connection state change
287 * intent will be broadcasted with the state. Users can get the
288 * disconnection state of the profile from this intent.
289 *
290 * <p> If the disconnection is initiated by a remote device, the state
291 * will transition from {@link #STATE_CONNECTED} to
292 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
293 * host (local) device the state will transition from
294 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
295 * state {@link #STATE_DISCONNECTED}. The transition to
296 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
297 * two scenarios.
298 *
299 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
300 * permission.
301 *
302 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700303 * @return false on immediate error, true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700304 * @hide
305 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800306 public boolean disconnect(BluetoothDevice device) {
307 if (DBG) log("disconnect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800308 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700309 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800310 try {
Jack He16eeac32017-08-17 12:11:18 -0700311 return service.disconnect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800312 } catch (RemoteException e) {
313 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
314 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700315 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700316 }
Jack He16eeac32017-08-17 12:11:18 -0700317 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800318 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700319 }
320
321 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800322 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700323 */
Jack He2992cd02017-08-22 21:21:23 -0700324 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800325 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700326 if (VDBG) log("getConnectedDevices()");
Ugo Yud0115462019-03-26 21:38:08 +0800327 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700328 if (service != null && isEnabled()) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800329 try {
Jack He16eeac32017-08-17 12:11:18 -0700330 return service.getConnectedDevices();
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800331 } catch (RemoteException e) {
332 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
333 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700334 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700335 }
Jack He16eeac32017-08-17 12:11:18 -0700336 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800337 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700338 }
339
340 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800341 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700342 */
Jack He2992cd02017-08-22 21:21:23 -0700343 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800344 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700345 if (VDBG) log("getDevicesMatchingStates()");
Ugo Yud0115462019-03-26 21:38:08 +0800346 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700347 if (service != null && isEnabled()) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800348 try {
Jack He16eeac32017-08-17 12:11:18 -0700349 return service.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800350 } catch (RemoteException e) {
351 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
352 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700353 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700354 }
Jack He16eeac32017-08-17 12:11:18 -0700355 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800356 return new ArrayList<BluetoothDevice>();
357 }
358
359 /**
360 * {@inheritDoc}
361 */
Jack He2992cd02017-08-22 21:21:23 -0700362 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800363 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700364 if (VDBG) log("getState(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800365 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700366 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800367 try {
Jack He16eeac32017-08-17 12:11:18 -0700368 return service.getConnectionState(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800369 } catch (RemoteException e) {
370 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
371 return BluetoothProfile.STATE_DISCONNECTED;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700372 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800373 }
Jack He16eeac32017-08-17 12:11:18 -0700374 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800375 return BluetoothProfile.STATE_DISCONNECTED;
376 }
377
378 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700379 * Set priority of the profile
380 *
381 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700382 * Priority can be one of {@link #PRIORITY_ON} or
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700383 * {@link #PRIORITY_OFF},
384 *
385 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
386 * permission.
387 *
388 * @param device Paired bluetooth device
389 * @param priority
390 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800391 * @hide
392 */
393 public boolean setPriority(BluetoothDevice device, int priority) {
394 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800395 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700396 if (service != null && isEnabled() && isValidDevice(device)) {
Jack He2992cd02017-08-22 21:21:23 -0700397 if (priority != BluetoothProfile.PRIORITY_OFF
398 && priority != BluetoothProfile.PRIORITY_ON) {
Jack Hea355e5e2017-08-22 16:06:54 -0700399 return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800400 }
401 try {
Jack He16eeac32017-08-17 12:11:18 -0700402 return service.setPriority(device, priority);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800403 } catch (RemoteException e) {
404 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
405 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700406 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800407 }
Jack He16eeac32017-08-17 12:11:18 -0700408 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800409 return false;
410 }
411
412 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700413 * Get the priority of the profile.
414 *
415 * <p> The priority can be any of:
416 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
417 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
418 *
419 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
420 *
421 * @param device Bluetooth device
422 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800423 * @hide
424 */
425 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700426 if (VDBG) log("getPriority(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800427 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700428 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800429 try {
Jack He16eeac32017-08-17 12:11:18 -0700430 return service.getPriority(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800431 } catch (RemoteException e) {
432 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
433 return BluetoothProfile.PRIORITY_OFF;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700434 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800435 }
Jack He16eeac32017-08-17 12:11:18 -0700436 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800437 return BluetoothProfile.PRIORITY_OFF;
438 }
439
440 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700441 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800442 }
443
Jack He16eeac32017-08-17 12:11:18 -0700444 private static boolean isValidDevice(BluetoothDevice device) {
445 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700446 }
447
Priti Aghera349e62f2012-04-09 12:13:17 -0700448 /**
449 * Initiate virtual unplug for a HID input device.
450 *
451 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
452 *
453 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700454 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700455 * @hide
456 */
457 public boolean virtualUnplug(BluetoothDevice device) {
458 if (DBG) log("virtualUnplug(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800459 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700460 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700461 try {
Jack He16eeac32017-08-17 12:11:18 -0700462 return service.virtualUnplug(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700463 } catch (RemoteException e) {
464 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
465 return false;
466 }
467 }
468
Jack He16eeac32017-08-17 12:11:18 -0700469 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700470 return false;
471
472 }
473
474 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700475 * Send Get_Protocol_Mode command to the connected HID input device.
476 *
477 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
478 *
479 * @param device Remote Bluetooth Device
480 * @return false on immediate error, true otherwise
481 * @hide
482 */
Priti Aghera349e62f2012-04-09 12:13:17 -0700483 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700484 if (VDBG) log("getProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800485 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700486 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700487 try {
Jack He16eeac32017-08-17 12:11:18 -0700488 return service.getProtocolMode(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700489 } catch (RemoteException e) {
490 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
491 return false;
492 }
493 }
Jack He16eeac32017-08-17 12:11:18 -0700494 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700495 return false;
Priti Aghera349e62f2012-04-09 12:13:17 -0700496 }
497
498 /**
499 * Send Set_Protocol_Mode command to the connected HID input device.
500 *
501 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
502 *
503 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700504 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700505 * @hide
506 */
507 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
508 if (DBG) log("setProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800509 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700510 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700511 try {
Jack He16eeac32017-08-17 12:11:18 -0700512 return service.setProtocolMode(device, protocolMode);
Priti Aghera349e62f2012-04-09 12:13:17 -0700513 } catch (RemoteException e) {
514 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
515 return false;
516 }
517 }
Jack He16eeac32017-08-17 12:11:18 -0700518 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700519 return false;
520 }
521
522 /**
523 * Send Get_Report command to the connected HID input device.
524 *
525 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
526 *
527 * @param device Remote Bluetooth Device
528 * @param reportType Report type
529 * @param reportId Report ID
530 * @param bufferSize Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700531 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700532 * @hide
533 */
Jack Hea355e5e2017-08-22 16:06:54 -0700534 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
535 int bufferSize) {
536 if (VDBG) {
Jack He16eeac32017-08-17 12:11:18 -0700537 log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
538 + "bufferSize=" + bufferSize);
Jack Hea355e5e2017-08-22 16:06:54 -0700539 }
Ugo Yud0115462019-03-26 21:38:08 +0800540 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700541 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700542 try {
Jack He16eeac32017-08-17 12:11:18 -0700543 return service.getReport(device, reportType, reportId, bufferSize);
Priti Aghera349e62f2012-04-09 12:13:17 -0700544 } catch (RemoteException e) {
545 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
546 return false;
547 }
548 }
Jack He16eeac32017-08-17 12:11:18 -0700549 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700550 return false;
551 }
552
553 /**
554 * Send Set_Report command to the connected HID input device.
555 *
556 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
557 *
558 * @param device Remote Bluetooth Device
559 * @param reportType Report type
560 * @param report Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700561 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700562 * @hide
563 */
564 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800565 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800566 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700567 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700568 try {
Jack He16eeac32017-08-17 12:11:18 -0700569 return service.setReport(device, reportType, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700570 } catch (RemoteException e) {
571 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
572 return false;
573 }
574 }
Jack He16eeac32017-08-17 12:11:18 -0700575 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700576 return false;
577 }
578
579 /**
580 * Send Send_Data command to the connected HID input device.
581 *
582 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
583 *
584 * @param device Remote Bluetooth Device
Ang Li707fd392014-06-25 13:16:01 -0700585 * @param report Report to send
Jack Hea355e5e2017-08-22 16:06:54 -0700586 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700587 * @hide
588 */
589 public boolean sendData(BluetoothDevice device, String report) {
590 if (DBG) log("sendData(" + device + "), report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800591 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700592 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700593 try {
Jack He16eeac32017-08-17 12:11:18 -0700594 return service.sendData(device, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700595 } catch (RemoteException e) {
596 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
597 return false;
598 }
599 }
Jack He16eeac32017-08-17 12:11:18 -0700600 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700601 return false;
602 }
Hemant Guptacef9ce32013-07-30 16:09:20 +0530603
604 /**
605 * Send Get_Idle_Time command to the connected HID input device.
606 *
607 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
608 *
609 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700610 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530611 * @hide
612 */
613 public boolean getIdleTime(BluetoothDevice device) {
614 if (DBG) log("getIdletime(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800615 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700616 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530617 try {
Jack He16eeac32017-08-17 12:11:18 -0700618 return service.getIdleTime(device);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530619 } catch (RemoteException e) {
620 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
621 return false;
622 }
623 }
Jack He16eeac32017-08-17 12:11:18 -0700624 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530625 return false;
626 }
627
628 /**
629 * Send Set_Idle_Time command to the connected HID input device.
630 *
631 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
632 *
633 * @param device Remote Bluetooth Device
634 * @param idleTime Idle time to be set on HID Device
Jack Hea355e5e2017-08-22 16:06:54 -0700635 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530636 * @hide
637 */
638 public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
639 if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
Ugo Yud0115462019-03-26 21:38:08 +0800640 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700641 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530642 try {
Jack He16eeac32017-08-17 12:11:18 -0700643 return service.setIdleTime(device, idleTime);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530644 } catch (RemoteException e) {
645 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
646 return false;
647 }
648 }
Jack He16eeac32017-08-17 12:11:18 -0700649 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530650 return false;
651 }
652
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700653 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700654 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700655 }
656}