blob: 26e3e271bffadbb196eb494d8e97a7fe2d71c38c [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 Sabnis30c597f2020-01-22 14:26:35 -0800419 public boolean setConnectionPolicy(@Nullable BluetoothDevice device,
420 @ConnectionPolicy int connectionPolicy) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800421 if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800422 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700423 if (service != null && isEnabled() && isValidDevice(device)) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800424 if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
425 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
Jack Hea355e5e2017-08-22 16:06:54 -0700426 return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800427 }
428 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800429 return service.setConnectionPolicy(device, connectionPolicy);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800430 } catch (RemoteException e) {
431 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
432 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700433 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800434 }
Jack He16eeac32017-08-17 12:11:18 -0700435 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800436 return false;
437 }
438
439 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700440 * Get the priority of the profile.
441 *
442 * <p> The priority can be any of:
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800443 * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700444 *
445 * @param device Bluetooth device
446 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800447 * @hide
448 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800449 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800450 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700451 if (VDBG) log("getPriority(" + device + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800452 return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
453 }
454
455 /**
456 * Get the connection policy of the profile.
457 *
458 * <p> The connection policy can be any of:
459 * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
460 * {@link #CONNECTION_POLICY_UNKNOWN}
461 *
462 * @param device Bluetooth device
463 * @return connection policy of the device
464 * @hide
465 */
466 @SystemApi
467 @RequiresPermission(Manifest.permission.BLUETOOTH)
Rahul Sabnis30c597f2020-01-22 14:26:35 -0800468 public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800469 if (VDBG) log("getConnectionPolicy(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800470 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700471 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800472 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800473 return service.getConnectionPolicy(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800474 } catch (RemoteException e) {
475 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800476 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700477 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800478 }
Jack He16eeac32017-08-17 12:11:18 -0700479 if (service == null) Log.w(TAG, "Proxy not attached to service");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800480 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800481 }
482
483 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700484 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800485 }
486
Jack He16eeac32017-08-17 12:11:18 -0700487 private static boolean isValidDevice(BluetoothDevice device) {
488 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700489 }
490
Priti Aghera349e62f2012-04-09 12:13:17 -0700491 /**
492 * Initiate virtual unplug for a HID input device.
493 *
494 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
495 *
496 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700497 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700498 * @hide
499 */
500 public boolean virtualUnplug(BluetoothDevice device) {
501 if (DBG) log("virtualUnplug(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800502 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700503 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700504 try {
Jack He16eeac32017-08-17 12:11:18 -0700505 return service.virtualUnplug(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700506 } catch (RemoteException e) {
507 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
508 return false;
509 }
510 }
511
Jack He16eeac32017-08-17 12:11:18 -0700512 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700513 return false;
514
515 }
516
517 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700518 * Send Get_Protocol_Mode command to the connected HID input device.
519 *
520 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
521 *
522 * @param device Remote Bluetooth Device
523 * @return false on immediate error, true otherwise
524 * @hide
525 */
Priti Aghera349e62f2012-04-09 12:13:17 -0700526 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700527 if (VDBG) log("getProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800528 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700529 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700530 try {
Jack He16eeac32017-08-17 12:11:18 -0700531 return service.getProtocolMode(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700532 } catch (RemoteException e) {
533 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
534 return false;
535 }
536 }
Jack He16eeac32017-08-17 12:11:18 -0700537 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700538 return false;
Priti Aghera349e62f2012-04-09 12:13:17 -0700539 }
540
541 /**
542 * Send Set_Protocol_Mode command to the connected HID input device.
543 *
544 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
545 *
546 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700547 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700548 * @hide
549 */
550 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
551 if (DBG) log("setProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800552 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700553 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700554 try {
Jack He16eeac32017-08-17 12:11:18 -0700555 return service.setProtocolMode(device, protocolMode);
Priti Aghera349e62f2012-04-09 12:13:17 -0700556 } catch (RemoteException e) {
557 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
558 return false;
559 }
560 }
Jack He16eeac32017-08-17 12:11:18 -0700561 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700562 return false;
563 }
564
565 /**
566 * Send Get_Report command to the connected HID input device.
567 *
568 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
569 *
570 * @param device Remote Bluetooth Device
571 * @param reportType Report type
572 * @param reportId Report ID
573 * @param bufferSize Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700574 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700575 * @hide
576 */
Jack Hea355e5e2017-08-22 16:06:54 -0700577 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
578 int bufferSize) {
579 if (VDBG) {
Jack He16eeac32017-08-17 12:11:18 -0700580 log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
581 + "bufferSize=" + bufferSize);
Jack Hea355e5e2017-08-22 16:06:54 -0700582 }
Ugo Yud0115462019-03-26 21:38:08 +0800583 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700584 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700585 try {
Jack He16eeac32017-08-17 12:11:18 -0700586 return service.getReport(device, reportType, reportId, bufferSize);
Priti Aghera349e62f2012-04-09 12:13:17 -0700587 } catch (RemoteException e) {
588 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
589 return false;
590 }
591 }
Jack He16eeac32017-08-17 12:11:18 -0700592 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700593 return false;
594 }
595
596 /**
597 * Send Set_Report command to the connected HID input device.
598 *
599 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
600 *
601 * @param device Remote Bluetooth Device
602 * @param reportType Report type
603 * @param report Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700604 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700605 * @hide
606 */
607 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800608 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800609 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700610 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700611 try {
Jack He16eeac32017-08-17 12:11:18 -0700612 return service.setReport(device, reportType, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700613 } catch (RemoteException e) {
614 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
615 return false;
616 }
617 }
Jack He16eeac32017-08-17 12:11:18 -0700618 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700619 return false;
620 }
621
622 /**
623 * Send Send_Data command to the connected HID input device.
624 *
625 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
626 *
627 * @param device Remote Bluetooth Device
Ang Li707fd392014-06-25 13:16:01 -0700628 * @param report Report to send
Jack Hea355e5e2017-08-22 16:06:54 -0700629 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700630 * @hide
631 */
632 public boolean sendData(BluetoothDevice device, String report) {
633 if (DBG) log("sendData(" + device + "), report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800634 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700635 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700636 try {
Jack He16eeac32017-08-17 12:11:18 -0700637 return service.sendData(device, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700638 } catch (RemoteException e) {
639 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
640 return false;
641 }
642 }
Jack He16eeac32017-08-17 12:11:18 -0700643 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700644 return false;
645 }
Hemant Guptacef9ce32013-07-30 16:09:20 +0530646
647 /**
648 * Send Get_Idle_Time command to the connected HID input device.
649 *
650 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
651 *
652 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700653 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530654 * @hide
655 */
656 public boolean getIdleTime(BluetoothDevice device) {
657 if (DBG) log("getIdletime(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800658 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700659 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530660 try {
Jack He16eeac32017-08-17 12:11:18 -0700661 return service.getIdleTime(device);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530662 } catch (RemoteException e) {
663 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
664 return false;
665 }
666 }
Jack He16eeac32017-08-17 12:11:18 -0700667 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530668 return false;
669 }
670
671 /**
672 * Send Set_Idle_Time command to the connected HID input device.
673 *
674 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
675 *
676 * @param device Remote Bluetooth Device
677 * @param idleTime Idle time to be set on HID Device
Jack Hea355e5e2017-08-22 16:06:54 -0700678 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530679 * @hide
680 */
681 public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
682 if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
Ugo Yud0115462019-03-26 21:38:08 +0800683 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700684 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530685 try {
Jack He16eeac32017-08-17 12:11:18 -0700686 return service.setIdleTime(device, idleTime);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530687 } catch (RemoteException e) {
688 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
689 return false;
690 }
691 }
Jack He16eeac32017-08-17 12:11:18 -0700692 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530693 return false;
694 }
695
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700696 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700697 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700698 }
699}