blob: 8f5cdf01f572c1ec2f96f313afb570c8dab9847f [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
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -080019import android.Manifest;
20import android.annotation.RequiresPermission;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070021import android.annotation.SdkConstant;
22import android.annotation.SdkConstant.SdkConstantType;
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -080023import android.annotation.SystemApi;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070024import android.content.Context;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060025import android.os.Binder;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070026import android.os.IBinder;
27import android.os.RemoteException;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070028import android.util.Log;
29
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070030import java.util.ArrayList;
31import java.util.List;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070032
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080033
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070034/**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080035 * This class provides the public APIs to control the Bluetooth Input
36 * Device Profile.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070037 *
Hansong Zhangc26c76c2017-10-20 15:55:59 -070038 * <p>BluetoothHidHost is a proxy object for controlling the Bluetooth
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080039 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
Hansong Zhangc26c76c2017-10-20 15:55:59 -070040 * the BluetoothHidHost proxy object.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070041 *
Jack Hea355e5e2017-08-22 16:06:54 -070042 * <p>Each method is protected with its appropriate permission.
43 *
44 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070045 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -070046public final class BluetoothHidHost implements BluetoothProfile {
47 private static final String TAG = "BluetoothHidHost";
fredc0f420372012-04-12 00:02:00 -070048 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070049 private static final boolean VDBG = false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070050
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080051 /**
52 * Intent used to broadcast the change in connection state of the Input
53 * Device profile.
54 *
55 * <p>This intent will have 3 extras:
56 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070057 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
58 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
59 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080060 * </ul>
61 *
62 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
63 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
64 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
65 *
66 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
67 * receive.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070068 */
69 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080070 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070071 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070072
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080073 /**
Priti Aghera349e62f2012-04-09 12:13:17 -070074 * @hide
75 */
76 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
77 public static final String ACTION_PROTOCOL_MODE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070078 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -070079
Mike J. Chend96d5cf2014-01-27 17:55:40 -080080 /**
81 * @hide
82 */
83 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chen8faffa42014-03-04 17:27:16 -080084 public static final String ACTION_HANDSHAKE =
Jack Hea355e5e2017-08-22 16:06:54 -070085 "android.bluetooth.input.profile.action.HANDSHAKE";
Mike J. Chen8faffa42014-03-04 17:27:16 -080086
87 /**
88 * @hide
89 */
90 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chend96d5cf2014-01-27 17:55:40 -080091 public static final String ACTION_REPORT =
Jack Hea355e5e2017-08-22 16:06:54 -070092 "android.bluetooth.input.profile.action.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -070093
94 /**
95 * @hide
96 */
97 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
98 public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
Jack Hea355e5e2017-08-22 16:06:54 -070099 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700100
Hemant Guptacef9ce32013-07-30 16:09:20 +0530101 /**
102 * @hide
103 */
104 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
105 public static final String ACTION_IDLE_TIME_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700106 "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -0700107
108 /**
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800109 * Return codes for the connect and disconnect Bluez / Dbus calls.
Jack Hea355e5e2017-08-22 16:06:54 -0700110 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800111 * @hide
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800112 */
113 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
114
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800115 /**
116 * @hide
117 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800118 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
119
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800120 /**
121 * @hide
122 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800123 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
124
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800125 /**
126 * @hide
127 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800128 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
129
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800130 /**
131 * @hide
132 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800133 public static final int INPUT_OPERATION_SUCCESS = 5004;
134
Priti Aghera349e62f2012-04-09 12:13:17 -0700135 /**
136 * @hide
137 */
138 public static final int PROTOCOL_REPORT_MODE = 0;
139
140 /**
141 * @hide
142 */
143 public static final int PROTOCOL_BOOT_MODE = 1;
144
145 /**
146 * @hide
147 */
148 public static final int PROTOCOL_UNSUPPORTED_MODE = 255;
149
150 /* int reportType, int reportType, int bufferSize */
151 /**
152 * @hide
153 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800154 public static final byte REPORT_TYPE_INPUT = 1;
Priti Aghera349e62f2012-04-09 12:13:17 -0700155
156 /**
157 * @hide
158 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800159 public static final byte REPORT_TYPE_OUTPUT = 2;
Priti Aghera349e62f2012-04-09 12:13:17 -0700160
161 /**
162 * @hide
163 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800164 public static final byte REPORT_TYPE_FEATURE = 3;
Priti Aghera349e62f2012-04-09 12:13:17 -0700165
166 /**
167 * @hide
168 */
169 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;
170
171 /**
172 * @hide
173 */
174 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;
175
176 /**
177 * @hide
178 */
Jack Hea355e5e2017-08-22 16:06:54 -0700179 public static final String EXTRA_PROTOCOL_MODE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700180 "android.bluetooth.BluetoothHidHost.extra.PROTOCOL_MODE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700181
182 /**
183 * @hide
184 */
Jack Hea355e5e2017-08-22 16:06:54 -0700185 public static final String EXTRA_REPORT_TYPE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700186 "android.bluetooth.BluetoothHidHost.extra.REPORT_TYPE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700187
188 /**
189 * @hide
190 */
Jack Hea355e5e2017-08-22 16:06:54 -0700191 public static final String EXTRA_REPORT_ID =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700192 "android.bluetooth.BluetoothHidHost.extra.REPORT_ID";
Priti Aghera349e62f2012-04-09 12:13:17 -0700193
194 /**
195 * @hide
196 */
Jack Hea355e5e2017-08-22 16:06:54 -0700197 public static final String EXTRA_REPORT_BUFFER_SIZE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700198 "android.bluetooth.BluetoothHidHost.extra.REPORT_BUFFER_SIZE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700199
200 /**
201 * @hide
202 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700203 public static final String EXTRA_REPORT = "android.bluetooth.BluetoothHidHost.extra.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -0700204
205 /**
206 * @hide
207 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700208 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothHidHost.extra.STATUS";
Mike J. Chen8faffa42014-03-04 17:27:16 -0800209
210 /**
211 * @hide
212 */
Jack Hea355e5e2017-08-22 16:06:54 -0700213 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700214 "android.bluetooth.BluetoothHidHost.extra.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700215
Hemant Guptacef9ce32013-07-30 16:09:20 +0530216 /**
217 * @hide
218 */
Jack Hea355e5e2017-08-22 16:06:54 -0700219 public static final String EXTRA_IDLE_TIME =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700220 "android.bluetooth.BluetoothHidHost.extra.IDLE_TIME";
Hemant Guptacef9ce32013-07-30 16:09:20 +0530221
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800222 private BluetoothAdapter mAdapter;
Ugo Yud0115462019-03-26 21:38:08 +0800223 private final BluetoothProfileConnector<IBluetoothHidHost> mProfileConnector =
224 new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST,
225 "BluetoothHidHost", IBluetoothHidHost.class.getName()) {
226 @Override
227 public IBluetoothHidHost getServiceInterface(IBinder service) {
228 return IBluetoothHidHost.Stub.asInterface(Binder.allowBlocking(service));
fredc0f420372012-04-12 00:02:00 -0700229 }
Ugo Yud0115462019-03-26 21:38:08 +0800230 };
fredc0f420372012-04-12 00:02:00 -0700231
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700232 /**
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700233 * Create a BluetoothHidHost proxy object for interacting with the local
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800234 * Bluetooth Service which handles the InputDevice profile
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700235 */
Ugo Yud0115462019-03-26 21:38:08 +0800236 /*package*/ BluetoothHidHost(Context context, ServiceListener listener) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800237 mAdapter = BluetoothAdapter.getDefaultAdapter();
Ugo Yud0115462019-03-26 21:38:08 +0800238 mProfileConnector.connect(context, listener);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700239 }
240
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800241 /*package*/ void close() {
Matthew Xie563e4142012-10-09 22:10:37 -0700242 if (VDBG) log("close()");
Ugo Yud0115462019-03-26 21:38:08 +0800243 mProfileConnector.disconnect();
244 }
fredc0f420372012-04-12 00:02:00 -0700245
Ugo Yud0115462019-03-26 21:38:08 +0800246 private IBluetoothHidHost getService() {
247 return mProfileConnector.getService();
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800248 }
249
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800250 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700251 * Initiate connection to a profile of the remote bluetooth device.
252 *
253 * <p> The system supports connection to multiple input devices.
254 *
255 * <p> This API returns false in scenarios like the profile on the
256 * device is already connected or Bluetooth is not turned on.
257 * When this API returns true, it is guaranteed that
258 * connection state intent for the profile will be broadcasted with
259 * the state. Users can get the connection state of the profile
260 * from this intent.
261 *
262 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
263 * permission.
264 *
265 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700266 * @return false on immediate error, true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800267 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700268 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800269 public boolean connect(BluetoothDevice device) {
270 if (DBG) log("connect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800271 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700272 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800273 try {
Jack He16eeac32017-08-17 12:11:18 -0700274 return service.connect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800275 } catch (RemoteException e) {
276 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
277 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700278 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700279 }
Jack He16eeac32017-08-17 12:11:18 -0700280 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700281 return false;
282 }
283
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800284 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700285 * Initiate disconnection from a profile
286 *
287 * <p> This API will return false in scenarios like the profile on the
288 * Bluetooth device is not in connected state etc. When this API returns,
289 * true, it is guaranteed that the connection state change
290 * intent will be broadcasted with the state. Users can get the
291 * disconnection state of the profile from this intent.
292 *
293 * <p> If the disconnection is initiated by a remote device, the state
294 * will transition from {@link #STATE_CONNECTED} to
295 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
296 * host (local) device the state will transition from
297 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
298 * state {@link #STATE_DISCONNECTED}. The transition to
299 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
300 * two scenarios.
301 *
302 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
303 * permission.
304 *
305 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700306 * @return false on immediate error, true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700307 * @hide
308 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800309 public boolean disconnect(BluetoothDevice device) {
310 if (DBG) log("disconnect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800311 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700312 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800313 try {
Jack He16eeac32017-08-17 12:11:18 -0700314 return service.disconnect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800315 } catch (RemoteException e) {
316 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
317 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700318 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700319 }
Jack He16eeac32017-08-17 12:11:18 -0700320 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800321 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700322 }
323
324 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800325 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700326 */
Jack He2992cd02017-08-22 21:21:23 -0700327 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800328 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700329 if (VDBG) log("getConnectedDevices()");
Ugo Yud0115462019-03-26 21:38:08 +0800330 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700331 if (service != null && isEnabled()) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800332 try {
Jack He16eeac32017-08-17 12:11:18 -0700333 return service.getConnectedDevices();
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800334 } catch (RemoteException e) {
335 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
336 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700337 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700338 }
Jack He16eeac32017-08-17 12:11:18 -0700339 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800340 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700341 }
342
343 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800344 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700345 */
Jack He2992cd02017-08-22 21:21:23 -0700346 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800347 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700348 if (VDBG) log("getDevicesMatchingStates()");
Ugo Yud0115462019-03-26 21:38:08 +0800349 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700350 if (service != null && isEnabled()) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800351 try {
Jack He16eeac32017-08-17 12:11:18 -0700352 return service.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800353 } catch (RemoteException e) {
354 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
355 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700356 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700357 }
Jack He16eeac32017-08-17 12:11:18 -0700358 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800359 return new ArrayList<BluetoothDevice>();
360 }
361
362 /**
363 * {@inheritDoc}
364 */
Jack He2992cd02017-08-22 21:21:23 -0700365 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800366 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700367 if (VDBG) log("getState(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800368 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700369 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800370 try {
Jack He16eeac32017-08-17 12:11:18 -0700371 return service.getConnectionState(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800372 } catch (RemoteException e) {
373 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
374 return BluetoothProfile.STATE_DISCONNECTED;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700375 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800376 }
Jack He16eeac32017-08-17 12:11:18 -0700377 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800378 return BluetoothProfile.STATE_DISCONNECTED;
379 }
380
381 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700382 * Set priority of the profile
383 *
384 * <p> The device should already be paired.
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800385 * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700386 *
387 * @param device Paired bluetooth device
388 * @param priority
389 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800390 * @hide
391 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800392 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800393 public boolean setPriority(BluetoothDevice device, int priority) {
394 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800395 return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
396 }
397
398 /**
399 * Set connection policy of the profile
400 *
401 * <p> The device should already be paired.
402 * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
403 * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
404 *
405 * @param device Paired bluetooth device
406 * @param connectionPolicy is the connection policy to set to for this profile
407 * @return true if connectionPolicy is set, false on error
408 * @hide
409 */
410 @SystemApi
411 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
412 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
413 if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800414 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700415 if (service != null && isEnabled() && isValidDevice(device)) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800416 if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
417 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
Jack Hea355e5e2017-08-22 16:06:54 -0700418 return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800419 }
420 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800421 return service.setConnectionPolicy(device, connectionPolicy);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800422 } catch (RemoteException e) {
423 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
424 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700425 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800426 }
Jack He16eeac32017-08-17 12:11:18 -0700427 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800428 return false;
429 }
430
431 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700432 * Get the priority of the profile.
433 *
434 * <p> The priority can be any of:
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800435 * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700436 *
437 * @param device Bluetooth device
438 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800439 * @hide
440 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800441 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800442 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700443 if (VDBG) log("getPriority(" + device + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800444 return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
445 }
446
447 /**
448 * Get the connection policy of the profile.
449 *
450 * <p> The connection policy can be any of:
451 * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
452 * {@link #CONNECTION_POLICY_UNKNOWN}
453 *
454 * @param device Bluetooth device
455 * @return connection policy of the device
456 * @hide
457 */
458 @SystemApi
459 @RequiresPermission(Manifest.permission.BLUETOOTH)
460 public int getConnectionPolicy(BluetoothDevice device) {
461 if (VDBG) log("getConnectionPolicy(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800462 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700463 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800464 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800465 return service.getConnectionPolicy(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800466 } catch (RemoteException e) {
467 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800468 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700469 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800470 }
Jack He16eeac32017-08-17 12:11:18 -0700471 if (service == null) Log.w(TAG, "Proxy not attached to service");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800472 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800473 }
474
475 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700476 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800477 }
478
Jack He16eeac32017-08-17 12:11:18 -0700479 private static boolean isValidDevice(BluetoothDevice device) {
480 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700481 }
482
Priti Aghera349e62f2012-04-09 12:13:17 -0700483 /**
484 * Initiate virtual unplug for a HID input device.
485 *
486 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
487 *
488 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700489 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700490 * @hide
491 */
492 public boolean virtualUnplug(BluetoothDevice device) {
493 if (DBG) log("virtualUnplug(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800494 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700495 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700496 try {
Jack He16eeac32017-08-17 12:11:18 -0700497 return service.virtualUnplug(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700498 } catch (RemoteException e) {
499 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
500 return false;
501 }
502 }
503
Jack He16eeac32017-08-17 12:11:18 -0700504 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700505 return false;
506
507 }
508
509 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700510 * Send Get_Protocol_Mode command to the connected HID input device.
511 *
512 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
513 *
514 * @param device Remote Bluetooth Device
515 * @return false on immediate error, true otherwise
516 * @hide
517 */
Priti Aghera349e62f2012-04-09 12:13:17 -0700518 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700519 if (VDBG) log("getProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800520 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700521 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700522 try {
Jack He16eeac32017-08-17 12:11:18 -0700523 return service.getProtocolMode(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700524 } catch (RemoteException e) {
525 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
526 return false;
527 }
528 }
Jack He16eeac32017-08-17 12:11:18 -0700529 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700530 return false;
Priti Aghera349e62f2012-04-09 12:13:17 -0700531 }
532
533 /**
534 * Send Set_Protocol_Mode command to the connected HID input device.
535 *
536 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
537 *
538 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700539 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700540 * @hide
541 */
542 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
543 if (DBG) log("setProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800544 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700545 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700546 try {
Jack He16eeac32017-08-17 12:11:18 -0700547 return service.setProtocolMode(device, protocolMode);
Priti Aghera349e62f2012-04-09 12:13:17 -0700548 } catch (RemoteException e) {
549 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
550 return false;
551 }
552 }
Jack He16eeac32017-08-17 12:11:18 -0700553 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700554 return false;
555 }
556
557 /**
558 * Send Get_Report command to the connected HID input device.
559 *
560 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
561 *
562 * @param device Remote Bluetooth Device
563 * @param reportType Report type
564 * @param reportId Report ID
565 * @param bufferSize Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700566 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700567 * @hide
568 */
Jack Hea355e5e2017-08-22 16:06:54 -0700569 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
570 int bufferSize) {
571 if (VDBG) {
Jack He16eeac32017-08-17 12:11:18 -0700572 log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
573 + "bufferSize=" + bufferSize);
Jack Hea355e5e2017-08-22 16:06:54 -0700574 }
Ugo Yud0115462019-03-26 21:38:08 +0800575 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700576 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700577 try {
Jack He16eeac32017-08-17 12:11:18 -0700578 return service.getReport(device, reportType, reportId, bufferSize);
Priti Aghera349e62f2012-04-09 12:13:17 -0700579 } catch (RemoteException e) {
580 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
581 return false;
582 }
583 }
Jack He16eeac32017-08-17 12:11:18 -0700584 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700585 return false;
586 }
587
588 /**
589 * Send Set_Report command to the connected HID input device.
590 *
591 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
592 *
593 * @param device Remote Bluetooth Device
594 * @param reportType Report type
595 * @param report Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700596 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700597 * @hide
598 */
599 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800600 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800601 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700602 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700603 try {
Jack He16eeac32017-08-17 12:11:18 -0700604 return service.setReport(device, reportType, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700605 } catch (RemoteException e) {
606 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
607 return false;
608 }
609 }
Jack He16eeac32017-08-17 12:11:18 -0700610 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700611 return false;
612 }
613
614 /**
615 * Send Send_Data command to the connected HID input device.
616 *
617 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
618 *
619 * @param device Remote Bluetooth Device
Ang Li707fd392014-06-25 13:16:01 -0700620 * @param report Report to send
Jack Hea355e5e2017-08-22 16:06:54 -0700621 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700622 * @hide
623 */
624 public boolean sendData(BluetoothDevice device, String report) {
625 if (DBG) log("sendData(" + device + "), report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800626 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700627 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700628 try {
Jack He16eeac32017-08-17 12:11:18 -0700629 return service.sendData(device, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700630 } catch (RemoteException e) {
631 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
632 return false;
633 }
634 }
Jack He16eeac32017-08-17 12:11:18 -0700635 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700636 return false;
637 }
Hemant Guptacef9ce32013-07-30 16:09:20 +0530638
639 /**
640 * Send Get_Idle_Time command to the connected HID input device.
641 *
642 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
643 *
644 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700645 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530646 * @hide
647 */
648 public boolean getIdleTime(BluetoothDevice device) {
649 if (DBG) log("getIdletime(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800650 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700651 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530652 try {
Jack He16eeac32017-08-17 12:11:18 -0700653 return service.getIdleTime(device);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530654 } catch (RemoteException e) {
655 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
656 return false;
657 }
658 }
Jack He16eeac32017-08-17 12:11:18 -0700659 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530660 return false;
661 }
662
663 /**
664 * Send Set_Idle_Time command to the connected HID input device.
665 *
666 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
667 *
668 * @param device Remote Bluetooth Device
669 * @param idleTime Idle time to be set on HID Device
Jack Hea355e5e2017-08-22 16:06:54 -0700670 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530671 * @hide
672 */
673 public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
674 if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
Ugo Yud0115462019-03-26 21:38:08 +0800675 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700676 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530677 try {
Jack He16eeac32017-08-17 12:11:18 -0700678 return service.setIdleTime(device, idleTime);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530679 } catch (RemoteException e) {
680 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
681 return false;
682 }
683 }
Jack He16eeac32017-08-17 12:11:18 -0700684 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530685 return false;
686 }
687
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700688 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700689 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700690 }
691}