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

Commit d7a91b70 authored by Aritra Sen's avatar Aritra Sen Committed by Automerger Merge Worker
Browse files

Merge changes I52a2d86e,I81268b4d into main am: 1785dcf8 am: 17764dc3

parents 6a570fde 17764dc3
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1381,6 +1381,16 @@ public class A2dpService extends ProfileService {
                device, BluetoothProfile.A2DP, toState, fromState);
    }

    /**
     * Retrieves the most recently connected device in the A2DP connected devices list.
     */
    public BluetoothDevice getFallbackDevice() {
        DatabaseManager dbManager = mAdapterService.getDatabase();
        return dbManager != null ? dbManager
            .getMostRecentlyConnectedDevicesInList(getConnectedDevices())
            : null;
    }

    /**
     * Binder object: must be a static class or memory leak may occur.
     */
+44 −95
Original line number Diff line number Diff line
@@ -373,7 +373,6 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
                return;
            }
            mHearingAidConnectedDevices.add(device);
        }
            // New connected device: select it as active
            if (setHearingAidActiveDevice(device)) {
                setA2dpActiveDevice(null, true);
@@ -381,6 +380,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
                setLeAudioActiveDevice(null, true);
            }
        }
    }

    private void handleLeAudioConnected(BluetoothDevice device) {
        synchronized (mLock) {
@@ -669,12 +669,8 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
    private void handleHearingAidActiveDeviceChanged(BluetoothDevice device) {
        synchronized (mLock) {
            if (DBG) {
                Log.d(
                        TAG,
                        "handleHearingAidActiveDeviceChanged: "
                                + device
                                + ", mHearingAidActiveDevices="
                                + mHearingAidActiveDevices);
                Log.d(TAG, "handleHearingAidActiveDeviceChanged: " + device
                        + ", mHearingAidActiveDevices=" + mHearingAidActiveDevices);
            }
            // Just assign locally the new value
            final HearingAidService hearingAidService = mFactory.getHearingAidService();
@@ -688,13 +684,13 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
                            hearingAidService.getConnectedPeerDevices(hiSyncId));
                }
            }
        }
            if (device != null) {
                setA2dpActiveDevice(null, true);
                setHfpActiveDevice(null);
                setLeAudioActiveDevice(null, true);
            }
        }
    }

    private void handleLeAudioActiveDeviceChanged(BluetoothDevice device) {
        synchronized (mLock) {
@@ -853,29 +849,26 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac

    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
    private boolean setHfpActiveDevice(BluetoothDevice device) {
        synchronized (mLock) {
            if (DBG) {
                Log.d(TAG, "setHfpActiveDevice(" + device + ")");
            }
        synchronized (mLock) {
            if (mPendingActiveDevice != null) {
                mHandler.removeCallbacksAndMessages(mPendingActiveDevice);
                mPendingActiveDevice = null;
            }
        }
            final HeadsetService headsetService = mFactory.getHeadsetService();
            if (headsetService == null) {
                return false;
            }
            BluetoothSinkAudioPolicy audioPolicy = headsetService.getHfpCallAudioPolicy(device);
        if (audioPolicy != null
                && audioPolicy.getActiveDevicePolicyAfterConnection()
            if (audioPolicy != null && audioPolicy.getActiveDevicePolicyAfterConnection()
                    == BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) {
                return false;
            }
            if (!headsetService.setActiveDevice(device)) {
                return false;
            }
        synchronized (mLock) {
            mHfpActiveDevice = device;
        }
        return true;
@@ -930,6 +923,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
            Log.d(TAG, "setLeAudioActiveDevice(" + device + ")"
                    + (device == null ? " hasFallbackDevice=" + hasFallbackDevice : ""));
        }
        synchronized (mLock) {
            final LeAudioService leAudioService = mFactory.getLeAudioService();
            if (leAudioService == null) {
                return false;
@@ -945,7 +939,6 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
                return false;
            }

        synchronized (mLock) {
            mLeAudioActiveDevice = device;
            if (device == null) {
                mLeHearingAidActiveDevice = null;
@@ -1019,13 +1012,13 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
        A2dpService a2dpService = mFactory.getA2dpService();
        BluetoothDevice a2dpFallbackDevice = null;
        if (a2dpService != null) {
            a2dpFallbackDevice = getA2dpFallbackDevice();
            a2dpFallbackDevice = a2dpService.getFallbackDevice();
        }

        HeadsetService headsetService = mFactory.getHeadsetService();
        BluetoothDevice headsetFallbackDevice = null;
        if (headsetService != null) {
            headsetFallbackDevice = getHfpFallbackDevice();
            headsetFallbackDevice = headsetService.getFallbackDevice();
        }

        List<BluetoothDevice> connectedDevices = new ArrayList<>();
@@ -1135,50 +1128,6 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac
        }
    }

    /** Retrieves the most recently connected device in the A2DP connected devices list. */
    public BluetoothDevice getA2dpFallbackDevice() {
        DatabaseManager dbManager = mAdapterService.getDatabase();
        synchronized (mLock) {
            return dbManager != null
                    ? dbManager.getMostRecentlyConnectedDevicesInList(mA2dpConnectedDevices)
                    : null;
        }
    }

    /** Retrieves the most recently connected device in the A2DP connected devices list. */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public BluetoothDevice getHfpFallbackDevice() {
        DatabaseManager dbManager = mAdapterService.getDatabase();
        return dbManager != null
                ? dbManager.getMostRecentlyConnectedDevicesInList(getHfpFallbackCandidates())
                : null;
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    List<BluetoothDevice> getHfpFallbackCandidates() {
        List<BluetoothDevice> fallbackCandidates;
        synchronized (mLock) {
            fallbackCandidates = new ArrayList<>(mHfpConnectedDevices);
        }
        List<BluetoothDevice> uninterestedCandidates = new ArrayList<>();
        for (BluetoothDevice device : fallbackCandidates) {
            byte[] deviceType =
                    mDbManager.getCustomMeta(device, BluetoothDevice.METADATA_DEVICE_TYPE);
            BluetoothClass deviceClass = device.getBluetoothClass();
            if ((deviceClass != null
                            && deviceClass.getMajorDeviceClass()
                                    == BluetoothClass.Device.WEARABLE_WRIST_WATCH)
                    || (deviceType != null
                            && BluetoothDevice.DEVICE_TYPE_WATCH.equals(new String(deviceType)))) {
                uninterestedCandidates.add(device);
            }
        }
        for (BluetoothDevice device : uninterestedCandidates) {
            fallbackCandidates.remove(device);
        }
        return fallbackCandidates;
    }

    @VisibleForTesting
    BluetoothDevice getA2dpActiveDevice() {
        return mA2dpActiveDevice;
+39 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static com.android.modules.utils.build.SdkLevel.isAtLeastU;

import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
@@ -52,7 +53,6 @@ import com.android.bluetooth.BluetoothMetricsProto;
import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.Utils;
import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.ActiveDeviceManager;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
@@ -125,7 +125,6 @@ public class HeadsetService extends ProfileService {
    private int mMaxHeadsetConnections = 1;
    private BluetoothDevice mActiveDevice;
    private AdapterService mAdapterService;
    private ActiveDeviceManager mActiveDeviceManager;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
    private Handler mStateMachinesThreadHandler;
@@ -184,7 +183,6 @@ public class HeadsetService extends ProfileService {
                "AdapterService cannot be null when HeadsetService starts");
        mDatabaseManager = Objects.requireNonNull(mAdapterService.getDatabase(),
                "DatabaseManager cannot be null when HeadsetService starts");
        mActiveDeviceManager = Objects.requireNonNull(mAdapterService.getActiveDeviceManager());
        // Step 2: Start handler thread for state machines
        mStateMachinesThread = new HandlerThread("HeadsetService.StateMachines");
        mStateMachinesThread.start();
@@ -1338,12 +1336,12 @@ public class HeadsetService extends ProfileService {
     * Remove the active device
     */
    private void removeActiveDevice() {
        BluetoothDevice fallbackDevice = mActiveDeviceManager.getHfpFallbackDevice();
        synchronized (mStateMachines) {
            // As per b/202602952, if we remove the active device due to a disconnection,
            // we need to check if another device is connected and set it active instead.
            // Calling this before any other active related calls has the same effect as
            // a classic active device switch.
            BluetoothDevice fallbackDevice = getFallbackDevice();
            if (fallbackDevice != null && mActiveDevice != null
                    && getConnectionState(mActiveDevice) != BluetoothProfile.STATE_CONNECTED) {
                setActiveDevice(fallbackDevice);
@@ -1997,8 +1995,11 @@ public class HeadsetService extends ProfileService {
                setActiveDevice(null);
            }
        }
        mActiveDeviceManager.profileConnectionStateChanged(
                BluetoothProfile.HEADSET, device, fromState, toState);

        mAdapterService
                .getActiveDeviceManager()
                .profileConnectionStateChanged(BluetoothProfile.HEADSET, device, fromState,
                    toState);
        mAdapterService
                .getSilenceDeviceManager()
                .hfpConnectionStateChanged(device, fromState, toState);
@@ -2263,6 +2264,38 @@ public class HeadsetService extends ProfileService {
                == mStateMachinesThread.getId());
    }

    /**
     * Retrieves the most recently connected device in the A2DP connected devices list.
     */
    public BluetoothDevice getFallbackDevice() {
        DatabaseManager dbManager = mAdapterService.getDatabase();
        return dbManager != null ? dbManager
            .getMostRecentlyConnectedDevicesInList(getFallbackCandidates(dbManager))
            : null;
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    List<BluetoothDevice> getFallbackCandidates(DatabaseManager dbManager) {
        List<BluetoothDevice> fallbackCandidates = getConnectedDevices();
        List<BluetoothDevice> uninterestedCandidates = new ArrayList<>();
        for (BluetoothDevice device : fallbackCandidates) {
            byte[] deviceType = dbManager.getCustomMeta(device,
                    BluetoothDevice.METADATA_DEVICE_TYPE);
            BluetoothClass deviceClass = device.getBluetoothClass();
            if ((deviceClass != null
                    && deviceClass.getMajorDeviceClass()
                    == BluetoothClass.Device.WEARABLE_WRIST_WATCH)
                    || (deviceType != null
                    && BluetoothDevice.DEVICE_TYPE_WATCH.equals(new String(deviceType)))) {
                uninterestedCandidates.add(device);
            }
        }
        for (BluetoothDevice device : uninterestedCandidates) {
            fallbackCandidates.remove(device);
        }
        return fallbackCandidates;
    }

    @Override
    public void dump(StringBuilder sb) {
        boolean isScoOn = mSystemInterface.getAudioManager().isBluetoothScoOn();
+16 −66
Original line number Diff line number Diff line
@@ -63,9 +63,8 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@MediumTest
@RunWith(AndroidJUnit4.class)
@@ -149,6 +148,21 @@ public class ActiveDeviceManagerTest {
        when(mHearingAidService.getHiSyncId(mHearingAidDevice)).thenReturn(mHearingAidHiSyncId);
        when(mHearingAidService.getConnectedPeerDevices(mHearingAidHiSyncId))
                .thenReturn(connectedHearingAidDevices);

        when(mA2dpService.getFallbackDevice()).thenAnswer(invocation -> {
            if (!mDeviceConnectionStack.isEmpty() && Objects.equals(mA2dpDevice,
                    mDeviceConnectionStack.get(mDeviceConnectionStack.size() - 1))) {
                return mA2dpDevice;
            }
            return null;
        });
        when(mHeadsetService.getFallbackDevice()).thenAnswer(invocation -> {
            if (!mDeviceConnectionStack.isEmpty() && Objects.equals(mHeadsetDevice,
                    mDeviceConnectionStack.get(mDeviceConnectionStack.size() - 1))) {
                return mHeadsetDevice;
            }
            return null;
        });
    }

    @After
@@ -1117,49 +1131,6 @@ public class ActiveDeviceManagerTest {
        verify(mHearingAidService, timeout(TIMEOUT_MS)).removeActiveDevice(false);
    }

    @Test
    public void testGetFallbackCandidates() {
        BluetoothDevice deviceA = TestUtils.getTestDevice(mAdapter, 0);
        BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1);

        // No connected device
        Assert.assertTrue(mActiveDeviceManager.getHfpFallbackCandidates().isEmpty());

        // One connected device
        headsetConnected(deviceA, true);
        TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
        Assert.assertTrue(mActiveDeviceManager.getHfpFallbackCandidates().contains(deviceA));

        // Two connected devices
        headsetConnected(deviceB, false);
        TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
        Assert.assertTrue(mActiveDeviceManager.getHfpFallbackCandidates().contains(deviceA));
        Assert.assertTrue(mActiveDeviceManager.getHfpFallbackCandidates().contains(deviceB));
    }

    @Test
    public void testGetFhpFallbackCandidates_HasWatchDevice() {
        BluetoothDevice deviceWatch = TestUtils.getTestDevice(mAdapter, 0);
        BluetoothDevice deviceRegular = TestUtils.getTestDevice(mAdapter, 1);

        // Make deviceWatch a watch
        mDatabaseManager.setCustomMeta(
                deviceWatch,
                BluetoothDevice.METADATA_DEVICE_TYPE,
                BluetoothDevice.DEVICE_TYPE_WATCH.getBytes());

        // Has a connected watch device
        headsetConnected(deviceWatch, false);
        TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
        Assert.assertTrue(mActiveDeviceManager.getHfpFallbackCandidates().isEmpty());

        // Two connected devices with one watch
        headsetConnected(deviceRegular, true);
        TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
        Assert.assertFalse(mActiveDeviceManager.getHfpFallbackCandidates().contains(deviceWatch));
        Assert.assertTrue(mActiveDeviceManager.getHfpFallbackCandidates().contains(deviceRegular));
    }

    /**
     * Helper to indicate A2dp connected for a device.
     */
@@ -1356,7 +1327,6 @@ public class ActiveDeviceManagerTest {

    private class TestDatabaseManager extends DatabaseManager {
        ArrayMap<BluetoothDevice, SparseIntArray> mProfileConnectionPolicy;
        final Map<String, Map<Integer, byte[]>> mMetadataCache = new HashMap<>();

        TestDatabaseManager(AdapterService service) {
            super(service);
@@ -1405,25 +1375,5 @@ public class ActiveDeviceManagerTest {
            }
            return policy.get(profile, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
        }

        @Override
        public boolean setCustomMeta(BluetoothDevice device, int key, byte[] newValue) {
            Map<Integer, byte[]> metadata = mMetadataCache.get(device.getAddress());
            if (metadata == null) {
                metadata = new ArrayMap<>();
                mMetadataCache.put(device.getAddress(), metadata);
            }
            metadata.put(key, newValue);
            return true;
        }

        @Override
        public byte[] getCustomMeta(BluetoothDevice device, int key) {
            Map<Integer, byte[]> metadata = mMetadataCache.get(device.getAddress());
            if (metadata == null) {
                return null;
            }
            return metadata.get(key);
        }
    }
}
+0 −2
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ public class ProfileServiceTest {
    @Rule public final ServiceTestRule mServiceTestRule = new ServiceTestRule();
    @Mock private AdapterService mMockAdapterService;
    @Mock private DatabaseManager mDatabaseManager;
    @Mock private ActiveDeviceManager mActiveDeviceManager;
    @Mock private LocationManager mLocationManager;

    private Class[] mProfiles;
@@ -149,7 +148,6 @@ public class ProfileServiceTest {
            }
        });
        doReturn(mDatabaseManager).when(mMockAdapterService).getDatabase();
        doReturn(mActiveDeviceManager).when(mMockAdapterService).getActiveDeviceManager();

        when(mMockAdapterService.getSystemService(Context.LOCATION_SERVICE))
                .thenReturn(mLocationManager);
Loading