blob: e9e1f6866908a9b0446c7209122f0d1c0dd0bcb3 [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 *
266 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
267 * permission.
268 *
269 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700270 * @return false on immediate error, true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800271 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700272 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800273 public boolean connect(BluetoothDevice device) {
274 if (DBG) log("connect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800275 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700276 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800277 try {
Jack He16eeac32017-08-17 12:11:18 -0700278 return service.connect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800279 } catch (RemoteException e) {
280 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
281 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700282 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700283 }
Jack He16eeac32017-08-17 12:11:18 -0700284 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700285 return false;
286 }
287
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800288 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700289 * Initiate disconnection from a profile
290 *
291 * <p> This API will return false in scenarios like the profile on the
292 * Bluetooth device is not in connected state etc. When this API returns,
293 * true, it is guaranteed that the connection state change
294 * intent will be broadcasted with the state. Users can get the
295 * disconnection state of the profile from this intent.
296 *
297 * <p> If the disconnection is initiated by a remote device, the state
298 * will transition from {@link #STATE_CONNECTED} to
299 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
300 * host (local) device the state will transition from
301 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
302 * state {@link #STATE_DISCONNECTED}. The transition to
303 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
304 * two scenarios.
305 *
306 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
307 * permission.
308 *
309 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700310 * @return false on immediate error, true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700311 * @hide
312 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800313 public boolean disconnect(BluetoothDevice device) {
314 if (DBG) log("disconnect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800315 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700316 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800317 try {
Jack He16eeac32017-08-17 12:11:18 -0700318 return service.disconnect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800319 } catch (RemoteException e) {
320 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
321 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700322 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700323 }
Jack He16eeac32017-08-17 12:11:18 -0700324 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800325 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700326 }
327
328 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800329 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700330 */
Jack He2992cd02017-08-22 21:21:23 -0700331 @Override
Rahul Sabnis946bf882020-02-25 11:33:43 -0800332 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
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 Sabnis946bf882020-02-25 11:33:43 -0800373 @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
374 public int getConnectionState(@NonNull BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700375 if (VDBG) log("getState(" + device + ")");
Rahul Sabnis946bf882020-02-25 11:33:43 -0800376 if (device == null) {
377 throw new IllegalArgumentException("device must not be null");
378 }
Ugo Yud0115462019-03-26 21:38:08 +0800379 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700380 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800381 try {
Jack He16eeac32017-08-17 12:11:18 -0700382 return service.getConnectionState(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800383 } catch (RemoteException e) {
384 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
385 return BluetoothProfile.STATE_DISCONNECTED;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700386 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800387 }
Jack He16eeac32017-08-17 12:11:18 -0700388 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800389 return BluetoothProfile.STATE_DISCONNECTED;
390 }
391
392 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700393 * Set priority of the profile
394 *
395 * <p> The device should already be paired.
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800396 * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700397 *
398 * @param device Paired bluetooth device
399 * @param priority
400 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800401 * @hide
402 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800403 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800404 public boolean setPriority(BluetoothDevice device, int priority) {
405 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800406 return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
407 }
408
409 /**
410 * Set connection policy of the profile
411 *
412 * <p> The device should already be paired.
413 * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
414 * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
415 *
416 * @param device Paired bluetooth device
417 * @param connectionPolicy is the connection policy to set to for this profile
418 * @return true if connectionPolicy is set, false on error
419 * @hide
420 */
421 @SystemApi
422 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
Rahul Sabnis946bf882020-02-25 11:33:43 -0800423 public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
Rahul Sabnis30c597f2020-01-22 14:26:35 -0800424 @ConnectionPolicy int connectionPolicy) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800425 if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
Rahul Sabnis946bf882020-02-25 11:33:43 -0800426 if (device == null) {
427 throw new IllegalArgumentException("device must not be null");
428 }
Ugo Yud0115462019-03-26 21:38:08 +0800429 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700430 if (service != null && isEnabled() && isValidDevice(device)) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800431 if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
432 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
Jack Hea355e5e2017-08-22 16:06:54 -0700433 return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800434 }
435 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800436 return service.setConnectionPolicy(device, connectionPolicy);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800437 } catch (RemoteException e) {
438 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
439 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700440 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800441 }
Jack He16eeac32017-08-17 12:11:18 -0700442 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800443 return false;
444 }
445
446 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700447 * Get the priority of the profile.
448 *
449 * <p> The priority can be any of:
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800450 * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700451 *
452 * @param device Bluetooth device
453 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800454 * @hide
455 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800456 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800457 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700458 if (VDBG) log("getPriority(" + device + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800459 return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
460 }
461
462 /**
463 * Get the connection policy of the profile.
464 *
465 * <p> The connection policy can be any of:
466 * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
467 * {@link #CONNECTION_POLICY_UNKNOWN}
468 *
469 * @param device Bluetooth device
470 * @return connection policy of the device
471 * @hide
472 */
473 @SystemApi
474 @RequiresPermission(Manifest.permission.BLUETOOTH)
Rahul Sabnis946bf882020-02-25 11:33:43 -0800475 public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800476 if (VDBG) log("getConnectionPolicy(" + device + ")");
Rahul Sabnis946bf882020-02-25 11:33:43 -0800477 if (device == null) {
478 throw new IllegalArgumentException("device must not be null");
479 }
Ugo Yud0115462019-03-26 21:38:08 +0800480 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700481 if (service != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800482 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800483 return service.getConnectionPolicy(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800484 } catch (RemoteException e) {
485 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800486 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700487 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800488 }
Jack He16eeac32017-08-17 12:11:18 -0700489 if (service == null) Log.w(TAG, "Proxy not attached to service");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800490 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800491 }
492
493 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700494 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800495 }
496
Jack He16eeac32017-08-17 12:11:18 -0700497 private static boolean isValidDevice(BluetoothDevice device) {
498 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700499 }
500
Priti Aghera349e62f2012-04-09 12:13:17 -0700501 /**
502 * Initiate virtual unplug for a HID input device.
503 *
504 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
505 *
506 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700507 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700508 * @hide
509 */
510 public boolean virtualUnplug(BluetoothDevice device) {
511 if (DBG) log("virtualUnplug(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800512 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700513 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700514 try {
Jack He16eeac32017-08-17 12:11:18 -0700515 return service.virtualUnplug(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700516 } catch (RemoteException e) {
517 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
518 return false;
519 }
520 }
521
Jack He16eeac32017-08-17 12:11:18 -0700522 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700523 return false;
524
525 }
526
527 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700528 * Send Get_Protocol_Mode command to the connected HID input device.
529 *
530 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
531 *
532 * @param device Remote Bluetooth Device
533 * @return false on immediate error, true otherwise
534 * @hide
535 */
Priti Aghera349e62f2012-04-09 12:13:17 -0700536 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700537 if (VDBG) log("getProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800538 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700539 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700540 try {
Jack He16eeac32017-08-17 12:11:18 -0700541 return service.getProtocolMode(device);
Priti Aghera349e62f2012-04-09 12:13:17 -0700542 } catch (RemoteException e) {
543 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
544 return false;
545 }
546 }
Jack He16eeac32017-08-17 12:11:18 -0700547 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700548 return false;
Priti Aghera349e62f2012-04-09 12:13:17 -0700549 }
550
551 /**
552 * Send Set_Protocol_Mode command to the connected HID input device.
553 *
554 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
555 *
556 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700557 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700558 * @hide
559 */
560 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
561 if (DBG) log("setProtocolMode(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800562 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700563 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700564 try {
Jack He16eeac32017-08-17 12:11:18 -0700565 return service.setProtocolMode(device, protocolMode);
Priti Aghera349e62f2012-04-09 12:13:17 -0700566 } catch (RemoteException e) {
567 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
568 return false;
569 }
570 }
Jack He16eeac32017-08-17 12:11:18 -0700571 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700572 return false;
573 }
574
575 /**
576 * Send Get_Report command to the connected HID input device.
577 *
578 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
579 *
580 * @param device Remote Bluetooth Device
581 * @param reportType Report type
582 * @param reportId Report ID
583 * @param bufferSize Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700584 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700585 * @hide
586 */
Jack Hea355e5e2017-08-22 16:06:54 -0700587 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
588 int bufferSize) {
589 if (VDBG) {
Jack He16eeac32017-08-17 12:11:18 -0700590 log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
591 + "bufferSize=" + bufferSize);
Jack Hea355e5e2017-08-22 16:06:54 -0700592 }
Ugo Yud0115462019-03-26 21:38:08 +0800593 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700594 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700595 try {
Jack He16eeac32017-08-17 12:11:18 -0700596 return service.getReport(device, reportType, reportId, bufferSize);
Priti Aghera349e62f2012-04-09 12:13:17 -0700597 } catch (RemoteException e) {
598 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
599 return false;
600 }
601 }
Jack He16eeac32017-08-17 12:11:18 -0700602 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700603 return false;
604 }
605
606 /**
607 * Send Set_Report command to the connected HID input device.
608 *
609 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
610 *
611 * @param device Remote Bluetooth Device
612 * @param reportType Report type
613 * @param report Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700614 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700615 * @hide
616 */
617 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800618 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800619 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700620 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700621 try {
Jack He16eeac32017-08-17 12:11:18 -0700622 return service.setReport(device, reportType, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700623 } catch (RemoteException e) {
624 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
625 return false;
626 }
627 }
Jack He16eeac32017-08-17 12:11:18 -0700628 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700629 return false;
630 }
631
632 /**
633 * Send Send_Data command to the connected HID input device.
634 *
635 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
636 *
637 * @param device Remote Bluetooth Device
Ang Li707fd392014-06-25 13:16:01 -0700638 * @param report Report to send
Jack Hea355e5e2017-08-22 16:06:54 -0700639 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700640 * @hide
641 */
642 public boolean sendData(BluetoothDevice device, String report) {
643 if (DBG) log("sendData(" + device + "), report=" + report);
Ugo Yud0115462019-03-26 21:38:08 +0800644 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700645 if (service != null && isEnabled() && isValidDevice(device)) {
Priti Aghera349e62f2012-04-09 12:13:17 -0700646 try {
Jack He16eeac32017-08-17 12:11:18 -0700647 return service.sendData(device, report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700648 } catch (RemoteException e) {
649 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
650 return false;
651 }
652 }
Jack He16eeac32017-08-17 12:11:18 -0700653 if (service == null) Log.w(TAG, "Proxy not attached to service");
Priti Aghera349e62f2012-04-09 12:13:17 -0700654 return false;
655 }
Hemant Guptacef9ce32013-07-30 16:09:20 +0530656
657 /**
658 * Send Get_Idle_Time command to the connected HID input device.
659 *
660 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
661 *
662 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700663 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530664 * @hide
665 */
666 public boolean getIdleTime(BluetoothDevice device) {
667 if (DBG) log("getIdletime(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800668 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700669 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530670 try {
Jack He16eeac32017-08-17 12:11:18 -0700671 return service.getIdleTime(device);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530672 } catch (RemoteException e) {
673 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
674 return false;
675 }
676 }
Jack He16eeac32017-08-17 12:11:18 -0700677 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530678 return false;
679 }
680
681 /**
682 * Send Set_Idle_Time command to the connected HID input device.
683 *
684 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
685 *
686 * @param device Remote Bluetooth Device
687 * @param idleTime Idle time to be set on HID Device
Jack Hea355e5e2017-08-22 16:06:54 -0700688 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530689 * @hide
690 */
691 public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
692 if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
Ugo Yud0115462019-03-26 21:38:08 +0800693 final IBluetoothHidHost service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700694 if (service != null && isEnabled() && isValidDevice(device)) {
Hemant Guptacef9ce32013-07-30 16:09:20 +0530695 try {
Jack He16eeac32017-08-17 12:11:18 -0700696 return service.setIdleTime(device, idleTime);
Hemant Guptacef9ce32013-07-30 16:09:20 +0530697 } catch (RemoteException e) {
698 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
699 return false;
700 }
701 }
Jack He16eeac32017-08-17 12:11:18 -0700702 if (service == null) Log.w(TAG, "Proxy not attached to service");
Hemant Guptacef9ce32013-07-30 16:09:20 +0530703 return false;
704 }
705
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700706 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700707 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700708 }
709}