blob: 9561d9383846787b42a6c9f842aa95de9a6993eb [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;
Rahul Sabnis9913cb52020-01-07 17:02:22 -080020import android.annotation.NonNull;
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -080021import android.annotation.RequiresPermission;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070022import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
Rahul Sabnis9913cb52020-01-07 17:02:22 -080024import android.annotation.SuppressLint;
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -080025import android.annotation.SystemApi;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070026import android.content.Context;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060027import android.os.Binder;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070028import android.os.IBinder;
29import android.os.RemoteException;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070030import android.util.Log;
31
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070032import java.util.ArrayList;
33import java.util.List;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070034
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080035
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070036/**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080037 * This class provides the public APIs to control the Bluetooth Input
38 * Device Profile.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070039 *
Hansong Zhangc26c76c2017-10-20 15:55:59 -070040 * <p>BluetoothHidHost is a proxy object for controlling the Bluetooth
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080041 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
Hansong Zhangc26c76c2017-10-20 15:55:59 -070042 * the BluetoothHidHost proxy object.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070043 *
Jack Hea355e5e2017-08-22 16:06:54 -070044 * <p>Each method is protected with its appropriate permission.
45 *
46 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070047 */
Rahul Sabnis9913cb52020-01-07 17:02:22 -080048@SystemApi
Hansong Zhangc26c76c2017-10-20 15:55:59 -070049public final class BluetoothHidHost implements BluetoothProfile {
50 private static final String TAG = "BluetoothHidHost";
fredc0f420372012-04-12 00:02:00 -070051 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070052 private static final boolean VDBG = false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070053
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080054 /**
55 * Intent used to broadcast the change in connection state of the Input
56 * Device profile.
57 *
58 * <p>This intent will have 3 extras:
59 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070060 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
61 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
62 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080063 * </ul>
64 *
65 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
66 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
67 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
68 *
69 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
70 * receive.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070071 */
Rahul Sabnis9913cb52020-01-07 17:02:22 -080072 @SuppressLint("ActionValue")
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070073 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080074 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070075 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070076
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080077 /**
Priti Aghera349e62f2012-04-09 12:13:17 -070078 * @hide
79 */
80 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
81 public static final String ACTION_PROTOCOL_MODE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070082 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -070083
Mike J. Chend96d5cf2014-01-27 17:55:40 -080084 /**
85 * @hide
86 */
87 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chen8faffa42014-03-04 17:27:16 -080088 public static final String ACTION_HANDSHAKE =
Jack Hea355e5e2017-08-22 16:06:54 -070089 "android.bluetooth.input.profile.action.HANDSHAKE";
Mike J. Chen8faffa42014-03-04 17:27:16 -080090
91 /**
92 * @hide
93 */
94 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chend96d5cf2014-01-27 17:55:40 -080095 public static final String ACTION_REPORT =
Jack Hea355e5e2017-08-22 16:06:54 -070096 "android.bluetooth.input.profile.action.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -070097
98 /**
99 * @hide
100 */
101 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
102 public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
Jack Hea355e5e2017-08-22 16:06:54 -0700103 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700104
Hemant Guptacef9ce32013-07-30 16:09:20 +0530105 /**
106 * @hide
107 */
108 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
109 public static final String ACTION_IDLE_TIME_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700110 "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -0700111
112 /**
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800113 * Return codes for the connect and disconnect Bluez / Dbus calls.
Jack Hea355e5e2017-08-22 16:06:54 -0700114 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800115 * @hide
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800116 */
117 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
118
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800119 /**
120 * @hide
121 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800122 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
123
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800124 /**
125 * @hide
126 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800127 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
128
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800129 /**
130 * @hide
131 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800132 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
133
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800134 /**
135 * @hide
136 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800137 public static final int INPUT_OPERATION_SUCCESS = 5004;
138
Priti Aghera349e62f2012-04-09 12:13:17 -0700139 /**
140 * @hide
141 */
142 public static final int PROTOCOL_REPORT_MODE = 0;
143
144 /**
145 * @hide
146 */
147 public static final int PROTOCOL_BOOT_MODE = 1;
148
149 /**
150 * @hide
151 */
152 public static final int PROTOCOL_UNSUPPORTED_MODE = 255;
153
154 /* int reportType, int reportType, int bufferSize */
155 /**
156 * @hide
157 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800158 public static final byte REPORT_TYPE_INPUT = 1;
Priti Aghera349e62f2012-04-09 12:13:17 -0700159
160 /**
161 * @hide
162 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800163 public static final byte REPORT_TYPE_OUTPUT = 2;
Priti Aghera349e62f2012-04-09 12:13:17 -0700164
165 /**
166 * @hide
167 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800168 public static final byte REPORT_TYPE_FEATURE = 3;
Priti Aghera349e62f2012-04-09 12:13:17 -0700169
170 /**
171 * @hide
172 */
173 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;
174
175 /**
176 * @hide
177 */
178 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;
179
180 /**
181 * @hide
182 */
Jack Hea355e5e2017-08-22 16:06:54 -0700183 public static final String EXTRA_PROTOCOL_MODE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700184 "android.bluetooth.BluetoothHidHost.extra.PROTOCOL_MODE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700185
186 /**
187 * @hide
188 */
Jack Hea355e5e2017-08-22 16:06:54 -0700189 public static final String EXTRA_REPORT_TYPE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700190 "android.bluetooth.BluetoothHidHost.extra.REPORT_TYPE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700191
192 /**
193 * @hide
194 */
Jack Hea355e5e2017-08-22 16:06:54 -0700195 public static final String EXTRA_REPORT_ID =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700196 "android.bluetooth.BluetoothHidHost.extra.REPORT_ID";
Priti Aghera349e62f2012-04-09 12:13:17 -0700197
198 /**
199 * @hide
200 */
Jack Hea355e5e2017-08-22 16:06:54 -0700201 public static final String EXTRA_REPORT_BUFFER_SIZE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700202 "android.bluetooth.BluetoothHidHost.extra.REPORT_BUFFER_SIZE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700203
204 /**
205 * @hide
206 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700207 public static final String EXTRA_REPORT = "android.bluetooth.BluetoothHidHost.extra.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -0700208
209 /**
210 * @hide
211 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700212 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothHidHost.extra.STATUS";
Mike J. Chen8faffa42014-03-04 17:27:16 -0800213
214 /**
215 * @hide
216 */
Jack Hea355e5e2017-08-22 16:06:54 -0700217 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700218 "android.bluetooth.BluetoothHidHost.extra.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700219
Hemant Guptacef9ce32013-07-30 16:09:20 +0530220 /**
221 * @hide
222 */
Jack Hea355e5e2017-08-22 16:06:54 -0700223 public static final String EXTRA_IDLE_TIME =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700224 "android.bluetooth.BluetoothHidHost.extra.IDLE_TIME";
Hemant Guptacef9ce32013-07-30 16:09:20 +0530225
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800226 private BluetoothAdapter mAdapter;
Ugo Yud0115462019-03-26 21:38:08 +0800227 private final BluetoothProfileConnector<IBluetoothHidHost> mProfileConnector =
228 new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST,
229 "BluetoothHidHost", IBluetoothHidHost.class.getName()) {
230 @Override
231 public IBluetoothHidHost getServiceInterface(IBinder service) {
232 return IBluetoothHidHost.Stub.asInterface(Binder.allowBlocking(service));
fredc0f420372012-04-12 00:02:00 -0700233 }
Ugo Yud0115462019-03-26 21:38:08 +0800234 };
fredc0f420372012-04-12 00:02:00 -0700235
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700236 /**
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700237 * Create a BluetoothHidHost proxy object for interacting with the local
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800238 * Bluetooth Service which handles the InputDevice profile
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700239 */
Ugo Yud0115462019-03-26 21:38:08 +0800240 /*package*/ BluetoothHidHost(Context context, ServiceListener listener) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800241 mAdapter = BluetoothAdapter.getDefaultAdapter();
Ugo Yud0115462019-03-26 21:38:08 +0800242 mProfileConnector.connect(context, listener);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700243 }
244
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800245 /*package*/ void close() {
Matthew Xie563e4142012-10-09 22:10:37 -0700246 if (VDBG) log("close()");
Ugo Yud0115462019-03-26 21:38:08 +0800247 mProfileConnector.disconnect();
248 }
fredc0f420372012-04-12 00:02:00 -0700249
Ugo Yud0115462019-03-26 21:38:08 +0800250 private IBluetoothHidHost getService() {
251 return mProfileConnector.getService();
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800252 }
253
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800254 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700255 * Initiate connection to a profile of the remote bluetooth device.
256 *
257 * <p> The system supports connection to multiple input devices.
258 *
259 * <p> This API returns false in scenarios like the profile on the
260 * device is already connected or Bluetooth is not turned on.
261 * When this API returns true, it is guaranteed that
262 * connection state intent for the profile will be broadcasted with
263 * the state. Users can get the connection state of the profile
264 * from this intent.
265 *
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700266 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700267 * @return false on immediate error, true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800268 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700269 */
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700270 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800271 public boolean connect(BluetoothDevice device) {
272 if (DBG) log("connect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800273 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700274 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800275 try {
Jack He16eeac32017-08-17 12:11:18 -0700276 return service.connect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800277 } catch (RemoteException e) {
278 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
279 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700280 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700281 }
Jack He16eeac32017-08-17 12:11:18 -0700282 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700283 return false;
284 }
285
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800286 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700287 * Initiate disconnection from a profile
288 *
289 * <p> This API will return false in scenarios like the profile on the
290 * Bluetooth device is not in connected state etc. When this API returns,
291 * true, it is guaranteed that the connection state change
292 * intent will be broadcasted with the state. Users can get the
293 * disconnection state of the profile from this intent.
294 *
295 * <p> If the disconnection is initiated by a remote device, the state
296 * will transition from {@link #STATE_CONNECTED} to
297 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
298 * host (local) device the state will transition from
299 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
300 * state {@link #STATE_DISCONNECTED}. The transition to
301 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
302 * two scenarios.
303 *
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700304 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700305 * @return false on immediate error, true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700306 * @hide
307 */
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700308 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
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}
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700326 *
327 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700328 */
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700329 @SystemApi
Jack He2992cd02017-08-22 21:21:23 -0700330 @Override
Rahul Sabnis946bf882020-02-25 11:33:43 -0800331 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
Rahul Sabnis9913cb52020-01-07 17:02:22 -0800332 public @NonNull List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700333 if (VDBG) log("getConnectedDevices()");
Ugo Yud0115462019-03-26 21:38:08 +0800334 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700335 if (service != null && isEnabled()) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800336 try {
Jack He16eeac32017-08-17 12:11:18 -0700337 return service.getConnectedDevices();
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800338 } catch (RemoteException e) {
339 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
340 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700341 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700342 }
Jack He16eeac32017-08-17 12:11:18 -0700343 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800344 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700345 }
346
347 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800348 * {@inheritDoc}
Rahul Sabnis9913cb52020-01-07 17:02:22 -0800349 *
350 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700351 */
Jack He2992cd02017-08-22 21:21:23 -0700352 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800353 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700354 if (VDBG) log("getDevicesMatchingStates()");
Ugo Yud0115462019-03-26 21:38:08 +0800355 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700356 if (service != null && isEnabled()) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800357 try {
Jack He16eeac32017-08-17 12:11:18 -0700358 return service.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800359 } catch (RemoteException e) {
360 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
361 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700362 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700363 }
Jack He16eeac32017-08-17 12:11:18 -0700364 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800365 return new ArrayList<BluetoothDevice>();
366 }
367
368 /**
369 * {@inheritDoc}
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700370 *
371 * @hide
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800372 */
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700373 @SystemApi
Jack He2992cd02017-08-22 21:21:23 -0700374 @Override
Rahul Sabnis946bf882020-02-25 11:33:43 -0800375 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
376 public int getConnectionState(@NonNull BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700377 if (VDBG) log("getState(" + device + ")");
Rahul Sabnis946bf882020-02-25 11:33:43 -0800378 if (device == null) {
379 throw new IllegalArgumentException("device must not be null");
380 }
Ugo Yud0115462019-03-26 21:38:08 +0800381 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700382 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800383 try {
Jack He16eeac32017-08-17 12:11:18 -0700384 return service.getConnectionState(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800385 } catch (RemoteException e) {
386 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
387 return BluetoothProfile.STATE_DISCONNECTED;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700388 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800389 }
Jack He16eeac32017-08-17 12:11:18 -0700390 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800391 return BluetoothProfile.STATE_DISCONNECTED;
392 }
393
394 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700395 * Set priority of the profile
396 *
397 * <p> The device should already be paired.
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800398 * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700399 *
400 * @param device Paired bluetooth device
401 * @param priority
402 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800403 * @hide
404 */
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700405 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800406 public boolean setPriority(BluetoothDevice device, int priority) {
407 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800408 return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
409 }
410
411 /**
412 * Set connection policy of the profile
413 *
414 * <p> The device should already be paired.
415 * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
416 * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
417 *
418 * @param device Paired bluetooth device
419 * @param connectionPolicy is the connection policy to set to for this profile
420 * @return true if connectionPolicy is set, false on error
421 * @hide
422 */
423 @SystemApi
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700424 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
Rahul Sabnis946bf882020-02-25 11:33:43 -0800425 public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
Rahul Sabnis30c597f2020-01-22 14:26:35 -0800426 @ConnectionPolicy int connectionPolicy) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800427 if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
Rahul Sabnis946bf882020-02-25 11:33:43 -0800428 if (device == null) {
429 throw new IllegalArgumentException("device must not be null");
430 }
Ugo Yud0115462019-03-26 21:38:08 +0800431 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700432 if (service != null && isEnabled() && isValidDevice(device)) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800433 if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
434 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
Jack Hea355e5e2017-08-22 16:06:54 -0700435 return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800436 }
437 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800438 return service.setConnectionPolicy(device, connectionPolicy);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800439 } catch (RemoteException e) {
440 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
441 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700442 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800443 }
Jack He16eeac32017-08-17 12:11:18 -0700444 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800445 return false;
446 }
447
448 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700449 * Get the priority of the profile.
450 *
451 * <p> The priority can be any of:
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800452 * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700453 *
454 * @param device Bluetooth device
455 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800456 * @hide
457 */
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700458 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800459 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700460 if (VDBG) log("getPriority(" + device + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800461 return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
462 }
463
464 /**
465 * Get the connection policy of the profile.
466 *
467 * <p> The connection policy can be any of:
468 * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
469 * {@link #CONNECTION_POLICY_UNKNOWN}
470 *
471 * @param device Bluetooth device
472 * @return connection policy of the device
473 * @hide
474 */
475 @SystemApi
Rahul Sabnis2c71d162020-03-18 17:46:33 -0700476 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
Rahul Sabnis946bf882020-02-25 11:33:43 -0800477 public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800478 if (VDBG) log("getConnectionPolicy(" + device + ")");
Rahul Sabnis946bf882020-02-25 11:33:43 -0800479 if (device == null) {
480 throw new IllegalArgumentException("device must not be null");
481 }
Ugo Yud0115462019-03-26 21:38:08 +0800482 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700483 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800484 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800485 return service.getConnectionPolicy(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800486 } catch (RemoteException e) {
487 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800488 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700489 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800490 }
Jack He16eeac32017-08-17 12:11:18 -0700491 if (service == null) Log.w(TAG, "Proxy not attached to service");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800492 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800493 }
494
495 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700496 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800497 }
498
Jack He16eeac32017-08-17 12:11:18 -0700499 private static boolean isValidDevice(BluetoothDevice device) {
500 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700501 }
502
Priti Aghera349e62f2012-04-09 12:13:17 -0700503 /**
504 * Initiate virtual unplug for a HID input device.
505 *
506 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
507 *
508 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700509 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700510 * @hide
511 */
512 public boolean virtualUnplug(BluetoothDevice device) {
513 if (DBG) log("virtualUnplug(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800514 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700515 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700516 try {
Jack He16eeac32017-08-17 12:11:18 -0700517 return service.virtualUnplug(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700518 } catch (RemoteException e) {
519 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
520 return false;
521 }
522 }
523
Jack He16eeac32017-08-17 12:11:18 -0700524 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700525 return false;
526
527 }
528
529 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700530 * Send Get_Protocol_Mode command to the connected HID input device.
531 *
532 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
533 *
534 * @param device Remote Bluetooth Device
535 * @return false on immediate error, true otherwise
536 * @hide
537 */
Priti Aghera349e62f2012-04-09 12:13:17 -0700538 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700539 if (VDBG) log("getProtocolMode(" + device + ")");
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.getProtocolMode(device);
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");
Jack Hea355e5e2017-08-22 16:06:54 -0700550 return false;
Priti Aghera349e62f2012-04-09 12:13:17 -0700551 }
552
553 /**
554 * Send Set_Protocol_Mode 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
Jack Hea355e5e2017-08-22 16:06:54 -0700559 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700560 * @hide
561 */
562 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
563 if (DBG) log("setProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800564 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700565 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700566 try {
Jack He16eeac32017-08-17 12:11:18 -0700567 return service.setProtocolMode(device, protocolMode);
Priti Aghera349e62f2012-04-09 12:13:17 -0700568 } catch (RemoteException e) {
569 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
570 return false;
571 }
572 }
Jack He16eeac32017-08-17 12:11:18 -0700573 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700574 return false;
575 }
576
577 /**
578 * Send Get_Report command to the connected HID input device.
579 *
580 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
581 *
582 * @param device Remote Bluetooth Device
583 * @param reportType Report type
584 * @param reportId Report ID
585 * @param bufferSize Report receiving buffer size
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 */
Jack Hea355e5e2017-08-22 16:06:54 -0700589 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
590 int bufferSize) {
591 if (VDBG) {
Jack He16eeac32017-08-17 12:11:18 -0700592 log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
593 + "bufferSize=" + bufferSize);
Jack Hea355e5e2017-08-22 16:06:54 -0700594 }
Ugo Yud0115462019-03-26 21:38:08 +0800595 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700596 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700597 try {
Jack He16eeac32017-08-17 12:11:18 -0700598 return service.getReport(device, reportType, reportId, bufferSize);
Priti Aghera349e62f2012-04-09 12:13:17 -0700599 } catch (RemoteException e) {
600 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
601 return false;
602 }
603 }
Jack He16eeac32017-08-17 12:11:18 -0700604 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700605 return false;
606 }
607
608 /**
609 * Send Set_Report command to the connected HID input device.
610 *
611 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
612 *
613 * @param device Remote Bluetooth Device
614 * @param reportType Report type
615 * @param report Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700616 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700617 * @hide
618 */
619 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800620 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800621 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700622 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700623 try {
Jack He16eeac32017-08-17 12:11:18 -0700624 return service.setReport(device, reportType, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700625 } catch (RemoteException e) {
626 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
627 return false;
628 }
629 }
Jack He16eeac32017-08-17 12:11:18 -0700630 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700631 return false;
632 }
633
634 /**
635 * Send Send_Data command to the connected HID input device.
636 *
637 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
638 *
639 * @param device Remote Bluetooth Device
Ang Li707fd392014-06-25 13:16:01 -0700640 * @param report Report to send
Jack Hea355e5e2017-08-22 16:06:54 -0700641 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700642 * @hide
643 */
644 public boolean sendData(BluetoothDevice device, String report) {
645 if (DBG) log("sendData(" + device + "), report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800646 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700647 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700648 try {
Jack He16eeac32017-08-17 12:11:18 -0700649 return service.sendData(device, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700650 } catch (RemoteException e) {
651 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
652 return false;
653 }
654 }
Jack He16eeac32017-08-17 12:11:18 -0700655 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700656 return false;
657 }
Hemant Guptacef9ce32013-07-30 16:09:20 +0530658
659 /**
660 * Send Get_Idle_Time command to the connected HID input device.
661 *
662 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
663 *
664 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700665 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530666 * @hide
667 */
668 public boolean getIdleTime(BluetoothDevice device) {
669 if (DBG) log("getIdletime(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800670 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700671 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530672 try {
Jack He16eeac32017-08-17 12:11:18 -0700673 return service.getIdleTime(device);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530674 } catch (RemoteException e) {
675 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
676 return false;
677 }
678 }
Jack He16eeac32017-08-17 12:11:18 -0700679 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530680 return false;
681 }
682
683 /**
684 * Send Set_Idle_Time command to the connected HID input device.
685 *
686 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
687 *
688 * @param device Remote Bluetooth Device
689 * @param idleTime Idle time to be set on HID Device
Jack Hea355e5e2017-08-22 16:06:54 -0700690 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530691 * @hide
692 */
693 public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
694 if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
Ugo Yud0115462019-03-26 21:38:08 +0800695 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700696 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530697 try {
Jack He16eeac32017-08-17 12:11:18 -0700698 return service.setIdleTime(device, idleTime);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530699 } catch (RemoteException e) {
700 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
701 return false;
702 }
703 }
Jack He16eeac32017-08-17 12:11:18 -0700704 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530705 return false;
706 }
707
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700708 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700709 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700710 }
711}