blob: c1233b800a5115d06b7d1e3ef19461be09ddae1a [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;
21import android.annotation.Nullable;
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -080022import android.annotation.RequiresPermission;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070023import android.annotation.SdkConstant;
24import android.annotation.SdkConstant.SdkConstantType;
Rahul Sabnis9913cb52020-01-07 17:02:22 -080025import android.annotation.SuppressLint;
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -080026import android.annotation.SystemApi;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070027import android.content.Context;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060028import android.os.Binder;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070029import android.os.IBinder;
30import android.os.RemoteException;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070031import android.util.Log;
32
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070033import java.util.ArrayList;
34import java.util.List;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070035
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080036
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070037/**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080038 * This class provides the public APIs to control the Bluetooth Input
39 * Device Profile.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070040 *
Hansong Zhangc26c76c2017-10-20 15:55:59 -070041 * <p>BluetoothHidHost is a proxy object for controlling the Bluetooth
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080042 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
Hansong Zhangc26c76c2017-10-20 15:55:59 -070043 * the BluetoothHidHost proxy object.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070044 *
Jack Hea355e5e2017-08-22 16:06:54 -070045 * <p>Each method is protected with its appropriate permission.
46 *
47 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070048 */
Rahul Sabnis9913cb52020-01-07 17:02:22 -080049@SystemApi
Hansong Zhangc26c76c2017-10-20 15:55:59 -070050public final class BluetoothHidHost implements BluetoothProfile {
51 private static final String TAG = "BluetoothHidHost";
fredc0f420372012-04-12 00:02:00 -070052 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070053 private static final boolean VDBG = false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070054
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080055 /**
56 * Intent used to broadcast the change in connection state of the Input
57 * Device profile.
58 *
59 * <p>This intent will have 3 extras:
60 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070061 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
62 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
63 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080064 * </ul>
65 *
66 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
67 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
68 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
69 *
70 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
71 * receive.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070072 */
Rahul Sabnis9913cb52020-01-07 17:02:22 -080073 @SuppressLint("ActionValue")
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070074 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080075 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070076 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070077
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080078 /**
Priti Aghera349e62f2012-04-09 12:13:17 -070079 * @hide
80 */
81 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
82 public static final String ACTION_PROTOCOL_MODE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070083 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -070084
Mike J. Chend96d5cf2014-01-27 17:55:40 -080085 /**
86 * @hide
87 */
88 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chen8faffa42014-03-04 17:27:16 -080089 public static final String ACTION_HANDSHAKE =
Jack Hea355e5e2017-08-22 16:06:54 -070090 "android.bluetooth.input.profile.action.HANDSHAKE";
Mike J. Chen8faffa42014-03-04 17:27:16 -080091
92 /**
93 * @hide
94 */
95 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chend96d5cf2014-01-27 17:55:40 -080096 public static final String ACTION_REPORT =
Jack Hea355e5e2017-08-22 16:06:54 -070097 "android.bluetooth.input.profile.action.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -070098
99 /**
100 * @hide
101 */
102 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
103 public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
Jack Hea355e5e2017-08-22 16:06:54 -0700104 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700105
Hemant Guptacef9ce32013-07-30 16:09:20 +0530106 /**
107 * @hide
108 */
109 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
110 public static final String ACTION_IDLE_TIME_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700111 "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -0700112
113 /**
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800114 * Return codes for the connect and disconnect Bluez / Dbus calls.
Jack Hea355e5e2017-08-22 16:06:54 -0700115 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800116 * @hide
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800117 */
118 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
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_ALREADY_CONNECTED = 5001;
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_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
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_GENERIC_FAILURE = 5003;
134
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800135 /**
136 * @hide
137 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800138 public static final int INPUT_OPERATION_SUCCESS = 5004;
139
Priti Aghera349e62f2012-04-09 12:13:17 -0700140 /**
141 * @hide
142 */
143 public static final int PROTOCOL_REPORT_MODE = 0;
144
145 /**
146 * @hide
147 */
148 public static final int PROTOCOL_BOOT_MODE = 1;
149
150 /**
151 * @hide
152 */
153 public static final int PROTOCOL_UNSUPPORTED_MODE = 255;
154
155 /* int reportType, int reportType, int bufferSize */
156 /**
157 * @hide
158 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800159 public static final byte REPORT_TYPE_INPUT = 1;
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_OUTPUT = 2;
Priti Aghera349e62f2012-04-09 12:13:17 -0700165
166 /**
167 * @hide
168 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800169 public static final byte REPORT_TYPE_FEATURE = 3;
Priti Aghera349e62f2012-04-09 12:13:17 -0700170
171 /**
172 * @hide
173 */
174 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;
175
176 /**
177 * @hide
178 */
179 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;
180
181 /**
182 * @hide
183 */
Jack Hea355e5e2017-08-22 16:06:54 -0700184 public static final String EXTRA_PROTOCOL_MODE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700185 "android.bluetooth.BluetoothHidHost.extra.PROTOCOL_MODE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700186
187 /**
188 * @hide
189 */
Jack Hea355e5e2017-08-22 16:06:54 -0700190 public static final String EXTRA_REPORT_TYPE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700191 "android.bluetooth.BluetoothHidHost.extra.REPORT_TYPE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700192
193 /**
194 * @hide
195 */
Jack Hea355e5e2017-08-22 16:06:54 -0700196 public static final String EXTRA_REPORT_ID =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700197 "android.bluetooth.BluetoothHidHost.extra.REPORT_ID";
Priti Aghera349e62f2012-04-09 12:13:17 -0700198
199 /**
200 * @hide
201 */
Jack Hea355e5e2017-08-22 16:06:54 -0700202 public static final String EXTRA_REPORT_BUFFER_SIZE =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700203 "android.bluetooth.BluetoothHidHost.extra.REPORT_BUFFER_SIZE";
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_REPORT = "android.bluetooth.BluetoothHidHost.extra.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -0700209
210 /**
211 * @hide
212 */
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700213 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothHidHost.extra.STATUS";
Mike J. Chen8faffa42014-03-04 17:27:16 -0800214
215 /**
216 * @hide
217 */
Jack Hea355e5e2017-08-22 16:06:54 -0700218 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700219 "android.bluetooth.BluetoothHidHost.extra.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700220
Hemant Guptacef9ce32013-07-30 16:09:20 +0530221 /**
222 * @hide
223 */
Jack Hea355e5e2017-08-22 16:06:54 -0700224 public static final String EXTRA_IDLE_TIME =
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700225 "android.bluetooth.BluetoothHidHost.extra.IDLE_TIME";
Hemant Guptacef9ce32013-07-30 16:09:20 +0530226
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800227 private BluetoothAdapter mAdapter;
Ugo Yud0115462019-03-26 21:38:08 +0800228 private final BluetoothProfileConnector<IBluetoothHidHost> mProfileConnector =
229 new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST,
230 "BluetoothHidHost", IBluetoothHidHost.class.getName()) {
231 @Override
232 public IBluetoothHidHost getServiceInterface(IBinder service) {
233 return IBluetoothHidHost.Stub.asInterface(Binder.allowBlocking(service));
fredc0f420372012-04-12 00:02:00 -0700234 }
Ugo Yud0115462019-03-26 21:38:08 +0800235 };
fredc0f420372012-04-12 00:02:00 -0700236
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700237 /**
Hansong Zhangc26c76c2017-10-20 15:55:59 -0700238 * Create a BluetoothHidHost proxy object for interacting with the local
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800239 * Bluetooth Service which handles the InputDevice profile
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700240 */
Ugo Yud0115462019-03-26 21:38:08 +0800241 /*package*/ BluetoothHidHost(Context context, ServiceListener listener) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800242 mAdapter = BluetoothAdapter.getDefaultAdapter();
Ugo Yud0115462019-03-26 21:38:08 +0800243 mProfileConnector.connect(context, listener);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700244 }
245
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800246 /*package*/ void close() {
Matthew Xie563e4142012-10-09 22:10:37 -0700247 if (VDBG) log("close()");
Ugo Yud0115462019-03-26 21:38:08 +0800248 mProfileConnector.disconnect();
249 }
fredc0f420372012-04-12 00:02:00 -0700250
Ugo Yud0115462019-03-26 21:38:08 +0800251 private IBluetoothHidHost getService() {
252 return mProfileConnector.getService();
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800253 }
254
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800255 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700256 * Initiate connection to a profile of the remote bluetooth device.
257 *
258 * <p> The system supports connection to multiple input devices.
259 *
260 * <p> This API returns false in scenarios like the profile on the
261 * device is already connected or Bluetooth is not turned on.
262 * When this API returns true, it is guaranteed that
263 * connection state intent for the profile will be broadcasted with
264 * the state. Users can get the connection state of the profile
265 * from this intent.
266 *
267 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
268 * permission.
269 *
270 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700271 * @return false on immediate error, true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800272 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700273 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800274 public boolean connect(BluetoothDevice device) {
275 if (DBG) log("connect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800276 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700277 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800278 try {
Jack He16eeac32017-08-17 12:11:18 -0700279 return service.connect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800280 } catch (RemoteException e) {
281 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
282 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700283 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700284 }
Jack He16eeac32017-08-17 12:11:18 -0700285 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700286 return false;
287 }
288
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800289 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700290 * Initiate disconnection from a profile
291 *
292 * <p> This API will return false in scenarios like the profile on the
293 * Bluetooth device is not in connected state etc. When this API returns,
294 * true, it is guaranteed that the connection state change
295 * intent will be broadcasted with the state. Users can get the
296 * disconnection state of the profile from this intent.
297 *
298 * <p> If the disconnection is initiated by a remote device, the state
299 * will transition from {@link #STATE_CONNECTED} to
300 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
301 * host (local) device the state will transition from
302 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
303 * state {@link #STATE_DISCONNECTED}. The transition to
304 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
305 * two scenarios.
306 *
307 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
308 * permission.
309 *
310 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700311 * @return false on immediate error, true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700312 * @hide
313 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800314 public boolean disconnect(BluetoothDevice device) {
315 if (DBG) log("disconnect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800316 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700317 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800318 try {
Jack He16eeac32017-08-17 12:11:18 -0700319 return service.disconnect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800320 } catch (RemoteException e) {
321 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
322 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700323 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700324 }
Jack He16eeac32017-08-17 12:11:18 -0700325 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800326 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700327 }
328
329 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800330 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700331 */
Jack He2992cd02017-08-22 21:21:23 -0700332 @Override
Rahul Sabnis9913cb52020-01-07 17:02:22 -0800333 public @NonNull List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700334 if (VDBG) log("getConnectedDevices()");
Ugo Yud0115462019-03-26 21:38:08 +0800335 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700336 if (service != null && isEnabled()) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800337 try {
Jack He16eeac32017-08-17 12:11:18 -0700338 return service.getConnectedDevices();
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800339 } catch (RemoteException e) {
340 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
341 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700342 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700343 }
Jack He16eeac32017-08-17 12:11:18 -0700344 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800345 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700346 }
347
348 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800349 * {@inheritDoc}
Rahul Sabnis9913cb52020-01-07 17:02:22 -0800350 *
351 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700352 */
Jack He2992cd02017-08-22 21:21:23 -0700353 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800354 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700355 if (VDBG) log("getDevicesMatchingStates()");
Ugo Yud0115462019-03-26 21:38:08 +0800356 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700357 if (service != null && isEnabled()) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800358 try {
Jack He16eeac32017-08-17 12:11:18 -0700359 return service.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800360 } catch (RemoteException e) {
361 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
362 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700363 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700364 }
Jack He16eeac32017-08-17 12:11:18 -0700365 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800366 return new ArrayList<BluetoothDevice>();
367 }
368
369 /**
370 * {@inheritDoc}
371 */
Jack He2992cd02017-08-22 21:21:23 -0700372 @Override
Rahul Sabnis9913cb52020-01-07 17:02:22 -0800373 public int getConnectionState(@Nullable BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700374 if (VDBG) log("getState(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800375 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700376 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800377 try {
Jack He16eeac32017-08-17 12:11:18 -0700378 return service.getConnectionState(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800379 } catch (RemoteException e) {
380 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
381 return BluetoothProfile.STATE_DISCONNECTED;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700382 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800383 }
Jack He16eeac32017-08-17 12:11:18 -0700384 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800385 return BluetoothProfile.STATE_DISCONNECTED;
386 }
387
388 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700389 * Set priority of the profile
390 *
391 * <p> The device should already be paired.
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800392 * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700393 *
394 * @param device Paired bluetooth device
395 * @param priority
396 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800397 * @hide
398 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800399 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800400 public boolean setPriority(BluetoothDevice device, int priority) {
401 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800402 return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
403 }
404
405 /**
406 * Set connection policy of the profile
407 *
408 * <p> The device should already be paired.
409 * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
410 * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
411 *
412 * @param device Paired bluetooth device
413 * @param connectionPolicy is the connection policy to set to for this profile
414 * @return true if connectionPolicy is set, false on error
415 * @hide
416 */
417 @SystemApi
418 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
Rahul Sabnis9913cb52020-01-07 17:02:22 -0800419 public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800420 if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800421 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700422 if (service != null && isEnabled() && isValidDevice(device)) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800423 if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
424 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
Jack Hea355e5e2017-08-22 16:06:54 -0700425 return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800426 }
427 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800428 return service.setConnectionPolicy(device, connectionPolicy);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800429 } catch (RemoteException e) {
430 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
431 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700432 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800433 }
Jack He16eeac32017-08-17 12:11:18 -0700434 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800435 return false;
436 }
437
438 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700439 * Get the priority of the profile.
440 *
441 * <p> The priority can be any of:
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800442 * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700443 *
444 * @param device Bluetooth device
445 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800446 * @hide
447 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800448 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800449 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700450 if (VDBG) log("getPriority(" + device + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800451 return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
452 }
453
454 /**
455 * Get the connection policy of the profile.
456 *
457 * <p> The connection policy can be any of:
458 * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
459 * {@link #CONNECTION_POLICY_UNKNOWN}
460 *
461 * @param device Bluetooth device
462 * @return connection policy of the device
463 * @hide
464 */
465 @SystemApi
466 @RequiresPermission(Manifest.permission.BLUETOOTH)
Rahul Sabnis9913cb52020-01-07 17:02:22 -0800467 public int getConnectionPolicy(@Nullable BluetoothDevice device) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800468 if (VDBG) log("getConnectionPolicy(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800469 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700470 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800471 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800472 return service.getConnectionPolicy(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800473 } catch (RemoteException e) {
474 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800475 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700476 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800477 }
Jack He16eeac32017-08-17 12:11:18 -0700478 if (service == null) Log.w(TAG, "Proxy not attached to service");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800479 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800480 }
481
482 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700483 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800484 }
485
Jack He16eeac32017-08-17 12:11:18 -0700486 private static boolean isValidDevice(BluetoothDevice device) {
487 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700488 }
489
Priti Aghera349e62f2012-04-09 12:13:17 -0700490 /**
491 * Initiate virtual unplug for a HID input device.
492 *
493 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
494 *
495 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700496 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700497 * @hide
498 */
499 public boolean virtualUnplug(BluetoothDevice device) {
500 if (DBG) log("virtualUnplug(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800501 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700502 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700503 try {
Jack He16eeac32017-08-17 12:11:18 -0700504 return service.virtualUnplug(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700505 } catch (RemoteException e) {
506 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
507 return false;
508 }
509 }
510
Jack He16eeac32017-08-17 12:11:18 -0700511 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700512 return false;
513
514 }
515
516 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700517 * Send Get_Protocol_Mode command to the connected HID input device.
518 *
519 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
520 *
521 * @param device Remote Bluetooth Device
522 * @return false on immediate error, true otherwise
523 * @hide
524 */
Priti Aghera349e62f2012-04-09 12:13:17 -0700525 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700526 if (VDBG) log("getProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800527 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700528 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700529 try {
Jack He16eeac32017-08-17 12:11:18 -0700530 return service.getProtocolMode(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700531 } catch (RemoteException e) {
532 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
533 return false;
534 }
535 }
Jack He16eeac32017-08-17 12:11:18 -0700536 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700537 return false;
Priti Aghera349e62f2012-04-09 12:13:17 -0700538 }
539
540 /**
541 * Send Set_Protocol_Mode command to the connected HID input device.
542 *
543 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
544 *
545 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700546 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700547 * @hide
548 */
549 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
550 if (DBG) log("setProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800551 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700552 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700553 try {
Jack He16eeac32017-08-17 12:11:18 -0700554 return service.setProtocolMode(device, protocolMode);
Priti Aghera349e62f2012-04-09 12:13:17 -0700555 } catch (RemoteException e) {
556 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
557 return false;
558 }
559 }
Jack He16eeac32017-08-17 12:11:18 -0700560 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700561 return false;
562 }
563
564 /**
565 * Send Get_Report command to the connected HID input device.
566 *
567 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
568 *
569 * @param device Remote Bluetooth Device
570 * @param reportType Report type
571 * @param reportId Report ID
572 * @param bufferSize Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700573 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700574 * @hide
575 */
Jack Hea355e5e2017-08-22 16:06:54 -0700576 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
577 int bufferSize) {
578 if (VDBG) {
Jack He16eeac32017-08-17 12:11:18 -0700579 log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
580 + "bufferSize=" + bufferSize);
Jack Hea355e5e2017-08-22 16:06:54 -0700581 }
Ugo Yud0115462019-03-26 21:38:08 +0800582 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700583 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700584 try {
Jack He16eeac32017-08-17 12:11:18 -0700585 return service.getReport(device, reportType, reportId, bufferSize);
Priti Aghera349e62f2012-04-09 12:13:17 -0700586 } catch (RemoteException e) {
587 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
588 return false;
589 }
590 }
Jack He16eeac32017-08-17 12:11:18 -0700591 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700592 return false;
593 }
594
595 /**
596 * Send Set_Report command to the connected HID input device.
597 *
598 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
599 *
600 * @param device Remote Bluetooth Device
601 * @param reportType Report type
602 * @param report Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700603 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700604 * @hide
605 */
606 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800607 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800608 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700609 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700610 try {
Jack He16eeac32017-08-17 12:11:18 -0700611 return service.setReport(device, reportType, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700612 } catch (RemoteException e) {
613 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
614 return false;
615 }
616 }
Jack He16eeac32017-08-17 12:11:18 -0700617 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700618 return false;
619 }
620
621 /**
622 * Send Send_Data command to the connected HID input device.
623 *
624 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
625 *
626 * @param device Remote Bluetooth Device
Ang Li707fd392014-06-25 13:16:01 -0700627 * @param report Report to send
Jack Hea355e5e2017-08-22 16:06:54 -0700628 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700629 * @hide
630 */
631 public boolean sendData(BluetoothDevice device, String report) {
632 if (DBG) log("sendData(" + device + "), report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800633 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700634 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700635 try {
Jack He16eeac32017-08-17 12:11:18 -0700636 return service.sendData(device, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700637 } catch (RemoteException e) {
638 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
639 return false;
640 }
641 }
Jack He16eeac32017-08-17 12:11:18 -0700642 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700643 return false;
644 }
Hemant Guptacef9ce32013-07-30 16:09:20 +0530645
646 /**
647 * Send Get_Idle_Time command to the connected HID input device.
648 *
649 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
650 *
651 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700652 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530653 * @hide
654 */
655 public boolean getIdleTime(BluetoothDevice device) {
656 if (DBG) log("getIdletime(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800657 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700658 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530659 try {
Jack He16eeac32017-08-17 12:11:18 -0700660 return service.getIdleTime(device);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530661 } catch (RemoteException e) {
662 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
663 return false;
664 }
665 }
Jack He16eeac32017-08-17 12:11:18 -0700666 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530667 return false;
668 }
669
670 /**
671 * Send Set_Idle_Time command to the connected HID input device.
672 *
673 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
674 *
675 * @param device Remote Bluetooth Device
676 * @param idleTime Idle time to be set on HID Device
Jack Hea355e5e2017-08-22 16:06:54 -0700677 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530678 * @hide
679 */
680 public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
681 if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
Ugo Yud0115462019-03-26 21:38:08 +0800682 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700683 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530684 try {
Jack He16eeac32017-08-17 12:11:18 -0700685 return service.setIdleTime(device, idleTime);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530686 } catch (RemoteException e) {
687 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
688 return false;
689 }
690 }
Jack He16eeac32017-08-17 12:11:18 -0700691 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530692 return false;
693 }
694
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700695 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700696 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700697 }
698}