blob: c48b15d102461ae0043be453997c02a4a3f8ace6 [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;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070025import android.os.IBinder;
26import android.os.RemoteException;
Priti Aghera349e62f2012-04-09 12:13:17 -070027import android.os.ServiceManager;
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);
263 if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
264 Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
265 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700266 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700267 return true;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700268 }
269
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800270 /*package*/ void close() {
Matthew Xie563e4142012-10-09 22:10:37 -0700271 if (VDBG) log("close()");
fredc0f420372012-04-12 00:02:00 -0700272 IBluetoothManager mgr = mAdapter.getBluetoothManager();
273 if (mgr != null) {
274 try {
275 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
276 } catch (Exception e) {
277 Log.e(TAG,"",e);
278 }
279 }
280
281 synchronized (mConnection) {
282 if (mService != null) {
283 try {
284 mService = null;
285 mContext.unbindService(mConnection);
286 } catch (Exception re) {
287 Log.e(TAG,"",re);
288 }
289 }
Matthew Xiebf246ef2012-03-21 23:15:06 -0700290 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800291 mServiceListener = null;
292 }
293
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800294 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700295 * Initiate connection to a profile of the remote bluetooth device.
296 *
297 * <p> The system supports connection to multiple input devices.
298 *
299 * <p> This API returns false in scenarios like the profile on the
300 * device is already connected or Bluetooth is not turned on.
301 * When this API returns true, it is guaranteed that
302 * connection state intent for the profile will be broadcasted with
303 * the state. Users can get the connection state of the profile
304 * from this intent.
305 *
306 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
307 * permission.
308 *
309 * @param device Remote Bluetooth Device
310 * @return false on immediate error,
311 * true otherwise
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800312 * @hide
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700313 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800314 public boolean connect(BluetoothDevice device) {
315 if (DBG) log("connect(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700316 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800317 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700318 return mService.connect(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 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800324 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700325 return false;
326 }
327
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800328 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700329 * Initiate disconnection from a profile
330 *
331 * <p> This API will return false in scenarios like the profile on the
332 * Bluetooth device is not in connected state etc. When this API returns,
333 * true, it is guaranteed that the connection state change
334 * intent will be broadcasted with the state. Users can get the
335 * disconnection state of the profile from this intent.
336 *
337 * <p> If the disconnection is initiated by a remote device, the state
338 * will transition from {@link #STATE_CONNECTED} to
339 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
340 * host (local) device the state will transition from
341 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
342 * state {@link #STATE_DISCONNECTED}. The transition to
343 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
344 * two scenarios.
345 *
346 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
347 * permission.
348 *
349 * @param device Remote Bluetooth Device
350 * @return false on immediate error,
351 * true otherwise
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700352 * @hide
353 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800354 public boolean disconnect(BluetoothDevice device) {
355 if (DBG) log("disconnect(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700356 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800357 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700358 return mService.disconnect(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800359 } catch (RemoteException e) {
360 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
361 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700362 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700363 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800364 if (mService == null) Log.w(TAG, "Proxy not attached to service");
365 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700366 }
367
368 /**
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800369 * {@inheritDoc}
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700370 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800371 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700372 if (VDBG) log("getConnectedDevices()");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800373 if (mService != null && isEnabled()) {
374 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700375 return mService.getConnectedDevices();
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800376 } catch (RemoteException e) {
377 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
378 return new ArrayList<BluetoothDevice>();
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 new ArrayList<BluetoothDevice>();
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 */
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800388 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700389 if (VDBG) log("getDevicesMatchingStates()");
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800390 if (mService != null && isEnabled()) {
391 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700392 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800393 } catch (RemoteException e) {
394 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
395 return new ArrayList<BluetoothDevice>();
Matthew Xiebf246ef2012-03-21 23:15:06 -0700396 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700397 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800398 if (mService == null) Log.w(TAG, "Proxy not attached to service");
399 return new ArrayList<BluetoothDevice>();
400 }
401
402 /**
403 * {@inheritDoc}
404 */
405 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700406 if (VDBG) log("getState(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700407 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800408 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700409 return mService.getConnectionState(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800410 } catch (RemoteException e) {
411 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
412 return BluetoothProfile.STATE_DISCONNECTED;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700413 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800414 }
415 if (mService == null) Log.w(TAG, "Proxy not attached to service");
416 return BluetoothProfile.STATE_DISCONNECTED;
417 }
418
419 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700420 * Set priority of the profile
421 *
422 * <p> The device should already be paired.
423 * Priority can be one of {@link #PRIORITY_ON} or
424 * {@link #PRIORITY_OFF},
425 *
426 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
427 * permission.
428 *
429 * @param device Paired bluetooth device
430 * @param priority
431 * @return true if priority is set, false on error
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800432 * @hide
433 */
434 public boolean setPriority(BluetoothDevice device, int priority) {
435 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700436 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800437 if (priority != BluetoothProfile.PRIORITY_OFF &&
438 priority != BluetoothProfile.PRIORITY_ON) {
439 return false;
440 }
441 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700442 return mService.setPriority(device, priority);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800443 } catch (RemoteException e) {
444 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
445 return false;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700446 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800447 }
448 if (mService == null) Log.w(TAG, "Proxy not attached to service");
449 return false;
450 }
451
452 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700453 * Get the priority of the profile.
454 *
455 * <p> The priority can be any of:
456 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
457 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
458 *
459 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
460 *
461 * @param device Bluetooth device
462 * @return priority of the device
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800463 * @hide
464 */
465 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700466 if (VDBG) log("getPriority(" + device + ")");
Matthew Xiebf246ef2012-03-21 23:15:06 -0700467 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800468 try {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700469 return mService.getPriority(device);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800470 } catch (RemoteException e) {
471 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
472 return BluetoothProfile.PRIORITY_OFF;
Matthew Xiebf246ef2012-03-21 23:15:06 -0700473 }
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800474 }
475 if (mService == null) Log.w(TAG, "Proxy not attached to service");
476 return BluetoothProfile.PRIORITY_OFF;
477 }
478
Matthew Xie9b693992013-10-10 11:21:40 -0700479 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xiebf246ef2012-03-21 23:15:06 -0700480 public void onServiceConnected(ComponentName className, IBinder service) {
481 if (DBG) Log.d(TAG, "Proxy object connected");
482 mService = IBluetoothInputDevice.Stub.asInterface(service);
483
484 if (mServiceListener != null) {
485 mServiceListener.onServiceConnected(BluetoothProfile.INPUT_DEVICE, BluetoothInputDevice.this);
486 }
487 }
488 public void onServiceDisconnected(ComponentName className) {
489 if (DBG) Log.d(TAG, "Proxy object disconnected");
490 mService = null;
491 if (mServiceListener != null) {
492 mServiceListener.onServiceDisconnected(BluetoothProfile.INPUT_DEVICE);
493 }
494 }
495 };
496
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800497 private boolean isEnabled() {
498 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
499 return false;
500 }
501
502 private boolean isValidDevice(BluetoothDevice device) {
503 if (device == null) return false;
504
505 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
506 return false;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700507 }
508
Priti Aghera349e62f2012-04-09 12:13:17 -0700509
510 /**
511 * Initiate virtual unplug for a HID input device.
512 *
513 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
514 *
515 * @param device Remote Bluetooth Device
516 * @return false on immediate error,
517 * true otherwise
518 * @hide
519 */
520 public boolean virtualUnplug(BluetoothDevice device) {
521 if (DBG) log("virtualUnplug(" + device + ")");
522 if (mService != null && isEnabled() && isValidDevice(device)) {
523 try {
524 return mService.virtualUnplug(device);
525 } catch (RemoteException e) {
526 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
527 return false;
528 }
529 }
530
531 if (mService == null) Log.w(TAG, "Proxy not attached to service");
532 return false;
533
534 }
535
536 /**
537 * Send Get_Protocol_Mode command to the connected HID input device.
538 *
539 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
540 *
541 * @param device Remote Bluetooth Device
542 * @return false on immediate error,
543 *true otherwise
544 * @hide
545 */
546 public boolean getProtocolMode(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700547 if (VDBG) log("getProtocolMode(" + device + ")");
Priti Aghera349e62f2012-04-09 12:13:17 -0700548 if (mService != null && isEnabled() && isValidDevice(device)) {
549 try {
550 return mService.getProtocolMode(device);
551 } catch (RemoteException e) {
552 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
553 return false;
554 }
555 }
556 if (mService == null) Log.w(TAG, "Proxy not attached to service");
557 return false;
558 }
559
560 /**
561 * Send Set_Protocol_Mode command to the connected HID input device.
562 *
563 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
564 *
565 * @param device Remote Bluetooth Device
566 * @return false on immediate error,
567 * true otherwise
568 * @hide
569 */
570 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
571 if (DBG) log("setProtocolMode(" + device + ")");
572 if (mService != null && isEnabled() && isValidDevice(device)) {
573 try {
574 return mService.setProtocolMode(device, protocolMode);
575 } catch (RemoteException e) {
576 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
577 return false;
578 }
579 }
580 if (mService == null) Log.w(TAG, "Proxy not attached to service");
581 return false;
582 }
583
584 /**
585 * Send Get_Report command to the connected HID input device.
586 *
587 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
588 *
589 * @param device Remote Bluetooth Device
590 * @param reportType Report type
591 * @param reportId Report ID
592 * @param bufferSize Report receiving buffer size
593 * @return false on immediate error,
594 * true otherwise
595 * @hide
596 */
597 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
Matthew Xie563e4142012-10-09 22:10:37 -0700598 if (VDBG) log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId + "bufferSize=" + bufferSize);
Priti Aghera349e62f2012-04-09 12:13:17 -0700599 if (mService != null && isEnabled() && isValidDevice(device)) {
600 try {
601 return mService.getReport(device, reportType, reportId, bufferSize);
602 } catch (RemoteException e) {
603 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
604 return false;
605 }
606 }
607 if (mService == null) Log.w(TAG, "Proxy not attached to service");
608 return false;
609 }
610
611 /**
612 * Send Set_Report command to the connected HID input device.
613 *
614 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
615 *
616 * @param device Remote Bluetooth Device
617 * @param reportType Report type
618 * @param report Report receiving buffer size
619 * @return false on immediate error,
620 * true otherwise
621 * @hide
622 */
623 public boolean setReport(BluetoothDevice device, byte reportType, String report) {
Mike J. Chen8faffa42014-03-04 17:27:16 -0800624 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
Priti Aghera349e62f2012-04-09 12:13:17 -0700625 if (mService != null && isEnabled() && isValidDevice(device)) {
626 try {
627 return mService.setReport(device, reportType, report);
628 } catch (RemoteException e) {
629 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
630 return false;
631 }
632 }
633 if (mService == null) Log.w(TAG, "Proxy not attached to service");
634 return false;
635 }
636
637 /**
638 * Send Send_Data command to the connected HID input device.
639 *
640 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
641 *
642 * @param device Remote Bluetooth Device
643 * @param data Data to send
644 * @return false on immediate error,
645 * true otherwise
646 * @hide
647 */
648 public boolean sendData(BluetoothDevice device, String report) {
649 if (DBG) log("sendData(" + device + "), report=" + report);
650 if (mService != null && isEnabled() && isValidDevice(device)) {
651 try {
652 return mService.sendData(device, report);
653 } catch (RemoteException e) {
654 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
655 return false;
656 }
657 }
658 if (mService == null) Log.w(TAG, "Proxy not attached to service");
659 return false;
660 }
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700661 private static void log(String msg) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800662 Log.d(TAG, msg);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700663 }
664}