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

Commit 5012fb00 authored by Jack He's avatar Jack He
Browse files

PhonePolicy: Only auto connect to the last active A2DP device

* Only auto connect to the last device indicated by
  BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED intent
* Ignore the intent when EXTRA_DEVICE is null since we cannot tell
  if setting active device to null is due to user action or due to
  device disconnection. Consider revising this policy in future
  revisions of phone policy

Bug: 79995170
Test: PhonePolicyTest, connect and toggle Bluetooth
Change-Id: I0a0b34e69c6db206fcb6ca67e7edd6421a61f586
parent dd070ba8
Loading
Loading
Loading
Loading
+149 −102
Original line number Diff line number Diff line
@@ -78,10 +78,10 @@ class PhonePolicy {
    private static final int MESSAGE_PROFILE_INIT_PRIORITIES = 2;
    private static final int MESSAGE_CONNECT_OTHER_PROFILES = 3;
    private static final int MESSAGE_ADAPTER_STATE_TURNED_ON = 4;
    private static final int MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED = 5;

    // Timeouts
    @VisibleForTesting
    static int sConnectOtherProfilesTimeoutMillis = 6000; // 6s
    @VisibleForTesting static int sConnectOtherProfilesTimeoutMillis = 6000; // 6s

    private final AdapterService mAdapterService;
    private final ServiceFactory mFactory;
@@ -110,6 +110,11 @@ class PhonePolicy {
                            BluetoothProfile.A2DP, -1, // No-op argument
                            intent).sendToTarget();
                    break;
                case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
                    mHandler.obtainMessage(MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED,
                            BluetoothProfile.A2DP, -1, // No-op argument
                            intent).sendToTarget();
                    break;
                case BluetoothAdapter.ACTION_STATE_CHANGED:
                    // Only pass the message on if the adapter has actually changed state from
                    // non-ON to ON. NOTE: ON is the state depicting BREDR ON and not just BLE ON.
@@ -169,6 +174,14 @@ class PhonePolicy {
                }
                break;

                case MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED: {
                    Intent intent = (Intent) msg.obj;
                    BluetoothDevice activeDevice =
                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    processProfileActiveDeviceChanged(activeDevice, msg.arg1);
                }
                break;

                case MESSAGE_CONNECT_OTHER_PROFILES: {
                    // Called when we try connect some profiles in processConnectOtherProfiles but
                    // we send a delayed message to try connecting the remaining profiles
@@ -195,6 +208,7 @@ class PhonePolicy {
        filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothDevice.ACTION_UUID);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
        mAdapterService.registerReceiver(mReceiver, filter);
    }

@@ -246,9 +260,9 @@ class PhonePolicy {
            panService.setPriority(device, BluetoothProfile.PRIORITY_ON);
        }

        if ((hearingAidService != null)
                && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)
                && (hearingAidService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)) {
        if ((hearingAidService != null) && BluetoothUuid.isUuidPresent(uuids,
                BluetoothUuid.HearingAid) && (hearingAidService.getPriority(device)
                == BluetoothProfile.PRIORITY_UNDEFINED)) {
            debugLog("setting hearing aid profile priority for device " + device);
            hearingAidService.setPriority(device, BluetoothProfile.PRIORITY_ON);
        }
@@ -269,13 +283,46 @@ class PhonePolicy {
                        break;
                }
                connectOtherProfile(device);
                setProfileAutoConnectionPriority(device, profileId, true);
            }
            if (prevState == BluetoothProfile.STATE_CONNECTING
                    && nextState == BluetoothProfile.STATE_DISCONNECTED) {
                setProfileAutoConnectionPriority(device, profileId, false);
                HeadsetService hsService = mFactory.getHeadsetService();
                boolean hsDisconnected = hsService == null || hsService.getConnectionState(device)
                        == BluetoothProfile.STATE_DISCONNECTED;
                A2dpService a2dpService = mFactory.getA2dpService();
                boolean a2dpDisconnected = a2dpService == null
                        || a2dpService.getConnectionState(device)
                        == BluetoothProfile.STATE_DISCONNECTED;
                debugLog("processProfileStateChanged, device=" + device + ", a2dpDisconnected="
                        + a2dpDisconnected + ", hsDisconnected=" + hsDisconnected);
                if (hsDisconnected && a2dpDisconnected) {
                    removeAutoConnectFromA2dpSink(device);
                    removeAutoConnectFromHeadset(device);
                }
            }
        }
    }

    private void processProfileActiveDeviceChanged(BluetoothDevice activeDevice, int profileId) {
        debugLog("processProfileActiveDeviceChanged, activeDevice=" + activeDevice + ", profile="
                + profileId);
        switch (profileId) {
            // Tracking active device changed intent only for A2DP so that we always connect to a
            // single device after toggling Bluetooth
            case BluetoothProfile.A2DP:
                // Ignore null active device since we don't know if the change is triggered by
                // normal device disconnection during Bluetooth shutdown or user action
                if (activeDevice == null) {
                    warnLog("processProfileActiveDeviceChanged: ignore null A2DP active device");
                    return;
                }
                for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
                    removeAutoConnectFromA2dpSink(device);
                    removeAutoConnectFromHeadset(device);
                }
                setAutoConnectForA2dpSink(activeDevice);
                setAutoConnectForHeadset(activeDevice);
                break;
        }
    }

