blob: ea7270ddb4876a0718b140cf7c1ef79e5b3a799c [file] [log] [blame]
Michael Wright9209c9c2015-09-03 17:57:01 +01001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
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 com.android.systemui.keyboard;
18
Michael Wright9209c9c2015-09-03 17:57:01 +010019import android.bluetooth.BluetoothAdapter;
20import android.bluetooth.BluetoothDevice;
Michael Wright9209c9c2015-09-03 17:57:01 +010021import android.bluetooth.le.BluetoothLeScanner;
22import android.bluetooth.le.ScanCallback;
23import android.bluetooth.le.ScanFilter;
Dmitry Torokhov79f00cf2015-10-22 10:07:53 -070024import android.bluetooth.le.ScanRecord;
Michael Wright9209c9c2015-09-03 17:57:01 +010025import android.bluetooth.le.ScanResult;
26import android.bluetooth.le.ScanSettings;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.DialogInterface;
Michael Wright9209c9c2015-09-03 17:57:01 +010030import android.content.res.Configuration;
31import android.hardware.input.InputManager;
32import android.os.Handler;
33import android.os.HandlerThread;
34import android.os.Looper;
35import android.os.Message;
36import android.os.Process;
37import android.os.SystemClock;
38import android.os.UserHandle;
39import android.provider.Settings.Secure;
40import android.text.TextUtils;
41import android.util.Slog;
Michael Wright9209c9c2015-09-03 17:57:01 +010042
43import com.android.settingslib.bluetooth.BluetoothCallback;
44import com.android.settingslib.bluetooth.CachedBluetoothDevice;
45import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
46import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
47import com.android.settingslib.bluetooth.LocalBluetoothManager;
48import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
49import com.android.systemui.R;
50import com.android.systemui.SystemUI;
51
52import java.io.FileDescriptor;
53import java.io.PrintWriter;
54import java.util.Arrays;
55import java.util.Collection;
56import java.util.List;
Michael Wright9209c9c2015-09-03 17:57:01 +010057import java.util.Set;
58
59public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeChangedListener {
60 private static final String TAG = "KeyboardUI";
61 private static final boolean DEBUG = false;
62
63 // Give BT some time to start after SyUI comes up. This avoids flashing a dialog in the user's
64 // face because BT starts a little bit later in the boot process than SysUI and it takes some
65 // time for us to receive the signal that it's starting.
66 private static final long BLUETOOTH_START_DELAY_MILLIS = 10 * 1000;
67
Dmitry Torokhov365bf062015-11-05 17:40:32 -080068 // We will be scanning up to 30 seconds, after which we'll stop.
69 private static final long BLUETOOTH_SCAN_TIMEOUT_MILLIS = 30 * 1000;
70
Michael Wright9209c9c2015-09-03 17:57:01 +010071 private static final int STATE_NOT_ENABLED = -1;
72 private static final int STATE_UNKNOWN = 0;
73 private static final int STATE_WAITING_FOR_BOOT_COMPLETED = 1;
74 private static final int STATE_WAITING_FOR_TABLET_MODE_EXIT = 2;
75 private static final int STATE_WAITING_FOR_DEVICE_DISCOVERY = 3;
76 private static final int STATE_WAITING_FOR_BLUETOOTH = 4;
Dmitry Torokhov365bf062015-11-05 17:40:32 -080077 private static final int STATE_PAIRING = 5;
78 private static final int STATE_PAIRED = 6;
79 private static final int STATE_USER_CANCELLED = 7;
80 private static final int STATE_DEVICE_NOT_FOUND = 8;
Michael Wright9209c9c2015-09-03 17:57:01 +010081
82 private static final int MSG_INIT = 0;
83 private static final int MSG_ON_BOOT_COMPLETED = 1;
84 private static final int MSG_PROCESS_KEYBOARD_STATE = 2;
85 private static final int MSG_ENABLE_BLUETOOTH = 3;
86 private static final int MSG_ON_BLUETOOTH_STATE_CHANGED = 4;
87 private static final int MSG_ON_DEVICE_BOND_STATE_CHANGED = 5;
88 private static final int MSG_ON_BLUETOOTH_DEVICE_ADDED = 6;
89 private static final int MSG_ON_BLE_SCAN_FAILED = 7;
90 private static final int MSG_SHOW_BLUETOOTH_DIALOG = 8;
91 private static final int MSG_DISMISS_BLUETOOTH_DIALOG = 9;
Dmitry Torokhov365bf062015-11-05 17:40:32 -080092 private static final int MSG_BLE_ABORT_SCAN = 10;
Michael Wright9209c9c2015-09-03 17:57:01 +010093
94 private volatile KeyboardHandler mHandler;
95 private volatile KeyboardUIHandler mUIHandler;
96
97 protected volatile Context mContext;
98
99 private boolean mEnabled;
100 private String mKeyboardName;
101 private CachedBluetoothDeviceManager mCachedDeviceManager;
102 private LocalBluetoothAdapter mLocalBluetoothAdapter;
103 private LocalBluetoothProfileManager mProfileManager;
104 private boolean mBootCompleted;
105 private long mBootCompletedTime;
106
107 private int mInTabletMode = InputManager.SWITCH_STATE_UNKNOWN;
Dmitry Torokhov365bf062015-11-05 17:40:32 -0800108 private int mScanAttempt = 0;
Michael Wright9209c9c2015-09-03 17:57:01 +0100109 private ScanCallback mScanCallback;
110 private BluetoothDialog mDialog;
111
112 private int mState;
113
114 @Override
115 public void start() {
116 mContext = super.mContext;
117 HandlerThread thread = new HandlerThread("Keyboard", Process.THREAD_PRIORITY_BACKGROUND);
118 thread.start();
119 mHandler = new KeyboardHandler(thread.getLooper());
120 mHandler.sendEmptyMessage(MSG_INIT);
121 }
122
123 @Override
124 protected void onConfigurationChanged(Configuration newConfig) {
125 }
126
127 @Override
128 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
129 pw.println("KeyboardUI:");
130 pw.println(" mEnabled=" + mEnabled);
131 pw.println(" mBootCompleted=" + mEnabled);
132 pw.println(" mBootCompletedTime=" + mBootCompletedTime);
133 pw.println(" mKeyboardName=" + mKeyboardName);
134 pw.println(" mInTabletMode=" + mInTabletMode);
135 pw.println(" mState=" + stateToString(mState));
136 }
137
138 @Override
139 protected void onBootCompleted() {
140 mHandler.sendEmptyMessage(MSG_ON_BOOT_COMPLETED);
141 }
142
143 @Override
144 public void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
145 if (DEBUG) {
146 Slog.d(TAG, "onTabletModeChanged(" + whenNanos + ", " + inTabletMode + ")");
147 }
148
149 if (inTabletMode && mInTabletMode != InputManager.SWITCH_STATE_ON
150 || !inTabletMode && mInTabletMode != InputManager.SWITCH_STATE_OFF) {
151 mInTabletMode = inTabletMode ?
152 InputManager.SWITCH_STATE_ON : InputManager.SWITCH_STATE_OFF;
153 processKeyboardState();
154 }
155 }
156
157 // Shoud only be called on the handler thread
158 private void init() {
159 Context context = mContext;
160 mKeyboardName =
161 context.getString(com.android.internal.R.string.config_packagedKeyboardName);
162 if (TextUtils.isEmpty(mKeyboardName)) {
163 if (DEBUG) {
164 Slog.d(TAG, "No packaged keyboard name given.");
165 }
166 return;
167 }
168
169 LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(context, null);
170 if (bluetoothManager == null) {
171 if (DEBUG) {
172 Slog.e(TAG, "Failed to retrieve LocalBluetoothManager instance");
173 }
174 return;
175 }
176 mEnabled = true;
177 mCachedDeviceManager = bluetoothManager.getCachedDeviceManager();
178 mLocalBluetoothAdapter = bluetoothManager.getBluetoothAdapter();
179 mProfileManager = bluetoothManager.getProfileManager();
180 bluetoothManager.getEventManager().registerCallback(new BluetoothCallbackHandler());
181
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800182 InputManager im = context.getSystemService(InputManager.class);
Michael Wright9209c9c2015-09-03 17:57:01 +0100183 im.registerOnTabletModeChangedListener(this, mHandler);
184 mInTabletMode = im.isInTabletMode();
185
186 processKeyboardState();
187 mUIHandler = new KeyboardUIHandler();
188 }
189
190 // Should only be called on the handler thread
191 private void processKeyboardState() {
192 mHandler.removeMessages(MSG_PROCESS_KEYBOARD_STATE);
193
194 if (!mEnabled) {
195 mState = STATE_NOT_ENABLED;
196 return;
197 }
198
199 if (!mBootCompleted) {
200 mState = STATE_WAITING_FOR_BOOT_COMPLETED;
201 return;
202 }
203
204 if (mInTabletMode != InputManager.SWITCH_STATE_OFF) {
205 if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY) {
206 stopScanning();
207 }
208 mState = STATE_WAITING_FOR_TABLET_MODE_EXIT;
209 return;
210 }
211
212 final int btState = mLocalBluetoothAdapter.getState();
213 if (btState == BluetoothAdapter.STATE_TURNING_ON || btState == BluetoothAdapter.STATE_ON
214 && mState == STATE_WAITING_FOR_BLUETOOTH) {
215 // If we're waiting for bluetooth but it has come on in the meantime, or is coming
216 // on, just dismiss the dialog. This frequently happens during device startup.
217 mUIHandler.sendEmptyMessage(MSG_DISMISS_BLUETOOTH_DIALOG);
218 }
219
220 if (btState == BluetoothAdapter.STATE_TURNING_ON) {
221 mState = STATE_WAITING_FOR_BLUETOOTH;
222 // Wait for bluetooth to fully come on.
223 return;
224 }
225
226 if (btState != BluetoothAdapter.STATE_ON) {
227 mState = STATE_WAITING_FOR_BLUETOOTH;
228 showBluetoothDialog();
229 return;
230 }
231
232 CachedBluetoothDevice device = getPairedKeyboard();
Dmitry Torokhov79f00cf2015-10-22 10:07:53 -0700233 if (mState == STATE_WAITING_FOR_TABLET_MODE_EXIT || mState == STATE_WAITING_FOR_BLUETOOTH) {
234 if (device != null) {
235 // If we're just coming out of tablet mode or BT just turned on,
236 // then we want to go ahead and automatically connect to the
237 // keyboard. We want to avoid this in other cases because we might
238 // be spuriously called after the user has manually disconnected
239 // the keyboard, meaning we shouldn't try to automtically connect
240 // it again.
241 mState = STATE_PAIRED;
242 device.connect(false);
243 return;
244 }
245 mCachedDeviceManager.clearNonBondedDevices();
Michael Wright9209c9c2015-09-03 17:57:01 +0100246 }
247
248 device = getDiscoveredKeyboard();
249 if (device != null) {
250 mState = STATE_PAIRING;
251 device.startPairing();
252 } else {
253 mState = STATE_WAITING_FOR_DEVICE_DISCOVERY;
254 startScanning();
255 }
256 }
257
258 // Should only be called on the handler thread
259 public void onBootCompletedInternal() {
260 mBootCompleted = true;
261 mBootCompletedTime = SystemClock.uptimeMillis();
262 if (mState == STATE_WAITING_FOR_BOOT_COMPLETED) {
263 processKeyboardState();
264 }
265 }
266
267 // Should only be called on the handler thread
268 private void showBluetoothDialog() {
269 if (isUserSetupComplete()) {
270 long now = SystemClock.uptimeMillis();
271 long earliestDialogTime = mBootCompletedTime + BLUETOOTH_START_DELAY_MILLIS;
272 if (earliestDialogTime < now) {
273 mUIHandler.sendEmptyMessage(MSG_SHOW_BLUETOOTH_DIALOG);
274 } else {
275 mHandler.sendEmptyMessageAtTime(MSG_PROCESS_KEYBOARD_STATE, earliestDialogTime);
276 }
277 } else {
278 // If we're in setup wizard and the keyboard is docked, just automatically enable BT.
279 mLocalBluetoothAdapter.enable();
280 }
281 }
282
283 private boolean isUserSetupComplete() {
284 ContentResolver resolver = mContext.getContentResolver();
285 return Secure.getIntForUser(
286 resolver, Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
287 }
288
289 private CachedBluetoothDevice getPairedKeyboard() {
290 Set<BluetoothDevice> devices = mLocalBluetoothAdapter.getBondedDevices();
291 for (BluetoothDevice d : devices) {
292 if (mKeyboardName.equals(d.getName())) {
293 return getCachedBluetoothDevice(d);
294 }
295 }
296 return null;
297 }
298
299 private CachedBluetoothDevice getDiscoveredKeyboard() {
300 Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
301 for (CachedBluetoothDevice d : devices) {
302 if (d.getName().equals(mKeyboardName)) {
303 return d;
304 }
305 }
306 return null;
307 }
308
309
310 private CachedBluetoothDevice getCachedBluetoothDevice(BluetoothDevice d) {
311 CachedBluetoothDevice cachedDevice = mCachedDeviceManager.findDevice(d);
312 if (cachedDevice == null) {
313 cachedDevice = mCachedDeviceManager.addDevice(
314 mLocalBluetoothAdapter, mProfileManager, d);
315 }
316 return cachedDevice;
317 }
318
319 private void startScanning() {
320 BluetoothLeScanner scanner = mLocalBluetoothAdapter.getBluetoothLeScanner();
321 ScanFilter filter = (new ScanFilter.Builder()).setDeviceName(mKeyboardName).build();
322 ScanSettings settings = (new ScanSettings.Builder())
323 .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
324 .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
325 .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
326 .setReportDelay(0)
327 .build();
328 mScanCallback = new KeyboardScanCallback();
329 scanner.startScan(Arrays.asList(filter), settings, mScanCallback);
Dmitry Torokhov365bf062015-11-05 17:40:32 -0800330
331 Message abortMsg = mHandler.obtainMessage(MSG_BLE_ABORT_SCAN, ++mScanAttempt, 0);
332 mHandler.sendMessageDelayed(abortMsg, BLUETOOTH_SCAN_TIMEOUT_MILLIS);
Michael Wright9209c9c2015-09-03 17:57:01 +0100333 }
334
335 private void stopScanning() {
336 if (mScanCallback != null) {
337 mLocalBluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
338 mScanCallback = null;
339 }
340 }
341
342 // Should only be called on the handler thread
Dmitry Torokhov365bf062015-11-05 17:40:32 -0800343 private void bleAbortScanInternal(int scanAttempt) {
344 if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && scanAttempt == mScanAttempt) {
345 if (DEBUG) {
346 Slog.d(TAG, "Bluetooth scan timed out");
347 }
348 stopScanning();
349 // FIXME: should we also try shutting off bluetooth if we enabled
350 // it in the first place?
351 mState = STATE_DEVICE_NOT_FOUND;
352 }
353 }
354
355 // Should only be called on the handler thread
Michael Wright9209c9c2015-09-03 17:57:01 +0100356 private void onDeviceAddedInternal(CachedBluetoothDevice d) {
357 if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && d.getName().equals(mKeyboardName)) {
358 stopScanning();
359 d.startPairing();
360 mState = STATE_PAIRING;
361 }
362 }
363
364 // Should only be called on the handler thread
365 private void onBluetoothStateChangedInternal(int bluetoothState) {
366 if (bluetoothState == BluetoothAdapter.STATE_ON && mState == STATE_WAITING_FOR_BLUETOOTH) {
367 processKeyboardState();
368 }
369 }
370
371 // Should only be called on the handler thread
372 private void onDeviceBondStateChangedInternal(CachedBluetoothDevice d, int bondState) {
373 if (d.getName().equals(mKeyboardName) && bondState == BluetoothDevice.BOND_BONDED) {
374 // We don't need to manually connect to the device here because it will automatically
375 // try to connect after it has been paired.
376 mState = STATE_PAIRED;
377 }
378 }
379
380 // Should only be called on the handler thread
381 private void onBleScanFailedInternal() {
382 mScanCallback = null;
383 if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY) {
384 mState = STATE_DEVICE_NOT_FOUND;
385 }
386 }
387
388 private final class KeyboardUIHandler extends Handler {
389 public KeyboardUIHandler() {
390 super(Looper.getMainLooper(), null, true /*async*/);
391 }
392 @Override
393 public void handleMessage(Message msg) {
394 switch(msg.what) {
395 case MSG_SHOW_BLUETOOTH_DIALOG: {
396 DialogInterface.OnClickListener listener = new BluetoothDialogClickListener();
397 mDialog = new BluetoothDialog(mContext);
398 mDialog.setTitle(R.string.enable_bluetooth_title);
399 mDialog.setMessage(R.string.enable_bluetooth_message);
400 mDialog.setPositiveButton(R.string.enable_bluetooth_confirmation_ok, listener);
401 mDialog.setNegativeButton(android.R.string.cancel, listener);
402 mDialog.show();
403 break;
404 }
405 case MSG_DISMISS_BLUETOOTH_DIALOG: {
406 if (mDialog != null) {
407 mDialog.dismiss();
408 mDialog = null;
409 }
410 break;
411 }
412 }
413 }
414 }
415
416 private final class KeyboardHandler extends Handler {
417 public KeyboardHandler(Looper looper) {
418 super(looper, null, true /*async*/);
419 }
420
421 @Override
422 public void handleMessage(Message msg) {
423 switch(msg.what) {
424 case MSG_INIT: {
425 init();
426 break;
427 }
428 case MSG_ON_BOOT_COMPLETED: {
429 onBootCompletedInternal();
430 break;
431 }
432 case MSG_PROCESS_KEYBOARD_STATE: {
433 processKeyboardState();
434 break;
435 }
436 case MSG_ENABLE_BLUETOOTH: {
437 boolean enable = msg.arg1 == 1;
438 if (enable) {
439 mLocalBluetoothAdapter.enable();
440 } else {
441 mState = STATE_USER_CANCELLED;
442 }
Dmitry Torokhov365bf062015-11-05 17:40:32 -0800443 break;
444 }
445 case MSG_BLE_ABORT_SCAN: {
446 int scanAttempt = msg.arg1;
447 bleAbortScanInternal(scanAttempt);
448 break;
Michael Wright9209c9c2015-09-03 17:57:01 +0100449 }
450 case MSG_ON_BLUETOOTH_STATE_CHANGED: {
451 int bluetoothState = msg.arg1;
452 onBluetoothStateChangedInternal(bluetoothState);
453 break;
454 }
455 case MSG_ON_DEVICE_BOND_STATE_CHANGED: {
456 CachedBluetoothDevice d = (CachedBluetoothDevice)msg.obj;
457 int bondState = msg.arg1;
458 onDeviceBondStateChangedInternal(d, bondState);
459 break;
460 }
461 case MSG_ON_BLUETOOTH_DEVICE_ADDED: {
462 BluetoothDevice d = (BluetoothDevice)msg.obj;
463 CachedBluetoothDevice cachedDevice = getCachedBluetoothDevice(d);
464 onDeviceAddedInternal(cachedDevice);
465 break;
466
467 }
468 case MSG_ON_BLE_SCAN_FAILED: {
469 onBleScanFailedInternal();
470 break;
471 }
472 }
473 }
474 }
475
476 private final class BluetoothDialogClickListener implements DialogInterface.OnClickListener {
477 @Override
478 public void onClick(DialogInterface dialog, int which) {
479 int enable = DialogInterface.BUTTON_POSITIVE == which ? 1 : 0;
480 mHandler.obtainMessage(MSG_ENABLE_BLUETOOTH, enable, 0).sendToTarget();
481 mDialog = null;
482 }
483 }
484
485 private final class KeyboardScanCallback extends ScanCallback {
Dmitry Torokhov79f00cf2015-10-22 10:07:53 -0700486
487 private boolean isDeviceDiscoverable(ScanResult result) {
488 final ScanRecord scanRecord = result.getScanRecord();
489 final int flags = scanRecord.getAdvertiseFlags();
490 final int BT_DISCOVERABLE_MASK = 0x03;
491
492 return (flags & BT_DISCOVERABLE_MASK) != 0;
493 }
494
Michael Wright9209c9c2015-09-03 17:57:01 +0100495 @Override
496 public void onBatchScanResults(List<ScanResult> results) {
497 if (DEBUG) {
498 Slog.d(TAG, "onBatchScanResults(" + results.size() + ")");
499 }
Dmitry Torokhov79f00cf2015-10-22 10:07:53 -0700500
501 BluetoothDevice bestDevice = null;
502 int bestRssi = Integer.MIN_VALUE;
503
504 for (ScanResult result : results) {
505 if (DEBUG) {
506 Slog.d(TAG, "onBatchScanResults: considering " + result);
Michael Wright9209c9c2015-09-03 17:57:01 +0100507 }
Dmitry Torokhov79f00cf2015-10-22 10:07:53 -0700508
509 if (isDeviceDiscoverable(result) && result.getRssi() > bestRssi) {
510 bestDevice = result.getDevice();
511 bestRssi = result.getRssi();
512 }
513 }
514
515 if (bestDevice != null) {
Michael Wright9209c9c2015-09-03 17:57:01 +0100516 mHandler.obtainMessage(MSG_ON_BLUETOOTH_DEVICE_ADDED, bestDevice).sendToTarget();
517 }
518 }
519
520 @Override
521 public void onScanFailed(int errorCode) {
522 if (DEBUG) {
523 Slog.d(TAG, "onScanFailed(" + errorCode + ")");
524 }
525 mHandler.obtainMessage(MSG_ON_BLE_SCAN_FAILED).sendToTarget();
526 }
527
528 @Override
529 public void onScanResult(int callbackType, ScanResult result) {
530 if (DEBUG) {
531 Slog.d(TAG, "onScanResult(" + callbackType + ", " + result + ")");
532 }
Dmitry Torokhov79f00cf2015-10-22 10:07:53 -0700533
534 if (isDeviceDiscoverable(result)) {
535 mHandler.obtainMessage(MSG_ON_BLUETOOTH_DEVICE_ADDED,
536 result.getDevice()).sendToTarget();
537 } else if (DEBUG) {
538 Slog.d(TAG, "onScanResult: device " + result.getDevice() +
539 " is not discoverable, ignoring");
540 }
Michael Wright9209c9c2015-09-03 17:57:01 +0100541 }
542 }
543
544 private final class BluetoothCallbackHandler implements BluetoothCallback {
545 @Override
546 public void onBluetoothStateChanged(int bluetoothState) {
547 mHandler.obtainMessage(MSG_ON_BLUETOOTH_STATE_CHANGED,
548 bluetoothState, 0).sendToTarget();
549 }
550
551 @Override
552 public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
553 mHandler.obtainMessage(MSG_ON_DEVICE_BOND_STATE_CHANGED,
554 bondState, 0, cachedDevice).sendToTarget();
555 }
556
557 @Override
558 public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { }
559 @Override
560 public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { }
561 @Override
562 public void onScanningStateChanged(boolean started) { }
563 @Override
564 public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
565 }
566
567 private static String stateToString(int state) {
568 switch (state) {
569 case STATE_NOT_ENABLED:
570 return "STATE_NOT_ENABLED";
571 case STATE_WAITING_FOR_BOOT_COMPLETED:
572 return "STATE_WAITING_FOR_BOOT_COMPLETED";
573 case STATE_WAITING_FOR_TABLET_MODE_EXIT:
574 return "STATE_WAITING_FOR_TABLET_MODE_EXIT";
575 case STATE_WAITING_FOR_DEVICE_DISCOVERY:
576 return "STATE_WAITING_FOR_DEVICE_DISCOVERY";
577 case STATE_WAITING_FOR_BLUETOOTH:
578 return "STATE_WAITING_FOR_BLUETOOTH";
Michael Wright9209c9c2015-09-03 17:57:01 +0100579 case STATE_PAIRING:
580 return "STATE_PAIRING";
581 case STATE_PAIRED:
582 return "STATE_PAIRED";
583 case STATE_USER_CANCELLED:
584 return "STATE_USER_CANCELLED";
585 case STATE_DEVICE_NOT_FOUND:
586 return "STATE_DEVICE_NOT_FOUND";
587 case STATE_UNKNOWN:
588 default:
589 return "STATE_UNKNOWN";
590 }
591 }
592}