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

Commit 3b2dcccc authored by Weilin Xu's avatar Weilin Xu
Browse files

Add HD radio support and program list unit tests

Added unit tests for new radio system APIs related to program list
and HD radio improvement.

Bug: 280300929
Test: atest BroadcastRadioTests
Change-Id: Id803958121df4b76de179b4f551134a0aadf8d9a
parent 2c38153e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ android_test {
        "androidx.test.rules",
        "truth",
        "testng",
        "android.hardware.radio.flags-aconfig-java",
        "flag-junit",
        "mockito-target-extended",
    ],
    libs: ["android.test.base"],
+82 −29
Original line number Diff line number Diff line
@@ -16,8 +16,6 @@

package android.hardware.radio;

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

import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -36,8 +34,14 @@ import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.os.Parcel;
import android.os.RemoteException;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.ArraySet;

import com.google.common.truth.Expect;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -143,12 +147,17 @@ public final class ProgramListTest {
    @Mock
    private RadioTuner.Callback mTunerCallbackMock;

    @Rule
    public final Expect mExpect = Expect.create();
    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();

    @Test
    public void getIdentifierTypes_forFilter() {
        ProgramList.Filter filter = new ProgramList.Filter(FILTER_IDENTIFIER_TYPES,
                FILTER_IDENTIFIERS, INCLUDE_CATEGORIES, EXCLUDE_MODIFICATIONS);

        assertWithMessage("Filtered identifier types").that(filter.getIdentifierTypes())
        mExpect.withMessage("Filtered identifier types").that(filter.getIdentifierTypes())
                .containsExactlyElementsIn(FILTER_IDENTIFIER_TYPES);
    }

@@ -157,7 +166,7 @@ public final class ProgramListTest {
        ProgramList.Filter filter = new ProgramList.Filter(FILTER_IDENTIFIER_TYPES,
                FILTER_IDENTIFIERS, INCLUDE_CATEGORIES, EXCLUDE_MODIFICATIONS);

        assertWithMessage("Filtered identifiers").that(filter.getIdentifiers())
        mExpect.withMessage("Filtered identifiers").that(filter.getIdentifiers())
                .containsExactlyElementsIn(FILTER_IDENTIFIERS);
    }

@@ -166,7 +175,7 @@ public final class ProgramListTest {
        ProgramList.Filter filter = new ProgramList.Filter(FILTER_IDENTIFIER_TYPES,
                FILTER_IDENTIFIERS, INCLUDE_CATEGORIES, EXCLUDE_MODIFICATIONS);

        assertWithMessage("Filter including categories")
        mExpect.withMessage("Filter including categories")
                .that(filter.areCategoriesIncluded()).isEqualTo(INCLUDE_CATEGORIES);
    }

@@ -175,7 +184,7 @@ public final class ProgramListTest {
        ProgramList.Filter filter = new ProgramList.Filter(FILTER_IDENTIFIER_TYPES,
                FILTER_IDENTIFIERS, INCLUDE_CATEGORIES, EXCLUDE_MODIFICATIONS);

        assertWithMessage("Filter excluding modifications")
        mExpect.withMessage("Filter excluding modifications")
                .that(filter.areModificationsExcluded()).isEqualTo(EXCLUDE_MODIFICATIONS);
    }

@@ -184,7 +193,7 @@ public final class ProgramListTest {
        ProgramList.Filter filter = new ProgramList.Filter(FILTER_IDENTIFIER_TYPES,
                FILTER_IDENTIFIERS, INCLUDE_CATEGORIES, EXCLUDE_MODIFICATIONS);

        assertWithMessage("Filter vendor obtained from filter without vendor filter")
        mExpect.withMessage("Filter vendor obtained from filter without vendor filter")
                .that(filter.getVendorFilter()).isNull();
    }

@@ -192,13 +201,13 @@ public final class ProgramListTest {
    public void getVendorFilter_forFilterWithVendorFilter() {
        ProgramList.Filter vendorFilter = new ProgramList.Filter(VENDOR_FILTER);

        assertWithMessage("Filter vendor obtained from filter with vendor filter")
        mExpect.withMessage("Filter vendor obtained from filter with vendor filter")
                .that(vendorFilter.getVendorFilter()).isEqualTo(VENDOR_FILTER);
    }

    @Test
    public void describeContents_forFilter() {
        assertWithMessage("Filter contents").that(TEST_FILTER.describeContents()).isEqualTo(0);
        mExpect.withMessage("Filter contents").that(TEST_FILTER.describeContents()).isEqualTo(0);
    }

    @Test
@@ -206,7 +215,7 @@ public final class ProgramListTest {
        ProgramList.Filter filterCompared = new ProgramList.Filter(FILTER_IDENTIFIER_TYPES,
                FILTER_IDENTIFIERS, INCLUDE_CATEGORIES, EXCLUDE_MODIFICATIONS);

        assertWithMessage("Hash code of the same filter")
        mExpect.withMessage("Hash code of the same filter")
                .that(filterCompared.hashCode()).isEqualTo(TEST_FILTER.hashCode());
    }

@@ -214,7 +223,7 @@ public final class ProgramListTest {
    public void hashCode_withDifferentFilters_notEquals() {
        ProgramList.Filter filterCompared = new ProgramList.Filter();

        assertWithMessage("Hash code of the different filter")
        mExpect.withMessage("Hash code of the different filter")
                .that(filterCompared.hashCode()).isNotEqualTo(TEST_FILTER.hashCode());
    }

@@ -227,7 +236,7 @@ public final class ProgramListTest {

        ProgramList.Filter filterFromParcel =
                ProgramList.Filter.CREATOR.createFromParcel(parcel);
        assertWithMessage("Filter created from parcel")
        mExpect.withMessage("Filter created from parcel")
                .that(filterFromParcel).isEqualTo(TEST_FILTER);
    }

@@ -235,36 +244,37 @@ public final class ProgramListTest {
    public void newArray_forFilterCreator() {
        ProgramList.Filter[] filters = ProgramList.Filter.CREATOR.newArray(CREATOR_ARRAY_SIZE);

        assertWithMessage("Program filters").that(filters).hasLength(CREATOR_ARRAY_SIZE);
        mExpect.withMessage("Program filters").that(filters).hasLength(CREATOR_ARRAY_SIZE);
    }

    @Test
    public void isPurge_forChunk() {
        assertWithMessage("Puring chunk").that(FM_DAB_ADD_CHUNK.isPurge()).isEqualTo(IS_PURGE);
        mExpect.withMessage("Puring chunk").that(FM_DAB_ADD_CHUNK.isPurge()).isEqualTo(IS_PURGE);
    }

    @Test
    public void isComplete_forChunk() {
        assertWithMessage("Complete chunk").that(FM_DAB_ADD_CHUNK.isComplete())
        mExpect.withMessage("Complete chunk").that(FM_DAB_ADD_CHUNK.isComplete())
                .isEqualTo(IS_COMPLETE);
    }

    @Test
    public void getModified_forChunk() {
        assertWithMessage("Modified program info in chunk")
        mExpect.withMessage("Modified program info in chunk")
                .that(FM_DAB_ADD_CHUNK.getModified())
                .containsExactly(FM_PROGRAM_INFO, DAB_PROGRAM_INFO_1, DAB_PROGRAM_INFO_2);
    }

    @Test
    public void getRemoved_forChunk() {
        assertWithMessage("Removed program identifiers in chunk")
        mExpect.withMessage("Removed program identifiers in chunk")
                .that(FM_DAB_ADD_CHUNK.getRemoved()).containsExactly(RDS_UNIQUE_IDENTIFIER);
    }

    @Test
    public void describeContents_forChunk() {
        assertWithMessage("Chunk contents").that(FM_DAB_ADD_CHUNK.describeContents()).isEqualTo(0);
        mExpect.withMessage("Chunk contents").that(FM_DAB_ADD_CHUNK.describeContents())
                .isEqualTo(0);
    }

    @Test
@@ -276,7 +286,7 @@ public final class ProgramListTest {

        ProgramList.Chunk chunkFromParcel =
                ProgramList.Chunk.CREATOR.createFromParcel(parcel);
        assertWithMessage("Chunk created from parcel")
        mExpect.withMessage("Chunk created from parcel")
                .that(chunkFromParcel).isEqualTo(FM_DAB_ADD_CHUNK);
    }

@@ -284,7 +294,7 @@ public final class ProgramListTest {
    public void newArray_forChunkCreator() {
        ProgramList.Chunk[] chunks = ProgramList.Chunk.CREATOR.newArray(CREATOR_ARRAY_SIZE);

        assertWithMessage("Chunks").that(chunks).hasLength(CREATOR_ARRAY_SIZE);
        mExpect.withMessage("Chunks").that(chunks).hasLength(CREATOR_ARRAY_SIZE);
    }

    @Test
@@ -295,7 +305,7 @@ public final class ProgramListTest {
        IllegalStateException thrown = assertThrows(IllegalStateException.class,
                () -> mRadioTuner.getProgramList(parameters));

        assertWithMessage("Exception for getting program list when not ready")
        mExpect.withMessage("Exception for getting program list when not ready")
                .that(thrown).hasMessageThat().contains("Program list is not ready yet");
    }

@@ -308,7 +318,7 @@ public final class ProgramListTest {
        RuntimeException thrown = assertThrows(RuntimeException.class,
                () -> mRadioTuner.getProgramList(parameters));

        assertWithMessage("Exception for getting program list when service is dead")
        mExpect.withMessage("Exception for getting program list when service is dead")
                .that(thrown).hasMessageThat().contains("Service died");
    }

@@ -330,7 +340,7 @@ public final class ProgramListTest {

        ProgramList nullProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);

        assertWithMessage("Exception for radio HAL client not supporting program list")
        mExpect.withMessage("Exception for radio HAL client not supporting program list")
                .that(nullProgramList).isNull();
    }

@@ -344,7 +354,7 @@ public final class ProgramListTest {
            mRadioTuner.getDynamicProgramList(TEST_FILTER);
        });

        assertWithMessage("Exception for radio HAL client service died")
        mExpect.withMessage("Exception for radio HAL client service died")
                .that(thrown).hasMessageThat().contains("Service died");
    }

@@ -360,7 +370,7 @@ public final class ProgramListTest {
        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(FM_IDENTIFIER);
        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(DAB_DMB_SID_EXT_IDENTIFIER);
        verify(mOnCompleteListenerMocks[0], CALLBACK_TIMEOUT).onComplete();
        assertWithMessage("Program info in program list after adding FM and DAB info")
        mExpect.withMessage("Program info in program list after adding FM and DAB info")
                .that(mProgramList.toList()).containsExactly(FM_PROGRAM_INFO, DAB_PROGRAM_INFO_1,
                        DAB_PROGRAM_INFO_2);
    }
@@ -378,7 +388,7 @@ public final class ProgramListTest {
        mTunerCallback.onProgramListUpdated(fmRemovedChunk);

        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(FM_IDENTIFIER);
        assertWithMessage("Program info in program list after removing FM id")
        mExpect.withMessage("Program info in program list after removing FM id")
                .that(mProgramList.toList()).containsExactly(DAB_PROGRAM_INFO_1,
                        DAB_PROGRAM_INFO_2);
    }
@@ -397,7 +407,7 @@ public final class ProgramListTest {

        verify(mListCallbackMocks[0], after(TIMEOUT_MS).never()).onItemRemoved(
                DAB_DMB_SID_EXT_IDENTIFIER);
        assertWithMessage("Program info in program list after removing part of DAB ids")
        mExpect.withMessage("Program info in program list after removing part of DAB ids")
                .that(mProgramList.toList()).containsExactly(FM_PROGRAM_INFO, DAB_PROGRAM_INFO_2);
    }

@@ -419,7 +429,7 @@ public final class ProgramListTest {
        mTunerCallback.onProgramListUpdated(dabRemovedChunk2);

        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(DAB_DMB_SID_EXT_IDENTIFIER);
        assertWithMessage("Program info in program list after removing all DAB ids")
        mExpect.withMessage("Program info in program list after removing all DAB ids")
                .that(mProgramList.toList()).containsExactly(FM_PROGRAM_INFO);
    }

@@ -448,7 +458,7 @@ public final class ProgramListTest {

        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(FM_IDENTIFIER);
        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemRemoved(DAB_DMB_SID_EXT_IDENTIFIER);
        assertWithMessage("Program list after purge chunk applied")
        mExpect.withMessage("Program list after purge chunk applied")
                .that(mProgramList.toList()).isEmpty();
    }

@@ -607,6 +617,49 @@ public final class ProgramListTest {
        verify(mTunerMock, CALLBACK_TIMEOUT).stopProgramListUpdates();
    }

    @Test
    public void get() throws Exception {
        createRadioTuner();
        mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
        registerListCallbacks(/* numCallbacks= */ 1);
        mTunerCallback.onProgramListUpdated(FM_ADD_INCOMPLETE_CHUNK);
        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(FM_IDENTIFIER);

        mExpect.withMessage(
                "FM program info in program list after updating with chunk of FM program")
                .that(mProgramList.get(FM_IDENTIFIER)).isEqualTo(FM_PROGRAM_INFO);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void getProgramInfos() throws Exception {
        createRadioTuner();
        mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
        registerListCallbacks(/* numCallbacks= */ 1);
        mTunerCallback.onProgramListUpdated(FM_DAB_ADD_CHUNK);
        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(FM_IDENTIFIER);
        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(DAB_DMB_SID_EXT_IDENTIFIER);

        mExpect.withMessage("FM program info in program list")
                .that(mProgramList.getProgramInfos(FM_IDENTIFIER)).containsExactly(FM_PROGRAM_INFO);
        mExpect.withMessage("All DAB program info in program list")
                .that(mProgramList.getProgramInfos(DAB_DMB_SID_EXT_IDENTIFIER))
                .containsExactly(DAB_PROGRAM_INFO_1, DAB_PROGRAM_INFO_2);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void getProgramInfos_withIdNotFound() throws Exception {
        createRadioTuner();
        mProgramList = mRadioTuner.getDynamicProgramList(TEST_FILTER);
        registerListCallbacks(/* numCallbacks= */ 1);
        mTunerCallback.onProgramListUpdated(FM_ADD_INCOMPLETE_CHUNK);
        verify(mListCallbackMocks[0], CALLBACK_TIMEOUT).onItemChanged(FM_IDENTIFIER);

        mExpect.withMessage("DAB program info in program list")
                .that(mProgramList.getProgramInfos(DAB_DMB_SID_EXT_IDENTIFIER)).isEmpty();
    }

    private static ProgramSelector createProgramSelector(int programType,
            ProgramSelector.Identifier identifier) {
        return new ProgramSelector(programType, identifier, /* secondaryIds= */ null,
+70 −5
Original line number Diff line number Diff line
@@ -32,8 +32,12 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Parcel;
import android.os.RemoteException;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.ArrayMap;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -42,6 +46,7 @@ import org.mockito.junit.MockitoJUnitRunner;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -90,10 +95,26 @@ public final class RadioManagerTest {
    private static final RadioManager.ModuleProperties AMFM_PROPERTIES =
            createAmFmProperties(/* dabFrequencyTable= */ null);

    private static final int DAB_INFO_FLAG_LIVE_VALUE = 1;
    private static final int DAB_INFO_FLAG_TUNED_VALUE = 1 << 4;
    private static final int DAB_INFO_FLAG_STEREO_VALUE = 1 << 5;
    private static final int HD_INFO_FLAG_LIVE_VALUE = 1;
    private static final int HD_INFO_FLAG_TUNED_VALUE = 1 << 4;
    private static final int HD_INFO_FLAG_STEREO_VALUE = 1 << 5;
    private static final int HD_INFO_FLAG_SIGNAL_ACQUISITION_VALUE = 1 << 6;
    private static final int HD_INFO_FLAG_SIS_ACQUISITION_VALUE = 1 << 7;
    /**
     * Info flags with live, tuned and stereo enabled
     * Info flags with live, tuned, and stereo enabled for DAB program
     */
    private static final int INFO_FLAGS = 0b110001;
    private static final int INFO_FLAGS_DAB = DAB_INFO_FLAG_LIVE_VALUE | DAB_INFO_FLAG_TUNED_VALUE
            | DAB_INFO_FLAG_STEREO_VALUE;
    /**
     * HD program info flags with live, tuned, stereo enabled, signal acquired, SIS information
     * available but audio unavailable
     */
    private static final int INFO_FLAGS_HD = HD_INFO_FLAG_LIVE_VALUE | HD_INFO_FLAG_TUNED_VALUE
            | HD_INFO_FLAG_STEREO_VALUE | HD_INFO_FLAG_SIGNAL_ACQUISITION_VALUE
            | HD_INFO_FLAG_SIS_ACQUISITION_VALUE;
    private static final int SIGNAL_QUALITY = 2;
    private static final ProgramSelector.Identifier DAB_SID_EXT_IDENTIFIER =
            new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
@@ -112,9 +133,20 @@ public final class RadioManagerTest {
                    new ProgramSelector.Identifier[]{
                            DAB_ENSEMBLE_IDENTIFIER, DAB_FREQUENCY_IDENTIFIER},
                    /* vendorIds= */ null);

    private static final long HD_FREQUENCY = 97_100;
    private static final ProgramSelector.Identifier HD_STATION_EXT_IDENTIFIER =
            new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT,
                    /* value= */ (HD_FREQUENCY << 36) | 0x1L);
    private static final ProgramSelector HD_SELECTOR = new ProgramSelector(
            ProgramSelector.PROGRAM_TYPE_FM_HD, HD_STATION_EXT_IDENTIFIER,
            new ProgramSelector.Identifier[]{}, /* vendorIds= */ null);

    private static final RadioMetadata METADATA = createMetadata();
    private static final RadioManager.ProgramInfo DAB_PROGRAM_INFO =
            createDabProgramInfo(DAB_SELECTOR);
    private static final RadioManager.ProgramInfo HD_PROGRAM_INFO = createHdProgramInfo(
            HD_SELECTOR);

    private static final int EVENT_ANNOUNCEMENT_TYPE = Announcement.TYPE_EVENT;
    private static final List<Announcement> TEST_ANNOUNCEMENT_LIST = Arrays.asList(
@@ -135,6 +167,9 @@ public final class RadioManagerTest {
    @Mock
    private ICloseHandle mCloseHandleMock;

    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();

    @Test
    public void getType_forBandDescriptor() {
        RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor();
@@ -926,6 +961,27 @@ public final class RadioManagerTest {
                .that(DAB_PROGRAM_INFO.isTrafficAnnouncementActive()).isFalse();
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void isSignalAcquired_forProgramInfo() {
        assertWithMessage("Signal acquisition status for HD program info")
                .that(HD_PROGRAM_INFO.isSignalAcquired()).isTrue();
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void isHdSisAvailable_forProgramInfo() {
        assertWithMessage("SIS information acquisition status for HD program")
                .that(HD_PROGRAM_INFO.isHdSisAvailable()).isTrue();
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void isHdAudioAvailable_forProgramInfo() {
        assertWithMessage("Audio acquisition status for HD program")
                .that(HD_PROGRAM_INFO.isHdAudioAvailable()).isFalse();
    }

    @Test
    public void getSignalStrength_forProgramInfo() {
        assertWithMessage("Signal strength of DAB program info")
@@ -1156,9 +1212,18 @@ public final class RadioManagerTest {
    }

    private static RadioManager.ProgramInfo createDabProgramInfo(ProgramSelector selector) {
        return new RadioManager.ProgramInfo(selector, DAB_SID_EXT_IDENTIFIER,
                DAB_FREQUENCY_IDENTIFIER, Arrays.asList(DAB_SID_EXT_IDENTIFIER_RELATED), INFO_FLAGS,
                SIGNAL_QUALITY, METADATA, /* vendorInfo= */ null);
        return new RadioManager.ProgramInfo(selector, selector.getPrimaryId(),
                DAB_FREQUENCY_IDENTIFIER, Arrays.asList(DAB_SID_EXT_IDENTIFIER_RELATED),
                INFO_FLAGS_DAB, SIGNAL_QUALITY, METADATA, /* vendorInfo= */ null);
    }

    private static RadioManager.ProgramInfo createHdProgramInfo(ProgramSelector selector) {
        long frequency = (selector.getPrimaryId().getValue() >> 32);
        ProgramSelector.Identifier physicallyTunedToId = new ProgramSelector.Identifier(
                ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, frequency);
        return new RadioManager.ProgramInfo(selector, selector.getPrimaryId(), physicallyTunedToId,
                Collections.emptyList(), INFO_FLAGS_HD, SIGNAL_QUALITY, METADATA,
                /* vendorInfo= */ null);
    }

    private void createRadioManager() throws RemoteException {
+125 −8

File changed.

Preview size limit exceeded, changes collapsed.

+84 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.after;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -35,9 +36,14 @@ import android.content.pm.ApplicationInfo;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.RemoteException;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -77,6 +83,9 @@ public final class TunerAdapterTest {
    @Mock
    private RadioTuner.Callback mCallbackMock;

    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();

    @Before
    public void setUp() throws Exception {
        mApplicationInfo.targetSdkVersion = TEST_TARGET_SDK_VERSION;
@@ -603,6 +612,44 @@ public final class TunerAdapterTest {
                .that(dabFmSoftLinking).isTrue();
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void isConfigFlagSet_withForceAnalogWhenFmForceAnalogSupported()
            throws Exception {
        when(mTunerMock.isConfigFlagSupported(anyInt())).thenReturn(true);
        when(mTunerMock.isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG_FM))
                .thenReturn(true);
        when(mTunerMock.isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG)).thenReturn(false);

        assertWithMessage("Force analog with feature flag enabled and force FM supported")
                .that(mRadioTuner.isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG)).isTrue();
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void isConfigFlagSet_withForceAnalogWhenFmForceAnalogNotSupported()
            throws Exception {
        when(mTunerMock.isConfigFlagSupported(RadioManager.CONFIG_FORCE_ANALOG_FM))
                .thenReturn(false);
        when(mTunerMock.isConfigFlagSupported(RadioManager.CONFIG_FORCE_ANALOG)).thenReturn(true);
        when(mTunerMock.isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG_FM)).thenReturn(true);
        when(mTunerMock.isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG)).thenReturn(false);

        assertWithMessage("Force analog with feature flag enabled but force FM unsupported")
                .that(mRadioTuner.isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG)).isFalse();
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void isConfigFlagSet_withForceAnalogWhenHdRadioImprovedFeatureNotEnabled()
            throws Exception {
        when(mTunerMock.isConfigFlagSupported(anyInt())).thenReturn(true);
        when(mTunerMock.isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG)).thenReturn(false);

        assertWithMessage("Force analog without Force FM enabled")
                .that(mRadioTuner.isConfigFlagSet(RadioManager.CONFIG_FORCE_ANALOG)).isFalse();
    }

    @Test
    public void isConfigFlagSet_whenServiceDied_fails() throws Exception {
        when(mTunerMock.isConfigFlagSet(anyInt())).thenThrow(new RemoteException());
@@ -635,6 +682,43 @@ public final class TunerAdapterTest {
                .that(thrown).hasMessageThat().contains("Service died");
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void setConfigFlag_withForceAnalogWhenFmForceAnalogSupported() throws Exception {
        when(mTunerMock.isConfigFlagSupported(anyInt())).thenReturn(true);

        mRadioTuner.setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, /* value= */ false);

        verify(mTunerMock, never()).setConfigFlag(eq(RadioManager.CONFIG_FORCE_ANALOG),
                anyBoolean());
        verify(mTunerMock).setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG_FM, false);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void setConfigFlag_withForceAnalogWhenFmForceAnalogNotSupported() throws Exception {
        when(mTunerMock.isConfigFlagSupported(anyInt())).thenReturn(true);
        when(mTunerMock.isConfigFlagSupported(RadioManager.CONFIG_FORCE_ANALOG_FM))
                .thenReturn(false);

        mRadioTuner.setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, /* value= */ false);

        verify(mTunerMock).setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, false);
        verify(mTunerMock, never()).setConfigFlag(eq(RadioManager.CONFIG_FORCE_ANALOG_FM),
                anyBoolean());
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_HD_RADIO_IMPROVED)
    public void setConfigFlag_withForceAnalogWhenHdRadioImprovedFeatureNotEnabled()
            throws Exception {
        when(mTunerMock.isConfigFlagSupported(anyInt())).thenReturn(true);

        mRadioTuner.setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, /* value= */ false);

        verify(mTunerMock).setConfigFlag(RadioManager.CONFIG_FORCE_ANALOG, false);
    }

    @Test
    public void getParameters_forTunerAdapter() throws Exception {
        List<String> parameterKeys = List.of("ParameterKeyMock");