@@ -286,68 +333,56 @@ class PhonePolicy {

    private void autoConnect() {
        if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) {
            errorLog("autoConnect() - BT is not ON. Exiting autoConnect");
            errorLog("autoConnect: BT is not ON. Exiting autoConnect");
            return;
        }

        if (!mAdapterService.isQuietModeEnabled()) {
            debugLog("autoConnect() - Initiate auto connection on BT on...");
            // Phone profiles.
            autoConnectHeadset();
            autoConnectA2dp();
        } else {
            debugLog("autoConnect() - BT is in quiet mode. Not initiating auto connections");
        }
    }

    private void autoConnectHeadset() {
        final HeadsetService hsService = mFactory.getHeadsetService();
        if (hsService == null) {
            errorLog("autoConnectHeadset, service is null");
            return;
        }
            debugLog("autoConnect: Initiate auto connection on BT on...");
            final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
            if (bondedDevices == null) {
            errorLog("autoConnectHeadset, bondedDevices are null");
                errorLog("autoConnect: bondedDevices are null");
                return;
            }
            for (BluetoothDevice device : bondedDevices) {
            int priority = hsService.getPriority(device);
            debugLog("autoConnectHeadset, attempt auto-connect with device " + device
                     + " priority " + priority);
            if (priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
                debugLog("autoConnectHeadset, Connecting HFP with " + device);
                hsService.connect(device);
            } else {
                debugLog("autoConnectHeadset, skipped auto-connect with device " + device
                         + " priority " + priority);
                autoConnectHeadset(device);
                autoConnectA2dp(device);
            }
        } else {
            debugLog("autoConnect() - BT is in quiet mode. Not initiating auto connections");
        }
    }

    private void autoConnectA2dp() {
    private void autoConnectA2dp(BluetoothDevice device) {
        final A2dpService a2dpService = mFactory.getA2dpService();
        if (a2dpService == null) {
            errorLog("autoConnectA2dp, service is null");
            return;
        }
        final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
        if (bondedDevices == null) {
            errorLog("autoConnectA2dp, bondedDevices are null");
            warnLog("autoConnectA2dp: service is null, failed to connect to " + device);
            return;
        }
        for (BluetoothDevice device : bondedDevices) {
            int priority = a2dpService.getPriority(device);
            debugLog("autoConnectA2dp, attempt auto-connect with device " + device
                     + " priority " + priority);
            if (priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
                debugLog("autoConnectA2dp, connecting A2DP with " + device);
        int a2dpPriority = a2dpService.getPriority(device);
        if (a2dpPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
            debugLog("autoConnectA2dp: connecting A2DP with " + device);
            a2dpService.connect(device);
        } else {
                debugLog("autoConnectA2dp, skipped auto-connect with device " + device
                         + " priority " + priority);
            debugLog("autoConnectA2dp: skipped auto-connect A2DP with device " + device
                    + " priority " + a2dpPriority);
        }
    }

    private void autoConnectHeadset(BluetoothDevice device) {
        final HeadsetService hsService = mFactory.getHeadsetService();
        if (hsService == null) {
            warnLog("autoConnectHeadset: service is null, failed to connect to " + device);
            return;
        }
        int headsetPriority = hsService.getPriority(device);
        if (headsetPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
            debugLog("autoConnectHeadset: Connecting HFP with " + device);
            hsService.connect(device);
        } else {
            debugLog("autoConnectHeadset: skipped auto-connect HFP with device " + device
                    + " priority " + headsetPriority);
        }
    }

    private void connectOtherProfile(BluetoothDevice device) {
@@ -444,62 +479,74 @@ class PhonePolicy {
        }
    }

    private void setProfileAutoConnectionPriority(BluetoothDevice device, int profileId,
            boolean autoConnect) {
        debugLog("setProfileAutoConnectionPriority: device=" + device + ", profile=" + profileId
                + ", autoConnect=" + autoConnect);
        switch (profileId) {
            case BluetoothProfile.HEADSET: {
    /**
     * Set a device's headset profile priority to PRIORITY_AUTO_CONNECT if device support that
     * profile
     *
     * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT
     */
    private void setAutoConnectForHeadset(BluetoothDevice device) {
        HeadsetService hsService = mFactory.getHeadsetService();
        if (hsService == null) {
                    warnLog("setProfileAutoConnectionPriority: HEADSET service is null");
                    break;
            warnLog("setAutoConnectForHeadset: HEADSET service is null");
            return;
        }
                removeAutoConnectFromDisconnectedHeadsets(hsService);
                if (autoConnect) {
        if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) {
            debugLog("setAutoConnectForHeadset: device " + device + " PRIORITY_AUTO_CONNECT");
            hsService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
        }
                break;
    }
            case BluetoothProfile.A2DP: {

    /**
     * Set a device's A2DP profile priority to PRIORITY_AUTO_CONNECT if device support that profile
     *
     * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT
     */
    private void setAutoConnectForA2dpSink(BluetoothDevice device) {
        A2dpService a2dpService = mFactory.getA2dpService();
        if (a2dpService == null) {
                    warnLog("setProfileAutoConnectionPriority: A2DP service is null");
                    break;
            warnLog("setAutoConnectForA2dpSink: A2DP service is null");
            return;
        }
                removeAutoConnectFromDisconnectedA2dpSinks(a2dpService);
                if (autoConnect) {
        if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) {
            debugLog("setAutoConnectForA2dpSink: device " + device + " PRIORITY_AUTO_CONNECT");
            a2dpService.setPriority(device, BluetoothProfile.PRIORITY_AUTO_CONNECT);
        }
                break;
            }
            default:
                Log.w(TAG, "Tried to set AutoConnect priority on invalid profile " + profileId);
                break;
        }
    }

    private void removeAutoConnectFromDisconnectedHeadsets(HeadsetService hsService) {
        List<BluetoothDevice> connectedDeviceList = hsService.getConnectedDevices();
        for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
            if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT
                    && !connectedDeviceList.contains(device)) {
                debugLog("removeAutoConnectFromDisconnectedHeadsets, device " + device
                        + " PRIORITY_ON");
                hsService.setPriority(device, BluetoothProfile.PRIORITY_ON);
    /**
     * Remove PRIORITY_AUTO_CONNECT from all headsets and set headset that used to have
     * PRIORITY_AUTO_CONNECT to PRIORITY_ON
     *
     * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed
     */
    private void removeAutoConnectFromHeadset(BluetoothDevice device) {
        HeadsetService hsService = mFactory.getHeadsetService();
        if (hsService == null) {
            warnLog("removeAutoConnectFromHeadset: HEADSET service is null");
            return;
        }
        if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT) {
            debugLog("removeAutoConnectFromHeadset: device " + device + " PRIORITY_ON");
            hsService.setPriority(device, BluetoothProfile.PRIORITY_ON);
        }
    }

    private void removeAutoConnectFromDisconnectedA2dpSinks(A2dpService a2dpService) {
        List<BluetoothDevice> connectedDeviceList = a2dpService.getConnectedDevices();
        for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
            if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT
                    && !connectedDeviceList.contains(device)) {
                debugLog("removeAutoConnectFromDisconnectedA2dpSinks, device " + device
                        + " PRIORITY_ON");
                a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
    /**
     * Remove PRIORITY_AUTO_CONNECT from all A2DP sinks and set A2DP sink that used to have
     * PRIORITY_AUTO_CONNECT to PRIORITY_ON
     *
     * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed
     */
    private void removeAutoConnectFromA2dpSink(BluetoothDevice device) {
        A2dpService a2dpService = mFactory.getA2dpService();
        if (a2dpService == null) {
            warnLog("removeAutoConnectFromA2dpSink: A2DP service is null");
            return;
        }
        if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT) {
            debugLog("removeAutoConnectFromA2dpSink: device " + device + " PRIORITY_ON");
            a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
        }
    }

+40 −37

File changed.

Preview size limit exceeded, changes collapsed.