Merge changes I6796917f,I1ce57702

* changes:
  Add test for AIDL radio service program info cache
  Add test for AIDL radio client program list update
This commit is contained in:
TreeHugger Robot
2023-01-11 21:45:22 +00:00
committed by Android (Google) Code Review
6 changed files with 787 additions and 22 deletions

View File

@@ -21,10 +21,15 @@ import android.hardware.broadcastradio.ProgramIdentifier;
import android.hardware.broadcastradio.ProgramInfo;
import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.broadcastradio.VendorKeyValue;
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
import java.util.List;
final class AidlTestUtils {
@@ -94,6 +99,14 @@ final class AidlTestUtils {
return makeHalProgramInfo(hwSel, hwSel.primaryId, hwSel.primaryId, hwSignalQuality);
}
static ProgramInfo programInfoToHalProgramInfo(RadioManager.ProgramInfo info) {
return makeHalProgramInfo(
ConversionUtils.programSelectorToHalProgramSelector(info.getSelector()),
ConversionUtils.identifierToHalProgramIdentifier(info.getLogicallyTunedTo()),
ConversionUtils.identifierToHalProgramIdentifier(info.getPhysicallyTunedTo()),
info.getSignalStrength());
}
static ProgramInfo makeHalProgramInfo(
android.hardware.broadcastradio.ProgramSelector hwSel,
ProgramIdentifier logicallyTunedTo, ProgramIdentifier physicallyTunedTo,
@@ -108,7 +121,23 @@ final class AidlTestUtils {
return hwInfo;
}
static ProgramListChunk makeProgramListChunk(boolean purge, boolean complete,
static ProgramListChunk makeHalChunk(boolean purge, boolean complete,
List<RadioManager.ProgramInfo> modified, List<ProgramSelector.Identifier> removed) {
ProgramInfo[] halModified =
new android.hardware.broadcastradio.ProgramInfo[modified.size()];
for (int i = 0; i < modified.size(); i++) {
halModified[i] = programInfoToHalProgramInfo(modified.get(i));
}
ProgramIdentifier[] halRemoved =
new android.hardware.broadcastradio.ProgramIdentifier[removed.size()];
for (int i = 0; i < removed.size(); i++) {
halRemoved[i] = ConversionUtils.identifierToHalProgramIdentifier(removed.get(i));
}
return makeHalChunk(purge, complete, halModified, halRemoved);
}
static ProgramListChunk makeHalChunk(boolean purge, boolean complete,
ProgramInfo[] modified, ProgramIdentifier[] removed) {
ProgramListChunk halChunk = new ProgramListChunk();
halChunk.purge = purge;
@@ -118,6 +147,21 @@ final class AidlTestUtils {
return halChunk;
}
static ProgramList.Chunk makeChunk(boolean purge, boolean complete,
List<RadioManager.ProgramInfo> modified,
List<ProgramSelector.Identifier> removed) throws RemoteException {
ArraySet<RadioManager.ProgramInfo> modifiedSet = new ArraySet<>();
if (modified != null) {
modifiedSet.addAll(modified);
}
ArraySet<ProgramSelector.Identifier> removedSet = new ArraySet<>();
if (removed != null) {
removedSet.addAll(removed);
}
ProgramList.Chunk chunk = new ProgramList.Chunk(purge, complete, modifiedSet, removedSet);
return chunk;
}
static VendorKeyValue makeVendorKeyValue(String vendorKey, String vendorValue) {
VendorKeyValue vendorKeyValue = new VendorKeyValue();
vendorKeyValue.key = vendorKey;

View File

@@ -328,7 +328,7 @@ public final class ConversionUtilsTest {
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,
ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(purge, complete,
new ProgramInfo[]{halDabInfo},
new ProgramIdentifier[]{TEST_HAL_VENDOR_ID, TEST_HAL_FM_FREQUENCY_ID});
@@ -353,7 +353,7 @@ public final class ConversionUtilsTest {
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,
ProgramListChunk halChunk = AidlTestUtils.makeHalChunk(purge, complete,
new ProgramInfo[]{halDabInfo}, new ProgramIdentifier[]{TEST_HAL_FM_FREQUENCY_ID});
ProgramList.Chunk chunk = ConversionUtils.chunkFromHalProgramListChunk(halChunk);

View File

@@ -0,0 +1,409 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.broadcastradio.aidl;
import android.hardware.broadcastradio.ProgramIdentifier;
import android.hardware.broadcastradio.ProgramInfo;
import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.radio.ProgramList;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
import android.os.RemoteException;
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.junit.MockitoJUnitRunner;
import java.util.List;
import java.util.Set;
/**
* Unit tests for AIDL ProgramInfoCache
*/
@RunWith(MockitoJUnitRunner.class)
public class ProgramInfoCacheTest {
private static final int TEST_SIGNAL_QUALITY = 90;
private static final ProgramSelector.Identifier TEST_FM_FREQUENCY_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
/* value= */ 88_500);
private static final RadioManager.ProgramInfo TEST_FM_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID, TEST_FM_FREQUENCY_ID,
TEST_SIGNAL_QUALITY);
private static final RadioManager.ProgramInfo TEST_FM_INFO_MODIFIED =
AidlTestUtils.makeProgramInfo(AidlTestUtils.makeProgramSelector(
ProgramSelector.PROGRAM_TYPE_FM, TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID,
TEST_FM_FREQUENCY_ID, /* signalQuality= */ 99);
private static final ProgramSelector.Identifier TEST_AM_FREQUENCY_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
/* value= */ 1_700);
private static final RadioManager.ProgramInfo TEST_AM_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
TEST_AM_FREQUENCY_ID), TEST_AM_FREQUENCY_ID, TEST_AM_FREQUENCY_ID,
TEST_SIGNAL_QUALITY);
private static final ProgramSelector.Identifier TEST_RDS_PI_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI,
/* value= */ 15_019);
private static final RadioManager.ProgramInfo TEST_RDS_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM, TEST_RDS_PI_ID),
TEST_RDS_PI_ID, new ProgramSelector.Identifier(
ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, /* value= */ 89_500),
TEST_SIGNAL_QUALITY);
private static final ProgramSelector.Identifier TEST_DAB_DMB_SID_EXT_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
/* value= */ 0xA000000111L);
private static final ProgramSelector.Identifier TEST_DAB_ENSEMBLE_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
/* value= */ 0x1001);
private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
/* value= */ 220_352);
private static final RadioManager.ProgramInfo TEST_DAB_INFO = AidlTestUtils.makeProgramInfo(
new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_DMB_SID_EXT_ID,
new ProgramSelector.Identifier[]{TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID},
/* vendorIds= */ null), TEST_DAB_DMB_SID_EXT_ID, TEST_DAB_FREQUENCY_ID,
TEST_SIGNAL_QUALITY);
private static final ProgramSelector.Identifier TEST_VENDOR_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_VENDOR_START,
/* value= */ 9_001);
private static final RadioManager.ProgramInfo TEST_VENDOR_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_VENDOR_START,
TEST_VENDOR_ID), TEST_VENDOR_ID, TEST_VENDOR_ID, TEST_SIGNAL_QUALITY);
private static final ProgramInfoCache FULL_PROGRAM_INFO_CACHE = new ProgramInfoCache(
/* filter= */ null, /* complete= */ true,
TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO, TEST_VENDOR_INFO);
@Rule
public final Expect expect = Expect.create();
@Test
public void isComplete_forCompleteProgramInfoCache_returnsTrue() {
expect.withMessage("Complete program info cache")
.that(FULL_PROGRAM_INFO_CACHE.isComplete()).isTrue();
}
@Test
public void isComplete_forIncompleteProgramInfoCache_returnsFalse() {
ProgramInfoCache programInfoCache = new ProgramInfoCache(/* filter= */ null,
/* complete= */ false);
expect.withMessage("Incomplete program info cache")
.that(programInfoCache.isComplete()).isFalse();
}
@Test
public void getFilter_forProgramInfoCache() {
ProgramList.Filter fmFilter = new ProgramList.Filter(
Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
ProgramInfoCache fmProgramInfoCache = new ProgramInfoCache(fmFilter);
expect.withMessage("Program info cache filter")
.that(fmProgramInfoCache.getFilter()).isEqualTo(fmFilter);
}
@Test
public void updateFromHalProgramListChunk_withPurgingCompleteChunk() {
ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
/* complete= */ false, TEST_FM_INFO);
ProgramListChunk chunk = AidlTestUtils.makeHalChunk(/* purge= */ true, /* complete= */ true,
new ProgramInfo[]{AidlTestUtils.programInfoToHalProgramInfo(TEST_RDS_INFO),
AidlTestUtils.programInfoToHalProgramInfo(TEST_VENDOR_INFO)},
new ProgramIdentifier[]{});
cache.updateFromHalProgramListChunk(chunk);
expect.withMessage("Program cache updated with purge-enabled and complete chunk")
.that(cache.toProgramInfoList())
.containsExactly(TEST_RDS_INFO, TEST_VENDOR_INFO);
expect.withMessage("Complete program cache").that(cache.isComplete()).isTrue();
}
@Test
public void updateFromHalProgramListChunk_withNonPurgingIncompleteChunk() {
ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
/* complete= */ false, TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO);
ProgramListChunk chunk = AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ false,
new ProgramInfo[]{AidlTestUtils.programInfoToHalProgramInfo(TEST_FM_INFO_MODIFIED),
AidlTestUtils.programInfoToHalProgramInfo(TEST_VENDOR_INFO)},
new ProgramIdentifier[]{ConversionUtils.identifierToHalProgramIdentifier(
TEST_RDS_PI_ID)});
cache.updateFromHalProgramListChunk(chunk);
expect.withMessage("Program cache updated with non-purging and incomplete chunk")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO, TEST_AM_INFO);
expect.withMessage("Incomplete program cache").that(cache.isComplete()).isFalse();
}
@Test
public void filterAndUpdateFromInternal_withNullFilter() {
ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
/* complete= */ true);
cache.filterAndUpdateFromInternal(FULL_PROGRAM_INFO_CACHE, /* purge= */ false);
expect.withMessage("Program cache filtered by null filter")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO,
TEST_VENDOR_INFO);
}
@Test
public void filterAndUpdateFromInternal_withEmptyFilter() {
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false));
cache.filterAndUpdateFromInternal(FULL_PROGRAM_INFO_CACHE, /* purge= */ false);
expect.withMessage("Program cache filtered by empty filter")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO,
TEST_VENDOR_INFO);
}
@Test
public void filterAndUpdateFromInternal_withFilterByIdentifierType() {
ProgramInfoCache cache = new ProgramInfoCache(
new ProgramList.Filter(Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
ProgramSelector.IDENTIFIER_TYPE_RDS_PI), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false));
cache.filterAndUpdateFromInternal(FULL_PROGRAM_INFO_CACHE, /* purge= */ false);
expect.withMessage("Program cache filtered by identifier type")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO);
}
@Test
public void filterAndUpdateFromInternal_withFilterByIdentifier() {
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(
new ArraySet<>(), Set.of(TEST_FM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID),
/* includeCategories= */ true, /* excludeModifications= */ false));
int maxNumModifiedPerChunk = 2;
int maxNumRemovedPerChunk = 2;
List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(
FULL_PROGRAM_INFO_CACHE, /* purge= */ true, maxNumModifiedPerChunk,
maxNumRemovedPerChunk);
expect.withMessage("Program cache filtered by identifier")
.that(cache.toProgramInfoList()).containsExactly(TEST_FM_INFO, TEST_DAB_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ true);
verifyChunkListComplete(programListChunks, FULL_PROGRAM_INFO_CACHE.isComplete());
verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO,
TEST_DAB_INFO);
verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
}
@Test
public void filterAndUpdateFromInternal_withFilterExcludingCategories() {
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
new ArraySet<>(), /* includeCategories= */ false,
/* excludeModifications= */ false));
int maxNumModifiedPerChunk = 3;
int maxNumRemovedPerChunk = 2;
List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(
FULL_PROGRAM_INFO_CACHE, /* purge= */ false, maxNumModifiedPerChunk,
maxNumRemovedPerChunk);
expect.withMessage("Program cache filtered by excluding categories")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO, TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ true);
verifyChunkListComplete(programListChunks, FULL_PROGRAM_INFO_CACHE.isComplete());
verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO,
TEST_AM_INFO, TEST_RDS_INFO, TEST_DAB_INFO);
verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
}
@Test
public void filterAndUpdateFromInternal_withFilterExcludingModifications() {
ProgramList.Filter filterExcludingModifications = new ProgramList.Filter(new ArraySet<>(),
new ArraySet<>(), /* includeCategories= */ true,
/* excludeModifications= */ true);
ProgramInfoCache cache = new ProgramInfoCache(filterExcludingModifications,
/* complete= */ true, TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO, TEST_DAB_INFO);
ProgramInfoCache halCache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO);
int maxNumModifiedPerChunk = 2;
int maxNumRemovedPerChunk = 2;
List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(halCache,
/* purge= */ false, maxNumModifiedPerChunk, maxNumRemovedPerChunk);
expect.withMessage("Program cache filtered by excluding modifications")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO, TEST_VENDOR_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ false);
verifyChunkListComplete(programListChunks, halCache.isComplete());
verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_VENDOR_INFO);
verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk, TEST_RDS_PI_ID,
TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID);
}
@Test
public void filterAndUpdateFromInternal_withPurge() {
ProgramInfoCache cache = new ProgramInfoCache(new ProgramList.Filter(new ArraySet<>(),
new ArraySet<>(), /* includeCategories= */ true,
/* excludeModifications= */ false),
/* complete= */ true, TEST_FM_INFO, TEST_RDS_INFO);
ProgramInfoCache halCache = new ProgramInfoCache(/* filter= */ null, /* complete= */ false,
TEST_FM_INFO_MODIFIED, TEST_DAB_INFO, TEST_VENDOR_INFO);
int maxNumModifiedPerChunk = 2;
int maxNumRemovedPerChunk = 2;
List<ProgramList.Chunk> programListChunks = cache.filterAndUpdateFromInternal(halCache,
/* purge= */ true, maxNumModifiedPerChunk, maxNumRemovedPerChunk);
expect.withMessage("Purged program cache").that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO_MODIFIED, TEST_DAB_INFO, TEST_VENDOR_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ true);
verifyChunkListComplete(programListChunks, halCache.isComplete());
verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
TEST_DAB_INFO, TEST_VENDOR_INFO);
verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
}
@Test
public void filterAndApplyChunkInternal_withPurgingIncompleteChunk() throws RemoteException {
ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
/* complete= */ false, TEST_FM_INFO, TEST_DAB_INFO);
ProgramList.Chunk chunk = AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ false,
List.of(TEST_FM_INFO_MODIFIED, TEST_RDS_INFO, TEST_VENDOR_INFO),
List.of(TEST_DAB_DMB_SID_EXT_ID));
int maxNumModifiedPerChunk = 2;
int maxNumRemovedPerChunk = 2;
List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(chunk,
maxNumModifiedPerChunk, maxNumRemovedPerChunk);
expect.withMessage("Program cache applied with non-purging and complete chunk")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO_MODIFIED, TEST_RDS_INFO, TEST_VENDOR_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ true);
verifyChunkListComplete(programListChunks, /* complete= */ false);
verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
TEST_RDS_INFO, TEST_VENDOR_INFO);
verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk);
}
@Test
public void filterAndApplyChunk_withNonPurgingCompleteChunk() throws RemoteException {
ProgramInfoCache cache = new ProgramInfoCache(/* filter= */ null,
/* complete= */ false, TEST_FM_INFO, TEST_RDS_INFO, TEST_AM_INFO, TEST_DAB_INFO);
ProgramList.Chunk chunk = AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
List.of(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO),
List.of(TEST_RDS_PI_ID, TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID));
int maxNumModifiedPerChunk = 2;
int maxNumRemovedPerChunk = 2;
List<ProgramList.Chunk> programListChunks = cache.filterAndApplyChunkInternal(chunk,
maxNumModifiedPerChunk, maxNumRemovedPerChunk);
expect.withMessage("Program cache applied with purge-enabled complete chunk")
.that(cache.toProgramInfoList())
.containsExactly(TEST_FM_INFO_MODIFIED, TEST_VENDOR_INFO);
verifyChunkListPurge(programListChunks, /* purge= */ false);
verifyChunkListComplete(programListChunks, /* complete= */ true);
verifyChunkListModified(programListChunks, maxNumModifiedPerChunk, TEST_FM_INFO_MODIFIED,
TEST_VENDOR_INFO);
verifyChunkListRemoved(programListChunks, maxNumRemovedPerChunk, TEST_RDS_PI_ID,
TEST_AM_FREQUENCY_ID, TEST_DAB_DMB_SID_EXT_ID);
}
private void verifyChunkListPurge(List<ProgramList.Chunk> chunks, boolean purge) {
if (chunks.isEmpty()) {
return;
}
for (int i = 0; i < chunks.size(); i++) {
ProgramList.Chunk chunk = chunks.get(i);
boolean expectedPurge = (i == 0 && purge);
expect.withMessage("Purge for chunk %s", i)
.that(chunk.isPurge()).isEqualTo(expectedPurge);
}
}
private void verifyChunkListComplete(List<ProgramList.Chunk> chunks, boolean complete) {
if (chunks.isEmpty()) {
return;
}
for (int i = 0; i < chunks.size(); i++) {
ProgramList.Chunk chunk = chunks.get(i);
boolean expectedComplete = (i == chunks.size() - 1 && complete);
expect.withMessage("Purge for chunk %s", i)
.that(chunk.isComplete()).isEqualTo(expectedComplete);
}
}
private void verifyChunkListModified(List<ProgramList.Chunk> chunks,
int maxModifiedPerChunk, RadioManager.ProgramInfo... expectedProgramInfos) {
if (chunks.isEmpty()) {
expect.withMessage("Empty program info list")
.that(expectedProgramInfos.length).isEqualTo(0);
return;
}
ArraySet<RadioManager.ProgramInfo> actualSet = new ArraySet<>();
for (int i = 0; i < chunks.size(); i++) {
Set<RadioManager.ProgramInfo> chunkModified = chunks.get(i).getModified();
actualSet.addAll(chunkModified);
expect.withMessage("Chunk %s modified program info array size", i)
.that(chunkModified.size()).isAtMost(maxModifiedPerChunk);
}
expect.withMessage("Program info items")
.that(actualSet).containsExactlyElementsIn(expectedProgramInfos);
}
private void verifyChunkListRemoved(List<ProgramList.Chunk> chunks,
int maxRemovedPerChunk, ProgramSelector.Identifier... expectedIdentifiers) {
if (chunks.isEmpty()) {
expect.withMessage("Empty program info list")
.that(expectedIdentifiers.length).isEqualTo(0);
return;
}
ArraySet<ProgramSelector.Identifier> actualSet = new ArraySet<>();
for (int i = 0; i < chunks.size(); i++) {
Set<ProgramSelector.Identifier> chunkRemoved = chunks.get(i).getRemoved();
actualSet.addAll(chunkRemoved);
expect.withMessage("Chunk %s removed identifier array size ", i)
.that(chunkRemoved.size()).isAtMost(maxRemovedPerChunk);
}
expect.withMessage("Removed identifier items")
.that(actualSet).containsExactlyElementsIn(expectedIdentifiers);
}
}

