1 /* 2 * Copyright (C) 2014 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 17 package com.android.tv.settings.accessories; 18 19 import android.app.Activity; 20 import android.app.FragmentManager; 21 import android.bluetooth.BluetoothDevice; 22 import android.content.Intent; 23 import android.hardware.hdmi.HdmiControlManager; 24 import android.hardware.hdmi.HdmiPlaybackClient; 25 import android.hardware.input.InputManager; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.os.Message; 29 import android.os.SystemClock; 30 import android.transition.TransitionManager; 31 import android.util.Log; 32 import android.view.KeyEvent; 33 import android.view.View; 34 import android.view.ViewGroup; 35 import android.view.WindowManager; 36 37 import androidx.annotation.NonNull; 38 39 import com.android.tv.settings.R; 40 41 import java.lang.ref.WeakReference; 42 import java.util.ArrayList; 43 import java.util.List; 44 45 /** 46 * Activity for detecting and adding (pairing) new bluetooth devices. 47 */ 48 public class AddAccessoryActivity extends Activity implements BluetoothDevicePairer.EventListener { 49 50 private static final boolean DEBUG = false; 51 private static final String TAG = "AddAccessoryActivity"; 52 53 private static final String ACTION_CONNECT_INPUT = 54 "com.google.android.intent.action.CONNECT_INPUT"; 55 56 private static final String INTENT_EXTRA_NO_INPUT_MODE = "no_input_mode"; 57 58 private static final String SAVED_STATE_PREFERENCE_FRAGMENT = 59 "AddAccessoryActivity.PREFERENCE_FRAGMENT"; 60 private static final String SAVED_STATE_CONTENT_FRAGMENT = 61 "AddAccessoryActivity.CONTENT_FRAGMENT"; 62 private static final String SAVED_STATE_BLUETOOTH_DEVICES = 63 "AddAccessoryActivity.BLUETOOTH_DEVICES"; 64 65 private static final String ADDRESS_NONE = "NONE"; 66 67 private static final int AUTOPAIR_COUNT = 10; 68 69 private static final int MSG_UPDATE_VIEW = 1; 70 private static final int MSG_REMOVE_CANCELED = 2; 71 private static final int MSG_PAIRING_COMPLETE = 3; 72 private static final int MSG_OP_TIMEOUT = 4; 73 private static final int MSG_RESTART = 5; 74 private static final int MSG_TRIGGER_SELECT_DOWN = 6; 75 private static final int MSG_TRIGGER_SELECT_UP = 7; 76 private static final int MSG_AUTOPAIR_TICK = 8; 77 private static final int MSG_START_AUTOPAIR_COUNTDOWN = 9; 78 79 private static final int CANCEL_MESSAGE_TIMEOUT = 3000; 80 private static final int DONE_MESSAGE_TIMEOUT = 3000; 81 private static final int PAIR_OPERATION_TIMEOUT = 120000; 82 private static final int CONNECT_OPERATION_TIMEOUT = 60000; 83 private static final int RESTART_DELAY = 3000; 84 private static final int LONG_PRESS_DURATION = 3000; 85 private static final int KEY_DOWN_TIME = 150; 86 private static final int TIME_TO_START_AUTOPAIR_COUNT = 5000; 87 private static final int EXIT_TIMEOUT_MILLIS = 90 * 1000; 88 89 private AddAccessoryPreferenceFragment mPreferenceFragment; 90 private AddAccessoryContentFragment mContentFragment; 91 92 // members related to Bluetooth pairing 93 private BluetoothDevicePairer mBluetoothPairer; 94 private int mPreviousStatus = BluetoothDevicePairer.STATUS_NONE; 95 private boolean mPairingSuccess = false; 96 private boolean mPairingBluetooth = false; 97 private List<BluetoothDevice> mBluetoothDevices; 98 private String mCancelledAddress = ADDRESS_NONE; 99 private String mCurrentTargetAddress = ADDRESS_NONE; 100 private String mCurrentTargetStatus = ""; 101 private boolean mPairingInBackground = false; 102 103 private boolean mDone = false; 104 105 private boolean mHwKeyDown; 106 private boolean mHwKeyDidSelect; 107 private boolean mNoInputMode; 108 109 // Internal message handler 110 private final MessageHandler mMsgHandler = new MessageHandler(); 111 112 private static class MessageHandler extends Handler { 113 114 private WeakReference<AddAccessoryActivity> mActivityRef = new WeakReference<>(null); 115 setActivity(AddAccessoryActivity activity)116 public void setActivity(AddAccessoryActivity activity) { 117 mActivityRef = new WeakReference<>(activity); 118 } 119 120 @Override handleMessage(Message msg)121 public void handleMessage(Message msg) { 122 final AddAccessoryActivity activity = mActivityRef.get(); 123 if (activity == null) { 124 return; 125 } 126 switch (msg.what) { 127 case MSG_UPDATE_VIEW: 128 activity.updateView(); 129 break; 130 case MSG_REMOVE_CANCELED: 131 activity.mCancelledAddress = ADDRESS_NONE; 132 activity.updateView(); 133 break; 134 case MSG_PAIRING_COMPLETE: 135 activity.finish(); 136 break; 137 case MSG_OP_TIMEOUT: 138 activity.handlePairingTimeout(); 139 break; 140 case MSG_RESTART: 141 if (activity.mBluetoothPairer != null) { 142 activity.mBluetoothPairer.start(); 143 activity.mBluetoothPairer.cancelPairing(); 144 } 145 break; 146 case MSG_TRIGGER_SELECT_DOWN: 147 activity.sendKeyEvent(KeyEvent.KEYCODE_DPAD_CENTER, true); 148 activity.mHwKeyDidSelect = true; 149 sendEmptyMessageDelayed(MSG_TRIGGER_SELECT_UP, KEY_DOWN_TIME); 150 activity.cancelPairingCountdown(); 151 break; 152 case MSG_TRIGGER_SELECT_UP: 153 activity.sendKeyEvent(KeyEvent.KEYCODE_DPAD_CENTER, false); 154 break; 155 case MSG_START_AUTOPAIR_COUNTDOWN: 156 activity.setPairingText( 157 activity.getString(R.string.accessories_autopair_msg, AUTOPAIR_COUNT)); 158 sendMessageDelayed(obtainMessage(MSG_AUTOPAIR_TICK, 159 AUTOPAIR_COUNT, 0, null), 1000); 160 break; 161 case MSG_AUTOPAIR_TICK: 162 int countToAutoPair = msg.arg1 - 1; 163 if (countToAutoPair <= 0) { 164 activity.setPairingText(null); 165 // AutoPair 166 activity.startAutoPairing(); 167 } else { 168 activity.setPairingText( 169 activity.getString(R.string.accessories_autopair_msg, 170 countToAutoPair)); 171 sendMessageDelayed(obtainMessage(MSG_AUTOPAIR_TICK, 172 countToAutoPair, 0, null), 1000); 173 } 174 break; 175 default: 176 super.handleMessage(msg); 177 } 178 } 179 } 180 181 private final Handler mAutoExitHandler = new Handler(); 182 183 private final Runnable mAutoExitRunnable = this::finish; 184 185 @Override onCreate(Bundle savedInstanceState)186 public void onCreate(Bundle savedInstanceState) { 187 super.onCreate(savedInstanceState); 188 189 setContentView(R.layout.lb_dialog_fragment); 190 191 mMsgHandler.setActivity(this); 192 193 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | 194 WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); 195 196 mNoInputMode = getIntent().getBooleanExtra(INTENT_EXTRA_NO_INPUT_MODE, false); 197 mHwKeyDown = false; 198 199 if (savedInstanceState == null) { 200 mBluetoothDevices = new ArrayList<>(); 201 } else { 202 mBluetoothDevices = 203 savedInstanceState.getParcelableArrayList(SAVED_STATE_BLUETOOTH_DEVICES); 204 } 205 206 final FragmentManager fm = getFragmentManager(); 207 if (savedInstanceState == null) { 208 mPreferenceFragment = AddAccessoryPreferenceFragment.newInstance(); 209 mContentFragment = AddAccessoryContentFragment.newInstance(); 210 fm.beginTransaction() 211 .add(R.id.action_fragment, mPreferenceFragment) 212 .add(R.id.content_fragment, mContentFragment) 213 .commit(); 214 } else { 215 mPreferenceFragment = (AddAccessoryPreferenceFragment) 216 fm.getFragment(savedInstanceState, 217 SAVED_STATE_PREFERENCE_FRAGMENT); 218 mContentFragment = (AddAccessoryContentFragment) 219 fm.getFragment(savedInstanceState, 220 SAVED_STATE_CONTENT_FRAGMENT); 221 } 222 sendCecOtpCommand((result) -> { 223 if (result == HdmiControlManager.RESULT_SUCCESS) { 224 Log.i(TAG, "One Touch Play successful"); 225 } else { 226 Log.i(TAG, "One Touch Play failed"); 227 } 228 }); 229 230 rearrangeViews(); 231 } 232 233 @Override onSaveInstanceState(@onNull Bundle outState)234 protected void onSaveInstanceState(@NonNull Bundle outState) { 235 super.onSaveInstanceState(outState); 236 getFragmentManager().putFragment(outState, 237 SAVED_STATE_PREFERENCE_FRAGMENT, mPreferenceFragment); 238 getFragmentManager().putFragment(outState, 239 SAVED_STATE_CONTENT_FRAGMENT, mContentFragment); 240 outState.putParcelableList(SAVED_STATE_BLUETOOTH_DEVICES, mBluetoothDevices); 241 } 242 243 @Override onStart()244 protected void onStart() { 245 super.onStart(); 246 247 if (DEBUG) { 248 Log.d(TAG, "onStart() mPairingInBackground = " + mPairingInBackground); 249 } 250 251 // Only do the following if we are not coming back to this activity from 252 // the Secure Pairing activity. 253 if (!mPairingInBackground) { 254 startBluetoothPairer(); 255 } 256 257 mPairingInBackground = false; 258 } 259 260 @Override onResume()261 public void onResume() { 262 super.onResume(); 263 if (mNoInputMode) { 264 // Start timer count down for exiting activity. 265 if (DEBUG) Log.d(TAG, "starting auto-exit timer"); 266 mAutoExitHandler.postDelayed(mAutoExitRunnable, EXIT_TIMEOUT_MILLIS); 267 } 268 } 269 270 @Override onPause()271 public void onPause() { 272 super.onPause(); 273 if (DEBUG) Log.d(TAG, "stopping auto-exit timer"); 274 mAutoExitHandler.removeCallbacks(mAutoExitRunnable); 275 } 276 277 278 @Override onStop()279 public void onStop() { 280 if (DEBUG) { 281 Log.d(TAG, "onStop()"); 282 } 283 if (!mPairingBluetooth) { 284 stopBluetoothPairer(); 285 mMsgHandler.removeCallbacksAndMessages(null); 286 } else { 287 // allow activity to remain in the background while we perform the 288 // BT Secure pairing. 289 mPairingInBackground = true; 290 } 291 292 super.onStop(); 293 } 294 295 @Override onDestroy()296 protected void onDestroy() { 297 super.onDestroy(); 298 stopBluetoothPairer(); 299 mMsgHandler.removeCallbacksAndMessages(null); 300 } 301 302 @Override onKeyUp(int keyCode, @NonNull KeyEvent event)303 public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { 304 if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME) { 305 if (mPairingBluetooth && !mDone) { 306 cancelBtPairing(); 307 } 308 } 309 return super.onKeyUp(keyCode, event); 310 } 311 312 @Override onNewIntent(Intent intent)313 public void onNewIntent(Intent intent) { 314 if (ACTION_CONNECT_INPUT.equals(intent.getAction()) && 315 (intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) == 0) { 316 317 KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 318 if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_PAIRING) { 319 if (event.getAction() == KeyEvent.ACTION_UP) { 320 onHwKeyEvent(false); 321 } else if (event.getAction() == KeyEvent.ACTION_DOWN) { 322 onHwKeyEvent(true); 323 } 324 } 325 } else { 326 setIntent(intent); 327 } 328 } 329 onActionClicked(String address)330 public void onActionClicked(String address) { 331 cancelPairingCountdown(); 332 if (!mDone) { 333 btDeviceClicked(address); 334 } 335 } 336 337 // Events related to a device HW key onHwKeyEvent(boolean keyDown)338 private void onHwKeyEvent(boolean keyDown) { 339 if (!mHwKeyDown) { 340 // HW key was in UP state before 341 if (keyDown) { 342 // Back key pressed down 343 mHwKeyDown = true; 344 mHwKeyDidSelect = false; 345 mMsgHandler.sendEmptyMessageDelayed(MSG_TRIGGER_SELECT_DOWN, LONG_PRESS_DURATION); 346 } 347 } else { 348 // HW key was in DOWN state before 349 if (!keyDown) { 350 // HW key released 351 mHwKeyDown = false; 352 mMsgHandler.removeMessages(MSG_TRIGGER_SELECT_DOWN); 353 if (!mHwKeyDidSelect) { 354 // key wasn't pressed long enough for selection, move selection 355 // to next item. 356 mPreferenceFragment.advanceSelection(); 357 } 358 mHwKeyDidSelect = false; 359 } 360 } 361 } 362 sendKeyEvent(int keyCode, boolean down)363 private void sendKeyEvent(int keyCode, boolean down) { 364 InputManager iMgr = (InputManager) getSystemService(INPUT_SERVICE); 365 if (iMgr != null) { 366 long time = SystemClock.uptimeMillis(); 367 KeyEvent evt = new KeyEvent(time, time, 368 down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, 369 keyCode, 0); 370 iMgr.injectInputEvent(evt, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 371 } 372 } 373 updateView()374 protected void updateView() { 375 if (mPreferenceFragment == null || isFinishing()) { 376 // view not yet ready, update will happen on first layout event 377 // or alternately we're done and don't need to do anything 378 return; 379 } 380 381 int prevNumDevices = mPreferenceFragment.getPreferenceScreen().getPreferenceCount(); 382 383 mPreferenceFragment.updateList(mBluetoothDevices, mCurrentTargetAddress, 384 mCurrentTargetStatus, mCancelledAddress); 385 386 if (mNoInputMode) { 387 if (DEBUG) Log.d(TAG, "stopping auto-exit timer"); 388 mAutoExitHandler.removeCallbacks(mAutoExitRunnable); 389 if (mBluetoothDevices.size() == 1 && prevNumDevices == 0) { 390 // first device added, start counter for autopair 391 mMsgHandler.sendEmptyMessageDelayed(MSG_START_AUTOPAIR_COUNTDOWN, 392 TIME_TO_START_AUTOPAIR_COUNT); 393 } else { 394 395 // Start timer count down for exiting activity. 396 if (DEBUG) Log.d(TAG, "starting auto-exit timer"); 397 mAutoExitHandler.postDelayed(mAutoExitRunnable, EXIT_TIMEOUT_MILLIS); 398 399 if (mBluetoothDevices.size() > 1) { 400 // More than one device found, cancel auto pair 401 cancelPairingCountdown(); 402 } 403 } 404 } 405 406 TransitionManager.beginDelayedTransition(findViewById(R.id.content_frame)); 407 408 rearrangeViews(); 409 } 410 rearrangeViews()411 private void rearrangeViews() { 412 final boolean empty = mBluetoothDevices.isEmpty(); 413 414 final View contentView = findViewById(R.id.content_fragment); 415 final ViewGroup.LayoutParams contentLayoutParams = contentView.getLayoutParams(); 416 contentLayoutParams.width = empty ? ViewGroup.LayoutParams.MATCH_PARENT : 417 getResources().getDimensionPixelSize(R.dimen.lb_content_section_width); 418 contentView.setLayoutParams(contentLayoutParams); 419 420 mContentFragment.setContentWidth(empty 421 ? getResources().getDimensionPixelSize(R.dimen.progress_fragment_content_width) 422 : getResources().getDimensionPixelSize(R.dimen.bt_progress_width_narrow)); 423 } 424 setPairingText(CharSequence text)425 private void setPairingText(CharSequence text) { 426 if (mContentFragment != null) { 427 mContentFragment.setExtraText(text); 428 } 429 } 430 cancelPairingCountdown()431 private void cancelPairingCountdown() { 432 // Cancel countdown 433 mMsgHandler.removeMessages(MSG_AUTOPAIR_TICK); 434 mMsgHandler.removeMessages(MSG_START_AUTOPAIR_COUNTDOWN); 435 setPairingText(null); 436 } 437 setTimeout(int timeout)438 private void setTimeout(int timeout) { 439 cancelTimeout(); 440 mMsgHandler.sendEmptyMessageDelayed(MSG_OP_TIMEOUT, timeout); 441 } 442 cancelTimeout()443 private void cancelTimeout() { 444 mMsgHandler.removeMessages(MSG_OP_TIMEOUT); 445 } 446 startAutoPairing()447 protected void startAutoPairing() { 448 if (mBluetoothDevices.size() > 0) { 449 onActionClicked(mBluetoothDevices.get(0).getAddress()); 450 } 451 } 452 btDeviceClicked(String clickedAddress)453 private void btDeviceClicked(String clickedAddress) { 454 if (mBluetoothPairer != null && !mBluetoothPairer.isInProgress()) { 455 if (mBluetoothPairer.getStatus() == BluetoothDevicePairer.STATUS_WAITING_TO_PAIR && 456 mBluetoothPairer.getTargetDevice() != null) { 457 cancelBtPairing(); 458 } else { 459 if (DEBUG) { 460 Log.d(TAG, "Looking for " + clickedAddress + 461 " in available devices to start pairing"); 462 } 463 for (BluetoothDevice target : mBluetoothDevices) { 464 if (target.getAddress().equalsIgnoreCase(clickedAddress)) { 465 if (DEBUG) { 466 Log.d(TAG, "Found it!"); 467 } 468 mCancelledAddress = ADDRESS_NONE; 469 setPairingBluetooth(true); 470 mBluetoothPairer.startPairing(target); 471 break; 472 } 473 } 474 } 475 } 476 } 477 cancelBtPairing()478 private void cancelBtPairing() { 479 // cancel current request to pair 480 if (mBluetoothPairer != null) { 481 if (mBluetoothPairer.getTargetDevice() != null) { 482 mCancelledAddress = mBluetoothPairer.getTargetDevice().getAddress(); 483 } else { 484 mCancelledAddress = ADDRESS_NONE; 485 } 486 mBluetoothPairer.cancelPairing(); 487 } 488 mPairingSuccess = false; 489 setPairingBluetooth(false); 490 mMsgHandler.sendEmptyMessageDelayed(MSG_REMOVE_CANCELED, 491 CANCEL_MESSAGE_TIMEOUT); 492 } 493 setPairingBluetooth(boolean pairing)494 private void setPairingBluetooth(boolean pairing) { 495 if (mPairingBluetooth != pairing) { 496 mPairingBluetooth = pairing; 497 } 498 } 499 startBluetoothPairer()500 private void startBluetoothPairer() { 501 stopBluetoothPairer(); 502 mBluetoothPairer = new BluetoothDevicePairer(this, this); 503 mBluetoothPairer.start(); 504 505 mBluetoothPairer.disableAutoPairing(); 506 507 mPairingSuccess = false; 508 statusChanged(); 509 } 510 stopBluetoothPairer()511 private void stopBluetoothPairer() { 512 if (mBluetoothPairer != null) { 513 mBluetoothPairer.setListener(null); 514 mBluetoothPairer.dispose(); 515 mBluetoothPairer = null; 516 } 517 } 518 getMessageForStatus(int status)519 private String getMessageForStatus(int status) { 520 final int msgId; 521 String msg; 522 523 switch (status) { 524 case BluetoothDevicePairer.STATUS_WAITING_TO_PAIR: 525 case BluetoothDevicePairer.STATUS_PAIRING: 526 msgId = R.string.accessory_state_pairing; 527 break; 528 case BluetoothDevicePairer.STATUS_CONNECTING: 529 msgId = R.string.accessory_state_connecting; 530 break; 531 case BluetoothDevicePairer.STATUS_ERROR: 532 msgId = R.string.accessory_state_error; 533 break; 534 default: 535 return ""; 536 } 537 538 msg = getString(msgId); 539 540 return msg; 541 } 542 543 @Override statusChanged()544 public void statusChanged() { 545 if (mBluetoothPairer == null) return; 546 547 int numDevices = mBluetoothPairer.getAvailableDevices().size(); 548 int status = mBluetoothPairer.getStatus(); 549 int oldStatus = mPreviousStatus; 550 mPreviousStatus = status; 551 552 String address = mBluetoothPairer.getTargetDevice() == null ? ADDRESS_NONE : 553 mBluetoothPairer.getTargetDevice().getAddress(); 554 555 if (DEBUG) { 556 String state = "?"; 557 switch (status) { 558 case BluetoothDevicePairer.STATUS_NONE: 559 state = "BluetoothDevicePairer.STATUS_NONE"; 560 break; 561 case BluetoothDevicePairer.STATUS_SCANNING: 562 state = "BluetoothDevicePairer.STATUS_SCANNING"; 563 break; 564 case BluetoothDevicePairer.STATUS_WAITING_TO_PAIR: 565 state = "BluetoothDevicePairer.STATUS_WAITING_TO_PAIR"; 566 break; 567 case BluetoothDevicePairer.STATUS_PAIRING: 568 state = "BluetoothDevicePairer.STATUS_PAIRING"; 569 break; 570 case BluetoothDevicePairer.STATUS_CONNECTING: 571 state = "BluetoothDevicePairer.STATUS_CONNECTING"; 572 break; 573 case BluetoothDevicePairer.STATUS_ERROR: 574 state = "BluetoothDevicePairer.STATUS_ERROR"; 575 break; 576 } 577 long time = mBluetoothPairer.getNextStageTime() - SystemClock.elapsedRealtime(); 578 Log.d(TAG, "Update received, number of devices:" + numDevices + " state: " + 579 state + " target device: " + address + " time to next event: " + time); 580 } 581 582 mBluetoothDevices.clear(); 583 mBluetoothDevices.addAll(mBluetoothPairer.getAvailableDevices()); 584 585 cancelTimeout(); 586 587 switch (status) { 588 case BluetoothDevicePairer.STATUS_NONE: 589 // if we just connected to something or just tried to connect 590 // to something, restart scanning just in case the user wants 591 // to pair another device. 592 if (oldStatus == BluetoothDevicePairer.STATUS_CONNECTING) { 593 if (mPairingSuccess) { 594 // Pairing complete 595 mCurrentTargetStatus = getString(R.string.accessory_state_paired); 596 mMsgHandler.sendEmptyMessage(MSG_UPDATE_VIEW); 597 mMsgHandler.sendEmptyMessageDelayed(MSG_PAIRING_COMPLETE, 598 DONE_MESSAGE_TIMEOUT); 599 mDone = true; 600 601 // Done, return here and just wait for the message 602 // to close the activity 603 return; 604 } 605 if (DEBUG) { 606 Log.d(TAG, "Invalidating and restarting."); 607 } 608 609 mBluetoothPairer.invalidateDevice(mBluetoothPairer.getTargetDevice()); 610 mBluetoothPairer.start(); 611 mBluetoothPairer.cancelPairing(); 612 setPairingBluetooth(false); 613 614 // if this looks like a successful connection run, reflect 615 // this in the UI, otherwise use the default message 616 if (!mPairingSuccess && BluetoothDevicePairer.hasValidInputDevice(this)) { 617 mPairingSuccess = true; 618 } 619 } 620 break; 621 case BluetoothDevicePairer.STATUS_SCANNING: 622 mPairingSuccess = false; 623 break; 624 case BluetoothDevicePairer.STATUS_WAITING_TO_PAIR: 625 break; 626 case BluetoothDevicePairer.STATUS_PAIRING: 627 // reset the pairing success value since this is now a new 628 // pairing run 629 mPairingSuccess = true; 630 setTimeout(PAIR_OPERATION_TIMEOUT); 631 break; 632 case BluetoothDevicePairer.STATUS_CONNECTING: 633 setTimeout(CONNECT_OPERATION_TIMEOUT); 634 break; 635 case BluetoothDevicePairer.STATUS_ERROR: 636 mPairingSuccess = false; 637 setPairingBluetooth(false); 638 if (mNoInputMode) { 639 clearDeviceList(); 640 } 641 break; 642 } 643 644 mCurrentTargetAddress = address; 645 mCurrentTargetStatus = getMessageForStatus(status); 646 mMsgHandler.sendEmptyMessage(MSG_UPDATE_VIEW); 647 } 648 clearDeviceList()649 private void clearDeviceList() { 650 mBluetoothDevices.clear(); 651 mBluetoothPairer.clearDeviceList(); 652 } 653 handlePairingTimeout()654 private void handlePairingTimeout() { 655 if (mPairingInBackground) { 656 finish(); 657 } else { 658 // Either Pairing or Connecting timeout out. 659 // Display error message and post delayed message to the scanning process. 660 mPairingSuccess = false; 661 if (mBluetoothPairer != null) { 662 mBluetoothPairer.cancelPairing(); 663 } 664 mCurrentTargetStatus = getString(R.string.accessory_state_error); 665 mMsgHandler.sendEmptyMessage(MSG_UPDATE_VIEW); 666 mMsgHandler.sendEmptyMessageDelayed(MSG_RESTART, RESTART_DELAY); 667 } 668 } 669 sendCecOtpCommand(HdmiPlaybackClient.OneTouchPlayCallback callback)670 private void sendCecOtpCommand(HdmiPlaybackClient.OneTouchPlayCallback callback) { 671 HdmiControlManager hdmiControlManager = 672 (HdmiControlManager) getSystemService(HDMI_CONTROL_SERVICE); 673 if (hdmiControlManager == null) { 674 Log.wtf(TAG, "no HdmiControlManager"); 675 return; 676 } 677 HdmiPlaybackClient client = hdmiControlManager.getPlaybackClient(); 678 if (client == null) { 679 if (DEBUG) Log.d(TAG, "no HdmiPlaybackClient"); 680 return; 681 } 682 client.oneTouchPlay(callback); 683 } 684 getBluetoothDevices()685 List<BluetoothDevice> getBluetoothDevices() { 686 return mBluetoothDevices; 687 } 688 getCurrentTargetAddress()689 String getCurrentTargetAddress() { 690 return mCurrentTargetAddress; 691 } 692 getCurrentTargetStatus()693 String getCurrentTargetStatus() { 694 return mCurrentTargetStatus; 695 } 696 getCancelledAddress()697 String getCancelledAddress() { 698 return mCancelledAddress; 699 } 700 } 701