Loading res/layout/bluetooth_pb_access.xml +2 −2 Original line number Diff line number Diff line Loading @@ -36,12 +36,12 @@ android:gravity="center_horizontal" android:textAppearance="?android:attr/textAppearanceMedium" /> <CheckBox android:id="@+id/bluetooth_pb_alwaysallowed" <CheckBox android:id="@+id/bluetooth_pb_remember_choice" style="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="2dip" android:text="@string/bluetooth_pb_alwaysallowed" /> android:text="@string/bluetooth_pb_remember_choice" /> </LinearLayout> Loading res/values/strings.xml +1 −1 Original line number Diff line number Diff line Loading @@ -323,7 +323,7 @@ <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> <string name="bluetooth_pb_remember_choice">Don\'t ask again</string> <!-- Date & time settings screen title --> <string name="date_and_time">Date & time settings</string> Loading src/com/android/settings/bluetooth/BluetoothPermissionActivity.java +53 −29 Original line number Diff line number Diff line Loading @@ -53,13 +53,12 @@ public class BluetoothPermissionActivity extends AlertActivity implements 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 CheckBox mRememberChoice; private boolean mRememberChoiceValue = false; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -70,6 +69,7 @@ public class BluetoothPermissionActivity extends AlertActivity implements } } }; private boolean mReceiverRegistered = false; private void dismissDialog() { this.dismiss(); Loading @@ -81,26 +81,31 @@ public class BluetoothPermissionActivity extends AlertActivity implements Intent i = getIntent(); String action = i.getAction(); if (!action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) { Log.e(TAG, "Error: this activity may be started only with intent " + "ACTION_CONNECTION_ACCESS_REQUEST"); finish(); return; } mDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); mReturnPackage = i.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME); mReturnClass = i.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME); int requestType = i.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); 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) { if (requestType == BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION) { showConnectionDialog(); } else if (requestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) { showPhonebookDialog(); } else { showPbapDialog(); } } else { Log.e(TAG, "Error: this activity may be started only with intent " + "ACTION_CONNECTION_ACCESS_REQUEST"); Log.e(TAG, "Error: bad request type: " + requestType); finish(); return; } registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)); mReceiverRegistered = true; } private void showConnectionDialog() { Loading @@ -116,11 +121,11 @@ public class BluetoothPermissionActivity extends AlertActivity implements setupAlert(); } private void showPbapDialog() { private void showPhonebookDialog() { 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.mView = createPhonebookDialogView(); p.mPositiveButtonText = getString(android.R.string.yes); p.mPositiveButtonListener = this; p.mNegativeButtonText = getString(android.R.string.no); Loading @@ -138,7 +143,7 @@ public class BluetoothPermissionActivity extends AlertActivity implements return mMessage1; } private String createPbapDisplayText() { private String createPhonebookDisplayText() { String mRemoteName = mDevice != null ? mDevice.getAliasName() : null; if (mRemoteName == null) mRemoteName = getString(R.string.unknown); Loading @@ -154,18 +159,18 @@ public class BluetoothPermissionActivity extends AlertActivity implements return mView; } private View createPbapDialogView() { private View createPhonebookDialogView() { 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() { messageView.setText(createPhonebookDisplayText()); mRememberChoice = (CheckBox)mView.findViewById(R.id.bluetooth_pb_remember_choice); mRememberChoice.setChecked(false); mRememberChoice.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { mAlwaysAllowedValue = true; mRememberChoiceValue = true; } else { mAlwaysAllowedValue = false; mRememberChoiceValue = false; } } }); Loading @@ -173,14 +178,22 @@ public class BluetoothPermissionActivity extends AlertActivity implements } private void onPositive() { if (DEBUG) Log.d(TAG, "onPositive mAlwaysAllowedValue: " + mAlwaysAllowedValue); if (DEBUG) Log.d(TAG, "onPositive mRememberChoiceValue: " + mRememberChoiceValue); if (mRememberChoiceValue) { savePhonebookPermissionChoice(CachedBluetoothDevice.PHONEBOOK_ACCESS_ALLOWED); } sendIntentToReceiver(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY, true, BluetoothDevice.EXTRA_ALWAYS_ALLOWED, mAlwaysAllowedValue); BluetoothDevice.EXTRA_ALWAYS_ALLOWED, mRememberChoiceValue); finish(); } private void onNegative() { if (DEBUG) Log.d(TAG, "onNegative mAlwaysAllowedValue: " + mAlwaysAllowedValue); if (DEBUG) Log.d(TAG, "onNegative mRememberChoiceValue: " + mRememberChoiceValue); if (mRememberChoiceValue) { savePhonebookPermissionChoice(CachedBluetoothDevice.PHONEBOOK_ACCESS_REJECTED); } sendIntentToReceiver(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY, false, null, false // dummy value, no effect since last param is null ); Loading Loading @@ -223,10 +236,21 @@ public class BluetoothPermissionActivity extends AlertActivity implements @Override protected void onDestroy() { super.onDestroy(); if (mReceiverRegistered) { unregisterReceiver(mReceiver); mReceiverRegistered = false; } } public boolean onPreferenceChange(Preference preference, Object newValue) { return true; } private void savePhonebookPermissionChoice(int permissionChoice) { LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(this); CachedBluetoothDeviceManager cachedDeviceManager = bluetoothManager.getCachedDeviceManager(); CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); cachedDevice.setPhonebookPermissionChoice(permissionChoice); } } src/com/android/settings/bluetooth/BluetoothPermissionRequest.java +92 −14 Original line number Diff line number Diff line Loading @@ -38,30 +38,44 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver { private static final boolean DEBUG = Utils.V; public static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth; Context mContext; int mRequestType; BluetoothDevice mDevice; String mReturnPackage = null; String mReturnClass = null; @Override public void onReceive(Context context, Intent intent) { mContext = context; 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, mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); mRequestType = 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); mReturnPackage = intent.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME); mReturnClass = 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); connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, mRequestType); connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, mReturnPackage); connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_CLASS_NAME, mReturnClass); // Check if user had made decisions on accepting or rejecting the phonebook access // request. If there is, reply the request and return, no need to start permission // activity dialog or notification. if (checkUserChoice()) { return; } String deviceAddress = device != null ? device.getAddress() : null; String deviceAddress = mDevice != null ? mDevice.getAddress() : null; PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); Loading @@ -76,14 +90,15 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver { // "Clear All Notifications" button Intent deleteIntent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); deleteIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); deleteIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); deleteIntent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, BluetoothDevice.CONNECTION_ACCESS_NO); Notification notification = new Notification(android.R.drawable.stat_sys_data_bluetooth, 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.getAliasName() : null; String deviceName = mDevice != null ? mDevice.getAliasName() : null; notification.setLatestEventInfo(context, context.getString(R.string.bluetooth_connection_permission_request), context.getString(R.string.bluetooth_connection_notif_message, deviceName), Loading @@ -104,4 +119,67 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver { manager.cancel(NOTIFICATION_ID); } } /** * @return true user had made a choice, this method replies to the request according * to user's previous decision * false user hadnot made any choice on this device */ private boolean checkUserChoice() { boolean processed = false; // we only remember PHONEBOOK permission if (mRequestType != BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) { return processed; } LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(mContext); CachedBluetoothDeviceManager cachedDeviceManager = bluetoothManager.getCachedDeviceManager(); CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); if (cachedDevice == null) { cachedDevice = cachedDeviceManager.addDevice(bluetoothManager.getBluetoothAdapter(), bluetoothManager.getProfileManager(), mDevice); } int phonebookPermission = cachedDevice.getPhonebookPermissionChoice(); if (phonebookPermission == CachedBluetoothDevice.PHONEBOOK_ACCESS_UNKNOWN) { return processed; } String intentName = BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY; if (phonebookPermission == CachedBluetoothDevice.PHONEBOOK_ACCESS_ALLOWED) { sendIntentToReceiver(intentName, true, BluetoothDevice.EXTRA_ALWAYS_ALLOWED, true); processed = true; } else if (phonebookPermission == CachedBluetoothDevice.PHONEBOOK_ACCESS_REJECTED) { sendIntentToReceiver(intentName, false, null, false // dummy value, no effect since previous param is null ); processed = true; } else { Log.e(TAG, "Bad phonebookPermission: " + phonebookPermission); } return processed; } 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); mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH_ADMIN); } } src/com/android/settings/bluetooth/CachedBluetoothDevice.java +46 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.settings.bluetooth; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.SharedPreferences; import android.os.ParcelUuid; import android.os.SystemClock; import android.text.TextUtils; Loading @@ -40,6 +42,7 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { private static final String TAG = "CachedBluetoothDevice"; private static final boolean DEBUG = Utils.V; private final Context mContext; private final LocalBluetoothAdapter mLocalAdapter; private final LocalBluetoothProfileManager mProfileManager; private final BluetoothDevice mDevice; Loading @@ -60,8 +63,20 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { private boolean mVisible; private int mPhonebookPermissionChoice; private final Collection<Callback> mCallbacks = new ArrayList<Callback>(); // Following constants indicate the user's choices of Phone book access settings // User hasn't made any choice or settings app has wiped out the memory final static int PHONEBOOK_ACCESS_UNKNOWN = 0; // User has accepted the connection and let Settings app remember the decision final static int PHONEBOOK_ACCESS_ALLOWED = 1; // User has rejected the connection and let Settings app remember the decision final static int PHONEBOOK_ACCESS_REJECTED = 2; private final static String PHONEBOOK_PREFS_NAME = "bluetooth_phonebook_permission"; /** * When we connect to multiple profiles, we only want to display a single * error even if they all fail. This tracks that state. Loading Loading @@ -125,9 +140,11 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { } } CachedBluetoothDevice(LocalBluetoothAdapter adapter, CachedBluetoothDevice(Context context, LocalBluetoothAdapter adapter, LocalBluetoothProfileManager profileManager, BluetoothDevice device) { mContext = context; mLocalAdapter = adapter; mProfileManager = profileManager; mDevice = device; Loading Loading @@ -305,9 +322,9 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { fetchName(); fetchBtClass(); updateProfiles(); fetchPhonebookPermissionChoice(); mVisible = false; dispatchAttributesChanged(); } Loading Loading @@ -470,6 +487,7 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { if (bondState == BluetoothDevice.BOND_NONE) { mProfiles.clear(); mConnectAfterPairing = false; // cancel auto-connect setPhonebookPermissionChoice(PHONEBOOK_ACCESS_UNKNOWN); } refresh(); Loading Loading @@ -580,4 +598,28 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { public interface Callback { void onDeviceAttributesChanged(); } int getPhonebookPermissionChoice() { return mPhonebookPermissionChoice; } void setPhonebookPermissionChoice(int permissionChoice) { SharedPreferences.Editor editor = mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME, Context.MODE_PRIVATE).edit(); if (permissionChoice == PHONEBOOK_ACCESS_UNKNOWN) { editor.remove(mDevice.getAddress()); } else { editor.putInt(mDevice.getAddress(), permissionChoice); } editor.commit(); mPhonebookPermissionChoice = permissionChoice; } private void fetchPhonebookPermissionChoice() { SharedPreferences preference = mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME, Context.MODE_PRIVATE); mPhonebookPermissionChoice = preference.getInt(mDevice.getAddress(), PHONEBOOK_ACCESS_UNKNOWN); } } Loading
res/layout/bluetooth_pb_access.xml +2 −2 Original line number Diff line number Diff line Loading @@ -36,12 +36,12 @@ android:gravity="center_horizontal" android:textAppearance="?android:attr/textAppearanceMedium" /> <CheckBox android:id="@+id/bluetooth_pb_alwaysallowed" <CheckBox android:id="@+id/bluetooth_pb_remember_choice" style="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="2dip" android:text="@string/bluetooth_pb_alwaysallowed" /> android:text="@string/bluetooth_pb_remember_choice" /> </LinearLayout> Loading
res/values/strings.xml +1 −1 Original line number Diff line number Diff line Loading @@ -323,7 +323,7 @@ <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> <string name="bluetooth_pb_remember_choice">Don\'t ask again</string> <!-- Date & time settings screen title --> <string name="date_and_time">Date & time settings</string> Loading
src/com/android/settings/bluetooth/BluetoothPermissionActivity.java +53 −29 Original line number Diff line number Diff line Loading @@ -53,13 +53,12 @@ public class BluetoothPermissionActivity extends AlertActivity implements 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 CheckBox mRememberChoice; private boolean mRememberChoiceValue = false; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -70,6 +69,7 @@ public class BluetoothPermissionActivity extends AlertActivity implements } } }; private boolean mReceiverRegistered = false; private void dismissDialog() { this.dismiss(); Loading @@ -81,26 +81,31 @@ public class BluetoothPermissionActivity extends AlertActivity implements Intent i = getIntent(); String action = i.getAction(); if (!action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) { Log.e(TAG, "Error: this activity may be started only with intent " + "ACTION_CONNECTION_ACCESS_REQUEST"); finish(); return; } mDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); mReturnPackage = i.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME); mReturnClass = i.getStringExtra(BluetoothDevice.EXTRA_CLASS_NAME); int requestType = i.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); 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) { if (requestType == BluetoothDevice.REQUEST_TYPE_PROFILE_CONNECTION) { showConnectionDialog(); } else if (requestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) { showPhonebookDialog(); } else { showPbapDialog(); } } else { Log.e(TAG, "Error: this activity may be started only with intent " + "ACTION_CONNECTION_ACCESS_REQUEST"); Log.e(TAG, "Error: bad request type: " + requestType); finish(); return; } registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL)); mReceiverRegistered = true; } private void showConnectionDialog() { Loading @@ -116,11 +121,11 @@ public class BluetoothPermissionActivity extends AlertActivity implements setupAlert(); } private void showPbapDialog() { private void showPhonebookDialog() { 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.mView = createPhonebookDialogView(); p.mPositiveButtonText = getString(android.R.string.yes); p.mPositiveButtonListener = this; p.mNegativeButtonText = getString(android.R.string.no); Loading @@ -138,7 +143,7 @@ public class BluetoothPermissionActivity extends AlertActivity implements return mMessage1; } private String createPbapDisplayText() { private String createPhonebookDisplayText() { String mRemoteName = mDevice != null ? mDevice.getAliasName() : null; if (mRemoteName == null) mRemoteName = getString(R.string.unknown); Loading @@ -154,18 +159,18 @@ public class BluetoothPermissionActivity extends AlertActivity implements return mView; } private View createPbapDialogView() { private View createPhonebookDialogView() { 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() { messageView.setText(createPhonebookDisplayText()); mRememberChoice = (CheckBox)mView.findViewById(R.id.bluetooth_pb_remember_choice); mRememberChoice.setChecked(false); mRememberChoice.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { mAlwaysAllowedValue = true; mRememberChoiceValue = true; } else { mAlwaysAllowedValue = false; mRememberChoiceValue = false; } } }); Loading @@ -173,14 +178,22 @@ public class BluetoothPermissionActivity extends AlertActivity implements } private void onPositive() { if (DEBUG) Log.d(TAG, "onPositive mAlwaysAllowedValue: " + mAlwaysAllowedValue); if (DEBUG) Log.d(TAG, "onPositive mRememberChoiceValue: " + mRememberChoiceValue); if (mRememberChoiceValue) { savePhonebookPermissionChoice(CachedBluetoothDevice.PHONEBOOK_ACCESS_ALLOWED); } sendIntentToReceiver(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY, true, BluetoothDevice.EXTRA_ALWAYS_ALLOWED, mAlwaysAllowedValue); BluetoothDevice.EXTRA_ALWAYS_ALLOWED, mRememberChoiceValue); finish(); } private void onNegative() { if (DEBUG) Log.d(TAG, "onNegative mAlwaysAllowedValue: " + mAlwaysAllowedValue); if (DEBUG) Log.d(TAG, "onNegative mRememberChoiceValue: " + mRememberChoiceValue); if (mRememberChoiceValue) { savePhonebookPermissionChoice(CachedBluetoothDevice.PHONEBOOK_ACCESS_REJECTED); } sendIntentToReceiver(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY, false, null, false // dummy value, no effect since last param is null ); Loading Loading @@ -223,10 +236,21 @@ public class BluetoothPermissionActivity extends AlertActivity implements @Override protected void onDestroy() { super.onDestroy(); if (mReceiverRegistered) { unregisterReceiver(mReceiver); mReceiverRegistered = false; } } public boolean onPreferenceChange(Preference preference, Object newValue) { return true; } private void savePhonebookPermissionChoice(int permissionChoice) { LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(this); CachedBluetoothDeviceManager cachedDeviceManager = bluetoothManager.getCachedDeviceManager(); CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); cachedDevice.setPhonebookPermissionChoice(permissionChoice); } }
src/com/android/settings/bluetooth/BluetoothPermissionRequest.java +92 −14 Original line number Diff line number Diff line Loading @@ -38,30 +38,44 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver { private static final boolean DEBUG = Utils.V; public static final int NOTIFICATION_ID = android.R.drawable.stat_sys_data_bluetooth; Context mContext; int mRequestType; BluetoothDevice mDevice; String mReturnPackage = null; String mReturnClass = null; @Override public void onReceive(Context context, Intent intent) { mContext = context; 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, mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); mRequestType = 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); mReturnPackage = intent.getStringExtra(BluetoothDevice.EXTRA_PACKAGE_NAME); mReturnClass = 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); connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, mRequestType); connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, mReturnPackage); connectionAccessIntent.putExtra(BluetoothDevice.EXTRA_CLASS_NAME, mReturnClass); // Check if user had made decisions on accepting or rejecting the phonebook access // request. If there is, reply the request and return, no need to start permission // activity dialog or notification. if (checkUserChoice()) { return; } String deviceAddress = device != null ? device.getAddress() : null; String deviceAddress = mDevice != null ? mDevice.getAddress() : null; PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); Loading @@ -76,14 +90,15 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver { // "Clear All Notifications" button Intent deleteIntent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); deleteIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); deleteIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice); deleteIntent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, BluetoothDevice.CONNECTION_ACCESS_NO); Notification notification = new Notification(android.R.drawable.stat_sys_data_bluetooth, 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.getAliasName() : null; String deviceName = mDevice != null ? mDevice.getAliasName() : null; notification.setLatestEventInfo(context, context.getString(R.string.bluetooth_connection_permission_request), context.getString(R.string.bluetooth_connection_notif_message, deviceName), Loading @@ -104,4 +119,67 @@ public final class BluetoothPermissionRequest extends BroadcastReceiver { manager.cancel(NOTIFICATION_ID); } } /** * @return true user had made a choice, this method replies to the request according * to user's previous decision * false user hadnot made any choice on this device */ private boolean checkUserChoice() { boolean processed = false; // we only remember PHONEBOOK permission if (mRequestType != BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) { return processed; } LocalBluetoothManager bluetoothManager = LocalBluetoothManager.getInstance(mContext); CachedBluetoothDeviceManager cachedDeviceManager = bluetoothManager.getCachedDeviceManager(); CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(mDevice); if (cachedDevice == null) { cachedDevice = cachedDeviceManager.addDevice(bluetoothManager.getBluetoothAdapter(), bluetoothManager.getProfileManager(), mDevice); } int phonebookPermission = cachedDevice.getPhonebookPermissionChoice(); if (phonebookPermission == CachedBluetoothDevice.PHONEBOOK_ACCESS_UNKNOWN) { return processed; } String intentName = BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY; if (phonebookPermission == CachedBluetoothDevice.PHONEBOOK_ACCESS_ALLOWED) { sendIntentToReceiver(intentName, true, BluetoothDevice.EXTRA_ALWAYS_ALLOWED, true); processed = true; } else if (phonebookPermission == CachedBluetoothDevice.PHONEBOOK_ACCESS_REJECTED) { sendIntentToReceiver(intentName, false, null, false // dummy value, no effect since previous param is null ); processed = true; } else { Log.e(TAG, "Bad phonebookPermission: " + phonebookPermission); } return processed; } 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); mContext.sendBroadcast(intent, android.Manifest.permission.BLUETOOTH_ADMIN); } }
src/com/android/settings/bluetooth/CachedBluetoothDevice.java +46 −4 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.settings.bluetooth; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.SharedPreferences; import android.os.ParcelUuid; import android.os.SystemClock; import android.text.TextUtils; Loading @@ -40,6 +42,7 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { private static final String TAG = "CachedBluetoothDevice"; private static final boolean DEBUG = Utils.V; private final Context mContext; private final LocalBluetoothAdapter mLocalAdapter; private final LocalBluetoothProfileManager mProfileManager; private final BluetoothDevice mDevice; Loading @@ -60,8 +63,20 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { private boolean mVisible; private int mPhonebookPermissionChoice; private final Collection<Callback> mCallbacks = new ArrayList<Callback>(); // Following constants indicate the user's choices of Phone book access settings // User hasn't made any choice or settings app has wiped out the memory final static int PHONEBOOK_ACCESS_UNKNOWN = 0; // User has accepted the connection and let Settings app remember the decision final static int PHONEBOOK_ACCESS_ALLOWED = 1; // User has rejected the connection and let Settings app remember the decision final static int PHONEBOOK_ACCESS_REJECTED = 2; private final static String PHONEBOOK_PREFS_NAME = "bluetooth_phonebook_permission"; /** * When we connect to multiple profiles, we only want to display a single * error even if they all fail. This tracks that state. Loading Loading @@ -125,9 +140,11 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { } } CachedBluetoothDevice(LocalBluetoothAdapter adapter, CachedBluetoothDevice(Context context, LocalBluetoothAdapter adapter, LocalBluetoothProfileManager profileManager, BluetoothDevice device) { mContext = context; mLocalAdapter = adapter; mProfileManager = profileManager; mDevice = device; Loading Loading @@ -305,9 +322,9 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { fetchName(); fetchBtClass(); updateProfiles(); fetchPhonebookPermissionChoice(); mVisible = false; dispatchAttributesChanged(); } Loading Loading @@ -470,6 +487,7 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { if (bondState == BluetoothDevice.BOND_NONE) { mProfiles.clear(); mConnectAfterPairing = false; // cancel auto-connect setPhonebookPermissionChoice(PHONEBOOK_ACCESS_UNKNOWN); } refresh(); Loading Loading @@ -580,4 +598,28 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { public interface Callback { void onDeviceAttributesChanged(); } int getPhonebookPermissionChoice() { return mPhonebookPermissionChoice; } void setPhonebookPermissionChoice(int permissionChoice) { SharedPreferences.Editor editor = mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME, Context.MODE_PRIVATE).edit(); if (permissionChoice == PHONEBOOK_ACCESS_UNKNOWN) { editor.remove(mDevice.getAddress()); } else { editor.putInt(mDevice.getAddress(), permissionChoice); } editor.commit(); mPhonebookPermissionChoice = permissionChoice; } private void fetchPhonebookPermissionChoice() { SharedPreferences preference = mContext.getSharedPreferences(PHONEBOOK_PREFS_NAME, Context.MODE_PRIVATE); mPhonebookPermissionChoice = preference.getInt(mDevice.getAddress(), PHONEBOOK_ACCESS_UNKNOWN); } }