diff options
5 files changed, 431 insertions, 57 deletions
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java index 3037f345b5a3..82db716fcdc2 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/AidlTestUtils.java @@ -19,6 +19,7 @@ import android.hardware.broadcastradio.IdentifierType; import android.hardware.broadcastradio.Metadata; import android.hardware.broadcastradio.ProgramIdentifier; import android.hardware.broadcastradio.ProgramInfo; +import android.hardware.broadcastradio.ProgramListChunk; import android.hardware.broadcastradio.VendorKeyValue; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; @@ -41,17 +42,18 @@ final class AidlTestUtils { /* dabFrequencyTable= */ null, /* vendorInfo= */ null); } - static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector, int signalQuality) { + static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector, + ProgramSelector.Identifier logicallyTunedTo, + ProgramSelector.Identifier physicallyTunedTo, int signalQuality) { return new RadioManager.ProgramInfo(selector, - selector.getPrimaryId(), selector.getPrimaryId(), /* relatedContents= */ null, + logicallyTunedTo, physicallyTunedTo, /* relatedContents= */ null, /* infoFlags= */ 0, signalQuality, new RadioMetadata.Builder().build(), new ArrayMap<>()); } - static RadioManager.ProgramInfo makeProgramInfo(int programType, - ProgramSelector.Identifier identifier, int signalQuality) { - ProgramSelector selector = makeProgramSelector(programType, identifier); - return makeProgramInfo(selector, signalQuality); + static RadioManager.ProgramInfo makeProgramInfo(ProgramSelector selector, int signalQuality) { + return makeProgramInfo(selector, selector.getPrimaryId(), selector.getPrimaryId(), + signalQuality); } static ProgramIdentifier makeHalIdentifier(@IdentifierType int type, long value) { @@ -87,21 +89,6 @@ final class AidlTestUtils { return hwSelector; } - static ProgramInfo programInfoToHalProgramInfo(RadioManager.ProgramInfo info) { - // Note that because ConversionUtils does not by design provide functions for all - // conversions, this function only copies fields that are set by makeProgramInfo(). - ProgramInfo hwInfo = new ProgramInfo(); - hwInfo.selector = ConversionUtils.programSelectorToHalProgramSelector(info.getSelector()); - hwInfo.logicallyTunedTo = - ConversionUtils.identifierToHalProgramIdentifier(info.getLogicallyTunedTo()); - hwInfo.physicallyTunedTo = - ConversionUtils.identifierToHalProgramIdentifier(info.getPhysicallyTunedTo()); - hwInfo.signalQuality = info.getSignalStrength(); - hwInfo.relatedContent = new ProgramIdentifier[]{}; - hwInfo.metadata = new Metadata[]{}; - return hwInfo; - } - static ProgramInfo makeHalProgramInfo( android.hardware.broadcastradio.ProgramSelector hwSel, int hwSignalQuality) { return makeHalProgramInfo(hwSel, hwSel.primaryId, hwSel.primaryId, hwSignalQuality); @@ -121,6 +108,16 @@ final class AidlTestUtils { return hwInfo; } + static ProgramListChunk makeProgramListChunk(boolean purge, boolean complete, + ProgramInfo[] modified, ProgramIdentifier[] removed) { + ProgramListChunk halChunk = new ProgramListChunk(); + halChunk.purge = purge; + halChunk.complete = complete; + halChunk.modified = modified; + halChunk.removed = removed; + return halChunk; + } + static VendorKeyValue makeVendorKeyValue(String vendorKey, String vendorValue) { VendorKeyValue vendorKeyValue = new VendorKeyValue(); vendorKeyValue.key = vendorKey; diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java index f4040825e9a7..98103f6eddd3 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java @@ -173,6 +173,19 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes } @Test + public void openSession_withoutAudio_fails() throws Exception { + createBroadcastRadioService(); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, + () -> mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID, + /* legacyConfig= */ null, /* withAudio= */ false, mTunerCallbackMock, + TARGET_SDK_VERSION)); + + assertWithMessage("Exception for opening session without audio") + .that(thrown).hasMessageThat().contains("not supported"); + } + + @Test public void binderDied_forDeathRecipient() throws Exception { createBroadcastRadioService(); diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java index 6604d2aea7c1..710c150c006c 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java @@ -22,9 +22,11 @@ import android.hardware.broadcastradio.DabTableEntry; import android.hardware.broadcastradio.IdentifierType; import android.hardware.broadcastradio.ProgramIdentifier; import android.hardware.broadcastradio.ProgramInfo; +import android.hardware.broadcastradio.ProgramListChunk; import android.hardware.broadcastradio.Properties; import android.hardware.broadcastradio.VendorKeyValue; import android.hardware.radio.Announcement; +import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.os.Build; @@ -35,19 +37,20 @@ import org.junit.Rule; import org.junit.Test; import java.util.Map; +import java.util.Set; public final class ConversionUtilsTest { - private static final int FM_LOWER_LIMIT = 87500; - private static final int FM_UPPER_LIMIT = 108000; + private static final int FM_LOWER_LIMIT = 87_500; + private static final int FM_UPPER_LIMIT = 108_000; private static final int FM_SPACING = 200; private static final int AM_LOWER_LIMIT = 540; - private static final int AM_UPPER_LIMIT = 1700; + private static final int AM_UPPER_LIMIT = 1_700; private static final int AM_SPACING = 10; private static final String DAB_ENTRY_LABEL_1 = "5A"; - private static final int DAB_ENTRY_FREQUENCY_1 = 174928; + private static final int DAB_ENTRY_FREQUENCY_1 = 174_928; private static final String DAB_ENTRY_LABEL_2 = "12D"; - private static final int DAB_ENTRY_FREQUENCY_2 = 229072; + private static final int DAB_ENTRY_FREQUENCY_2 = 229_072; private static final String VENDOR_INFO_KEY_1 = "vendorKey1"; private static final String VENDOR_INFO_VALUE_1 = "vendorValue1"; private static final String VENDOR_INFO_KEY_2 = "vendorKey2"; @@ -62,7 +65,10 @@ public final class ConversionUtilsTest { private static final int TEST_SIGNAL_QUALITY = 1; private static final long TEST_DAB_DMB_SID_EXT_VALUE = 0xA000000111L; private static final long TEST_DAB_ENSEMBLE_VALUE = 0x1001; - private static final long TEST_DAB_FREQUENCY_VALUE = 220352; + private static final long TEST_DAB_FREQUENCY_VALUE = 220_352; + private static final long TEST_FM_FREQUENCY_VALUE = 92_100; + private static final long TEST_VENDOR_ID_VALUE = 9_901; + private static final ProgramSelector.Identifier TEST_DAB_SID_EXT_ID = new ProgramSelector.Identifier( ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT, TEST_DAB_DMB_SID_EXT_VALUE); @@ -72,6 +78,13 @@ public final class ConversionUtilsTest { private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID = new ProgramSelector.Identifier( ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, TEST_DAB_FREQUENCY_VALUE); + private static final ProgramSelector.Identifier TEST_FM_FREQUENCY_ID = + new ProgramSelector.Identifier( + ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, TEST_FM_FREQUENCY_VALUE); + private static final ProgramSelector.Identifier TEST_VENDOR_ID = + new ProgramSelector.Identifier( + ProgramSelector.IDENTIFIER_TYPE_VENDOR_START, TEST_VENDOR_ID_VALUE); + private static final ProgramIdentifier TEST_HAL_DAB_SID_EXT_ID = AidlTestUtils.makeHalIdentifier(IdentifierType.DAB_SID_EXT, TEST_DAB_DMB_SID_EXT_VALUE); private static final ProgramIdentifier TEST_HAL_DAB_ENSEMBLE_ID = @@ -79,6 +92,19 @@ public final class ConversionUtilsTest { private static final ProgramIdentifier TEST_HAL_DAB_FREQUENCY_ID = AidlTestUtils.makeHalIdentifier(IdentifierType.DAB_FREQUENCY_KHZ, TEST_DAB_FREQUENCY_VALUE); + private static final ProgramIdentifier TEST_HAL_FM_FREQUENCY_ID = + AidlTestUtils.makeHalIdentifier(IdentifierType.AMFM_FREQUENCY_KHZ, + TEST_FM_FREQUENCY_VALUE); + private static final ProgramIdentifier TEST_HAL_VENDOR_ID = + AidlTestUtils.makeHalIdentifier(IdentifierType.VENDOR_START, + TEST_VENDOR_ID_VALUE); + + private static final ProgramSelector TEST_DAB_SELECTOR = new ProgramSelector( + ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID, + new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID}, + /* vendorIds= */ null); + private static final ProgramSelector TEST_FM_SELECTOR = + AidlTestUtils.makeFmSelector(TEST_FM_FREQUENCY_VALUE); private static final int TEST_ENABLED_TYPE = Announcement.TYPE_EMERGENCY; private static final int TEST_ANNOUNCEMENT_FREQUENCY = FM_LOWER_LIMIT + FM_SPACING; @@ -200,13 +226,8 @@ public final class ConversionUtilsTest { @Test public void programSelectorToHalProgramSelector_withValidSelector() { - ProgramSelector dabSelector = new ProgramSelector( - ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID, - new ProgramSelector.Identifier[]{TEST_DAB_ENSEMBLE_ID, TEST_DAB_FREQUENCY_ID}, - new long[0]); - android.hardware.broadcastradio.ProgramSelector halDabSelector = - ConversionUtils.programSelectorToHalProgramSelector(dabSelector); + ConversionUtils.programSelectorToHalProgramSelector(TEST_DAB_SELECTOR); expect.withMessage("Primary identifier of converted HAL DAB selector") .that(halDabSelector.primaryId).isEqualTo(TEST_HAL_DAB_SID_EXT_ID); @@ -297,27 +318,136 @@ public final class ConversionUtilsTest { } @Test - public void programSelectorMeetsSdkVersionRequirement_withLowerVersionId_returnsFalse() { - ProgramSelector dabSelector = new ProgramSelector( - ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID, - new ProgramSelector.Identifier[]{TEST_DAB_ENSEMBLE_ID, TEST_DAB_FREQUENCY_ID}, - new long[0]); + public void chunkFromHalProgramListChunk_withValidChunk() { + boolean purge = false; + boolean complete = true; + android.hardware.broadcastradio.ProgramSelector halDabSelector = + AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{ + TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID}); + ProgramInfo halDabInfo = AidlTestUtils.makeHalProgramInfo(halDabSelector, + TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY); + RadioManager.ProgramInfo dabInfo = + ConversionUtils.programInfoFromHalProgramInfo(halDabInfo); + ProgramListChunk halChunk = AidlTestUtils.makeProgramListChunk(purge, complete, + new ProgramInfo[]{halDabInfo}, + new ProgramIdentifier[]{TEST_HAL_VENDOR_ID, TEST_HAL_FM_FREQUENCY_ID}); + + ProgramList.Chunk chunk = ConversionUtils.chunkFromHalProgramListChunk(halChunk); + + expect.withMessage("Purged state of the converted valid program list chunk") + .that(chunk.isPurge()).isEqualTo(purge); + expect.withMessage("Completion state of the converted valid program list chunk") + .that(chunk.isComplete()).isEqualTo(complete); + expect.withMessage("Modified program info in the converted valid program list chunk") + .that(chunk.getModified()).containsExactly(dabInfo); + expect.withMessage("Removed program ides in the converted valid program list chunk") + .that(chunk.getRemoved()).containsExactly(TEST_VENDOR_ID, TEST_FM_FREQUENCY_ID); + } - expect.withMessage("Selector %s not meeting required SDK version", dabSelector) - .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(dabSelector, + @Test + public void chunkFromHalProgramListChunk_withInvalidModifiedProgramInfo() { + boolean purge = true; + boolean complete = false; + android.hardware.broadcastradio.ProgramSelector halDabSelector = + AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{ + TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID}); + ProgramInfo halDabInfo = AidlTestUtils.makeHalProgramInfo(halDabSelector, + TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_ENSEMBLE_ID, TEST_SIGNAL_QUALITY); + ProgramListChunk halChunk = AidlTestUtils.makeProgramListChunk(purge, complete, + new ProgramInfo[]{halDabInfo}, new ProgramIdentifier[]{TEST_HAL_FM_FREQUENCY_ID}); + + ProgramList.Chunk chunk = ConversionUtils.chunkFromHalProgramListChunk(halChunk); + + expect.withMessage("Purged state of the converted invalid program list chunk") + .that(chunk.isPurge()).isEqualTo(purge); + expect.withMessage("Completion state of the converted invalid program list chunk") + .that(chunk.isComplete()).isEqualTo(complete); + expect.withMessage("Modified program info in the converted invalid program list chunk") + .that(chunk.getModified()).isEmpty(); + expect.withMessage("Removed program ids in the converted invalid program list chunk") + .that(chunk.getRemoved()).containsExactly(TEST_FM_FREQUENCY_ID); + } + + @Test + public void programSelectorMeetsSdkVersionRequirement_withLowerVersionId_returnsFalse() { + expect.withMessage("Selector %s without required SDK version", TEST_DAB_SELECTOR) + .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(TEST_DAB_SELECTOR, Build.VERSION_CODES.TIRAMISU)).isFalse(); } @Test public void programSelectorMeetsSdkVersionRequirement_withRequiredVersionId_returnsTrue() { - ProgramSelector fmSelector = AidlTestUtils.makeFmSelector(/* freq= */ 97100); + expect.withMessage("Selector %s with required SDK version", TEST_FM_SELECTOR) + .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(TEST_FM_SELECTOR, + Build.VERSION_CODES.TIRAMISU)).isTrue(); + } + + @Test + public void programInfoMeetsSdkVersionRequirement_withLowerVersionId_returnsFalse() { + RadioManager.ProgramInfo dabProgramInfo = AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR, + TEST_DAB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY); + + expect.withMessage("Program info %s without required SDK version", dabProgramInfo) + .that(ConversionUtils.programInfoMeetsSdkVersionRequirement(dabProgramInfo, + Build.VERSION_CODES.TIRAMISU)).isFalse(); + } + + @Test + public void programInfoMeetsSdkVersionRequirement_withRequiredVersionId_returnsTrue() { + RadioManager.ProgramInfo fmProgramInfo = AidlTestUtils.makeProgramInfo(TEST_FM_SELECTOR, + TEST_SIGNAL_QUALITY); - expect.withMessage("Selector %s meeting required SDK version", fmSelector) - .that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(fmSelector, + expect.withMessage("Program info %s with required SDK version", fmProgramInfo) + .that(ConversionUtils.programInfoMeetsSdkVersionRequirement(fmProgramInfo, Build.VERSION_CODES.TIRAMISU)).isTrue(); } @Test + public void convertChunkToTargetSdkVersion_withLowerSdkVersion() { + RadioManager.ProgramInfo dabProgramInfo = AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR, + TEST_DAB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY); + RadioManager.ProgramInfo fmProgramInfo = AidlTestUtils.makeProgramInfo(TEST_FM_SELECTOR, + TEST_SIGNAL_QUALITY); + ProgramList.Chunk chunk = new ProgramList.Chunk(/* purge= */ true, + /* complete= */ true, Set.of(dabProgramInfo, fmProgramInfo), + Set.of(TEST_DAB_SID_EXT_ID, TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID)); + + ProgramList.Chunk convertedChunk = ConversionUtils.convertChunkToTargetSdkVersion(chunk, + Build.VERSION_CODES.TIRAMISU); + + expect.withMessage( + "Purged state of the converted program list chunk with lower SDK version") + .that(convertedChunk.isPurge()).isEqualTo(chunk.isPurge()); + expect.withMessage( + "Completion state of the converted program list chunk with lower SDK version") + .that(convertedChunk.isComplete()).isEqualTo(chunk.isComplete()); + expect.withMessage( + "Modified program info in the converted program list chunk with lower SDK version") + .that(convertedChunk.getModified()).containsExactly(fmProgramInfo); + expect.withMessage( + "Removed program ids in the converted program list chunk with lower SDK version") + .that(convertedChunk.getRemoved()) + .containsExactly(TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID); + } + + @Test + public void convertChunkToTargetSdkVersion_withRequiredSdkVersion() { + RadioManager.ProgramInfo dabProgramInfo = AidlTestUtils.makeProgramInfo(TEST_DAB_SELECTOR, + TEST_DAB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY); + RadioManager.ProgramInfo fmProgramInfo = AidlTestUtils.makeProgramInfo(TEST_FM_SELECTOR, + TEST_SIGNAL_QUALITY); + ProgramList.Chunk chunk = new ProgramList.Chunk(/* purge= */ true, + /* complete= */ true, Set.of(dabProgramInfo, fmProgramInfo), + Set.of(TEST_DAB_SID_EXT_ID, TEST_DAB_ENSEMBLE_ID, TEST_VENDOR_ID)); + + ProgramList.Chunk convertedChunk = ConversionUtils.convertChunkToTargetSdkVersion(chunk, + Build.VERSION_CODES.CUR_DEVELOPMENT); + + expect.withMessage("Converted program list chunk with required SDK version") + .that(convertedChunk).isEqualTo(chunk); + } + + @Test public void announcementFromHalAnnouncement_typesMatch() { expect.withMessage("Announcement type") .that(ANNOUNCEMENT.getType()).isEqualTo(TEST_ENABLED_TYPE); diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java index 201a50f49f88..d7723acf6f05 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java @@ -26,7 +26,9 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -43,6 +45,8 @@ import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; import android.os.Build; +import android.os.ParcelableException; +import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.ArrayMap; import android.util.ArraySet; @@ -57,7 +61,6 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.verification.VerificationWithTimeout; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -71,10 +74,10 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { timeout(/* millis= */ 200); private static final int SIGNAL_QUALITY = 1; private static final long AM_FM_FREQUENCY_SPACING = 500; - private static final long[] AM_FM_FREQUENCY_LIST = {97500, 98100, 99100}; + private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100}; private static final RadioManager.FmBandDescriptor FM_BAND_DESCRIPTOR = new RadioManager.FmBandDescriptor(RadioManager.REGION_ITU_1, RadioManager.BAND_FM, - /* lowerLimit= */ 87500, /* upperLimit= */ 108000, /* spacing= */ 100, + /* lowerLimit= */ 87_500, /* upperLimit= */ 108_000, /* spacing= */ 100, /* stereo= */ false, /* rds= */ false, /* ta= */ false, /* af= */ false, /* ea= */ false); private static final RadioManager.BandConfig FM_BAND_CONFIG = @@ -200,6 +203,17 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void setConfiguration_forNonCurrentUser_doesNotInvokesCallback() throws Exception { + openAidlClients(/* numClients= */ 1); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].setConfiguration(FM_BAND_CONFIG); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + .onConfigurationChanged(FM_BAND_CONFIG); + } + + @Test public void getConfiguration() throws Exception { openAidlClients(/* numClients= */ 1); mTunerSessions[0].setConfiguration(FM_BAND_CONFIG); @@ -365,7 +379,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test - public void tune_forCurrentUser_doesNotTune() throws Exception { + public void tune_forNonCurrentUser_doesNotTune() throws Exception { openAidlClients(/* numClients= */ 1); doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); @@ -379,6 +393,21 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void tune_withHalHasUnknownError_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + doThrow(new ServiceSpecificException(Result.UNKNOWN_ERROR)) + .when(mBroadcastRadioMock).tune(any()); + + ParcelableException thrown = assertThrows(ParcelableException.class, () -> { + mTunerSessions[0].tune(sel); + }); + + assertWithMessage("Exception for tuning when HAL has unknown error") + .that(thrown).hasMessageThat().contains("UNKNOWN_ERROR"); + } + + @Test public void step_withDirectionUp() throws Exception { long initFreq = AM_FM_FREQUENCY_LIST[1]; ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq); @@ -413,6 +442,35 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void step_forNonCurrentUser_doesNotStep() throws Exception { + long initFreq = AM_FM_FREQUENCY_LIST[1]; + ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq); + openAidlClients(/* numClients= */ 1); + mHalCurrentInfo = AidlTestUtils.makeHalProgramInfo( + ConversionUtils.programSelectorToHalProgramSelector(initialSel), SIGNAL_QUALITY); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + .onCurrentProgramInfoChanged(any()); + } + + @Test + public void step_withHalInInvalidState_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + doThrow(new ServiceSpecificException(Result.INVALID_STATE)) + .when(mBroadcastRadioMock).step(anyBoolean()); + + IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> { + mTunerSessions[0].step(/* directionDown= */ true, /* skipSubChannel= */ false); + }); + + assertWithMessage("Exception for stepping when HAL is in invalid state") + .that(thrown).hasMessageThat().contains("INVALID_STATE"); + } + + @Test public void seek_withDirectionUp() throws Exception { long initFreq = AM_FM_FREQUENCY_LIST[2]; ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq); @@ -454,11 +512,44 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { ConversionUtils.programSelectorToHalProgramSelector(initialSel), SIGNAL_QUALITY); mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false); + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT) .onCurrentProgramInfoChanged(seekUpInfo); } @Test + public void seek_forNonCurrentUser_doesNotSeek() throws Exception { + long initFreq = AM_FM_FREQUENCY_LIST[2]; + ProgramSelector initialSel = AidlTestUtils.makeFmSelector(initFreq); + RadioManager.ProgramInfo seekUpInfo = AidlTestUtils.makeProgramInfo( + AidlTestUtils.makeFmSelector(getSeekFrequency(initFreq, /* seekDown= */ true)), + SIGNAL_QUALITY); + openAidlClients(/* numClients= */ 1); + mHalCurrentInfo = AidlTestUtils.makeHalProgramInfo( + ConversionUtils.programSelectorToHalProgramSelector(initialSel), SIGNAL_QUALITY); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + .onCurrentProgramInfoChanged(seekUpInfo); + } + + @Test + public void seek_withHalHasInternalError_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + doThrow(new ServiceSpecificException(Result.INTERNAL_ERROR)) + .when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean()); + + ParcelableException thrown = assertThrows(ParcelableException.class, () -> { + mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false); + }); + + assertWithMessage("Exception for seeking when HAL has internal error") + .that(thrown).hasMessageThat().contains("INTERNAL_ERROR"); + } + + @Test public void cancel() throws Exception { openAidlClients(/* numClients= */ 1); ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); @@ -470,6 +561,32 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void cancel_forNonCurrentUser_doesNotCancel() throws Exception { + openAidlClients(/* numClients= */ 1); + ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + mTunerSessions[0].tune(initialSel); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].cancel(); + + verify(mBroadcastRadioMock, never()).cancel(); + } + + @Test + public void cancel_whenHalThrowsRemoteException_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + String exceptionMessage = "HAL service died."; + doThrow(new RemoteException(exceptionMessage)).when(mBroadcastRadioMock).cancel(); + + RuntimeException thrown = assertThrows(RuntimeException.class, () -> { + mTunerSessions[0].cancel(); + }); + + assertWithMessage("Exception for canceling when HAL throws remote exception") + .that(thrown).hasMessageThat().contains(exceptionMessage); + } + + @Test public void getImage_withInvalidId_throwsIllegalArgumentException() throws Exception { openAidlClients(/* numClients= */ 1); int imageId = IBroadcastRadio.INVALID_IMAGE; @@ -493,6 +610,21 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void getImage_whenHalThrowsException_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + String exceptionMessage = "HAL service died."; + when(mBroadcastRadioMock.getImage(anyInt())) + .thenThrow(new RemoteException(exceptionMessage)); + + RuntimeException thrown = assertThrows(RuntimeException.class, () -> { + mTunerSessions[0].getImage(/* id= */ 1); + }); + + assertWithMessage("Exception for getting image when HAL throws remote exception") + .that(thrown).hasMessageThat().contains(exceptionMessage); + } + + @Test public void startBackgroundScan() throws Exception { openAidlClients(/* numClients= */ 1); @@ -502,6 +634,16 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void startBackgroundScan_forNonCurrentUser_doesNotInvokesCallback() throws Exception { + openAidlClients(/* numClients= */ 1); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].startBackgroundScan(); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete(); + } + + @Test public void stopProgramListUpdates() throws Exception { openAidlClients(/* numClients= */ 1); ProgramList.Filter aidlFilter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(), @@ -514,6 +656,19 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void stopProgramListUpdates_forNonCurrentUser_doesNotStopUpdates() throws Exception { + openAidlClients(/* numClients= */ 1); + ProgramList.Filter aidlFilter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(), + /* includeCategories= */ true, /* excludeModifications= */ false); + mTunerSessions[0].startProgramListUpdates(aidlFilter); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].stopProgramListUpdates(); + + verify(mBroadcastRadioMock, never()).stopProgramListUpdates(); + } + + @Test public void isConfigFlagSupported_withUnsupportedFlag_returnsFalse() throws Exception { openAidlClients(/* numClients= */ 1); int flag = UNSUPPORTED_CONFIG_FLAG; @@ -569,6 +724,17 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void setConfigFlag_forNonCurrentUser_doesNotSetConfigFlag() throws Exception { + openAidlClients(/* numClients= */ 1); + int flag = UNSUPPORTED_CONFIG_FLAG + 1; + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].setConfigFlag(flag, /* value= */ true); + + verify(mBroadcastRadioMock, never()).setConfigFlag(flag, /* value= */ true); + } + + @Test public void isConfigFlagSet_withUnsupportedFlag_throwsRuntimeException() throws Exception { openAidlClients(/* numClients= */ 1); @@ -578,7 +744,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { mTunerSessions[0].isConfigFlagSet(flag); }); - assertWithMessage("Exception for check if unsupported flag %s is set", flag) + assertWithMessage("Exception for checking if unsupported flag %s is set", flag) .that(thrown).hasMessageThat().contains("isConfigFlagSet: NOT_SUPPORTED"); } @@ -596,6 +762,20 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void isConfigFlagSet_whenHalThrowsRemoteException_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + int flag = UNSUPPORTED_CONFIG_FLAG + 1; + doThrow(new RemoteException()).when(mBroadcastRadioMock).isConfigFlagSet(anyInt()); + + RuntimeException thrown = assertThrows(RuntimeException.class, () -> { + mTunerSessions[0].isConfigFlagSet(flag); + }); + + assertWithMessage("Exception for checking config flag when HAL throws remote exception") + .that(thrown).hasMessageThat().contains("Failed to check flag"); + } + + @Test public void setParameters_withMockParameters() throws Exception { openAidlClients(/* numClients= */ 1); Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1", @@ -608,16 +788,58 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { } @Test + public void setParameters_forNonCurrentUser_doesNotSetParameters() throws Exception { + openAidlClients(/* numClients= */ 1); + Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1", + "mockParam2", "mockValue2"); + doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + + mTunerSessions[0].setParameters(parametersSet); + + verify(mBroadcastRadioMock, never()).setParameters(any()); + } + + @Test + public void setParameters_whenHalThrowsRemoteException_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + Map<String, String> parametersSet = Map.of("mockParam1", "mockValue1", + "mockParam2", "mockValue2"); + String exceptionMessage = "HAL service died."; + when(mBroadcastRadioMock.setParameters(any())) + .thenThrow(new RemoteException(exceptionMessage)); + + RuntimeException thrown = assertThrows(RuntimeException.class, () -> { + mTunerSessions[0].setParameters(parametersSet); + }); + + assertWithMessage("Exception for setting parameters when HAL throws remote exception") + .that(thrown).hasMessageThat().contains(exceptionMessage); + } + + @Test public void getParameters_withMockKeys() throws Exception { openAidlClients(/* numClients= */ 1); - List<String> parameterKeys = new ArrayList<>(2); - parameterKeys.add("mockKey1"); - parameterKeys.add("mockKey2"); + List<String> parameterKeys = List.of("mockKey1", "mockKey2"); mTunerSessions[0].getParameters(parameterKeys); - verify(mBroadcastRadioMock).getParameters( - parameterKeys.toArray(new String[0])); + verify(mBroadcastRadioMock).getParameters(parameterKeys.toArray(new String[0])); + } + + @Test + public void getParameters_whenServiceThrowsRemoteException_fails() throws Exception { + openAidlClients(/* numClients= */ 1); + List<String> parameterKeys = List.of("mockKey1", "mockKey2"); + String exceptionMessage = "HAL service died."; + when(mBroadcastRadioMock.getParameters(any())) + .thenThrow(new RemoteException(exceptionMessage)); + + RuntimeException thrown = assertThrows(RuntimeException.class, () -> { + mTunerSessions[0].getParameters(parameterKeys); + }); + + assertWithMessage("Exception for getting parameters when HAL throws remote exception") + .that(thrown).hasMessageThat().contains(exceptionMessage); } @Test diff --git a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java index d580d5ce8fa6..c0a238feb9b5 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java @@ -627,10 +627,22 @@ final class ConversionUtils { if (isAtLeastU(targetSdkVersion)) { return chunk; } - Set<RadioManager.ProgramInfo> modified = chunk.getModified(); - modified.removeIf(info -> !programInfoMeetsSdkVersionRequirement(info, targetSdkVersion)); - Set<ProgramSelector.Identifier> removed = chunk.getRemoved(); - removed.removeIf(id -> isNewIdentifierInU(id)); + Set<RadioManager.ProgramInfo> modified = new ArraySet<>(); + Iterator<RadioManager.ProgramInfo> modifiedIterator = chunk.getModified().iterator(); + while (modifiedIterator.hasNext()) { + RadioManager.ProgramInfo info = modifiedIterator.next(); + if (programInfoMeetsSdkVersionRequirement(info, targetSdkVersion)) { + modified.add(info); + } + } + Set<ProgramSelector.Identifier> removed = new ArraySet<>(); + Iterator<ProgramSelector.Identifier> removedIterator = chunk.getRemoved().iterator(); + while (removedIterator.hasNext()) { + ProgramSelector.Identifier id = removedIterator.next(); + if (!isNewIdentifierInU(id)) { + removed.add(id); + } + } return new ProgramList.Chunk(chunk.isPurge(), chunk.isComplete(), modified, removed); } |