• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.settings.bluetooth;
18 
19 import android.bluetooth.BluetoothDevice;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.os.Bundle;
26 import android.text.Editable;
27 import android.text.InputFilter;
28 import android.text.InputType;
29 import android.text.TextWatcher;
30 import android.text.InputFilter.LengthFilter;
31 import android.util.Log;
32 import android.view.View;
33 import android.widget.Button;
34 import android.widget.EditText;
35 import android.widget.TextView;
36 
37 import com.android.internal.app.AlertActivity;
38 import com.android.internal.app.AlertController;
39 import com.android.settings.R;
40 
41 /**
42  * BluetoothPairingDialog asks the user to enter a PIN / Passkey / simple confirmation
43  * for pairing with a remote Bluetooth device. It is an activity that appears as a dialog.
44  */
45 public class BluetoothPairingDialog extends AlertActivity implements DialogInterface.OnClickListener,
46         TextWatcher {
47     private static final String TAG = "BluetoothPairingDialog";
48 
49     private final int BLUETOOTH_PIN_MAX_LENGTH = 16;
50     private final int BLUETOOTH_PASSKEY_MAX_LENGTH = 6;
51     private LocalBluetoothManager mLocalManager;
52     private BluetoothDevice mDevice;
53     private int mType;
54     private String mPasskey;
55     private EditText mPairingView;
56     private Button mOkButton;
57 
58     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
59         @Override
60         public void onReceive(Context context, Intent intent) {
61             if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
62                 int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
63                                                    BluetoothDevice.ERROR);
64                 if (bondState == BluetoothDevice.BOND_BONDED ||
65                         bondState == BluetoothDevice.BOND_NONE) {
66                     dismissDialog();
67                 }
68             } else if(BluetoothDevice.ACTION_PAIRING_CANCEL.equals(intent.getAction())) {
69                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
70                 if (device == null || device.equals(mDevice)) {
71                     dismissDialog();
72                 }
73             }
74         }
75     };
76 
77     @Override
onCreate(Bundle savedInstanceState)78     protected void onCreate(Bundle savedInstanceState) {
79         super.onCreate(savedInstanceState);
80 
81         Intent intent = getIntent();
82         if (!intent.getAction().equals(BluetoothDevice.ACTION_PAIRING_REQUEST))
83         {
84             Log.e(TAG,
85                   "Error: this activity may be started only with intent " +
86                   BluetoothDevice.ACTION_PAIRING_REQUEST);
87             finish();
88         }
89 
90         mLocalManager = LocalBluetoothManager.getInstance(this);
91         mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
92         mType = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.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_PASSKEY_CONFIRMATION){
98             int passkey =
99                 intent.getIntExtra(BluetoothDevice.EXTRA_PASSKEY, BluetoothDevice.ERROR);
100             if (passkey == BluetoothDevice.ERROR) {
101                 Log.e(TAG, "Invalid ConfirmationPasskey received, not showing any dialog");
102                 return;
103             }
104             mPasskey = String.format("%06d", passkey);
105             createConfirmationDialog();
106         } else if (mType == BluetoothDevice.PAIRING_VARIANT_CONSENT) {
107             createConsentDialog();
108         } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
109             int passkey =
110                 intent.getIntExtra(BluetoothDevice.EXTRA_PASSKEY, BluetoothDevice.ERROR);
111             if (passkey == BluetoothDevice.ERROR) {
112                 Log.e(TAG, "Invalid ConfirmationPasskey received, not showing any dialog");
113                 return;
114             }
115             mPasskey = String.format("%06d", passkey);
116             createDisplayPasskeyDialog();
117         } else if (mType == BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT) {
118             createConsentDialog();
119         } else {
120             Log.e(TAG, "Incorrect pairing type received, not showing any dialog");
121         }
122 
123         /*
124          * Leave this registered through pause/resume since we still want to
125          * finish the activity in the background if pairing is canceled.
126          */
127         registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_PAIRING_CANCEL));
128         registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED));
129     }
130 
createUserEntryDialog()131     private void createUserEntryDialog() {
132         final AlertController.AlertParams p = mAlertParams;
133         p.mIconId = android.R.drawable.ic_dialog_info;
134         p.mTitle = getString(R.string.bluetooth_pairing_request);
135         p.mView = createView();
136         p.mPositiveButtonText = getString(android.R.string.ok);
137         p.mPositiveButtonListener = this;
138         p.mNegativeButtonText = getString(android.R.string.cancel);
139         p.mNegativeButtonListener = this;
140         setupAlert();
141 
142         mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
143         mOkButton.setEnabled(false);
144     }
145 
createView()146     private View createView() {
147         View view = getLayoutInflater().inflate(R.layout.bluetooth_pin_entry, null);
148 
149         String name = mLocalManager.getCachedDeviceManager().getName(mDevice);
150         TextView messageView = (TextView) view.findViewById(R.id.message);
151         mPairingView = (EditText) view.findViewById(R.id.text);
152         mPairingView.addTextChangedListener(this);
153 
154         if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) {
155             messageView.setText(getString(R.string.bluetooth_enter_pin_msg, name));
156             // Maximum of 16 characters in a PIN adb sync
157             mPairingView.setFilters(new InputFilter[] {
158                     new LengthFilter(BLUETOOTH_PIN_MAX_LENGTH) });
159         } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY){
160             messageView.setText(getString(R.string.bluetooth_enter_passkey_msg, name));
161             // Maximum of 6 digits for passkey
162             mPairingView.setInputType(InputType.TYPE_CLASS_NUMBER |
163                     InputType.TYPE_NUMBER_FLAG_SIGNED);
164             mPairingView.setFilters(new InputFilter[] {
165                     new LengthFilter(BLUETOOTH_PASSKEY_MAX_LENGTH)});
166         } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION) {
167             mPairingView.setVisibility(View.GONE);
168             messageView.setText(getString(R.string.bluetooth_confirm_passkey_msg, name,
169                     mPasskey));
170         } else if (mType == BluetoothDevice.PAIRING_VARIANT_CONSENT) {
171             mPairingView.setVisibility(View.GONE);
172             messageView.setText(getString(R.string.bluetooth_incoming_pairing_msg, name));
173         } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
174             mPairingView.setVisibility(View.GONE);
175             messageView.setText(getString(R.string.bluetooth_display_passkey_msg, name, mPasskey));
176         } else if (mType == BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT) {
177             mPairingView.setVisibility(View.GONE);
178             messageView.setText(getString(R.string.bluetooth_incoming_pairing_msg, name));
179         } else {
180             Log.e(TAG, "Incorrect pairing type received, not creating view");
181         }
182         return view;
183     }
184 
createConfirmationDialog()185     private void createConfirmationDialog() {
186         final AlertController.AlertParams p = mAlertParams;
187         p.mIconId = android.R.drawable.ic_dialog_info;
188         p.mTitle = getString(R.string.bluetooth_pairing_request);
189         p.mView = createView();
190         p.mPositiveButtonText = getString(R.string.bluetooth_pairing_accept);
191         p.mPositiveButtonListener = this;
192         p.mNegativeButtonText = getString(R.string.bluetooth_pairing_decline);
193         p.mNegativeButtonListener = this;
194         setupAlert();
195     }
196 
createConsentDialog()197     private void createConsentDialog() {
198         final AlertController.AlertParams p = mAlertParams;
199         p.mIconId = android.R.drawable.ic_dialog_info;
200         p.mTitle = getString(R.string.bluetooth_pairing_request);
201         p.mView = createView();
202         p.mPositiveButtonText = getString(R.string.bluetooth_pairing_accept);
203         p.mPositiveButtonListener = this;
204         p.mNegativeButtonText = getString(R.string.bluetooth_pairing_decline);
205         p.mNegativeButtonListener = this;
206         setupAlert();
207     }
208 
createDisplayPasskeyDialog()209     private void createDisplayPasskeyDialog() {
210         final AlertController.AlertParams p = mAlertParams;
211         p.mIconId = android.R.drawable.ic_dialog_info;
212         p.mTitle = getString(R.string.bluetooth_pairing_request);
213         p.mView = createView();
214         p.mPositiveButtonText = getString(android.R.string.ok);
215         p.mPositiveButtonListener = this;
216         setupAlert();
217 
218         // Since its only a notification, send an OK to the framework,
219         // indicating that the dialog has been displayed.
220         mDevice.setPairingConfirmation(true);
221     }
222 
223     @Override
onDestroy()224     protected void onDestroy() {
225         super.onDestroy();
226         unregisterReceiver(mReceiver);
227     }
228 
afterTextChanged(Editable s)229     public void afterTextChanged(Editable s) {
230         if (s.length() > 0) {
231             mOkButton.setEnabled(true);
232         }
233     }
234 
dismissDialog()235     private void dismissDialog() {
236         this.dismiss();
237     }
238 
onPair(String value)239     private void onPair(String value) {
240         if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) {
241             byte[] pinBytes = BluetoothDevice.convertPinToBytes(value);
242             if (pinBytes == null) {
243                 return;
244             }
245             mDevice.setPin(pinBytes);
246         } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY) {
247             int passkey = Integer.parseInt(value);
248             mDevice.setPasskey(passkey);
249         } else if (mType == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION) {
250             mDevice.setPairingConfirmation(true);
251         } else if (mType ==  BluetoothDevice.PAIRING_VARIANT_CONSENT) {
252             mDevice.setPairingConfirmation(true);
253         } else if (mType == BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY) {
254             // Do Nothing.
255         } else if (mType == BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT) {
256             mDevice.setRemoteOutOfBandData();
257         } else {
258             Log.e(TAG, "Incorrect pairing type received");
259         }
260     }
261 
onCancel()262     private void onCancel() {
263         mDevice.cancelPairingUserInput();
264     }
265 
onClick(DialogInterface dialog, int which)266     public void onClick(DialogInterface dialog, int which) {
267         switch (which) {
268             case DialogInterface.BUTTON_POSITIVE:
269                 onPair(mPairingView.getText().toString());
270                 break;
271 
272             case DialogInterface.BUTTON_NEGATIVE:
273                 onCancel();
274                 break;
275         }
276     }
277 
278     /* Not used */
beforeTextChanged(CharSequence s, int start, int count, int after)279     public void beforeTextChanged(CharSequence s, int start, int count, int after) {
280     }
281 
282     /* Not used */
onTextChanged(CharSequence s, int start, int before, int count)283     public void onTextChanged(CharSequence s, int start, int before, int count) {
284     }
285 
286 }
287