Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b707255a authored by Matthew Xie's avatar Matthew Xie
Browse files

Remember user choice for phone book access permission dialog

Change the always-allowed checkbox to be don't-ask-again checkbox to remember
user's decision so that user will not be bothered agian if he/she checks
the don't-ask-again checkbox
bug 5099661

Change-Id: If32ab8e93313bbd33ff040553083f0cf9359b69e
parent 9403d8b2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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>

+1 −1
Original line number Diff line number Diff line
@@ -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 &amp; time settings</string>
+53 −29
Original line number Diff line number Diff line
@@ -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) {
@@ -70,6 +69,7 @@ public class BluetoothPermissionActivity extends AlertActivity implements
            }
        }
    };
    private boolean mReceiverRegistered = false;

    private void dismissDialog() {
        this.dismiss();
@@ -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() {
@@ -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);
@@ -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);
@@ -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;
                }
            }
            });
@@ -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
                             );
@@ -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);
    }
}
+92 −14
Original line number Diff line number Diff line
@@ -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);
@@ -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),
@@ -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);
    }
}
+46 −4
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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.
@@ -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;
@@ -305,9 +322,9 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
        fetchName();
        fetchBtClass();
        updateProfiles();
        fetchPhonebookPermissionChoice();

        mVisible = false;

        dispatchAttributesChanged();
    }

@@ -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();
@@ -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