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

Commit 868fefe9 authored by Jakub Tyszkowski (xWF)'s avatar Jakub Tyszkowski (xWF) Committed by Gerrit Code Review
Browse files

Merge "AvrcpTarget: Fix not unregistering AudioDeviceCallback" into main

parents 95654635 442bc1dd
Loading
Loading
Loading
Loading
+23 −6
Original line number Diff line number Diff line
@@ -66,7 +66,6 @@ public class AvrcpTargetService extends ProfileService {

    // Cover Art Service (Storage + BIP Server)
    private final AvrcpCoverArtService mAvrcpCoverArtService;
    private final AdapterService mAdapterService;
    private final AvrcpVersion mAvrcpVersion;
    private final MediaPlayerList mMediaPlayerList;
    private final PlayerSettingsManager mPlayerSettingsManager;
@@ -100,12 +99,29 @@ public class AvrcpTargetService extends ProfileService {
    private static AvrcpTargetService sInstance = null;

    public AvrcpTargetService(AdapterService adapterService) {
        this(
                requireNonNull(adapterService),
                adapterService.getSystemService(AudioManager.class),
                AvrcpNativeInterface.getInstance(),
                new AvrcpVolumeManager(
                        requireNonNull(adapterService),
                        adapterService.getSystemService(AudioManager.class),
                        AvrcpNativeInterface.getInstance()),
                Looper.myLooper());
    }

    @VisibleForTesting
    AvrcpTargetService(
            AdapterService adapterService,
            AudioManager audioManager,
            AvrcpNativeInterface nativeInterface,
            AvrcpVolumeManager volumeManager,
            Looper looper) {
        super(requireNonNull(adapterService));
        mAdapterService = adapterService;
        mAudioManager = requireNonNull(getSystemService(AudioManager.class));
        mNativeInterface = requireNonNull(AvrcpNativeInterface.getInstance());
        mAudioManager = requireNonNull(audioManager);
        mNativeInterface = requireNonNull(nativeInterface);

        mMediaPlayerList = new MediaPlayerList(Looper.myLooper(), this);
        mMediaPlayerList = new MediaPlayerList(looper, this);

        IntentFilter userFilter = new IntentFilter();
        userFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -119,7 +135,7 @@ public class AvrcpTargetService extends ProfileService {
        mNativeInterface.init(this);

        mAvrcpVersion = AvrcpVersion.getCurrentSystemPropertiesValue();
        mVolumeManager = new AvrcpVolumeManager(mAdapterService, mAudioManager, mNativeInterface);
        mVolumeManager = requireNonNull(volumeManager);

        UserManager userManager = getApplicationContext().getSystemService(UserManager.class);
        if (userManager.isUserUnlocked()) {
@@ -257,6 +273,7 @@ public class AvrcpTargetService extends ProfileService {
        mPlayerSettingsManager.cleanup();
        mMediaPlayerList.cleanup();
        mNativeInterface.cleanup();
        mVolumeManager.cleanup();
        getApplicationContext().unregisterReceiver(mUserUnlockedReceiver);
    }

+5 −0
Original line number Diff line number Diff line
@@ -421,6 +421,11 @@ class AvrcpVolumeManager extends AudioDeviceCallback {
        mDeviceMap.remove(device);
    }

    /** Cleans up and unregisters any registered callbacks. */
    void cleanup() {
        mAudioManager.unregisterAudioDeviceCallback(this);
    }

    public void dump(StringBuilder sb) {
        sb.append("AvrcpVolumeManager:\n");
        sb.append("  mCurrentDevice: ").append(mCurrentDevice).append("\n");
+102 −0
Original line number Diff line number Diff line
@@ -18,17 +18,41 @@ package com.android.bluetooth.avrcp;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.media.AudioDeviceCallback;
import android.media.AudioManager;
import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.os.UserManager;
import android.os.test.TestLooper;

import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.TestUtils;
import com.android.bluetooth.audio_util.Image;
import com.android.bluetooth.audio_util.Metadata;
import com.android.bluetooth.btservice.AdapterService;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.ArrayList;
import java.util.List;
@@ -37,8 +61,63 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class AvrcpTargetServiceTest {

    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

    private @Mock AdapterService mMockAdapterService;
    private @Mock AudioManager mMockAudioManager;
    private @Mock AvrcpNativeInterface mMockNativeInterface;
    private @Mock UserManager mMockUserManager;
    private @Mock Resources mMockResources;
    private @Mock SharedPreferences mMockSharedPreferences;
    private @Mock SharedPreferences.Editor mMockSharedPreferencesEditor;

    private @Captor ArgumentCaptor<AudioDeviceCallback> mAudioDeviceCb;

    private MediaSessionManager mMediaSessionManager;
    private TestLooper mLooper;

    private static final String TEST_DATA = "-1";

    @Before
    public void setUp() throws Exception {
        mLooper = new TestLooper();
        mLooper.startAutoDispatch();

        doReturn(mMockAudioManager)
                .when(mMockAdapterService)
                .getSystemService(Context.AUDIO_SERVICE);
        doReturn(Context.AUDIO_SERVICE)
                .when(mMockAdapterService)
                .getSystemServiceName(AudioManager.class);

        mMediaSessionManager =
                InstrumentationRegistry.getInstrumentation()
                        .getTargetContext()
                        .getSystemService(MediaSessionManager.class);
        TestUtils.mockGetSystemService(
                mMockAdapterService,
                Context.MEDIA_SESSION_SERVICE,
                MediaSessionManager.class,
                mMediaSessionManager);

        doReturn(mLooper.getNewExecutor()).when(mMockAdapterService).getMainExecutor();

        doReturn(mMockAdapterService).when(mMockAdapterService).getApplicationContext();
        TestUtils.mockGetSystemService(
                mMockAdapterService, Context.USER_SERVICE, UserManager.class, mMockUserManager);
        doReturn(mMockResources).when(mMockAdapterService).getResources();

        doReturn(mMockSharedPreferencesEditor).when(mMockSharedPreferences).edit();
        doReturn(mMockSharedPreferences)
                .when(mMockAdapterService)
                .getSharedPreferences(anyString(), anyInt());
    }

    @After
    public void tearDown() throws Exception {
        mLooper.stopAutoDispatchAndIgnoreExceptions();
    }

    @Test
    public void testQueueUpdateData() {
        List<Metadata> firstQueue = new ArrayList<Metadata>();
@@ -75,4 +154,27 @@ public class AvrcpTargetServiceTest {
        Metadata.Builder builder = new Metadata.Builder();
        return builder.useDefaults().build();
    }

    @Test
    public void testServiceInstance() {
        AvrcpVolumeManager volumeManager =
                new AvrcpVolumeManager(
                        mMockAdapterService, mMockAudioManager, mMockNativeInterface);
        AvrcpTargetService service =
                new AvrcpTargetService(
                        mMockAdapterService,
                        mMockAudioManager,
                        mMockNativeInterface,
                        volumeManager,
                        mLooper.getLooper());

        service.start();
        verify(mMockAudioManager)
                .registerAudioDeviceCallback(mAudioDeviceCb.capture(), anyObject());

        service.stop();
        service.cleanup();
        assertThat(mAudioDeviceCb.getValue()).isNotNull();
        verify(mMockAudioManager).unregisterAudioDeviceCallback(mAudioDeviceCb.getValue());
    }
}