blob: e3288f3c7c88ef899c060d9f41e7785e4e5bab1d [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 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080038 *<p>BluetoothInputDevice is a proxy object for controlling the Bluetooth
39 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
40 * the BluetoothInputDevice proxy object.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070041 *
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080042 *<p>Each method is protected with its appropriate permission.
43 *@hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070044 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080045public final class BluetoothInputDevice implements BluetoothProfile {
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070046 private static final String TAG = "BluetoothInputDevice";
fredc0f420372012-04-12 00:02:00 -070047 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070048 private static final boolean VDBG = false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070049
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080050 /**
51 * Intent used to broadcast the change in connection state of the Input
52 * Device profile.
53 *
54 * <p>This intent will have 3 extras:
55 * <ul>
56 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
57 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
58 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
59 * </ul>
60 *
61 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
62 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
63 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
64 *
65 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
66 * receive.
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070067 */
68 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -080069 public static final String ACTION_CONNECTION_STATE_CHANGED =
70 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070071
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -080072 /**
Priti Aghera349e62f2012-04-09 12:13:17 -070073 * @hide
74 */
75 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
76 public static final String ACTION_PROTOCOL_MODE_CHANGED =
77 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
78
Mike J. Chend96d5cf2014-01-27 17:55:40 -080079 /**
80 * @hide
81 */
82 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chen8faffa42014-03-04 17:27:16 -080083 public static final String ACTION_HANDSHAKE =
84 "android.bluetooth.input.profile.action.HANDSHAKE";
85
86 /**
87 * @hide
88 */
89 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike J. Chend96d5cf2014-01-27 17:55:40 -080090 public static final String ACTION_REPORT =
91 "android.bluetooth.input.profile.action.REPORT";
Priti Aghera349e62f2012-04-09 12:13:17 -070092
93 /**
94 * @hide
95 */
96 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
97 public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
98 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
99
100
101 /**
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800102 * Return codes for the connect and disconnect Bluez / Dbus calls.
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800103 * @hide
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800104 */
105 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
106
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800107 /**
108 * @hide
109 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800110 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
111
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800112 /**
113 * @hide
114 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800115 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
116
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800117 /**
118 * @hide
119 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800120 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
121
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800122 /**
123 * @hide
124 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800125 public static final int INPUT_OPERATION_SUCCESS = 5004;
126
Priti Aghera349e62f2012-04-09 12:13:17 -0700127 /**
128 * @hide
129 */
130 public static final int PROTOCOL_REPORT_MODE = 0;
131
132 /**
133 * @hide
134 */
135 public static final int PROTOCOL_BOOT_MODE = 1;
136
137 /**
138 * @hide
139 */
140 public static final int PROTOCOL_UNSUPPORTED_MODE = 255;
141
142 /* int reportType, int reportType, int bufferSize */
143 /**
144 * @hide
145 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800146 public static final byte REPORT_TYPE_INPUT = 1;
Priti Aghera349e62f2012-04-09 12:13:17 -0700147
148 /**
149 * @hide
150 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800151 public static final byte REPORT_TYPE_OUTPUT = 2;
Priti Aghera349e62f2012-04-09 12:13:17 -0700152
153 /**
154 * @hide
155 */
Mike J. Chen1b47f7c2014-01-27 16:27:04 -0800156 public static final byte REPORT_TYPE_FEATURE = 3;
Priti Aghera349e62f2012-04-09 12:13:17 -0700157
158 /**
159 * @hide
160 */
161 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;
162
163 /**
164 * @hide
165 */
166 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;
167
168 /**
169 * @hide
170 */
171 public static final String EXTRA_PROTOCOL_MODE = "android.bluetooth.BluetoothInputDevice.extra.PROTOCOL_MODE";
172
173 /**
174 * @hide
175 */
176 public static final String EXTRA_REPORT_TYPE = "android.bluetooth.BluetoothInputDevice.extra.REPORT_TYPE";
177
178 /**
179 * @hide
180 */
181 public static final String EXTRA_REPORT_ID = "android.bluetooth.BluetoothInputDevice.extra.REPORT_ID";
182
183 /**
184 * @hide
185 */
186 public static final String EXTRA_REPORT_BUFFER_SIZE = "android.bluetooth.BluetoothInputDevice.extra.REPORT_BUFFER_SIZE";
187
188 /**
189 * @hide
190 */
191 public static final String EXTRA_REPORT = "android.bluetooth.BluetoothInputDevice.extra.REPORT";
192
193 /**
194 * @hide
195 */
Mike J. Chen8faffa42014-03-04 17:27:16 -0800196 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothInputDevice.extra.STATUS";
197
198 /**
199 * @hide
200 */
Priti Aghera349e62f2012-04-09 12:13:17 -0700201 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS";
202
Matthew Xiebf246ef2012-03-21 23:15:06 -0700203 private Context mContext;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800204 private ServiceListener mServiceListener;
205 private BluetoothAdapter mAdapter;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700206 private IBluetoothInputDevice mService;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700207
fredc0f420372012-04-12 00:02:00 -0700208 final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
209 new IBluetoothStateChangeCallback.Stub() {
210 public void onBluetoothStateChange(boolean up) {
211 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
212 if (!up) {
Matthew Xie563e4142012-10-09 22:10:37 -0700213 if (VDBG) Log.d(TAG,"Unbinding service...");
fredc0f420372012-04-12 00:02:00 -0700214 synchronized (mConnection) {
215 try {
216 mService = null;
217 mContext.unbindService(mConnection);
218 } catch (Exception re) {
219 Log.e(TAG,"",re);
220 }
221 }
222 } else {
223 synchronized (mConnection) {
224 try {
225 if (mService == null) {
Matthew Xie563e4142012-10-09 22:10:37 -0700226 if (VDBG) Log.d(TAG,"Binding service...");
Dianne Hackborn221ea892013-08-04 16:50:16 -0700227 doBind();
fredc0f420372012-04-12 00:02:00 -0700228 }
229 } catch (Exception re) {
230 Log.e(TAG,"",re);
231 }
232 }
233 }
234 }
235 };
236
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700237 /**
238 * Create a BluetoothInputDevice proxy object for interacting with the local
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800239 * Bluetooth Service which handles the InputDevice profile
240 *
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700241 */
Matthew Xiebf246ef2012-03-21 23:15:06 -0700242 /*package*/ BluetoothInputDevice(Context context, ServiceListener l) {
243 mContext = context;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800244 mServiceListener = l;
245 mAdapter = BluetoothAdapter.getDefaultAdapter();
fredc0f420372012-04-12 00:02:00 -0700246
247 IBluetoothManager mgr = mAdapter.getBluetoothManager();
248 if (mgr != null) {
249 try {
250 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
251 } catch (RemoteException e) {
252 Log.e(TAG,"",e);
253 }
254 }
255
Dianne Hackborn221ea892013-08-04 16:50:16 -0700256 doBind();
257 }
258
259 boolean doBind() {
260 Intent intent = new Intent(IBluetoothInputDevice.class.getName());
261 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
262 intent.setComponent(comp);
Dianne Hackborn466ce962014-03-19 18:06:58 -0700263 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
264 android.os.Process.myUserHandle())) {
Dianne Hackborn221ea892013-08-04 16:50:16 -0700265 Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
266 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700267 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700268 return true;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700269 }
270
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800271 /*package*/ void close() {
Matthew Xie563e4142012-10-09 22:10:37 -0700272 if (VDBG) log("close()");
fredc0f420372012-04-12 00:02:00 -0700273 IBluetoothManager mgr = mAdapter.getBluetoothManager();
274 if (mgr != null) {
275 try {
276 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
277 } catch (Exception e) {
278 Log.e(TAG,"",e);
279 }
280 }
281
282 synchronized (mConnection) {
283 if (mService != null) {
284 try {
285 mService = null;
286 mContext.unbindService(mConnection);
287 } catch (Exception re) {
288 Log.e(TAG,"",re);
289 }
290 }
Matthew Xiebf246ef2012-03-21 23:15:06 -0700291 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800292 mServiceListener = null;
293 }
294
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800295 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700296 * Initiate connection to a profile of the remote bluetooth device.
297 *
298 * <p> The system supports connection to multiple input devices.
299 *
300 * <p> This API returns false in scenarios like the profile on the
301 * device is already connected or Bluetooth is not turned on.
302 * When this API returns true, it is guaranteed that
303 * connection state intent for the profile will be broadcasted with
304 * the state. Users can get the connection state of the profile
305 * from this intent.
306 *
307 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
308 * permission.
309 *
310 * @param device Remote Bluetooth Device
311 * @return false on immediate error,
312 * true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800313 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700314 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800315 public boolean connect(BluetoothDevice device) {
316 if (DBG) log("connect(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700317 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800318 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700319 return mService.connect(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 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800325 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700326 return false;
327 }
328
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800329 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700330 * Initiate disconnection from a profile
331 *
332 * <p> This API will return false in scenarios like the profile on the
333 * Bluetooth device is not in connected state etc. When this API returns,
334 * true, it is guaranteed that the connection state change
335 * intent will be broadcasted with the state. Users can get the
336 * disconnection state of the profile from this intent.
337 *
338 * <p> If the disconnection is initiated by a remote device, the state
339 * will transition from {@link #STATE_CONNECTED} to
340 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
341 * host (local) device the state will transition from
342 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
343 * state {@link #STATE_DISCONNECTED}. The transition to
344 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
345 * two scenarios.
346 *
347 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
348 * permission.
349 *
350 * @param device Remote Bluetooth Device
351 * @return false on immediate error,
352 * true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700353 * @hide
354 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800355 public boolean disconnect(BluetoothDevice device) {
356 if (DBG) log("disconnect(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700357 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800358 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700359 return mService.disconnect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800360 } catch (RemoteException e) {
361 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
362 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700363 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700364 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800365 if (mService == null) Log.w(TAG, "Proxy not attached to service");
366 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700367 }
368
369 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800370 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700371 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800372 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700373 if (VDBG) log("getConnectedDevices()");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800374 if (mService != null && isEnabled()) {
375 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700376 return mService.getConnectedDevices();
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800377 } catch (RemoteException e) {
378 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
379 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700380 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700381 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800382 if (mService == null) Log.w(TAG, "Proxy not attached to service");
383 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700384 }
385
386 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800387 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700388 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800389 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700390 if (VDBG) log("getDevicesMatchingStates()");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800391 if (mService != null && isEnabled()) {
392 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700393 return mService.getDevicesMatchingConnectionStates(states);
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>();
401 }
402
403 /**
404 * {@inheritDoc}
405 */
406 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700407 if (VDBG) log("getState(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700408 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800409 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700410 return mService.getConnectionState(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800411 } catch (RemoteException e) {
412 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
413 return BluetoothProfile.STATE_DISCONNECTED;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700414 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800415 }
416 if (mService == null) Log.w(TAG, "Proxy not attached to service");
417 return BluetoothProfile.STATE_DISCONNECTED;
418 }
419
420 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700421 * Set priority of the profile
422 *
423 * <p> The device should already be paired.
424 * Priority can be one of {@link #PRIORITY_ON} or
425 * {@link #PRIORITY_OFF},
426 *
427 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
428 * permission.
429 *
430 * @param device Paired bluetooth device
431 * @param priority
432 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800433 * @hide
434 */
435 public boolean setPriority(BluetoothDevice device, int priority) {
436 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700437 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800438 if (priority != BluetoothProfile.PRIORITY_OFF &&
439 priority != BluetoothProfile.PRIORITY_ON) {
440 return false;
441 }
442 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700443 return mService.setPriority(device, priority);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800444 } catch (RemoteException e) {
445 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
446 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700447 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800448 }
449 if (mService == null) Log.w(TAG, "Proxy not attached to service");
450 return false;
451 }
452
453 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700454 * Get the priority of the profile.
455 *
456 * <p> The priority can be any of:
457 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
458 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
459 *
460 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
461 *
462 * @param device Bluetooth device
463 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800464 * @hide
465 */
466 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700467 if (VDBG) log("getPriority(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700468 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800469 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700470 return mService.getPriority(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800471 } catch (RemoteException e) {
472 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
473 return BluetoothProfile.PRIORITY_OFF;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700474 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800475 }
476 if (mService == null) Log.w(TAG, "Proxy not attached to service");
477 return BluetoothProfile.PRIORITY_OFF;
478 }
479
Matthew Xie9b693992013-10-10 11:21:40 -0700480 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700481 public void onServiceConnected(ComponentName className, IBinder service) {
482 if (DBG) Log.d(TAG, "Proxy object connected");
Jeff Sharkey0a17db12016-11-04 11:23:46 -0600483 mService = IBluetoothInputDevice.Stub.asInterface(Binder.allowBlocking(service));
Matthew Xiebf246ef2012-03-21 23:15:06 -0700484
485 if (mServiceListener != null) {
486 mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, BluetoothInputDevice.this);
487 }
488 }
489 public void onServiceDisconnected(ComponentName className) {
490 if (DBG) Log.d(TAG, "Proxy object disconnected");
491 mService = null;
492 if (mServiceListener != null) {
493 mServiceListener.onServiceDisconnected(BluetoothProfile.INPUT_DEVICE);
494 }
495 }
496 };
497
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800498 private boolean isEnabled() {
499 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
500 return false;
501 }
502
503 private boolean isValidDevice(BluetoothDevice device) {
504 if (device == null) return false;
505
506 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
507 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700508 }
509
Priti Aghera349e62f2012-04-09 12:13:17 -0700510
511 /**
512 * Initiate virtual unplug for a HID input device.
513 *
514 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
515 *
516 * @param device Remote Bluetooth Device
517 * @return false on immediate error,
518 * true otherwise
519 * @hide
520 */
521 public boolean virtualUnplug(BluetoothDevice device) {
522 if (DBG) log("virtualUnplug(" + device + ")");
523 if (mService != null && isEnabled() && isValidDevice(device)) {
524 try {
525 return mService.virtualUnplug(device);
526 } catch (RemoteException e) {
527 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
528 return false;
529 }
530 }
531
532 if (mService == null) Log.w(TAG, "Proxy not attached to service");
533 return false;
534
535 }
536
537 /**
538 * Send Get_Protocol_Mode command to the connected HID input device.
539 *
540 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
541 *
542 * @param device Remote Bluetooth Device
543 * @return false on immediate error,
544 *true otherwise
545 * @hide
546 */
547 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700548 if (VDBG) log("getProtocolMode(" + device + ")");
Priti Aghera349e62f2012-04-09 12:13:17 -0700549 if (mService != null && isEnabled() && isValidDevice(device)) {
550 try {
551 return mService.getProtocolMode(device);
552 } catch (RemoteException e) {
553 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
554 return false;
555 }
556 }
557 if (mService == null) Log.w(TAG, "Proxy not attached to service");
558 return false;
559 }
560
561 /**
562 * Send Set_Protocol_Mode command to the connected HID input device.
563 *
564 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
565 *
566 * @param device Remote Bluetooth Device
567 * @return false on immediate error,
568 * true otherwise
569 * @hide
570 */
571 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
572 if (DBG) log("setProtocolMode(" + device + ")");
573 if (mService != null && isEnabled() && isValidDevice(device)) {
574 try {
575 return mService.setProtocolMode(device, protocolMode);
576 } catch (RemoteException e) {
577 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
578 return false;
579 }
580 }
581 if (mService == null) Log.w(TAG, "Proxy not attached to service");
582 return false;
583 }
584
585 /**
586 * Send Get_Report command to the connected HID input device.
587 *
588 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
589 *
590 * @param device Remote Bluetooth Device
591 * @param reportType Report type
592 * @param reportId Report ID
593 * @param bufferSize Report receiving buffer size
594 * @return false on immediate error,
595 * true otherwise
596 * @hide
597 */
598 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
Matthew Xie563e4142012-10-09 22:10:37 -0700599 if (VDBG) log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId + "bufferSize=" + bufferSize);
Priti Aghera349e62f2012-04-09 12:13:17 -0700600 if (mService != null && isEnabled() && isValidDevice(device)) {
601 try {
602 return mService.getReport(device, reportType, reportId, bufferSize);
603 } catch (RemoteException e) {
604 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
605 return false;
606 }
607 }
608 if (mService == null) Log.w(TAG, "Proxy not attached to service");
609 return false;
610 }
611
612 /**
613 * Send Set_Report command to the connected HID input device.
614 *
615 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
616 *
617 * @param device Remote Bluetooth Device
618 * @param reportType Report type
619 * @param report Report receiving buffer size
620 * @return false on immediate error,
621 * true otherwise
622 * @hide
623 */
624 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800625 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700626 if (mService != null && isEnabled() && isValidDevice(device)) {
627 try {
628 return mService.setReport(device, reportType, report);
629 } catch (RemoteException e) {
630 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
631 return false;
632 }
633 }
634 if (mService == null) Log.w(TAG, "Proxy not attached to service");
635 return false;
636 }
637
638 /**
639 * Send Send_Data command to the connected HID input device.
640 *
641 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
642 *
643 * @param device Remote Bluetooth Device
Ang Li707fd392014-06-25 13:16:01 -0700644 * @param report Report to send
Priti Aghera349e62f2012-04-09 12:13:17 -0700645 * @return false on immediate error,
646 * true otherwise
647 * @hide
648 */
649 public boolean sendData(BluetoothDevice device, String report) {
650 if (DBG) log("sendData(" + device + "), report=" + report);
651 if (mService != null && isEnabled() && isValidDevice(device)) {
652 try {
653 return mService.sendData(device, report);
654 } catch (RemoteException e) {
655 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
656 return false;
657 }
658 }
659 if (mService == null) Log.w(TAG, "Proxy not attached to service");
660 return false;
661 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700662 private static void log(String msg) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800663 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700664 }
665}