BluetoothPbapActivity.java revision eb7b90f5b93db1230a5b64caa3d8d05a642e33a6
1/* 2 * Copyright (c) 2008-2009, Motorola, Inc. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * - Neither the name of the Motorola, Inc. nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33package com.android.bluetooth.pbap; 34 35import com.android.bluetooth.R; 36 37import android.content.BroadcastReceiver; 38import android.content.Context; 39import android.content.DialogInterface; 40import android.content.Intent; 41import android.content.IntentFilter; 42import android.os.Bundle; 43import android.os.Handler; 44import android.os.Message; 45import android.preference.Preference; 46import android.text.InputFilter; 47import android.text.TextWatcher; 48import android.text.InputFilter.LengthFilter; 49import android.util.Log; 50import android.view.View; 51import android.widget.CheckBox; 52import android.widget.EditText; 53import android.widget.TextView; 54import android.widget.Button; 55 56import com.android.internal.app.AlertActivity; 57import com.android.internal.app.AlertController; 58 59/** 60 * PbapActivity shows two dialogues: One for accepting incoming pbap request and 61 * the other prompts the user to enter a session key for authentication with a 62 * remote Bluetooth device. 63 */ 64public class BluetoothPbapActivity extends AlertActivity implements 65 DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener, TextWatcher { 66 private static final String TAG = "BluetoothPbapActivity"; 67 68 private static final boolean V = BluetoothPbapService.VERBOSE; 69 70 private static final int BLUETOOTH_OBEX_AUTHKEY_MAX_LENGTH = 16; 71 72 private static final int DIALOG_YES_NO_AUTH = 1; 73 74 private static final String KEY_USER_TIMEOUT = "user_timeout"; 75 76 private View mView; 77 78 private EditText mKeyView; 79 80 private TextView messageView; 81 82 private String mSessionKey = ""; 83 84 private int mCurrentDialog; 85 86 private Button mOkButton; 87 88 private CheckBox mAlwaysAllowed; 89 90 private boolean mTimeout = false; 91 92 private boolean mAlwaysAllowedValue = true; 93 94 private static final int DISMISS_TIMEOUT_DIALOG = 0; 95 96 private static final int DISMISS_TIMEOUT_DIALOG_VALUE = 2000; 97 98 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 99 @Override 100 public void onReceive(Context context, Intent intent) { 101 if (!BluetoothPbapService.USER_CONFIRM_TIMEOUT_ACTION.equals(intent.getAction())) { 102 return; 103 } 104 onTimeout(); 105 } 106 }; 107 108 @Override 109 protected void onCreate(Bundle savedInstanceState) { 110 super.onCreate(savedInstanceState); 111 Intent i = getIntent(); 112 String action = i.getAction(); 113 if (action.equals(BluetoothPbapService.AUTH_CHALL_ACTION)) { 114 showPbapDialog(DIALOG_YES_NO_AUTH); 115 mCurrentDialog = DIALOG_YES_NO_AUTH; 116 } else { 117 Log.e(TAG, "Error: this activity may be started only with intent " 118 + "PBAP_ACCESS_REQUEST or PBAP_AUTH_CHALL "); 119 finish(); 120 } 121 registerReceiver(mReceiver, new IntentFilter( 122 BluetoothPbapService.USER_CONFIRM_TIMEOUT_ACTION)); 123 } 124 125 private void showPbapDialog(int id) { 126 final AlertController.AlertParams p = mAlertParams; 127 switch (id) { 128 case DIALOG_YES_NO_AUTH: 129 p.mTitle = getString(R.string.pbap_session_key_dialog_header); 130 p.mView = createView(DIALOG_YES_NO_AUTH); 131 p.mPositiveButtonText = getString(android.R.string.ok); 132 p.mPositiveButtonListener = this; 133 p.mNegativeButtonText = getString(android.R.string.cancel); 134 p.mNegativeButtonListener = this; 135 setupAlert(); 136 mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); 137 mOkButton.setEnabled(false); 138 break; 139 default: 140 break; 141 } 142 } 143 144 private String createDisplayText(final int id) { 145 String mRemoteName = BluetoothPbapService.getRemoteDeviceName(); 146 switch (id) { 147 case DIALOG_YES_NO_AUTH: 148 String mMessage2 = getString(R.string.pbap_session_key_dialog_title, mRemoteName); 149 return mMessage2; 150 default: 151 return null; 152 } 153 } 154 155 private View createView(final int id) { 156 switch (id) { 157 case DIALOG_YES_NO_AUTH: 158 mView = getLayoutInflater().inflate(R.layout.auth, null); 159 messageView = (TextView)mView.findViewById(R.id.message); 160 messageView.setText(createDisplayText(id)); 161 mKeyView = (EditText)mView.findViewById(R.id.text); 162 mKeyView.addTextChangedListener(this); 163 mKeyView.setFilters(new InputFilter[] { 164 new LengthFilter(BLUETOOTH_OBEX_AUTHKEY_MAX_LENGTH) 165 }); 166 return mView; 167 default: 168 return null; 169 } 170 } 171 172 private void onPositive() { 173 if (!mTimeout) { 174 if (mCurrentDialog == DIALOG_YES_NO_AUTH) { 175 sendIntentToReceiver(BluetoothPbapService.AUTH_RESPONSE_ACTION, 176 BluetoothPbapService.EXTRA_SESSION_KEY, mSessionKey); 177 mKeyView.removeTextChangedListener(this); 178 } 179 } 180 mTimeout = false; 181 finish(); 182 } 183 184 private void onNegative() { 185 if (mCurrentDialog == DIALOG_YES_NO_AUTH) { 186 sendIntentToReceiver(BluetoothPbapService.AUTH_CANCELLED_ACTION, null, null); 187 mKeyView.removeTextChangedListener(this); 188 } 189 finish(); 190 } 191 192 private void sendIntentToReceiver(final String intentName, final String extraName, 193 final String extraValue) { 194 Intent intent = new Intent(intentName); 195 intent.setClassName(BluetoothPbapService.THIS_PACKAGE_NAME, BluetoothPbapReceiver.class 196 .getName()); 197 if (extraName != null) { 198 intent.putExtra(extraName, extraValue); 199 } 200 sendBroadcast(intent); 201 } 202 203 private void sendIntentToReceiver(final String intentName, final String extraName, 204 final boolean extraValue) { 205 Intent intent = new Intent(intentName); 206 intent.setClassName(BluetoothPbapService.THIS_PACKAGE_NAME, BluetoothPbapReceiver.class 207 .getName()); 208 if (extraName != null) { 209 intent.putExtra(extraName, extraValue); 210 } 211 sendBroadcast(intent); 212 } 213 214 public void onClick(DialogInterface dialog, int which) { 215 switch (which) { 216 case DialogInterface.BUTTON_POSITIVE: 217 if (mCurrentDialog == DIALOG_YES_NO_AUTH) { 218 mSessionKey = mKeyView.getText().toString(); 219 } 220 onPositive(); 221 break; 222 223 case DialogInterface.BUTTON_NEGATIVE: 224 onNegative(); 225 break; 226 default: 227 break; 228 } 229 } 230 231 private void onTimeout() { 232 mTimeout = true; 233 if (mCurrentDialog == DIALOG_YES_NO_AUTH) { 234 messageView.setText(getString(R.string.pbap_authentication_timeout_message, 235 BluetoothPbapService.getRemoteDeviceName())); 236 mKeyView.setVisibility(View.GONE); 237 mKeyView.clearFocus(); 238 mKeyView.removeTextChangedListener(this); 239 mOkButton.setEnabled(true); 240 mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE); 241 } 242 243 mTimeoutHandler.sendMessageDelayed(mTimeoutHandler.obtainMessage(DISMISS_TIMEOUT_DIALOG), 244 DISMISS_TIMEOUT_DIALOG_VALUE); 245 } 246 247 @Override 248 protected void onRestoreInstanceState(Bundle savedInstanceState) { 249 super.onRestoreInstanceState(savedInstanceState); 250 mTimeout = savedInstanceState.getBoolean(KEY_USER_TIMEOUT); 251 if (V) Log.v(TAG, "onRestoreInstanceState() mTimeout: " + mTimeout); 252 if (mTimeout) { 253 onTimeout(); 254 } 255 } 256 257 @Override 258 protected void onSaveInstanceState(Bundle outState) { 259 super.onSaveInstanceState(outState); 260 outState.putBoolean(KEY_USER_TIMEOUT, mTimeout); 261 } 262 263 @Override 264 protected void onDestroy() { 265 super.onDestroy(); 266 unregisterReceiver(mReceiver); 267 } 268 269 public boolean onPreferenceChange(Preference preference, Object newValue) { 270 return true; 271 } 272 273 public void beforeTextChanged(CharSequence s, int start, int before, int after) { 274 } 275 276 public void onTextChanged(CharSequence s, int start, int before, int count) { 277 } 278 279 public void afterTextChanged(android.text.Editable s) { 280 if (s.length() > 0) { 281 mOkButton.setEnabled(true); 282 } 283 } 284 285 private final Handler mTimeoutHandler = new Handler() { 286 @Override 287 public void handleMessage(Message msg) { 288 switch (msg.what) { 289 case DISMISS_TIMEOUT_DIALOG: 290 if (V) Log.v(TAG, "Received DISMISS_TIMEOUT_DIALOG msg."); 291 finish(); 292 break; 293 default: 294 break; 295 } 296 } 297 }; 298} 299