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

Commit 92f92b54 authored by Matthew Xie's avatar Matthew Xie Committed by Android (Google) Code Review
Browse files

Merge "Remember user choice for phone book access permission dialog"

parents 33d76c30 b707255a
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