diff options
-rw-r--r-- | AndroidManifest.xml | 19 | ||||
-rw-r--r-- | res/layout/bluetooth_connection_access.xml | 40 | ||||
-rw-r--r-- | res/layout/bluetooth_pb_access.xml | 48 | ||||
-rw-r--r-- | res/values/strings.xml | 9 | ||||
-rw-r--r-- | src/com/android/settings/bluetooth/BluetoothPermissionActivity.java | 232 | ||||
-rw-r--r-- | src/com/android/settings/bluetooth/BluetoothPermissionRequest.java | 107 |
6 files changed, 455 insertions, 0 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5b6d24a..e5ccb78 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -981,6 +981,25 @@ </intent-filter> </receiver> + <receiver android:name=".bluetooth.BluetoothPermissionRequest"> + <intent-filter> + <action android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" /> + <action android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" /> + </intent-filter> + </receiver> + + <activity android:name=".bluetooth.BluetoothPermissionActivity" + android:label="@string/bluetooth_connection_permission_request" + android:excludeFromRecents="true" + android:permission="android.permission.BLUETOOTH_ADMIN" + android:theme="@*android:style/Theme.Holo.Dialog.Alert"> + <intent-filter> + <action android:name="android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST" /> + <action android:name="android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <activity android:name="ActivityPicker" android:label="@string/activity_picker_label" android:theme="@*android:style/Theme.Dialog.Alert" diff --git a/res/layout/bluetooth_connection_access.xml b/res/layout/bluetooth_connection_access.xml new file mode 100644 index 0000000..1e74162 --- /dev/null +++ b/res/layout/bluetooth_connection_access.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2011, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <LinearLayout + android:layout_height="match_parent" + android:layout_width="match_parent" + android:orientation="vertical"> + + <TextView + android:id="@+id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="20dip" + android:layout_marginRight="20dip" + android:gravity="center_horizontal" + android:textAppearance="?android:attr/textAppearanceMedium" /> + </LinearLayout> + +</ScrollView> diff --git a/res/layout/bluetooth_pb_access.xml b/res/layout/bluetooth_pb_access.xml new file mode 100644 index 0000000..80f78a6 --- /dev/null +++ b/res/layout/bluetooth_pb_access.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <LinearLayout + android:layout_height="match_parent" + android:layout_width="match_parent" + android:orientation="vertical"> + + <TextView + android:id="@+id/message" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="20dip" + android:layout_marginRight="20dip" + android:gravity="center_horizontal" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <CheckBox android:id="@+id/bluetooth_pb_alwaysallowed" + style="?android:attr/textAppearanceMedium" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="2dip" + android:text="@string/bluetooth_pb_alwaysallowed" /> + + </LinearLayout> + +</ScrollView> diff --git a/res/values/strings.xml b/res/values/strings.xml index 364ae3e..7b2339e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -295,6 +295,15 @@ <!-- Bluetooth connection permission Alert Activity text [CHAR LIMIT=none]--> <string name="bluetooth_connection_dialog_text">"Do you want to connect to \u0022<xliff:g id="device_name">%1$s</xliff:g>\u0022?"</string> + <!-- Activity label of BluetoothPbPermissionActivity, also used as Strings in the permission dialog [CHAR LIMIT=none] --> + <string name="bluetooth_phonebook_request">"Phone book request"</string> + + <!-- Bluetooth phone book permission Alert Activity text [CHAR LIMIT=none] --> + <string name="bluetooth_pb_acceptance_dialog_text">%1$s would like to access your contacts and call history. Give access to %2$s?</string> + + <!-- Bluetooth phone book permission Alert Activity checkbox text [CHAR LIMIT=none] --> + <string name="bluetooth_pb_alwaysallowed">Always allowed?</string> + <!-- Date & time settings screen title --> <string name="date_and_time">Date & time settings</string> <!-- Date/time settings. Summary of the checkbox for choosing between 12 hour time or 24 hour time. Sample of 12-hour time --> diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java new file mode 100644 index 0000000..1a0965c --- /dev/null +++ b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.bluetooth; + +import android.bluetooth.BluetoothDevice; +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.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 com.android.internal.app.AlertActivity; +import com.android.internal.app.AlertController; + +import com.android.settings.R; + +/** + * BluetoothPermissionActivity shows a dialog for accepting incoming + * profile connection request from untrusted devices. + * It is also used to show a dialogue for accepting incoming phonebook + * read request. The request could be initiated by PBAP PCE or by HF AT+CPBR. + */ +public class BluetoothPermissionActivity extends AlertActivity implements + DialogInterface.OnClickListener, Preference.OnPreferenceChangeListener { + private static final String TAG = "BluetoothPermissionActivity"; + private static final boolean DEBUG = Utils.D; + + private View mView; + private TextView messageView; + private Button mOkButton; + private BluetoothDevice mDevice; + + private CheckBox mAlwaysAllowed; + private boolean mAlwaysAllowedValue = true; + + private String mReturnPackage = null; + private String mReturnClass = null; + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)) { + BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (mDevice.equals(device)) dismissDialog(); + } + } + }; + + private void dismissDialog() { + this.dismiss(); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent i = getIntent(); + String action = i.getAction(); + mDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + mReturnPackage = i.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME); + mReturnClass = i.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME); + + if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) { + mDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + if (i.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, + BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) == + BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION) { + showConnectionDialog(); + } else { + showPbapDialog(); + } + } else { + Log.e(TAG, "Error: this activity may be started only with intent " + + "ACTION_CONNECTION_ACCESS_REQUEST"); + finish(); + } + registerReceiver(mReceiver, + new IntentFilter(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)); + } + + private void showConnectionDialog() { + final AlertController.AlertParams p = mAlertParams; + p.mIconId = android.R.drawable.ic_dialog_info; + p.mTitle = getString(R.string.bluetooth_connection_permission_request); + p.mView = createConnectionDialogView(); + p.mPositiveButtonText = getString(R.string.yes); + p.mPositiveButtonListener = this; + p.mNegativeButtonText = getString(R.string.no); + p.mNegativeButtonListener = this; + mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); + setupAlert(); + } + + private void showPbapDialog() { + final AlertController.AlertParams p = mAlertParams; + p.mIconId = android.R.drawable.ic_dialog_info; + p.mTitle = getString(R.string.bluetooth_phonebook_request); + p.mView = createPbapDialogView(); + p.mPositiveButtonText = getString(android.R.string.yes); + p.mPositiveButtonListener = this; + p.mNegativeButtonText = getString(android.R.string.no); + p.mNegativeButtonListener = this; + mOkButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); + setupAlert(); + } + + private String createConnectionDisplayText() { + String mRemoteName = mDevice != null ? mDevice.getName() : null; + + if (mRemoteName == null) mRemoteName = getString(R.string.unknown); + String mMessage1 = getString(R.string.bluetooth_connection_dialog_text, + mRemoteName); + return mMessage1; + } + + private String createPbapDisplayText() { + String mRemoteName = mDevice != null ? mDevice.getName() : null; + + if (mRemoteName == null) mRemoteName = getString(R.string.unknown); + String mMessage1 = getString(R.string.bluetooth_pb_acceptance_dialog_text, + mRemoteName, mRemoteName); + return mMessage1; + } + + private View createConnectionDialogView() { + mView = getLayoutInflater().inflate(R.layout.bluetooth_connection_access, null); + messageView = (TextView)mView.findViewById(R.id.message); + messageView.setText(createConnectionDisplayText()); + return mView; + } + + private View createPbapDialogView() { + mView = getLayoutInflater().inflate(R.layout.bluetooth_pb_access, null); + messageView = (TextView)mView.findViewById(R.id.message); + messageView.setText(createPbapDisplayText()); + mAlwaysAllowed = (CheckBox)mView.findViewById(R.id.bluetooth_pb_alwaysallowed); + mAlwaysAllowed.setChecked(true); + mAlwaysAllowed.setOnCheckedChangeListener(new OnCheckedChangeListener() { + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + mAlwaysAllowedValue = true; + } else { + mAlwaysAllowedValue = false; + } + } + }); + return mView; + } + + private void onPositive() { + if (DEBUG) Log.d(TAG, "onPositive mAlwaysAllowedValue: " + mAlwaysAllowedValue); + sendIntentToReceiver(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY, true, + BluetoothDevice.EXTRA_ALWAYS_ALLOWED, mAlwaysAllowedValue); + finish(); + } + + private void onNegative() { + if (DEBUG) Log.d(TAG, "onNegative mAlwaysAllowedValue: " + mAlwaysAllowedValue); + sendIntentToReceiver(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY, false, + null, false // dummy value, no effect since last param is null + ); + finish(); + } + + private void sendIntentToReceiver(final String intentName, final boolean allowed, + final String extraName, final boolean extraValue) { + Intent intent = new Intent(intentName); + + if (mReturnPackage != null && mReturnClass != null) { + intent.setClassName(mReturnPackage, mReturnClass); + } + + intent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, + allowed ? BluetoothDevice.CONNECTION_ACCESS_YES : + BluetoothDevice.CONNECTION_ACCESS_NO); + + if (extraName != null) { + intent.putExtra(extraName, extraValue); + } + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); + sendBroadcast(intent, android.Manifest.permission.BLUETOOTH_ADMIN); + } + + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + onPositive(); + break; + + case DialogInterface.BUTTON_NEGATIVE: + onNegative(); + break; + default: + break; + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unregisterReceiver(mReceiver); + } + + public boolean onPreferenceChange(Preference preference, Object newValue) { + return true; + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java new file mode 100644 index 0000000..c769ba6 --- /dev/null +++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.bluetooth; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.PowerManager; +import android.util.Log; + +import com.android.settings.R; + +/** + * BluetoothPermissionRequest is a receiver to receive Bluetooth connection + * access request. + */ +public final class BluetoothPermissionRequest extends BroadcastReceiver { + + private static final String TAG = "BluetoothPermissionRequest"; + private static final boolean DEBUG = Utils.V; + public static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth; + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (DEBUG) Log.d(TAG, "onReceive"); + + if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) { + // convert broadcast intent into activity intent (same action string) + BluetoothDevice device = + intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, + BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION); + String returnPackage = intent.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME); + String returnClass = intent.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME); + + Intent connectionAccessIntent = new Intent(action); + connectionAccessIntent.setClass(context, BluetoothPermissionActivity.class); + connectionAccessIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, requestType); + connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); + connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, returnPackage); + connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_CLASS_NAME, returnClass); + + String deviceAddress = device != null ? device.getAddress() : null; + + PowerManager powerManager = + (PowerManager) context.getSystemService(Context.POWER_SERVICE); + + if (powerManager.isScreenOn() && + LocalBluetoothPreferences.shouldShowDialogInForeground(context, deviceAddress) ) { + context.startActivity(connectionAccessIntent); + } else { + // Put up a notification that leads to the dialog + + // Create an intent triggered by clicking on the + // "Clear All Notifications" button + + Intent deleteIntent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); + deleteIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); + deleteIntent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, + BluetoothDevice.CONNECTION_ACCESS_NO); + + Notification notification = new Notification(android.R.drawable.stat_sys_data_bluetooth, + context.getString(R.string.bluetooth_connection_permission_request), + System.currentTimeMillis()); + String deviceName = device != null ? device.getName() : null; + notification.setLatestEventInfo(context, + context.getString(R.string.bluetooth_connection_permission_request), + context.getString(R.string.bluetooth_connection_notif_message, deviceName), + PendingIntent.getActivity(context, 0, connectionAccessIntent, 0)); + notification.flags = Notification.FLAG_AUTO_CANCEL | + Notification.FLAG_ONLY_ALERT_ONCE; + notification.defaults = Notification.DEFAULT_SOUND; + notification.deleteIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0); + + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(NOTIFICATION_ID, notification); + } + } else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)) { + // Remove the notification + NotificationManager manager = (NotificationManager) context + .getSystemService(Context.NOTIFICATION_SERVICE); + manager.cancel(NOTIFICATION_ID); + } + } +} |