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

Commit 700ea968 authored by Edward Jee's avatar Edward Jee Committed by Android (Google) Code Review
Browse files

Merge "Migrates PBAP and MAP access permission data from Settings to Bluetooth." into lmp-dev

parents 1703c915 6788c9b1
Loading
Loading
Loading
Loading
+100 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -107,6 +108,11 @@ public class AdapterService extends Service {
    static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
    static final String RECEIVE_MAP_PERM = android.Manifest.permission.RECEIVE_BLUETOOTH_MAP;

    private static final String PHONEBOOK_ACCESS_PERMISSION_PREFERENCE_FILE =
            "phonebook_access_permission";
    private static final String MESSAGE_ACCESS_PERMISSION_PREFERENCE_FILE =
            "message_access_permission";

    private static final int ADAPTER_SERVICE_TYPE=Service.START_STICKY;

    static {
@@ -962,6 +968,50 @@ public class AdapterService extends Service {
            return service.setPairingConfirmation(device, accept);
        }

        public int getPhonebookAccessPermission(BluetoothDevice device) {
            if (!Utils.checkCaller()) {
                Log.w(TAG, "getPhonebookAccessPermission() - Not allowed for non-active user");
                return BluetoothDevice.ACCESS_UNKNOWN;
            }

            AdapterService service = getService();
            if (service == null) return BluetoothDevice.ACCESS_UNKNOWN;
            return service.getPhonebookAccessPermission(device);
        }

        public boolean setPhonebookAccessPermission(BluetoothDevice device, int value) {
            if (!Utils.checkCaller()) {
                Log.w(TAG, "setPhonebookAccessPermission() - Not allowed for non-active user");
                return false;
            }

            AdapterService service = getService();
            if (service == null) return false;
            return service.setPhonebookAccessPermission(device, value);
        }

        public int getMessageAccessPermission(BluetoothDevice device) {
            if (!Utils.checkCaller()) {
                Log.w(TAG, "getMessageAccessPermission() - Not allowed for non-active user");
                return BluetoothDevice.ACCESS_UNKNOWN;
            }

            AdapterService service = getService();
            if (service == null) return BluetoothDevice.ACCESS_UNKNOWN;
            return service.getMessageAccessPermission(device);
        }

        public boolean setMessageAccessPermission(BluetoothDevice device, int value) {
            if (!Utils.checkCaller()) {
                Log.w(TAG, "setMessageAccessPermission() - Not allowed for non-active user");
                return false;
            }

            AdapterService service = getService();
            if (service == null) return false;
            return service.setMessageAccessPermission(device, value);
        }

        public void sendConnectionStateChange(BluetoothDevice
                device, int profile, int state, int prevState) {
            AdapterService service = getService();
@@ -1479,6 +1529,56 @@ public class AdapterService extends Service {
                accept, 0);
    }

    int getPhonebookAccessPermission(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        SharedPreferences pref = getSharedPreferences(PHONEBOOK_ACCESS_PERMISSION_PREFERENCE_FILE,
                Context.MODE_PRIVATE);
        if (!pref.contains(device.getAddress())) {
            return BluetoothDevice.ACCESS_UNKNOWN;
        }
        return pref.getBoolean(device.getAddress(), false)
                ? BluetoothDevice.ACCESS_ALLOWED : BluetoothDevice.ACCESS_REJECTED;
    }

    boolean setPhonebookAccessPermission(BluetoothDevice device, int value) {
        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
                                       "Need BLUETOOTH PRIVILEGED permission");
        SharedPreferences pref = getSharedPreferences(PHONEBOOK_ACCESS_PERMISSION_PREFERENCE_FILE,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = pref.edit();
        if (value == BluetoothDevice.ACCESS_UNKNOWN) {
            editor.remove(device.getAddress());
        } else {
            editor.putBoolean(device.getAddress(), value == BluetoothDevice.ACCESS_ALLOWED);
        }
        return editor.commit();
    }

    int getMessageAccessPermission(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
        SharedPreferences pref = getSharedPreferences(MESSAGE_ACCESS_PERMISSION_PREFERENCE_FILE,
                Context.MODE_PRIVATE);
        if (!pref.contains(device.getAddress())) {
            return BluetoothDevice.ACCESS_UNKNOWN;
        }
        return pref.getBoolean(device.getAddress(), false)
                ? BluetoothDevice.ACCESS_ALLOWED : BluetoothDevice.ACCESS_REJECTED;
    }

    boolean setMessageAccessPermission(BluetoothDevice device, int value) {
        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
                                       "Need BLUETOOTH PRIVILEGED permission");
        SharedPreferences pref = getSharedPreferences(MESSAGE_ACCESS_PERMISSION_PREFERENCE_FILE,
                Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = pref.edit();
        if (value == BluetoothDevice.ACCESS_UNKNOWN) {
            editor.remove(device.getAddress());
        } else {
            editor.putBoolean(device.getAddress(), value == BluetoothDevice.ACCESS_ALLOWED);
        }
        return editor.commit();
    }

     void sendConnectionStateChange(BluetoothDevice
            device, int profile, int state, int prevState) {
        // TODO(BT) permission check?
+4 −0
Original line number Diff line number Diff line
@@ -192,6 +192,10 @@ final class BondStateMachine extends StateMachine {
                        }
                        if (newState == BluetoothDevice.BOND_NONE)
                        {
                            mAdapterService.setPhonebookAccessPermission(dev,
                                    BluetoothDevice.ACCESS_UNKNOWN);
                            mAdapterService.setMessageAccessPermission(dev,
                                    BluetoothDevice.ACCESS_UNKNOWN);
                            // Set the profile Priorities to undefined
                            clearProfilePriorty(dev);
                        }
+41 −28
Original line number Diff line number Diff line
@@ -141,8 +141,8 @@ public class AtPhonebook {
        return mCheckingAccessPermission;
    }

    public void setCheckingAccessPermission(boolean checkAccessPermission) {
        mCheckingAccessPermission = checkAccessPermission;
    public void setCheckingAccessPermission(boolean checkingAccessPermission) {
        mCheckingAccessPermission = checkingAccessPermission;
    }

    public void setCpbrIndex(int cpbrIndex) {
@@ -346,15 +346,24 @@ public class AtPhonebook {
                mCpbrIndex2 = index2;
                mCheckingAccessPermission = true;

                if (checkAccessPermission(remoteDevice)) {
                int permission = checkAccessPermission(remoteDevice);
                if (permission == BluetoothDevice.ACCESS_ALLOWED) {
                    mCheckingAccessPermission = false;
                    atCommandResult = processCpbrCommand(remoteDevice);
                    mCpbrIndex1 = mCpbrIndex2 = -1;
                    mStateMachine.atResponseCodeNative(atCommandResult, atCommandErrorCode,
                                         getByteAddress(remoteDevice));
                    break;
                } else if (permission == BluetoothDevice.ACCESS_REJECTED) {
                    mCheckingAccessPermission = false;
                    mCpbrIndex1 = mCpbrIndex2 = -1;
                    mStateMachine.atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR,
                            BluetoothCmeError.AG_FAILURE, getByteAddress(remoteDevice));
                }
                // no reponse here, will continue the process in handleAccessPermissionResult
                // If checkAccessPermission(remoteDevice) has returned
                // BluetoothDevice.ACCESS_UNKNOWN, we will continue the process in
                // HeadsetStateMachine.handleAccessPermissionResult(Intent) once HeadsetService
                // receives BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY from Settings app.
                break;
            case TYPE_UNKNOWN:
            default:
@@ -579,27 +588,31 @@ public class AtPhonebook {
        return atCommandResult;
    }

    // Check if the remote device has premission to read our phone book
    // Return true if it has the permission
    // false if not known and we have sent our Intent to check
    private boolean checkAccessPermission(BluetoothDevice remoteDevice) {
    /**
     * Checks if the remote device has premission to read our phone book.
     * If the return value is {@link BluetoothDevice#ACCESS_UNKNOWN}, it means this method has sent
     * an Intent to Settings application to ask user preference.
     *
     * @return {@link BluetoothDevice#ACCESS_UNKNOWN}, {@link BluetoothDevice#ACCESS_ALLOWED} or
     *         {@link BluetoothDevice#ACCESS_REJECTED}.
     */
    private int checkAccessPermission(BluetoothDevice remoteDevice) {
        log("checkAccessPermission");
        boolean trust = remoteDevice.getTrustState();

        if (trust) {
            return true;
        }
        int permission = remoteDevice.getPhonebookAccessPermission();

        if (permission == BluetoothDevice.ACCESS_UNKNOWN) {
            log("checkAccessPermission - ACTION_CONNECTION_ACCESS_REQUEST");
            Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
            intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
            intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
            BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, remoteDevice);
        // Leave EXTRA_PACKAGE_NAME and EXTRA_CLASS_NAME field empty
        // BluetoothHandsfree's broadcast receiver is anonymous, cannot be targeted
            // Leave EXTRA_PACKAGE_NAME and EXTRA_CLASS_NAME field empty.
            // BluetoothHandsfree's broadcast receiver is anonymous, cannot be targeted.
            mContext.sendOrderedBroadcast(intent, BLUETOOTH_ADMIN_PERM);
        return false;
        }

        return permission;
    }

    private static String getPhoneType(int type) {
+13 −9
Original line number Diff line number Diff line
@@ -3208,12 +3208,17 @@ final class HeadsetStateMachine extends StateMachine {
            // has set mCheckingAccessPermission to false
            if (intent.getAction().equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) {
                if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
                    BluetoothDevice.CONNECTION_ACCESS_NO) ==
                    BluetoothDevice.CONNECTION_ACCESS_YES) {
                                       BluetoothDevice.CONNECTION_ACCESS_NO)
                        == BluetoothDevice.CONNECTION_ACCESS_YES) {
                    if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) {
                        mCurrentDevice.setTrust(true);
                        mCurrentDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
                    }
                    atCommandResult = mPhonebook.processCpbrCommand(device);
                } else {
                    if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) {
                        mCurrentDevice.setPhonebookAccessPermission(
                                BluetoothDevice.ACCESS_REJECTED);
                    }
                }
            }
            mPhonebook.setCpbrIndex(-1);
@@ -3221,11 +3226,10 @@ final class HeadsetStateMachine extends StateMachine {

            if (atCommandResult >= 0) {
                atResponseCodeNative(atCommandResult, atCommandErrorCode, getByteAddress(device));
            }
            else
            } else {
                log("handleAccessPermissionResult - RESULT_NONE");
            }
        else {
        } else {
            Log.e(TAG, "Phonebook handle null");
            if (device != null) {
                atResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR, 0,
+44 −37
Original line number Diff line number Diff line
@@ -149,7 +149,7 @@ public class BluetoothMapService extends ProfileService {

    private boolean mIsWaitingAuthorization = false;
    private boolean mRemoveTimeoutMsg = false;
    private boolean mTrust = false; // Temp. fix for missing BluetoothDevice.getTrustState()
    private int mPermission = BluetoothDevice.ACCESS_UNKNOWN;
    private boolean mAccountChanged = false;

    // package and class name to which we send intent to check phone book access permission
@@ -167,7 +167,6 @@ public class BluetoothMapService extends ProfileService {

    }


    private final void closeService() {
        if (DEBUG) Log.d(TAG, "MAP Service closeService in");

@@ -186,7 +185,7 @@ public class BluetoothMapService extends ProfileService {
        }

        mIsWaitingAuthorization = false;
        mTrust = false;
        mPermission = BluetoothDevice.ACCESS_UNKNOWN;
        setState(BluetoothMap.STATE_DISCONNECTED);

        if (mWakeLock != null) {
@@ -296,7 +295,7 @@ public class BluetoothMapService extends ProfileService {

        if(lastMasInst) {
            setState(BluetoothMap.STATE_DISCONNECTED);
            mTrust = false;
            mPermission = BluetoothDevice.ACCESS_UNKNOWN;
            mRemoteDevice = null;
            if(mAccountChanged) {
                updateMasInstances(UPDATE_MAS_INSTANCES_ACCOUNT_DISCONNECT);
@@ -396,17 +395,13 @@ public class BluetoothMapService extends ProfileService {
            return;
        }
        BluetoothMapMasInstance masInst = mMasInstances.get(masId);
        // getTrustState() is not implemented, use local cache
        // boolean trust = mRemoteDevice.getTrustState(); // Need to ensure we are still trusted
        boolean trust = mTrust;
        if (DEBUG) Log.d(TAG, "GetTrustState() = " + trust);

        if (trust) {
        // Need to ensure we are still allowed.
        if (DEBUG) Log.d(TAG, "mPermission = " + mPermission);
        if (mPermission == BluetoothDevice.ACCESS_ALLOWED) {
            try {
                if (DEBUG) Log.d(TAG, "incoming connection accepted from: "
                        + sRemoteDeviceName + " automatically as trusted device");
                if(mBluetoothMnsObexClient != null
                   && masInst != null) {
                if (mBluetoothMnsObexClient != null && masInst != null) {
                    masInst.startObexServerSession(mBluetoothMnsObexClient);
                } else {
                    startObexServerSessions();
@@ -418,6 +413,7 @@ public class BluetoothMapService extends ProfileService {
            }
        }
    }

    public int getState() {
        return mState;
    }
@@ -756,8 +752,9 @@ public class BluetoothMapService extends ProfileService {
     * @return
     */
    public boolean onConnect(BluetoothDevice remoteDevice, BluetoothMapMasInstance masInst) {

        boolean sendIntent = false;
        boolean cancelConnection = false;

        // As this can be called from each MasInstance, we need to lock access to member variables
        synchronized(this) {
            if (mRemoteDevice == null) {
@@ -768,10 +765,13 @@ public class BluetoothMapService extends ProfileService {
                    sRemoteDeviceName = getString(R.string.defaultname);
                }

                if(mTrust == false) {
                mPermission = mRemoteDevice.getMessageAccessPermission();
                if (mPermission == BluetoothDevice.ACCESS_UNKNOWN) {
                    sendIntent = true;
                    mIsWaitingAuthorization = true;
                    setUserTimeoutAlarm();
                } else if (mPermission == BluetoothDevice.ACCESS_REJECTED) {
                    cancelConnection = true;
                }
            } else if (!mRemoteDevice.equals(remoteDevice)) {
                Log.w(TAG, "Unexpected connection from a second Remote Device received. name: " +
@@ -781,11 +781,9 @@ public class BluetoothMapService extends ProfileService {
            } // Else second connection to same device, just continue
        }


        if(sendIntent == true) {
            /* This will trigger */
            Intent intent = new
                Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
        if (sendIntent) {
            // This will trigger Settings app's dialog.
            Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
            intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS);
            intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
                            BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS);
@@ -796,11 +794,9 @@ public class BluetoothMapService extends ProfileService {
                    + sRemoteDeviceName);
            //Queue USER_TIMEOUT to disconnect MAP OBEX session. If user doesn't
            //accept or reject authorization request




        } else {
        } else if (cancelConnection) {
            sendConnectCancelMessage();
        } else if (mPermission == BluetoothDevice.ACCESS_ALLOWED) {
            /* Signal to the service that we have a incoming connection. */
            sendConnectMessage(masInst.getMasId());
        }
@@ -892,8 +888,8 @@ public class BluetoothMapService extends ProfileService {
                                               BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS);
                if (DEBUG) Log.d(TAG, "Received ACTION_CONNECTION_ACCESS_REPLY:" +
                           requestType + "isWaitingAuthorization:" + mIsWaitingAuthorization);
                if ((!mIsWaitingAuthorization) ||
                    (requestType != BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS)) {
                if ((!mIsWaitingAuthorization)
                        || (requestType != BluetoothDevice.REQUEST_TYPE_MESSAGE_ACCESS)) {
                    // this reply is not for us
                    return;
                }
@@ -906,20 +902,31 @@ public class BluetoothMapService extends ProfileService {
                }

                if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
                                       BluetoothDevice.CONNECTION_ACCESS_NO) ==
                    BluetoothDevice.CONNECTION_ACCESS_YES) {
                                       BluetoothDevice.CONNECTION_ACCESS_NO)
                        == BluetoothDevice.CONNECTION_ACCESS_YES) {
                    // Bluetooth connection accepted by user
                    mPermission = BluetoothDevice.ACCESS_ALLOWED;
                    if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) {
                        // Not implemented in BluetoothDevice
                        //boolean result = mRemoteDevice.setTrust(true);
                        //if (DEBUG) Log.d(TAG, "setTrust() result=" + result);
                        boolean result = mRemoteDevice.setMessageAccessPermission(
                                BluetoothDevice.ACCESS_ALLOWED);
                        if (DEBUG) {
                            Log.d(TAG, "setMessageAccessPermission(ACCESS_ALLOWED) result="
                                    + result);
                        }
                    }
                    mTrust = true;
                    sendConnectMessage(-1); // -1 indicates all MAS instances
                } else {
                    // Auth. declined by user, serverSession should not be running, but
                    // call stop anyway to restart listener.
                    mTrust = false;
                    mPermission = BluetoothDevice.ACCESS_REJECTED;
                    if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) {
                        boolean result = mRemoteDevice.setMessageAccessPermission(
                                BluetoothDevice.ACCESS_REJECTED);
                        if (DEBUG) {
                            Log.d(TAG, "setMessageAccessPermission(ACCESS_REJECTED) result="
                                    + result);
                        }
                    }
                    sendConnectCancelMessage();
                }
            } else if (action.equals(ACTION_SHOW_MAPS_EMAIL_SETTINGS)) {
Loading