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

Commit 0d3afb25 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
(cherry picked from commit f3bff5dcae6cd8f7571d23ed06d8d59207434f1b)
parent c1acf200
Loading
Loading
Loading
Loading
+149 −102
Original line number Original line 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_PROFILE_INIT_PRIORITIES = 2;
    private static final int MESSAGE_CONNECT_OTHER_PROFILES = 3;
    private static final int MESSAGE_CONNECT_OTHER_PROFILES = 3;
    private static final int MESSAGE_ADAPTER_STATE_TURNED_ON = 4;
    private static final int MESSAGE_ADAPTER_STATE_TURNED_ON = 4;
    private static final int MESSAGE_PROFILE_ACTIVE_DEVICE_CHANGED = 5;


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


    private final AdapterService mAdapterService;
    private final AdapterService mAdapterService;
    private final ServiceFactory mFactory;
    private final ServiceFactory mFactory;
@@ -110,6 +110,11 @@ class PhonePolicy {
                            BluetoothProfile.A2DP, -1, // No-op argument
                            BluetoothProfile.A2DP, -1, // No-op argument
                            intent).sendToTarget();
                            intent).sendToTarget();
                    break;
                    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:
                case BluetoothAdapter.ACTION_STATE_CHANGED:
                    // Only pass the message on if the adapter has actually changed state from
                    // 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.
                    // non-ON to ON. NOTE: ON is the state depicting BREDR ON and not just BLE ON.
@@ -169,6 +174,14 @@ class PhonePolicy {
                }
                }
                break;
                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: {
                case MESSAGE_CONNECT_OTHER_PROFILES: {
                    // Called when we try connect some profiles in processConnectOtherProfiles but
                    // Called when we try connect some profiles in processConnectOtherProfiles but
                    // we send a delayed message to try connecting the remaining profiles
                    // 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(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
        filter.addAction(BluetoothDevice.ACTION_UUID);
        filter.addAction(BluetoothDevice.ACTION_UUID);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
        mAdapterService.registerReceiver(mReceiver, filter);
        mAdapterService.registerReceiver(mReceiver, filter);
    }
    }


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


        if ((hearingAidService != null)
        if ((hearingAidService != null) && BluetoothUuid.isUuidPresent(uuids,
                && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HearingAid)
                BluetoothUuid.HearingAid) && (hearingAidService.getPriority(device)
                && (hearingAidService.getPriority(device) == BluetoothProfile.PRIORITY_UNDEFINED)) {
                == BluetoothProfile.PRIORITY_UNDEFINED)) {
            debugLog("setting hearing aid profile priority for device " + device);
            debugLog("setting hearing aid profile priority for device " + device);
            hearingAidService.setPriority(device, BluetoothProfile.PRIORITY_ON);
            hearingAidService.setPriority(device, BluetoothProfile.PRIORITY_ON);
        }
        }
