1 /* 2 * Copyright (C) 2017 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.car.settings.bluetooth; 18 19 import android.annotation.Nullable; 20 import android.bluetooth.BluetoothDevice; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.os.Bundle; 26 27 import androidx.annotation.VisibleForTesting; 28 import androidx.fragment.app.FragmentActivity; 29 30 import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; 31 32 /** 33 * BluetoothPairingDialog asks the user to enter a PIN / Passkey / simple confirmation 34 * for pairing with a remote Bluetooth device. It is an activity that appears as a dialog. 35 */ 36 public class BluetoothPairingDialog extends FragmentActivity { 37 public static final String FRAGMENT_TAG = "bluetooth.pairing.fragment"; 38 39 private BluetoothPairingController mBluetoothPairingController; 40 private boolean mReceiverRegistered = false; 41 42 /** 43 * Dismiss the dialog if the bond state changes to bonded or none, 44 * or if pairing was canceled for {@link BluetoothPairingController#mDevice}. 45 */ 46 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 47 @Override 48 public void onReceive(Context context, Intent intent) { 49 String action = intent.getAction(); 50 if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) { 51 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 52 BluetoothDevice.ERROR); 53 if (bondState == BluetoothDevice.BOND_BONDED || 54 bondState == BluetoothDevice.BOND_NONE) { 55 dismiss(); 56 } 57 } else if (BluetoothDevice.ACTION_PAIRING_CANCEL.equals(action)) { 58 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 59 if (device == null || mBluetoothPairingController.deviceEquals(device)) { 60 dismiss(); 61 } 62 } 63 } 64 }; 65 66 @Override onCreate(@ullable Bundle savedInstanceState)67 protected void onCreate(@Nullable Bundle savedInstanceState) { 68 super.onCreate(savedInstanceState); 69 70 getLifecycle().addObserver(new HideNonSystemOverlayMixin(this)); 71 72 Intent intent = getIntent(); 73 mBluetoothPairingController = new BluetoothPairingController(intent, this); 74 // build the dialog fragment 75 boolean fragmentFound = true; 76 // check if the fragment has been preloaded 77 BluetoothPairingDialogFragment bluetoothFragment = 78 (BluetoothPairingDialogFragment) getSupportFragmentManager().findFragmentByTag( 79 FRAGMENT_TAG); 80 // dismiss the fragment if it is already used 81 if (bluetoothFragment != null && (bluetoothFragment.isPairingControllerSet() 82 || bluetoothFragment.isPairingDialogActivitySet())) { 83 bluetoothFragment.dismiss(); 84 bluetoothFragment = null; 85 } 86 // build a new fragment if it is null 87 if (bluetoothFragment == null) { 88 fragmentFound = false; 89 bluetoothFragment = new BluetoothPairingDialogFragment(); 90 } 91 bluetoothFragment.setPairingController(mBluetoothPairingController); 92 bluetoothFragment.setPairingDialogActivity(this); 93 // pass the fragment to the manager when it is created from scratch 94 if (!fragmentFound) { 95 bluetoothFragment.show(getSupportFragmentManager(), FRAGMENT_TAG); 96 } 97 /* 98 * Leave this registered through pause/resume since we still want to 99 * finish the activity in the background if pairing is canceled. 100 */ 101 registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_PAIRING_CANCEL)); 102 registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)); 103 mReceiverRegistered = true; 104 } 105 106 @Override onDestroy()107 protected void onDestroy() { 108 super.onDestroy(); 109 if (mReceiverRegistered) { 110 mReceiverRegistered = false; 111 unregisterReceiver(mReceiver); 112 } 113 } 114 115 @VisibleForTesting dismiss()116 void dismiss() { 117 if (!isFinishing()) { 118 finish(); 119 } 120 } 121 } 122