View File

@@ -37,7 +37,9 @@ import android.graphics.Bitmap;
import android.hardware.broadcastradio.IBroadcastRadio;
import android.hardware.broadcastradio.ITunerCallback;
import android.hardware.broadcastradio.IdentifierType;
import android.hardware.broadcastradio.ProgramFilter;
import android.hardware.broadcastradio.ProgramInfo;
import android.hardware.broadcastradio.ProgramListChunk;
import android.hardware.broadcastradio.Result;
import android.hardware.broadcastradio.VendorKeyValue;
import android.hardware.radio.ProgramList;
@@ -61,8 +63,10 @@ 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;
import java.util.Set;
/**
* Tests for AIDL HAL TunerSession.
@@ -72,7 +76,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
private static final int TARGET_SDK_VERSION = Build.VERSION_CODES.CUR_DEVELOPMENT;
private static final VerificationWithTimeout CALLBACK_TIMEOUT =
timeout(/* millis= */ 200);
private static final int SIGNAL_QUALITY = 1;
private static final int SIGNAL_QUALITY = 90;
private static final long AM_FM_FREQUENCY_SPACING = 500;
private static final long[] AM_FM_FREQUENCY_LIST = {97_500, 98_100, 99_100};
private static final RadioManager.FmBandDescriptor FM_BAND_DESCRIPTOR =
@@ -84,6 +88,27 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
new RadioManager.FmBandConfig(FM_BAND_DESCRIPTOR);
private static final int UNSUPPORTED_CONFIG_FLAG = 0;
private static final ProgramSelector.Identifier TEST_FM_FREQUENCY_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
/* value= */ 88_500);
private static final ProgramSelector.Identifier TEST_RDS_PI_ID =
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI,
/* value= */ 15_019);
private static final RadioManager.ProgramInfo TEST_FM_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID, TEST_FM_FREQUENCY_ID,
SIGNAL_QUALITY);
private static final RadioManager.ProgramInfo TEST_FM_INFO_MODIFIED =
AidlTestUtils.makeProgramInfo(AidlTestUtils.makeProgramSelector(
ProgramSelector.PROGRAM_TYPE_FM, TEST_FM_FREQUENCY_ID), TEST_FM_FREQUENCY_ID,
TEST_FM_FREQUENCY_ID, /* signalQuality= */ 100);
private static final RadioManager.ProgramInfo TEST_RDS_INFO = AidlTestUtils.makeProgramInfo(
AidlTestUtils.makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM, TEST_RDS_PI_ID),
TEST_RDS_PI_ID, new ProgramSelector.Identifier(
ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, /* value= */ 89_500),
SIGNAL_QUALITY);
// Mocks
@Mock private IBroadcastRadio mBroadcastRadioMock;
private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
@@ -393,7 +418,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void tune_withHalHasUnknownError_fails() throws Exception {
public void tune_withUnknownErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
doThrow(new ServiceSpecificException(Result.UNKNOWN_ERROR))
@@ -403,7 +428,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
mTunerSessions[0].tune(sel);
});
assertWithMessage("Exception for tuning when HAL has unknown error")
assertWithMessage("Unknown error HAL exception when tuning")
.that(thrown).hasMessageThat().contains("UNKNOWN_ERROR");
}
@@ -536,7 +561,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void seek_withHalHasInternalError_fails() throws Exception {
public void seek_withInternalErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
doThrow(new ServiceSpecificException(Result.INTERNAL_ERROR))
.when(mBroadcastRadioMock).seek(anyBoolean(), anyBoolean());
@@ -545,7 +570,7 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
});
assertWithMessage("Exception for seeking when HAL has internal error")
assertWithMessage("Internal error HAL exception when seeking")
.that(thrown).hasMessageThat().contains("INTERNAL_ERROR");
}
@@ -643,12 +668,277 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete();
}
@Test
public void startProgramListUpdates_withEmptyFilter() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(filter);
List<RadioManager.ProgramInfo> modified = List.of(TEST_FM_INFO, TEST_RDS_INFO);
List<ProgramSelector.Identifier> removed = new ArrayList<>();
ProgramListChunk halProgramList = AidlTestUtils.makeHalChunk(/* purge= */ true,
/* complete= */ true, modified, removed);
ProgramList.Chunk expectedProgramList =
AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true, modified, removed);
mTunerSessions[0].startProgramListUpdates(filter);
mHalTunerCallback.onProgramListUpdated(halProgramList);
verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
.onProgramListUpdated(expectedProgramList);
}
@Test
public void startProgramListUpdates_withCallbackCalledForMultipleTimes() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
mTunerSessions[0].startProgramListUpdates(filter);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
/* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
}
@Test
public void startProgramListUpdates_withTheSameFilterForMultipleTimes() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
mTunerSessions[0].startProgramListUpdates(filter);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
/* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
mTunerSessions[0].startProgramListUpdates(filter);
verify(mBroadcastRadioMock).startProgramListUpdates(any());
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
}
@Test
public void startProgramListUpdates_withNullFilter() throws Exception {
openAidlClients(/* numClients= */ 1);
mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ true,
/* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
verify(mBroadcastRadioMock).startProgramListUpdates(any());
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ true, /* complete= */ true,
List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
List.of(TEST_FM_INFO_MODIFIED), List.of(TEST_RDS_PI_ID)));
}
@Test
public void startProgramListUpdates_withIdFilter() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter idFilter = new ProgramList.Filter(new ArraySet<>(),
Set.of(TEST_RDS_PI_ID), /* includeCategories= */ true,
/* excludeModifications= */ true);
ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(idFilter);
mTunerSessions[0].startProgramListUpdates(idFilter);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_RDS_INFO), new ArrayList<>()));
verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
List.of(TEST_RDS_INFO), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(any());
}
@Test
public void startProgramListUpdates_withFilterExcludingModifications() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filterExcludingModifications = new ProgramList.Filter(
Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ true);
ProgramFilter halFilter =
ConversionUtils.filterToHalProgramFilter(filterExcludingModifications);
mTunerSessions[0].startProgramListUpdates(filterExcludingModifications);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
List.of(TEST_FM_INFO), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(any());
}
@Test
public void startProgramListUpdates_withFilterIncludingModifications() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filterIncludingModifications = new ProgramList.Filter(
Set.of(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
ProgramFilter halFilter =
ConversionUtils.filterToHalProgramFilter(filterIncludingModifications);
mTunerSessions[0].startProgramListUpdates(filterIncludingModifications);
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
List.of(TEST_FM_INFO), new ArrayList<>()));
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onProgramListUpdated(
AidlTestUtils.makeChunk(/* purge= */ false, /* complete= */ true,
List.of(TEST_FM_INFO_MODIFIED), new ArrayList<>()));
}
@Test
public void onProgramListUpdated_afterSessionClosed_doesNotUpdates() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
mTunerSessions[0].startProgramListUpdates(filter);
mTunerSessions[0].close();
verify(mBroadcastRadioMock).stopProgramListUpdates();
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onProgramListUpdated(any());
}
@Test
public void startProgramListUpdates_forMultipleSessions() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
ProgramList.Filter fmIdFilter = new ProgramList.Filter(new ArraySet<>(),
Set.of(TEST_FM_FREQUENCY_ID), /* includeCategories= */ false,
/* excludeModifications= */ true);
ProgramList.Filter filterExcludingCategories = new ProgramList.Filter(new ArraySet<>(),
new ArraySet<>(), /* includeCategories= */ true,
/* excludeModifications= */ true);
ProgramList.Filter rdsTypeFilter = new ProgramList.Filter(
Set.of(ProgramSelector.IDENTIFIER_TYPE_RDS_PI), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
mTunerSessions[0].startProgramListUpdates(fmIdFilter);
ProgramFilter halFilter = ConversionUtils.filterToHalProgramFilter(fmIdFilter);
verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
mTunerSessions[1].startProgramListUpdates(filterExcludingCategories);
halFilter.identifiers = new android.hardware.broadcastradio.ProgramIdentifier[]{};
halFilter.includeCategories = true;
verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
mTunerSessions[2].startProgramListUpdates(rdsTypeFilter);
halFilter.excludeModifications = false;
verify(mBroadcastRadioMock).startProgramListUpdates(halFilter);
}
@Test
public void onProgramListUpdated_forMultipleSessions() throws Exception {
int numSessions = 3;
openAidlClients(numSessions);
List<ProgramList.Filter> filters = List.of(new ProgramList.Filter(
Set.of(ProgramSelector.IDENTIFIER_TYPE_RDS_PI), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false),
new ProgramList.Filter(new ArraySet<>(), Set.of(TEST_FM_FREQUENCY_ID),
/* includeCategories= */ false, /* excludeModifications= */ true),
new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ true));
for (int index = 0; index < numSessions; index++) {
mTunerSessions[index].startProgramListUpdates(filters.get(index));
}
mHalTunerCallback.onProgramListUpdated(AidlTestUtils.makeHalChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO, TEST_RDS_INFO), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT)
.onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_RDS_INFO), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[1], CALLBACK_TIMEOUT)
.onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_FM_INFO), new ArrayList<>()));
verify(mAidlTunerCallbackMocks[2], CALLBACK_TIMEOUT)
.onProgramListUpdated(AidlTestUtils.makeChunk(/* purge= */ false,
/* complete= */ true, List.of(TEST_RDS_INFO, TEST_FM_INFO),
new ArrayList<>()));
}
@Test
public void startProgramListUpdates_forNonCurrentUser_doesNotStartUpdates() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
mTunerSessions[0].startProgramListUpdates(filter);
verify(mBroadcastRadioMock, never()).startProgramListUpdates(any());
}
@Test
public void startProgramListUpdates_withUnknownErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
doThrow(new ServiceSpecificException(Result.UNKNOWN_ERROR))
.when(mBroadcastRadioMock).startProgramListUpdates(any());
ParcelableException thrown = assertThrows(ParcelableException.class, () -> {
mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
});
assertWithMessage("Unknown error HAL exception when updating program list")
.that(thrown).hasMessageThat().contains("UNKNOWN_ERROR");
}
@Test
public void stopProgramListUpdates() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter aidlFilter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
mTunerSessions[0].startProgramListUpdates(aidlFilter);
mTunerSessions[0].startProgramListUpdates(filter);
mTunerSessions[0].stopProgramListUpdates();
@@ -658,9 +948,9 @@ 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<>(),
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
mTunerSessions[0].startProgramListUpdates(aidlFilter);
mTunerSessions[0].startProgramListUpdates(filter);
doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
mTunerSessions[0].stopProgramListUpdates();