@@ -269,13 +283,46 @@ class PhonePolicy {
                        break;
                        break;
                }
                }
                connectOtherProfile(device);
                connectOtherProfile(device);
                setProfileAutoConnectionPriority(device, profileId, true);
            }
            }
            if (prevState == BluetoothProfile.STATE_CONNECTING
            if (prevState == BluetoothProfile.STATE_CONNECTING
                    && nextState == BluetoothProfile.STATE_DISCONNECTED) {
                    && 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() {
    private void autoConnect() {
        if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) {
        if (mAdapterService.getState() != BluetoothAdapter.STATE_ON) {
            errorLog("autoConnect() - BT is not ON. Exiting autoConnect");
            errorLog("autoConnect: BT is not ON. Exiting autoConnect");
            return;
            return;
        }
        }


        if (!mAdapterService.isQuietModeEnabled()) {
        if (!mAdapterService.isQuietModeEnabled()) {
            debugLog("autoConnect() - Initiate auto connection on BT on...");
            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;
        }
            final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
            final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
            if (bondedDevices == null) {
            if (bondedDevices == null) {
            errorLog("autoConnectHeadset, bondedDevices are null");
                errorLog("autoConnect: bondedDevices are null");
                return;
                return;
            }
            }
            for (BluetoothDevice device : bondedDevices) {
            for (BluetoothDevice device : bondedDevices) {
            int priority = hsService.getPriority(device);
                autoConnectHeadset(device);
            debugLog("autoConnectHeadset, attempt auto-connect with device " + device
                autoConnectA2dp(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);
            }
            }
        } 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();
        final A2dpService a2dpService = mFactory.getA2dpService();
        if (a2dpService == null) {
        if (a2dpService == null) {
            errorLog("autoConnectA2dp, service is null");
            warnLog("autoConnectA2dp: service is null, failed to connect to " + device);
            return;
        }
        final BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
        if (bondedDevices == null) {
            errorLog("autoConnectA2dp, bondedDevices are null");
            return;
            return;
        }
        }
        for (BluetoothDevice device : bondedDevices) {
        int a2dpPriority = a2dpService.getPriority(device);
            int priority = a2dpService.getPriority(device);
        if (a2dpPriority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
            debugLog("autoConnectA2dp, attempt auto-connect with device " + device
            debugLog("autoConnectA2dp: connecting A2DP with " + device);
                     + " priority " + priority);
            if (priority == BluetoothProfile.PRIORITY_AUTO_CONNECT) {
                debugLog("autoConnectA2dp, connecting A2DP with " + device);
            a2dpService.connect(device);
            a2dpService.connect(device);
        } else {
        } else {
                debugLog("autoConnectA2dp, skipped auto-connect with device " + device
            debugLog("autoConnectA2dp: skipped auto-connect A2DP with device " + device
                         + " priority " + priority);
                    + " 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) {
    private void connectOtherProfile(BluetoothDevice device) {
@@ -444,62 +479,74 @@ class PhonePolicy {
        }
        }
    }
    }


    private void setProfileAutoConnectionPriority(BluetoothDevice device, int profileId,
    /**
            boolean autoConnect) {
     * Set a device's headset profile priority to PRIORITY_AUTO_CONNECT if device support that
        debugLog("setProfileAutoConnectionPriority: device=" + device + ", profile=" + profileId
     * profile
                + ", autoConnect=" + autoConnect);
     *
        switch (profileId) {
     * @param device device whose headset profile priority should be PRIORITY_AUTO_CONNECT
            case BluetoothProfile.HEADSET: {
     */
    private void setAutoConnectForHeadset(BluetoothDevice device) {
        HeadsetService hsService = mFactory.getHeadsetService();
        HeadsetService hsService = mFactory.getHeadsetService();
        if (hsService == null) {
        if (hsService == null) {
                    warnLog("setProfileAutoConnectionPriority: HEADSET service is null");
            warnLog("setAutoConnectForHeadset: HEADSET service is null");
                    break;
            return;
        }
        }
                removeAutoConnectFromDisconnectedHeadsets(hsService);
        if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) {
                if (autoConnect) {
            debugLog("setAutoConnectForHeadset: device " + device + " PRIORITY_AUTO_CONNECT");
            hsService.setPriority(device, BluetoothProfile.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();
        A2dpService a2dpService = mFactory.getA2dpService();
        if (a2dpService == null) {
        if (a2dpService == null) {
                    warnLog("setProfileAutoConnectionPriority: A2DP service is null");
            warnLog("setAutoConnectForA2dpSink: A2DP service is null");
                    break;
            return;
        }
        }
                removeAutoConnectFromDisconnectedA2dpSinks(a2dpService);
        if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_ON) {
                if (autoConnect) {
            debugLog("setAutoConnectForA2dpSink: device " + device + " PRIORITY_AUTO_CONNECT");
            a2dpService.setPriority(device, BluetoothProfile.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();
     * Remove PRIORITY_AUTO_CONNECT from all headsets and set headset that used to have
        for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
     * PRIORITY_AUTO_CONNECT to PRIORITY_ON
            if (hsService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT
     *
                    && !connectedDeviceList.contains(device)) {
     * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed
                debugLog("removeAutoConnectFromDisconnectedHeadsets, device " + device
     */
                        + " PRIORITY_ON");
    private void removeAutoConnectFromHeadset(BluetoothDevice device) {
                hsService.setPriority(device, BluetoothProfile.PRIORITY_ON);
        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();
     * Remove PRIORITY_AUTO_CONNECT from all A2DP sinks and set A2DP sink that used to have
        for (BluetoothDevice device : mAdapterService.getBondedDevices()) {
     * PRIORITY_AUTO_CONNECT to PRIORITY_ON
            if (a2dpService.getPriority(device) >= BluetoothProfile.PRIORITY_AUTO_CONNECT
     *
                    && !connectedDeviceList.contains(device)) {
     * @param device device whose PRIORITY_AUTO_CONNECT priority should be removed
                debugLog("removeAutoConnectFromDisconnectedA2dpSinks, device " + device
     */
                        + " PRIORITY_ON");
    private void removeAutoConnectFromA2dpSink(BluetoothDevice device) {
                a2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
        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.