1d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez/* 2d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Copyright (C) 2016 The Android Open Source Project 3d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * 4d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Licensed under the Apache License, Version 2.0 (the "License"); 5d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * you may not use this file except in compliance with the License. 6d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * You may obtain a copy of the License at 7d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * 8d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * http://www.apache.org/licenses/LICENSE-2.0 9d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * 10d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Unless required by applicable law or agreed to in writing, software 11d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * distributed under the License is distributed on an "AS IS" BASIS, 12d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * See the License for the specific language governing permissions and 14d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * limitations under the License. 15d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 16d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezpackage com.android.settings.bluetooth; 17d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 18d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.app.AlertDialog; 19d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.app.Dialog; 20d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.content.DialogInterface; 21d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.content.DialogInterface.OnClickListener; 22d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.os.Bundle; 23d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.text.Editable; 24d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.text.InputFilter; 25d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.text.InputFilter.LengthFilter; 26d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.text.InputType; 27d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.text.TextWatcher; 28d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.util.Log; 29d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.view.View; 30d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.widget.Button; 31d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.widget.CheckBox; 32d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.widget.EditText; 33d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport android.widget.TextView; 34265d3c2a0c36251bf8a9f571d7239b6dd404d942Tamas Berghammerimport com.android.internal.logging.nano.MetricsProto.MetricsEvent; 35d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport com.android.settings.R; 36d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezimport com.android.settings.core.instrumentation.InstrumentedDialogFragment; 37d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 38d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez/** 39d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * A dialogFragment used by {@link BluetoothPairingDialog} to create an appropriately styled dialog 40d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * for the bluetooth device. 41d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 42d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinezpublic class BluetoothPairingDialogFragment extends InstrumentedDialogFragment implements 43d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez TextWatcher, OnClickListener { 44d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 45d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private static final String TAG = "BTPairingDialogFragment"; 46d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 47d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private AlertDialog.Builder mBuilder; 48d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private AlertDialog mDialog; 49f492c28cc17e6def6d196e466256081662848be4Salvador Martinez private BluetoothPairingController mPairingController; 502a67cf046511865107f78104b4296b8967d1cd5bJack He private BluetoothPairingDialog mPairingDialogActivity; 51d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private EditText mPairingView; 52d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 53d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * The interface we expect a listener to implement. Typically this should be done by 54d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * the controller. 55d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 56d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez public interface BluetoothPairingDialogListener { 57d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 58d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez void onDialogNegativeClick(BluetoothPairingDialogFragment dialog); 59d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 60d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez void onDialogPositiveClick(BluetoothPairingDialogFragment dialog); 61d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 62d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 63d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez @Override 64d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez public Dialog onCreateDialog(Bundle savedInstanceState) { 652a67cf046511865107f78104b4296b8967d1cd5bJack He if (!isPairingControllerSet()) { 66d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez throw new IllegalStateException( 672a67cf046511865107f78104b4296b8967d1cd5bJack He "Must call setPairingController() before showing dialog"); 682a67cf046511865107f78104b4296b8967d1cd5bJack He } 692a67cf046511865107f78104b4296b8967d1cd5bJack He if (!isPairingDialogActivitySet()) { 702a67cf046511865107f78104b4296b8967d1cd5bJack He throw new IllegalStateException( 712a67cf046511865107f78104b4296b8967d1cd5bJack He "Must call setPairingDialogActivity() before showing dialog"); 72d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 73d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder = new AlertDialog.Builder(getActivity()); 74d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mDialog = setupDialog(); 75d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mDialog.setCanceledOnTouchOutside(false); 76d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return mDialog; 77d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 78d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 79d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez @Override 80d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez public void beforeTextChanged(CharSequence s, int start, int count, int after) { 81d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 82d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 83d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez @Override 84d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez public void onTextChanged(CharSequence s, int start, int before, int count) { 85d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 86d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 87d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez @Override 88d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez public void afterTextChanged(Editable s) { 89d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez // enable the positive button when we detect potentially valid input 90d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez Button positiveButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE); 91d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez if (positiveButton != null) { 92d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez positiveButton.setEnabled(mPairingController.isPasskeyValid(s)); 93d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 94d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez // notify the controller about user input 95d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.updateUserInput(s.toString()); 96d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 97d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 98d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez @Override 99d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez public void onClick(DialogInterface dialog, int which) { 100d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez if (which == DialogInterface.BUTTON_POSITIVE) { 101d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.onDialogPositiveClick(this); 102d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } else if (which == DialogInterface.BUTTON_NEGATIVE) { 103d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.onDialogNegativeClick(this); 104d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 1052a67cf046511865107f78104b4296b8967d1cd5bJack He mPairingDialogActivity.dismiss(); 106d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 107d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 108d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez @Override 109d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez public int getMetricsCategory() { 110d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return MetricsEvent.BLUETOOTH_DIALOG_FRAGMENT; 111d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 112d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 113d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 114f492c28cc17e6def6d196e466256081662848be4Salvador Martinez * Used in testing to get a reference to the dialog. 115f492c28cc17e6def6d196e466256081662848be4Salvador Martinez * @return - The fragments current dialog 116f492c28cc17e6def6d196e466256081662848be4Salvador Martinez */ 117f492c28cc17e6def6d196e466256081662848be4Salvador Martinez protected AlertDialog getmDialog() { 118f492c28cc17e6def6d196e466256081662848be4Salvador Martinez return mDialog; 119f492c28cc17e6def6d196e466256081662848be4Salvador Martinez } 120f492c28cc17e6def6d196e466256081662848be4Salvador Martinez 121f492c28cc17e6def6d196e466256081662848be4Salvador Martinez /** 122d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Sets the controller that the fragment should use. this method MUST be called 123d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * before you try to show the dialog or an error will be thrown. An implementation 124f492c28cc17e6def6d196e466256081662848be4Salvador Martinez * of a pairing controller can be found at {@link BluetoothPairingController}. A 125f492c28cc17e6def6d196e466256081662848be4Salvador Martinez * controller may not be substituted once it is assigned. Forcibly switching a 126f492c28cc17e6def6d196e466256081662848be4Salvador Martinez * controller for a new one will lead to undefined behavior. 127d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 1282a67cf046511865107f78104b4296b8967d1cd5bJack He void setPairingController(BluetoothPairingController pairingController) { 1292a67cf046511865107f78104b4296b8967d1cd5bJack He if (isPairingControllerSet()) { 130f492c28cc17e6def6d196e466256081662848be4Salvador Martinez throw new IllegalStateException("The controller can only be set once. " 131f492c28cc17e6def6d196e466256081662848be4Salvador Martinez + "Forcibly replacing it will lead to undefined behavior"); 132f492c28cc17e6def6d196e466256081662848be4Salvador Martinez } 133d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController = pairingController; 134d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 135d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 136d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 1372a67cf046511865107f78104b4296b8967d1cd5bJack He * Checks whether mPairingController is set 1382a67cf046511865107f78104b4296b8967d1cd5bJack He * @return True when mPairingController is set, False otherwise 1392a67cf046511865107f78104b4296b8967d1cd5bJack He */ 1402a67cf046511865107f78104b4296b8967d1cd5bJack He boolean isPairingControllerSet() { 1412a67cf046511865107f78104b4296b8967d1cd5bJack He return mPairingController != null; 1422a67cf046511865107f78104b4296b8967d1cd5bJack He } 1432a67cf046511865107f78104b4296b8967d1cd5bJack He 1442a67cf046511865107f78104b4296b8967d1cd5bJack He /** 1452a67cf046511865107f78104b4296b8967d1cd5bJack He * Sets the BluetoothPairingDialog activity that started this fragment 1462a67cf046511865107f78104b4296b8967d1cd5bJack He * @param pairingDialogActivity The pairing dialog activty that started this fragment 1472a67cf046511865107f78104b4296b8967d1cd5bJack He */ 1482a67cf046511865107f78104b4296b8967d1cd5bJack He void setPairingDialogActivity(BluetoothPairingDialog pairingDialogActivity) { 1492a67cf046511865107f78104b4296b8967d1cd5bJack He if (isPairingDialogActivitySet()) { 1502a67cf046511865107f78104b4296b8967d1cd5bJack He throw new IllegalStateException("The pairing dialog activity can only be set once"); 1512a67cf046511865107f78104b4296b8967d1cd5bJack He } 1522a67cf046511865107f78104b4296b8967d1cd5bJack He mPairingDialogActivity = pairingDialogActivity; 1532a67cf046511865107f78104b4296b8967d1cd5bJack He } 1542a67cf046511865107f78104b4296b8967d1cd5bJack He 1552a67cf046511865107f78104b4296b8967d1cd5bJack He /** 1562a67cf046511865107f78104b4296b8967d1cd5bJack He * Checks whether mPairingDialogActivity is set 1572a67cf046511865107f78104b4296b8967d1cd5bJack He * @return True when mPairingDialogActivity is set, False otherwise 1582a67cf046511865107f78104b4296b8967d1cd5bJack He */ 1592a67cf046511865107f78104b4296b8967d1cd5bJack He boolean isPairingDialogActivitySet() { 1602a67cf046511865107f78104b4296b8967d1cd5bJack He return mPairingDialogActivity != null; 1612a67cf046511865107f78104b4296b8967d1cd5bJack He } 1622a67cf046511865107f78104b4296b8967d1cd5bJack He 1632a67cf046511865107f78104b4296b8967d1cd5bJack He /** 164d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Creates the appropriate type of dialog and returns it. 165d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 166d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private AlertDialog setupDialog() { 167d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez AlertDialog dialog; 168d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez switch (mPairingController.getDialogType()) { 169d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez case BluetoothPairingController.USER_ENTRY_DIALOG: 170d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez dialog = createUserEntryDialog(); 171d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez break; 172d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez case BluetoothPairingController.CONFIRMATION_DIALOG: 173d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez dialog = createConsentDialog(); 174d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez break; 175d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez case BluetoothPairingController.DISPLAY_PASSKEY_DIALOG: 176d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez dialog = createDisplayPasskeyOrPinDialog(); 177d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez break; 178d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez default: 179d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez dialog = null; 180d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez Log.e(TAG, "Incorrect pairing type received, not showing any dialog"); 181d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 182d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return dialog; 183d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 184d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 185d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 186d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Returns a dialog with UI elements that allow a user to provide input. 187d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 188d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private AlertDialog createUserEntryDialog() { 189d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setTitle(getString(R.string.bluetooth_pairing_request, 190d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.getDeviceName())); 191d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setView(createPinEntryView()); 192d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setPositiveButton(getString(android.R.string.ok), this); 193d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setNegativeButton(getString(android.R.string.cancel), this); 194d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez AlertDialog dialog = mBuilder.create(); 195f492c28cc17e6def6d196e466256081662848be4Salvador Martinez dialog.setOnShowListener(d -> mDialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(false)); 196d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return dialog; 197d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 198d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 199d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 200d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Creates the custom view with UI elements for user input. 201d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 202d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private View createPinEntryView() { 203d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez View view = getActivity().getLayoutInflater().inflate(R.layout.bluetooth_pin_entry, null); 204d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez TextView messageViewCaptionHint = (TextView) view.findViewById(R.id.pin_values_hint); 205d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez TextView messageView2 = (TextView) view.findViewById(R.id.message_below_pin); 206d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez CheckBox alphanumericPin = (CheckBox) view.findViewById(R.id.alphanumeric_pin); 207d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez CheckBox contactSharing = (CheckBox) view.findViewById( 208d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez R.id.phonebook_sharing_message_entry_pin); 209d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook, 210d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.getDeviceName())); 211d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez EditText pairingView = (EditText) view.findViewById(R.id.text); 212d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 213d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez contactSharing.setVisibility(mPairingController.isProfileReady() 214d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez ? View.GONE : View.VISIBLE); 215d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez contactSharing.setOnCheckedChangeListener(mPairingController); 216d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez contactSharing.setChecked(mPairingController.getContactSharingState()); 217d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 218d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingView = pairingView; 219d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 220f492c28cc17e6def6d196e466256081662848be4Salvador Martinez pairingView.setInputType(InputType.TYPE_CLASS_NUMBER); 221d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez pairingView.addTextChangedListener(this); 222d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez alphanumericPin.setOnCheckedChangeListener((buttonView, isChecked) -> { 223d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez // change input type for soft keyboard to numeric or alphanumeric 224d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez if (isChecked) { 225d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingView.setInputType(InputType.TYPE_CLASS_TEXT); 226d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } else { 227d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER); 228d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 229d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez }); 230d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 231f492c28cc17e6def6d196e466256081662848be4Salvador Martinez int messageId = mPairingController.getDeviceVariantMessageId(); 232f492c28cc17e6def6d196e466256081662848be4Salvador Martinez int messageIdHint = mPairingController.getDeviceVariantMessageHintId(); 233d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez int maxLength = mPairingController.getDeviceMaxPasskeyLength(); 234d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez alphanumericPin.setVisibility(mPairingController.pairingCodeIsAlphanumeric() 235d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez ? View.VISIBLE : View.GONE); 236f492c28cc17e6def6d196e466256081662848be4Salvador Martinez if (messageId != BluetoothPairingController.INVALID_DIALOG_TYPE) { 237f492c28cc17e6def6d196e466256081662848be4Salvador Martinez messageView2.setText(messageId); 238f492c28cc17e6def6d196e466256081662848be4Salvador Martinez } else { 239f492c28cc17e6def6d196e466256081662848be4Salvador Martinez messageView2.setVisibility(View.GONE); 240f492c28cc17e6def6d196e466256081662848be4Salvador Martinez } 241f492c28cc17e6def6d196e466256081662848be4Salvador Martinez if (messageIdHint != BluetoothPairingController.INVALID_DIALOG_TYPE) { 242f492c28cc17e6def6d196e466256081662848be4Salvador Martinez messageViewCaptionHint.setText(messageIdHint); 243f492c28cc17e6def6d196e466256081662848be4Salvador Martinez } else { 244f492c28cc17e6def6d196e466256081662848be4Salvador Martinez messageViewCaptionHint.setVisibility(View.GONE); 245f492c28cc17e6def6d196e466256081662848be4Salvador Martinez } 246d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez pairingView.setFilters(new InputFilter[]{ 247d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez new LengthFilter(maxLength)}); 248d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 249d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return view; 250d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 251d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 252d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 253d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Creates a dialog with UI elements that allow the user to confirm a pairing request. 254d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 255d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private AlertDialog createConfirmationDialog() { 256d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setTitle(getString(R.string.bluetooth_pairing_request, 257d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.getDeviceName())); 258d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setView(createView()); 259f492c28cc17e6def6d196e466256081662848be4Salvador Martinez mBuilder.setPositiveButton(getString(R.string.bluetooth_pairing_accept), this); 260f492c28cc17e6def6d196e466256081662848be4Salvador Martinez mBuilder.setNegativeButton(getString(R.string.bluetooth_pairing_decline), this); 261d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez AlertDialog dialog = mBuilder.create(); 262d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return dialog; 263d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 264d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 265d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 266d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Creates a dialog with UI elements that allow the user to consent to a pairing request. 267d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 268d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private AlertDialog createConsentDialog() { 269d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return createConfirmationDialog(); 270d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 271d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 272d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 273d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Creates a dialog that informs users of a pairing request and shows them the passkey/pin 274d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * of the device. 275d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 276d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private AlertDialog createDisplayPasskeyOrPinDialog() { 277d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setTitle(getString(R.string.bluetooth_pairing_request, 278d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.getDeviceName())); 279d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setView(createView()); 280d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mBuilder.setNegativeButton(getString(android.R.string.cancel), this); 281d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez AlertDialog dialog = mBuilder.create(); 282d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 283d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez // Tell the controller the dialog has been created. 284d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.notifyDialogDisplayed(); 285d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 286d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return dialog; 287d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 288d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 289d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez /** 290d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * Creates a custom view for dialogs which need to show users additional information but do 291d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez * not require user input. 292d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez */ 293d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez private View createView() { 294d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez View view = getActivity().getLayoutInflater().inflate(R.layout.bluetooth_pin_confirm, null); 295d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez TextView pairingViewCaption = (TextView) view.findViewById(R.id.pairing_caption); 296d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez TextView pairingViewContent = (TextView) view.findViewById(R.id.pairing_subhead); 297d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez TextView messagePairing = (TextView) view.findViewById(R.id.pairing_code_message); 298d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez CheckBox contactSharing = (CheckBox) view.findViewById( 299d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez R.id.phonebook_sharing_message_confirm_pin); 300d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook, 301d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.getDeviceName())); 302d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 303d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez contactSharing.setVisibility( 304d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez mPairingController.isProfileReady() ? View.GONE : View.VISIBLE); 305d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez contactSharing.setChecked(mPairingController.getContactSharingState()); 306d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez contactSharing.setOnCheckedChangeListener(mPairingController); 307d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 308d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez messagePairing.setVisibility(mPairingController.isDisplayPairingKeyVariant() 309d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez ? View.VISIBLE : View.GONE); 310d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez if (mPairingController.hasPairingContent()) { 311d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez pairingViewCaption.setVisibility(View.VISIBLE); 312d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez pairingViewContent.setVisibility(View.VISIBLE); 313d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez pairingViewContent.setText(mPairingController.getPairingContent()); 314d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 315d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez return view; 316d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez } 317d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez 318d98d0837d85d11b29967c924638a1f0af6e08e24Salvador Martinez} 319