blob: a9a9010c7edbf0e7f3060a3bb591b5226c27b79a [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
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
Matthew Xiebf246ef2012-03-21 23:15:06 -070021import android.content.ComponentName;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070022import android.content.Context;
Matthew Xiebf246ef2012-03-21 23:15:06 -070023import android.content.Intent;
24import android.content.ServiceConnection;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060025import android.os.Binder;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070026import android.os.IBinder;
27import android.os.RemoteException;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070028import android.util.Log;
29
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070030import java.util.ArrayList;
31import java.util.List;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070032
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080033
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070034/**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080035 * This class provides the public APIs to control the Bluetooth Input
36 * Device Profile.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070037 *
Jack Hea355e5e2017-08-22 16:06:54 -070038 * <p>BluetoothInputDevice is a proxy object for controlling the Bluetooth
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080039 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
40 * the BluetoothInputDevice proxy object.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070041 *
Jack Hea355e5e2017-08-22 16:06:54 -070042 * <p>Each method is protected with its appropriate permission.
43 *
44 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070045 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080046public final class BluetoothInputDevice implements BluetoothProfile {
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070047 private static final String TAG = "BluetoothInputDevice";
fredc0f420372012-04-12 00:02:00 -070048 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070049 private static final boolean VDBG = false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070050
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080051 /**
52 * Intent used to broadcast the change in connection state of the Input
53 * Device profile.
54 *
55 * <p>This intent will have 3 extras:
56 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070057 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
58 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
59 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080060 * </ul>
61 *
62 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
63 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
64 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
65 *
66 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
67 * receive.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070068 */
69 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080070 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070071 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070072
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080073 /**
Priti Aghera349e62f2012-04-09 12:13:17 -070074 * @hide
75 */
76 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
77 public static final String ACTION_PROTOCOL_MODE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070078 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -070079
Mike J. Chend96d5cf2014-01-27 17:55:40 -080080 /**
81 * @hide
82 */
83 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chen8faffa42014-03-04 17:27:16 -080084 public static final String ACTION_HANDSHAKE =
Jack Hea355e5e2017-08-22 16:06:54 -070085 "android.bluetooth.input.profile.action.HANDSHAKE";
Mike J. Chen8faffa42014-03-04 17:27:16 -080086
87 /**
88 * @hide
89 */
90 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chend96d5cf2014-01-27 17:55:40 -080091 public static final String ACTION_REPORT =
Jack Hea355e5e2017-08-22 16:06:54 -070092 "android.bluetooth.input.profile.action.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -070093
94 /**
95 * @hide
96 */
97 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
98 public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
Jack Hea355e5e2017-08-22 16:06:54 -070099 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700100
Hemant Guptacef9ce32013-07-30 16:09:20 +0530101 /**
102 * @hide
103 */
104 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
105 public static final String ACTION_IDLE_TIME_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700106 "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
Priti Aghera349e62f2012-04-09 12:13:17 -0700107
108 /**
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800109 * Return codes for the connect and disconnect Bluez / Dbus calls.
Jack Hea355e5e2017-08-22 16:06:54 -0700110 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800111 * @hide
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800112 */
113 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
114
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800115 /**
116 * @hide
117 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800118 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
119
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800120 /**
121 * @hide
122 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800123 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
124
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800125 /**
126 * @hide
127 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800128 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
129
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800130 /**
131 * @hide
132 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800133 public static final int INPUT_OPERATION_SUCCESS = 5004;
134
Priti Aghera349e62f2012-04-09 12:13:17 -0700135 /**
136 * @hide
137 */
138 public static final int PROTOCOL_REPORT_MODE = 0;
139
140 /**
141 * @hide
142 */
143 public static final int PROTOCOL_BOOT_MODE = 1;
144
145 /**
146 * @hide
147 */
148 public static final int PROTOCOL_UNSUPPORTED_MODE = 255;
149
150 /* int reportType, int reportType, int bufferSize */
151 /**
152 * @hide
153 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800154 public static final byte REPORT_TYPE_INPUT = 1;
Priti Aghera349e62f2012-04-09 12:13:17 -0700155
156 /**
157 * @hide
158 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800159 public static final byte REPORT_TYPE_OUTPUT = 2;
Priti Aghera349e62f2012-04-09 12:13:17 -0700160
161 /**
162 * @hide
163 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800164 public static final byte REPORT_TYPE_FEATURE = 3;
Priti Aghera349e62f2012-04-09 12:13:17 -0700165
166 /**
167 * @hide
168 */
169 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;
170
171 /**
172 * @hide
173 */
174 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;
175
176 /**
177 * @hide
178 */
Jack Hea355e5e2017-08-22 16:06:54 -0700179 public static final String EXTRA_PROTOCOL_MODE =
180 "android.bluetooth.BluetoothInputDevice.extra.PROTOCOL_MODE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700181
182 /**
183 * @hide
184 */
Jack Hea355e5e2017-08-22 16:06:54 -0700185 public static final String EXTRA_REPORT_TYPE =
186 "android.bluetooth.BluetoothInputDevice.extra.REPORT_TYPE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700187
188 /**
189 * @hide
190 */
Jack Hea355e5e2017-08-22 16:06:54 -0700191 public static final String EXTRA_REPORT_ID =
192 "android.bluetooth.BluetoothInputDevice.extra.REPORT_ID";
Priti Aghera349e62f2012-04-09 12:13:17 -0700193
194 /**
195 * @hide
196 */
Jack Hea355e5e2017-08-22 16:06:54 -0700197 public static final String EXTRA_REPORT_BUFFER_SIZE =
198 "android.bluetooth.BluetoothInputDevice.extra.REPORT_BUFFER_SIZE";
Priti Aghera349e62f2012-04-09 12:13:17 -0700199
200 /**
201 * @hide
202 */
203 public static final String EXTRA_REPORT = "android.bluetooth.BluetoothInputDevice.extra.REPORT";
204
205 /**
206 * @hide
207 */
Mike J. Chen8faffa42014-03-04 17:27:16 -0800208 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothInputDevice.extra.STATUS";
209
210 /**
211 * @hide
212 */
Jack Hea355e5e2017-08-22 16:06:54 -0700213 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS =
214 "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS";
Priti Aghera349e62f2012-04-09 12:13:17 -0700215
Hemant Guptacef9ce32013-07-30 16:09:20 +0530216 /**
217 * @hide
218 */
Jack Hea355e5e2017-08-22 16:06:54 -0700219 public static final String EXTRA_IDLE_TIME =
220 "android.bluetooth.BluetoothInputDevice.extra.IDLE_TIME";
Hemant Guptacef9ce32013-07-30 16:09:20 +0530221
Matthew Xiebf246ef2012-03-21 23:15:06 -0700222 private Context mContext;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800223 private ServiceListener mServiceListener;
224 private BluetoothAdapter mAdapter;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700225 private IBluetoothInputDevice mService;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700226
Jack He2992cd02017-08-22 21:21:23 -0700227 private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
fredc0f420372012-04-12 00:02:00 -0700228 new IBluetoothStateChangeCallback.Stub() {
229 public void onBluetoothStateChange(boolean up) {
230 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
231 if (!up) {
Jack Hea355e5e2017-08-22 16:06:54 -0700232 if (VDBG) Log.d(TAG, "Unbinding service...");
fredc0f420372012-04-12 00:02:00 -0700233 synchronized (mConnection) {
234 try {
235 mService = null;
236 mContext.unbindService(mConnection);
237 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700238 Log.e(TAG, "", re);
fredc0f420372012-04-12 00:02:00 -0700239 }
240 }
241 } else {
242 synchronized (mConnection) {
243 try {
244 if (mService == null) {
Jack Hea355e5e2017-08-22 16:06:54 -0700245 if (VDBG) Log.d(TAG, "Binding service...");
Dianne Hackborn221ea892013-08-04 16:50:16 -0700246 doBind();
fredc0f420372012-04-12 00:02:00 -0700247 }
248 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700249 Log.e(TAG, "", re);
fredc0f420372012-04-12 00:02:00 -0700250 }
251 }
252 }
253 }
Jack Hea355e5e2017-08-22 16:06:54 -0700254 };
fredc0f420372012-04-12 00:02:00 -0700255
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700256 /**
257 * Create a BluetoothInputDevice proxy object for interacting with the local
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800258 * Bluetooth Service which handles the InputDevice profile
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700259 */
Matthew Xiebf246ef2012-03-21 23:15:06 -0700260 /*package*/ BluetoothInputDevice(Context context, ServiceListener l) {
261 mContext = context;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800262 mServiceListener = l;
263 mAdapter = BluetoothAdapter.getDefaultAdapter();
fredc0f420372012-04-12 00:02:00 -0700264
265 IBluetoothManager mgr = mAdapter.getBluetoothManager();
266 if (mgr != null) {
267 try {
268 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
269 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700270 Log.e(TAG, "", e);
fredc0f420372012-04-12 00:02:00 -0700271 }
272 }
273
Dianne Hackborn221ea892013-08-04 16:50:16 -0700274 doBind();
275 }
276
277 boolean doBind() {
278 Intent intent = new Intent(IBluetoothInputDevice.class.getName());
279 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
280 intent.setComponent(comp);
Dianne Hackborn466ce962014-03-19 18:06:58 -0700281 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
282 android.os.Process.myUserHandle())) {
Dianne Hackborn221ea892013-08-04 16:50:16 -0700283 Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
284 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700285 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700286 return true;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700287 }
288
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800289 /*package*/ void close() {
Matthew Xie563e4142012-10-09 22:10:37 -0700290 if (VDBG) log("close()");
fredc0f420372012-04-12 00:02:00 -0700291 IBluetoothManager mgr = mAdapter.getBluetoothManager();
292 if (mgr != null) {
293 try {
294 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
295 } catch (Exception e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700296 Log.e(TAG, "", e);
fredc0f420372012-04-12 00:02:00 -0700297 }
298 }
299
300 synchronized (mConnection) {
301 if (mService != null) {
302 try {
303 mService = null;
304 mContext.unbindService(mConnection);
305 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700306 Log.e(TAG, "", re);
fredc0f420372012-04-12 00:02:00 -0700307 }
Jack Hea355e5e2017-08-22 16:06:54 -0700308 }
Matthew Xiebf246ef2012-03-21 23:15:06 -0700309 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800310 mServiceListener = null;
311 }
312
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800313 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700314 * Initiate connection to a profile of the remote bluetooth device.
315 *
316 * <p> The system supports connection to multiple input devices.
317 *
318 * <p> This API returns false in scenarios like the profile on the
319 * device is already connected or Bluetooth is not turned on.
320 * When this API returns true, it is guaranteed that
321 * connection state intent for the profile will be broadcasted with
322 * the state. Users can get the connection state of the profile
323 * from this intent.
324 *
325 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
326 * permission.
327 *
328 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700329 * @return false on immediate error, true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800330 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700331 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800332 public boolean connect(BluetoothDevice device) {
333 if (DBG) log("connect(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700334 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800335 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700336 return mService.connect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800337 } catch (RemoteException e) {
338 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
339 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700340 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700341 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800342 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700343 return false;
344 }
345
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800346 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700347 * Initiate disconnection from a profile
348 *
349 * <p> This API will return false in scenarios like the profile on the
350 * Bluetooth device is not in connected state etc. When this API returns,
351 * true, it is guaranteed that the connection state change
352 * intent will be broadcasted with the state. Users can get the
353 * disconnection state of the profile from this intent.
354 *
355 * <p> If the disconnection is initiated by a remote device, the state
356 * will transition from {@link #STATE_CONNECTED} to
357 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
358 * host (local) device the state will transition from
359 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
360 * state {@link #STATE_DISCONNECTED}. The transition to
361 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
362 * two scenarios.
363 *
364 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
365 * permission.
366 *
367 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700368 * @return false on immediate error, true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700369 * @hide
370 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800371 public boolean disconnect(BluetoothDevice device) {
372 if (DBG) log("disconnect(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700373 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800374 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700375 return mService.disconnect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800376 } catch (RemoteException e) {
377 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
378 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700379 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700380 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800381 if (mService == null) Log.w(TAG, "Proxy not attached to service");
382 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700383 }
384
385 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800386 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700387 */
Jack He2992cd02017-08-22 21:21:23 -0700388 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800389 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700390 if (VDBG) log("getConnectedDevices()");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800391 if (mService != null && isEnabled()) {
392 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700393 return mService.getConnectedDevices();
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800394 } catch (RemoteException e) {
395 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
396 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700397 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700398 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800399 if (mService == null) Log.w(TAG, "Proxy not attached to service");
400 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700401 }
402
403 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800404 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700405 */
Jack He2992cd02017-08-22 21:21:23 -0700406 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800407 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700408 if (VDBG) log("getDevicesMatchingStates()");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800409 if (mService != null && isEnabled()) {
410 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700411 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800412 } catch (RemoteException e) {
413 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
414 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700415 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700416 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800417 if (mService == null) Log.w(TAG, "Proxy not attached to service");
418 return new ArrayList<BluetoothDevice>();
419 }
420
421 /**
422 * {@inheritDoc}
423 */
Jack He2992cd02017-08-22 21:21:23 -0700424 @Override
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800425 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700426 if (VDBG) log("getState(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700427 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800428 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700429 return mService.getConnectionState(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800430 } catch (RemoteException e) {
431 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
432 return BluetoothProfile.STATE_DISCONNECTED;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700433 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800434 }
435 if (mService == null) Log.w(TAG, "Proxy not attached to service");
436 return BluetoothProfile.STATE_DISCONNECTED;
437 }
438
439 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700440 * Set priority of the profile
441 *
442 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700443 * Priority can be one of {@link #PRIORITY_ON} or
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700444 * {@link #PRIORITY_OFF},
445 *
446 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
447 * permission.
448 *
449 * @param device Paired bluetooth device
450 * @param priority
451 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800452 * @hide
453 */
454 public boolean setPriority(BluetoothDevice device, int priority) {
455 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700456 if (mService != null && isEnabled() && isValidDevice(device)) {
Jack He2992cd02017-08-22 21:21:23 -0700457 if (priority != BluetoothProfile.PRIORITY_OFF
458 && priority != BluetoothProfile.PRIORITY_ON) {
Jack Hea355e5e2017-08-22 16:06:54 -0700459 return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800460 }
461 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700462 return mService.setPriority(device, priority);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800463 } catch (RemoteException e) {
464 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
465 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700466 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800467 }
468 if (mService == null) Log.w(TAG, "Proxy not attached to service");
469 return false;
470 }
471
472 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700473 * Get the priority of the profile.
474 *
475 * <p> The priority can be any of:
476 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
477 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
478 *
479 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
480 *
481 * @param device Bluetooth device
482 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800483 * @hide
484 */
485 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700486 if (VDBG) log("getPriority(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700487 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800488 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700489 return mService.getPriority(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800490 } catch (RemoteException e) {
491 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
492 return BluetoothProfile.PRIORITY_OFF;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700493 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800494 }
495 if (mService == null) Log.w(TAG, "Proxy not attached to service");
496 return BluetoothProfile.PRIORITY_OFF;
497 }
498
Matthew Xie9b693992013-10-10 11:21:40 -0700499 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700500 public void onServiceConnected(ComponentName className, IBinder service) {
501 if (DBG) Log.d(TAG, "Proxy object connected");
Jeff Sharkey0a17db12016-11-04 11:23:46 -0600502 mService = IBluetoothInputDevice.Stub.asInterface(Binder.allowBlocking(service));
Matthew Xiebf246ef2012-03-21 23:15:06 -0700503
504 if (mServiceListener != null) {
Jack Hea355e5e2017-08-22 16:06:54 -0700505 mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE,
506 BluetoothInputDevice.this);
Matthew Xiebf246ef2012-03-21 23:15:06 -0700507 }
508 }
Jack Hea355e5e2017-08-22 16:06:54 -0700509
Matthew Xiebf246ef2012-03-21 23:15:06 -0700510 public void onServiceDisconnected(ComponentName className) {
511 if (DBG) Log.d(TAG, "Proxy object disconnected");
512 mService = null;
513 if (mServiceListener != null) {
514 mServiceListener.onServiceDisconnected(BluetoothProfile.INPUT_DEVICE);
515 }
516 }
517 };
518
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800519 private boolean isEnabled() {
Jack Hea355e5e2017-08-22 16:06:54 -0700520 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
521 return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800522 }
523
524 private boolean isValidDevice(BluetoothDevice device) {
Jack Hea355e5e2017-08-22 16:06:54 -0700525 if (device == null) return false;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800526
Jack Hea355e5e2017-08-22 16:06:54 -0700527 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
528 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700529 }
530
Priti Aghera349e62f2012-04-09 12:13:17 -0700531
532 /**
533 * Initiate virtual unplug for a HID input device.
534 *
535 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
536 *
537 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700538 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700539 * @hide
540 */
541 public boolean virtualUnplug(BluetoothDevice device) {
542 if (DBG) log("virtualUnplug(" + device + ")");
543 if (mService != null && isEnabled() && isValidDevice(device)) {
544 try {
545 return mService.virtualUnplug(device);
546 } catch (RemoteException e) {
547 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
548 return false;
549 }
550 }
551
552 if (mService == null) Log.w(TAG, "Proxy not attached to service");
553 return false;
554
555 }
556
557 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700558 * Send Get_Protocol_Mode command to the connected HID input device.
559 *
560 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
561 *
562 * @param device Remote Bluetooth Device
563 * @return false on immediate error, true otherwise
564 * @hide
565 */
Priti Aghera349e62f2012-04-09 12:13:17 -0700566 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700567 if (VDBG) log("getProtocolMode(" + device + ")");
Priti Aghera349e62f2012-04-09 12:13:17 -0700568 if (mService != null && isEnabled() && isValidDevice(device)) {
569 try {
570 return mService.getProtocolMode(device);
571 } catch (RemoteException e) {
572 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
573 return false;
574 }
575 }
576 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700577 return false;
Priti Aghera349e62f2012-04-09 12:13:17 -0700578 }
579
580 /**
581 * Send Set_Protocol_Mode command to the connected HID input device.
582 *
583 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
584 *
585 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700586 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700587 * @hide
588 */
589 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
590 if (DBG) log("setProtocolMode(" + device + ")");
591 if (mService != null && isEnabled() && isValidDevice(device)) {
592 try {
593 return mService.setProtocolMode(device, protocolMode);
594 } catch (RemoteException e) {
595 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
596 return false;
597 }
598 }
599 if (mService == null) Log.w(TAG, "Proxy not attached to service");
600 return false;
601 }
602
603 /**
604 * Send Get_Report command to the connected HID input device.
605 *
606 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
607 *
608 * @param device Remote Bluetooth Device
609 * @param reportType Report type
610 * @param reportId Report ID
611 * @param bufferSize Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700612 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700613 * @hide
614 */
Jack Hea355e5e2017-08-22 16:06:54 -0700615 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
616 int bufferSize) {
617 if (VDBG) {
618 log(
619 "getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
620 + "bufferSize=" + bufferSize);
621 }
Priti Aghera349e62f2012-04-09 12:13:17 -0700622 if (mService != null && isEnabled() && isValidDevice(device)) {
623 try {
624 return mService.getReport(device, reportType, reportId, bufferSize);
625 } catch (RemoteException e) {
626 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
627 return false;
628 }
629 }
630 if (mService == null) Log.w(TAG, "Proxy not attached to service");
631 return false;
632 }
633
634 /**
635 * Send Set_Report command to the connected HID input device.
636 *
637 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
638 *
639 * @param device Remote Bluetooth Device
640 * @param reportType Report type
641 * @param report Report receiving buffer size
Jack Hea355e5e2017-08-22 16:06:54 -0700642 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700643 * @hide
644 */
645 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800646 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700647 if (mService != null && isEnabled() && isValidDevice(device)) {
648 try {
649 return mService.setReport(device, reportType, report);
650 } catch (RemoteException e) {
651 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
652 return false;
653 }
654 }
655 if (mService == null) Log.w(TAG, "Proxy not attached to service");
656 return false;
657 }
658
659 /**
660 * Send Send_Data command to the connected HID input device.
661 *
662 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
663 *
664 * @param device Remote Bluetooth Device
Ang Li707fd392014-06-25 13:16:01 -0700665 * @param report Report to send
Jack Hea355e5e2017-08-22 16:06:54 -0700666 * @return false on immediate error, true otherwise
Priti Aghera349e62f2012-04-09 12:13:17 -0700667 * @hide
668 */
669 public boolean sendData(BluetoothDevice device, String report) {
670 if (DBG) log("sendData(" + device + "), report=" + report);
671 if (mService != null && isEnabled() && isValidDevice(device)) {
672 try {
673 return mService.sendData(device, report);
674 } catch (RemoteException e) {
675 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
676 return false;
677 }
678 }
679 if (mService == null) Log.w(TAG, "Proxy not attached to service");
680 return false;
681 }
Hemant Guptacef9ce32013-07-30 16:09:20 +0530682
683 /**
684 * Send Get_Idle_Time command to the connected HID input device.
685 *
686 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
687 *
688 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700689 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530690 * @hide
691 */
692 public boolean getIdleTime(BluetoothDevice device) {
693 if (DBG) log("getIdletime(" + device + ")");
694 if (mService != null && isEnabled() && isValidDevice(device)) {
695 try {
696 return mService.getIdleTime(device);
697 } catch (RemoteException e) {
698 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
699 return false;
700 }
701 }
702 if (mService == null) Log.w(TAG, "Proxy not attached to service");
703 return false;
704 }
705
706 /**
707 * Send Set_Idle_Time command to the connected HID input device.
708 *
709 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
710 *
711 * @param device Remote Bluetooth Device
712 * @param idleTime Idle time to be set on HID Device
Jack Hea355e5e2017-08-22 16:06:54 -0700713 * @return false on immediate error, true otherwise
Hemant Guptacef9ce32013-07-30 16:09:20 +0530714 * @hide
715 */
716 public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
717 if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
718 if (mService != null && isEnabled() && isValidDevice(device)) {
719 try {
720 return mService.setIdleTime(device, idleTime);
721 } catch (RemoteException e) {
722 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
723 return false;
724 }
725 }
726 if (mService == null) Log.w(TAG, "Proxy not attached to service");
727 return false;
728 }
729
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700730 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700731 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700732 }
733}