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:
committed by
Android (Google) Code Review
commit
535034b8f9
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user