BluetoothPairingDialog.java revision 3a76bcaa83c15f96832f934e67e6f0190e72a3dc
1/* 2 * Copyright (C) 2008 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.settings.bluetooth; 18 19import android.bluetooth.BluetoothClass; 20import android.bluetooth.BluetoothDevice; 21import android.bluetooth.BluetoothIntent; 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.DialogInterface; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.os.Bundle; 28import android.text.Editable; 29import android.text.InputFilter; 30import android.text.InputType; 31import android.text.TextWatcher; 32import android.text.InputFilter.LengthFilter; 33import android.util.Log; 34import android.view.View; 35import android.widget.Button; 36import android.widget.EditText; 37import android.widget.TextView; 38 39import com.android.internal.app.AlertActivity; 40import com.android.internal.app.AlertController; 41import com.android.settings.R; 42 43/** 44 * BluetoothPairingDialog asks the user to enter a PIN / Passkey / simple confirmation 45 * for pairing with a remote Bluetooth device. It is an activity that appears as a dialog. 46 */ 47public class BluetoothPairingDialog extends AlertActivity implements DialogInterface.OnClickListener, 48 TextWatcher { 49 private static final String TAG = "BluetoothPairingDialog"; 50 51 private final int BLUETOOTH_PIN_MAX_LENGTH = 16; 52 private final int BLUETOOTH_PASSKEY_MAX_LENGTH = 6; 53 private LocalBluetoothManager mLocalManager; 54 private String mAddress; 55 private int mType; 56 private int mConfirmationPasskey; 57 private EditText mPairingView; 58 private Button mOkButton; 59 60 private static final String INSTANCE_KEY_PAIRING_CANCELED = "received_pairing_canceled"; 61 private boolean mReceivedPairingCanceled; 62 63 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 64 @Override 65 public void onReceive(Context context, Intent intent) { 66 if (!BluetoothIntent.PAIRING_CANCEL_ACTION.equals(intent.getAction())) { 67 return; 68 } 69 70 String address = intent.getStringExtra(BluetoothIntent.ADDRESS); 71 if (address == null || address.equals(mAddress)) { 72 onReceivedPairingCanceled(); 73 } 74 } 75 }; 76 77 @Override 78 protected void onCreate(Bundle savedInstanceState) { 79 super.onCreate(savedInstanceState); 80 81 Intent intent = getIntent(); 82 if (!intent.getAction().equals(BluetoothIntent.PAIRING_REQUEST_ACTION)) 83 { 84 Log.e(TAG, 85 "Error: this activity may be started only with intent " + 86 BluetoothIntent.PAIRING_REQUEST_ACTION); 87 finish(); 88 } 89 90 mLocalManager = LocalBluetoothManager.getInstance(this); 91 mAddress = intent.getStringExtra(BluetoothIntent.ADDRESS); 92 mType = intent.getIntExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothClass.ERROR); 93 if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) { 94 createUserEntryDialog(); 95 } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY) { 96 createUserEntryDialog(); 97 } else if (mType == BluetoothDevice.PAIRING_VARIANT_CONFIRMATION){ 98 mConfirmationPasskey = 99 intent.getIntExtra(BluetoothIntent.PASSKEY, BluetoothClass.ERROR); 100 if (mConfirmationPasskey == BluetoothClass.ERROR) { 101 Log.e(TAG, "Invalid ConfirmationPasskey received, not showing any dialog"); 102 return; 103 } 104 createConfirmationDialog(); 105 } else { 106 Log.e(TAG, "Incorrect pairing type received, not showing any dialog"); 107 } 108 109 /* 110 * Leave this registered through pause/resume since we still want to 111 * finish the activity in the background if pairing is canceled. 112 */ 113 registerReceiver(mReceiver, new IntentFilter(BluetoothIntent.PAIRING_CANCEL_ACTION)); 114 } 115 116 private void createUserEntryDialog() { 117 final AlertController.AlertParams p = mAlertParams; 118 p.mIconId = android.R.drawable.ic_dialog_info; 119 p.mTitle = getString(R.string.bluetooth_pin_entry); 120 p.mView = createView(); 121 p.mPositiveButtonText = getString(android.R.string.ok); 122 p.mPositiveButtonListener = this; 123 p.mNegativeButtonText = getString(android.R.string.cancel); 124 p.mNegativeButtonListener = this; 125 setupAlert(); 126 127 mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); 128 mOkButton.setEnabled(false); 129 } 130 131 private View createView() { 132 View view = getLayoutInflater().inflate(R.layout.bluetooth_pin_entry, null); 133 134 String name = mLocalManager.getLocalDeviceManager().getName(mAddress); 135 TextView messageView = (TextView) view.findViewById(R.id.message); 136 mPairingView = (EditText) view.findViewById(R.id.text); 137 mPairingView.addTextChangedListener(this); 138 139 if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) { 140 messageView.setText(getString(R.string.bluetooth_enter_pin_msg, name)); 141 // Maximum of 16 characters in a PIN adb sync 142 mPairingView.setFilters(new InputFilter[] { 143 new LengthFilter(BLUETOOTH_PIN_MAX_LENGTH) }); 144 } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY){ 145 messageView.setText(getString(R.string.bluetooth_enter_passkey_msg, name)); 146 // Maximum of 6 digits for passkey 147 mPairingView.setInputType(InputType.TYPE_NUMBER_FLAG_SIGNED); 148 mPairingView.setFilters(new InputFilter[] { 149 new LengthFilter(BLUETOOTH_PASSKEY_MAX_LENGTH)}); 150 } else { 151 mPairingView.setVisibility(View.GONE); 152 messageView.setText(getString(R.string.bluetooth_confirm_passkey_msg, name, 153 mConfirmationPasskey)); 154 } 155 return view; 156 } 157 158 private void createConfirmationDialog() { 159 final AlertController.AlertParams p = mAlertParams; 160 p.mIconId = android.R.drawable.ic_dialog_info; 161 p.mTitle = getString(R.string.bluetooth_pin_entry); 162 p.mView = createView(); 163 p.mPositiveButtonText = getString(android.R.string.yes); 164 p.mPositiveButtonListener = this; 165 p.mNegativeButtonText = getString(android.R.string.no); 166 p.mNegativeButtonListener = this; 167 setupAlert(); 168 } 169 170 @Override 171 protected void onRestoreInstanceState(Bundle savedInstanceState) { 172 super.onRestoreInstanceState(savedInstanceState); 173 174 mReceivedPairingCanceled = savedInstanceState.getBoolean(INSTANCE_KEY_PAIRING_CANCELED); 175 if (mReceivedPairingCanceled) { 176 onReceivedPairingCanceled(); 177 } 178 } 179 180 @Override 181 protected void onSaveInstanceState(Bundle outState) { 182 super.onSaveInstanceState(outState); 183 184 outState.putBoolean(INSTANCE_KEY_PAIRING_CANCELED, mReceivedPairingCanceled); 185 } 186 187 @Override 188 protected void onDestroy() { 189 super.onDestroy(); 190 191 unregisterReceiver(mReceiver); 192 } 193 194 195 196 public void afterTextChanged(Editable s) { 197 if (s.length() > 0) { 198 mOkButton.setEnabled(true); 199 } 200 } 201 202 private void onReceivedPairingCanceled() { 203 mReceivedPairingCanceled = true; 204 205 TextView messageView = (TextView) findViewById(R.id.message); 206 messageView.setText(getString(R.string.bluetooth_pairing_error_message, 207 mLocalManager.getLocalDeviceManager().getName(mAddress))); 208 209 mPairingView.setVisibility(View.GONE); 210 mPairingView.clearFocus(); 211 mPairingView.removeTextChangedListener(this); 212 213 mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); 214 mOkButton.setEnabled(true); 215 mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE); 216 } 217 218 private void onPair(String value) { 219 if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) { 220 byte[] pinBytes = BluetoothDevice.convertPinToBytes(value); 221 if (pinBytes == null) { 222 return; 223 } 224 mLocalManager.getBluetoothManager().setPin(mAddress, pinBytes); 225 } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY) { 226 int passkey = Integer.getInteger(value); 227 mLocalManager.getBluetoothManager().setPasskey(mAddress, passkey); 228 } else { 229 mLocalManager.getBluetoothManager().setPairingConfirmation(mAddress, true); 230 } 231 } 232 233 private void onCancel() { 234 if (mType == BluetoothDevice.PAIRING_VARIANT_CONFIRMATION) { 235 mLocalManager.getBluetoothManager().setPairingConfirmation(mAddress, false); 236 } else { 237 mLocalManager.getBluetoothManager().cancelBondProcess(mAddress); 238 } 239 } 240 241 public void onClick(DialogInterface dialog, int which) { 242 switch (which) { 243 case DialogInterface.BUTTON_POSITIVE: 244 onPair(mPairingView.getText().toString()); 245 break; 246 247 case DialogInterface.BUTTON_NEGATIVE: 248 onCancel(); 249 break; 250 } 251 } 252 253 /* Not used */ 254 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 255 } 256 257 /* Not used */ 258 public void onTextChanged(CharSequence s, int start, int before, int count) { 259 } 260 261} 262