blob: 9d98f0da9b1d25b34d2da154b9bef76566d178ab [file] [log] [blame]
/*
* Copyright (c) 2008-2009, Motorola, Inc.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the Motorola, Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.android.bluetooth.pbap;
import com.android.bluetooth.R;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.Preference;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Button;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.text.InputFilter;
import android.text.TextWatcher;
import android.text.InputFilter.LengthFilter;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
/**
* PbapActivity shows two dialogues: One for accepting incoming pbap request and
* the other prompts the user to enter a session key for authentication with a
* remote Bluetooth device.
*/
public class BluetoothPbapActivity extends AlertActivity implements
DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener, TextWatcher {
private static final String TAG = "BluetoothPbapActivity";
private static final boolean V = BluetoothPbapService.VERBOSE;
private static final int BLUETOOTH_OBEX_AUTHKEY_MAX_LENGTH = 16;
private static final int DIALOG_YES_NO_AUTH = 1;
private static final String KEY_USER_TIMEOUT = "user_timeout";
private View mView;
private EditText mKeyView;
private TextView messageView;
private String mSessionKey = "";
private int mCurrentDialog;
private Button mOkButton;
private CheckBox mAlwaysAllowed;
private boolean mTimeout = false;
private boolean mAlwaysAllowedValue = true;
private static final int DISMISS_TIMEOUT_DIALOG = 0;
private static final int DISMISS_TIMEOUT_DIALOG_VALUE = 2000;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!BluetoothPbapService.USER_CONFIRM_TIMEOUT_ACTION.equals(intent.getAction())) {
return;
}
onTimeout();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
String action = i.getAction();
if (action.equals(BluetoothPbapService.AUTH_CHALL_ACTION)) {
showPbapDialog(DIALOG_YES_NO_AUTH);
mCurrentDialog = DIALOG_YES_NO_AUTH;
} else {
Log.e(TAG, "Error: this activity may be started only with intent "
+ "PBAP_ACCESS_REQUEST or PBAP_AUTH_CHALL ");
finish();
}
registerReceiver(mReceiver, new IntentFilter(
BluetoothPbapService.USER_CONFIRM_TIMEOUT_ACTION));
}
private void showPbapDialog(int id) {
final AlertController.AlertParams p = mAlertParams;
switch (id) {
case DIALOG_YES_NO_AUTH:
p.mTitle = getString(R.string.pbap_session_key_dialog_header);
p.mView = createView(DIALOG_YES_NO_AUTH);
p.mPositiveButtonText = getString(android.R.string.ok);
p.mPositiveButtonListener = this;
p.mNegativeButtonText = getString(android.R.string.cancel);
p.mNegativeButtonListener = this;
setupAlert();
mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOkButton.setEnabled(false);
break;
default:
break;
}
}
private String createDisplayText(final int id) {
String mRemoteName = BluetoothPbapService.getRemoteDeviceName();
switch (id) {
case DIALOG_YES_NO_AUTH:
String mMessage2 = getString(R.string.pbap_session_key_dialog_title, mRemoteName);
return mMessage2;
default:
return null;
}
}
private View createView(final int id) {
switch (id) {
case DIALOG_YES_NO_AUTH:
mView = getLayoutInflater().inflate(R.layout.auth, null);
messageView = (TextView)mView.findViewById(R.id.message);
messageView.setText(createDisplayText(id));
mKeyView = (EditText)mView.findViewById(R.id.text);
mKeyView.addTextChangedListener(this);
mKeyView.setFilters(new InputFilter[] {
new LengthFilter(BLUETOOTH_OBEX_AUTHKEY_MAX_LENGTH)
});
return mView;
default:
return null;
}
}
private void onPositive() {
if (!mTimeout) {
if (mCurrentDialog == DIALOG_YES_NO_AUTH) {
sendIntentToReceiver(BluetoothPbapService.AUTH_RESPONSE_ACTION,
BluetoothPbapService.EXTRA_SESSION_KEY, mSessionKey);
mKeyView.removeTextChangedListener(this);
}
}
mTimeout = false;
finish();
}
private void onNegative() {
if (mCurrentDialog == DIALOG_YES_NO_AUTH) {
sendIntentToReceiver(BluetoothPbapService.AUTH_CANCELLED_ACTION, null, null);
mKeyView.removeTextChangedListener(this);
}
finish();
}
private void sendIntentToReceiver(final String intentName, final String extraName,
final String extraValue) {
Intent intent = new Intent(intentName);
intent.setClassName(BluetoothPbapService.THIS_PACKAGE_NAME, BluetoothPbapReceiver.class
.getName());
if (extraName != null) {
intent.putExtra(extraName, extraValue);
}
sendBroadcast(intent);
}
private void sendIntentToReceiver(final String intentName, final String extraName,
final boolean extraValue) {
Intent intent = new Intent(intentName);
intent.setClassName(BluetoothPbapService.THIS_PACKAGE_NAME, BluetoothPbapReceiver.class
.getName());
if (extraName != null) {
intent.putExtra(extraName, extraValue);
}
sendBroadcast(intent);
}
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
if (mCurrentDialog == DIALOG_YES_NO_AUTH) {
mSessionKey = mKeyView.getText().toString();
}
onPositive();
break;
case DialogInterface.BUTTON_NEGATIVE:
onNegative();
break;
default:
break;
}
}
private void onTimeout() {
mTimeout = true;
if (mCurrentDialog == DIALOG_YES_NO_AUTH) {
messageView.setText(getString(R.string.pbap_authentication_timeout_message,
BluetoothPbapService.getRemoteDeviceName()));
mKeyView.setVisibility(View.GONE);
mKeyView.clearFocus();
mKeyView.removeTextChangedListener(this);
mOkButton.setEnabled(true);
mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
}
mTimeoutHandler.sendMessageDelayed(mTimeoutHandler.obtainMessage(DISMISS_TIMEOUT_DIALOG),
DISMISS_TIMEOUT_DIALOG_VALUE);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mTimeout = savedInstanceState.getBoolean(KEY_USER_TIMEOUT);
if (V) Log.v(TAG, "onRestoreInstanceState() mTimeout: " + mTimeout);
if (mTimeout) {
onTimeout();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_USER_TIMEOUT, mTimeout);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
public boolean onPreferenceChange(Preference preference, Object newValue) {
return true;
}
public void beforeTextChanged(CharSequence s, int start, int before, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void afterTextChanged(android.text.Editable s) {
if (s.length() > 0) {
mOkButton.setEnabled(true);
}
}
private final Handler mTimeoutHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DISMISS_TIMEOUT_DIALOG:
if (V) Log.v(TAG, "Received DISMISS_TIMEOUT_DIALOG msg.");
finish();
break;
default:
break;
}
}
};
}