View File

@@ -373,7 +373,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void tune_withHalHasUnknownError_fails() throws Exception {
public void tune_withUnknownErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramSelector sel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
doAnswer(invocation -> Result.UNKNOWN_ERROR).when(mHalTunerSessionMock).tune(any());
@@ -382,7 +382,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
mTunerSessions[0].tune(sel);
});
assertWithMessage("Exception for tuning when HAL has unknown error")
assertWithMessage("Unknown error HAL exception when tuning")
.that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
}
@@ -513,7 +513,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
}
@Test
public void seek_withHalHasInternalError_fails() throws Exception {
public void seek_withInternalErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
doAnswer(invocation -> Result.INTERNAL_ERROR).when(mHalTunerSessionMock)
.scan(anyBoolean(), anyBoolean());
@@ -522,7 +522,7 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
mTunerSessions[0].seek(/* directionDown= */ true, /* skipSubChannel= */ false);
});
assertWithMessage("Exception for seeking when HAL has internal error")
assertWithMessage("Internal error HAL exception when seeking")
.that(thrown).hasMessageThat().contains(Result.toString(Result.INTERNAL_ERROR));
}
@@ -632,6 +632,32 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)).onBackgroundScanComplete();
}
@Test
public void startProgramListUpdates_forNonCurrentUser_doesNotStartUpdates() throws Exception {
openAidlClients(/* numClients= */ 1);
ProgramList.Filter filter = new ProgramList.Filter(new ArraySet<>(), new ArraySet<>(),
/* includeCategories= */ true, /* excludeModifications= */ false);
doReturn(false).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
mTunerSessions[0].startProgramListUpdates(filter);
verify(mHalTunerSessionMock, never()).startProgramListUpdates(any());
}
@Test
public void startProgramListUpdates_withUnknownErrorFromHal_fails() throws Exception {
openAidlClients(/* numClients= */ 1);
doAnswer(invocation -> Result.UNKNOWN_ERROR).when(mHalTunerSessionMock)
.startProgramListUpdates(any());
ParcelableException thrown = assertThrows(ParcelableException.class, () -> {
mTunerSessions[0].startProgramListUpdates(/* filter= */ null);
});
assertWithMessage("Unknown error HAL exception when updating program list")
.that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR));
}
@Test
public void stopProgramListUpdates() throws Exception {
openAidlClients(/* numClients= */ 1);

View File

@@ -86,12 +86,8 @@ final class ProgramInfoCache {
}
@VisibleForTesting
boolean programInfosAreExactly(RadioManager.ProgramInfo... programInfos) {
Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> expectedMap = new ArrayMap<>();
for (int i = 0; i < programInfos.length; i++) {
expectedMap.put(programInfos[i].getSelector().getPrimaryId(), programInfos[i]);
}
return expectedMap.equals(mProgramInfoMap);
List<RadioManager.ProgramInfo> toProgramInfoList() {
return new ArrayList<>(mProgramInfoMap.values());
}
@Override