Improve DAB support in radio service and manager
The full support for using 44-bit DAB primary identifier in AIDL was implemented. Whether program selectors and program info sent between AIDL HAL and HAL client are valid was checked in HAL client. Unit tests for checking target SDK version and converting program selector and info broadcast radio were added. In addition, existing unit tests were updated by using DAB_DMB_SID_EXT identifier type instead and using more meaningful values for DAB identifiers. Bug: 261912181 Test: atest com.android.server.broadcastradio Test: atest android.hardware.radio.tests.unittests Change-Id: I9e705acafea4fb6c5b77d1ba647097ad43ba7cf9
This commit is contained in:
@@ -65,12 +65,12 @@ public final class ProgramSelector implements Parcelable {
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int PROGRAM_TYPE_INVALID = 0;
|
||||
/** Analogue AM radio (with or without RDS).
|
||||
/** Analog AM radio (with or without RDS).
|
||||
* @deprecated use {@link ProgramIdentifier} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int PROGRAM_TYPE_AM = 1;
|
||||
/** analogue FM radio (with or without RDS).
|
||||
/** analog FM radio (with or without RDS).
|
||||
* @deprecated use {@link ProgramIdentifier} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -125,25 +125,50 @@ public final class ProgramSelector implements Parcelable {
|
||||
public @interface ProgramType {}
|
||||
|
||||
public static final int IDENTIFIER_TYPE_INVALID = 0;
|
||||
/** kHz */
|
||||
/**
|
||||
* Primary identifier for analog (without RDS) AM/FM stations:
|
||||
* frequency in kHz.
|
||||
*
|
||||
* <p>This identifier also contains band information:
|
||||
* <li>
|
||||
* <ul><500kHz: AM LW.
|
||||
* <ul>500kHz - 1705kHz: AM MW.
|
||||
* <ul>1.71MHz - 30MHz: AM SW.
|
||||
* <ul>>60MHz: FM.
|
||||
* </li>
|
||||
*/
|
||||
public static final int IDENTIFIER_TYPE_AMFM_FREQUENCY = 1;
|
||||
/** 16bit */
|
||||
/**
|
||||
* 16bit primary identifier for FM RDS station.
|
||||
*/
|
||||
public static final int IDENTIFIER_TYPE_RDS_PI = 2;
|
||||
/**
|
||||
* 64bit compound primary identifier for HD Radio.
|
||||
*
|
||||
* Consists of (from the LSB):
|
||||
* - 32bit: Station ID number;
|
||||
* - 4bit: HD_SUBCHANNEL;
|
||||
* - 18bit: AMFM_FREQUENCY.
|
||||
* The remaining bits should be set to zeros when writing on the chip side
|
||||
* <p>Consists of (from the LSB):
|
||||
* <li>
|
||||
* <ul>132bit: Station ID number.
|
||||
* <ul>14bit: HD_SUBCHANNEL.
|
||||
* <ul>18bit: AMFM_FREQUENCY.
|
||||
* </li>
|
||||
*
|
||||
* <p>While station ID number should be unique globally, it sometimes gets
|
||||
* abused by broadcasters (i.e. not being set at all). To ensure local
|
||||
* uniqueness, AMFM_FREQUENCY_KHZ was added here. Global uniqueness is
|
||||
* a best-effort - see {@link IDENTIFIER_TYPE_HD_STATION_NAME}.
|
||||
*
|
||||
* <p>HD Radio subchannel is a value in range of 0-7.
|
||||
* This index is 0-based (where 0 is MPS and 1..7 are SPS),
|
||||
* as opposed to HD Radio standard (where it's 1-based).
|
||||
*
|
||||
* <p>The remaining bits should be set to zeros when writing on the chip side
|
||||
* and ignored when read.
|
||||
*/
|
||||
public static final int IDENTIFIER_TYPE_HD_STATION_ID_EXT = 3;
|
||||
/**
|
||||
* HD Radio subchannel - a value of range 0-7.
|
||||
* HD Radio subchannel - a value in range of 0-7.
|
||||
*
|
||||
* The subchannel index is 0-based (where 0 is MPS and 1..7 are SPS),
|
||||
* <p>The subchannel index is 0-based (where 0 is MPS and 1..7 are SPS),
|
||||
* as opposed to HD Radio standard (where it's 1-based).
|
||||
*
|
||||
* @deprecated use IDENTIFIER_TYPE_HD_STATION_ID_EXT instead
|
||||
@@ -153,16 +178,16 @@ public final class ProgramSelector implements Parcelable {
|
||||
/**
|
||||
* 64bit additional identifier for HD Radio.
|
||||
*
|
||||
* Due to Station ID abuse, some HD_STATION_ID_EXT identifiers may be not
|
||||
* <p>Due to Station ID abuse, some HD_STATION_ID_EXT identifiers may be not
|
||||
* globally unique. To provide a best-effort solution, a short version of
|
||||
* station name may be carried as additional identifier and may be used
|
||||
* by the tuner hardware to double-check tuning.
|
||||
*
|
||||
* The name is limited to the first 8 A-Z0-9 characters (lowercase letters
|
||||
* must be converted to uppercase). Encoded in little-endian ASCII:
|
||||
* the first character of the name is the LSB.
|
||||
* <p>The name is limited to the first 8 A-Z0-9 characters (lowercase
|
||||
* letters must be converted to uppercase). Encoded in little-endian
|
||||
* ASCII: the first character of the name is the LSB.
|
||||
*
|
||||
* For example: "Abc" is encoded as 0x434241.
|
||||
* <p>For example: "Abc" is encoded as 0x434241.
|
||||
*/
|
||||
public static final int IDENTIFIER_TYPE_HD_STATION_NAME = 10004;
|
||||
/**
|
||||
@@ -175,17 +200,19 @@ public final class ProgramSelector implements Parcelable {
|
||||
/**
|
||||
* 28bit compound primary identifier for Digital Audio Broadcasting.
|
||||
*
|
||||
* Consists of (from the LSB):
|
||||
* - 16bit: SId;
|
||||
* - 8bit: ECC code;
|
||||
* - 4bit: SCIdS.
|
||||
* <p>Consists of (from the LSB):
|
||||
* <li>
|
||||
* <ul>16bit: SId.
|
||||
* <ul>8bit: ECC code.
|
||||
* <ul>4bit: SCIdS.
|
||||
* </li>
|
||||
*
|
||||
* SCIdS (Service Component Identifier within the Service) value
|
||||
* <p>SCIdS (Service Component Identifier within the Service) value
|
||||
* of 0 represents the main service, while 1 and above represents
|
||||
* secondary services.
|
||||
*
|
||||
* The remaining bits should be set to zeros when writing on the chip side
|
||||
* and ignored when read.
|
||||
* <p>The remaining bits should be set to zeros when writing on the chip
|
||||
* side and ignored when read.
|
||||
*
|
||||
* @deprecated use {@link #IDENTIFIER_TYPE_DAB_DMB_SID_EXT} instead
|
||||
*/
|
||||
@@ -197,7 +224,9 @@ public final class ProgramSelector implements Parcelable {
|
||||
public static final int IDENTIFIER_TYPE_DAB_SCID = 7;
|
||||
/** kHz */
|
||||
public static final int IDENTIFIER_TYPE_DAB_FREQUENCY = 8;
|
||||
/** 24bit */
|
||||
/**
|
||||
* 24bit primary identifier for Digital Radio Mondiale.
|
||||
*/
|
||||
public static final int IDENTIFIER_TYPE_DRMO_SERVICE_ID = 9;
|
||||
/** kHz */
|
||||
public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10;
|
||||
@@ -207,7 +236,9 @@ public final class ProgramSelector implements Parcelable {
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11;
|
||||
/** 32bit */
|
||||
/**
|
||||
* 32bit primary identifier for SiriusXM Satellite Radio.
|
||||
*/
|
||||
public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12;
|
||||
/** 0-999 range */
|
||||
public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13;
|
||||
@@ -224,15 +255,15 @@ public final class ProgramSelector implements Parcelable {
|
||||
* of 0 represents the main service, while 1 and above represents
|
||||
* secondary services.
|
||||
*
|
||||
* The remaining bits should be set to zeros when writing on the chip side
|
||||
* and ignored when read.
|
||||
* <p>The remaining bits should be set to zeros when writing on the chip
|
||||
* side and ignored when read.
|
||||
*/
|
||||
public static final int IDENTIFIER_TYPE_DAB_DMB_SID_EXT = 14;
|
||||
/**
|
||||
* Primary identifier for vendor-specific radio technology.
|
||||
* The value format is determined by a vendor.
|
||||
*
|
||||
* It must not be used in any other programType than corresponding VENDOR
|
||||
* <p>It must not be used in any other programType than corresponding VENDOR
|
||||
* type between VENDOR_START and VENDOR_END (eg. identifier type 1015 must
|
||||
* not be used in any program type other than 1015).
|
||||
*/
|
||||
|
||||
@@ -72,9 +72,9 @@ public final class ProgramListTest {
|
||||
/* value= */ 94300);
|
||||
private static final ProgramSelector.Identifier RDS_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_RDS_PI, 15019);
|
||||
private static final ProgramSelector.Identifier DAB_SID_EXT_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT,
|
||||
/* value= */ 0x10000111);
|
||||
private static final ProgramSelector.Identifier DAB_DMB_SID_EXT_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
|
||||
/* value= */ 0xA000000111L);
|
||||
private static final ProgramSelector.Identifier DAB_ENSEMBLE_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
|
||||
/* value= */ 0x1013);
|
||||
@@ -89,7 +89,7 @@ public final class ProgramListTest {
|
||||
|
||||
private static final ProgramList.Chunk FM_RDS_ADD_CHUNK = new ProgramList.Chunk(IS_PURGE,
|
||||
IS_COMPLETE, Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
|
||||
Set.of(DAB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
private static final ProgramList.Chunk FM_ADD_INCOMPLETE_CHUNK = new ProgramList.Chunk(IS_PURGE,
|
||||
/* complete= */ false, Set.of(FM_PROGRAM_INFO), new ArraySet<>());
|
||||
private static final ProgramList.Filter TEST_FILTER = new ProgramList.Filter(
|
||||
@@ -216,7 +216,7 @@ public final class ProgramListTest {
|
||||
public void isPurge_forChunk() {
|
||||
ProgramList.Chunk chunk = new ProgramList.Chunk(IS_PURGE, IS_COMPLETE,
|
||||
Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
|
||||
Set.of(DAB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
|
||||
assertWithMessage("Puring chunk").that(chunk.isPurge()).isEqualTo(IS_PURGE);
|
||||
}
|
||||
@@ -225,7 +225,7 @@ public final class ProgramListTest {
|
||||
public void isComplete_forChunk() {
|
||||
ProgramList.Chunk chunk = new ProgramList.Chunk(IS_PURGE, IS_COMPLETE,
|
||||
Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
|
||||
Set.of(DAB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
|
||||
assertWithMessage("Complete chunk").that(chunk.isComplete()).isEqualTo(IS_COMPLETE);
|
||||
}
|
||||
@@ -234,7 +234,7 @@ public final class ProgramListTest {
|
||||
public void getModified_forChunk() {
|
||||
ProgramList.Chunk chunk = new ProgramList.Chunk(IS_PURGE, IS_COMPLETE,
|
||||
Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
|
||||
Set.of(DAB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
|
||||
assertWithMessage("Modified program info in chunk")
|
||||
.that(chunk.getModified()).containsExactly(FM_PROGRAM_INFO, RDS_PROGRAM_INFO);
|
||||
@@ -244,10 +244,10 @@ public final class ProgramListTest {
|
||||
public void getRemoved_forChunk() {
|
||||
ProgramList.Chunk chunk = new ProgramList.Chunk(IS_PURGE, IS_COMPLETE,
|
||||
Set.of(FM_PROGRAM_INFO, RDS_PROGRAM_INFO),
|
||||
Set.of(DAB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
Set.of(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER));
|
||||
|
||||
assertWithMessage("Removed program identifiers in chunk").that(chunk.getRemoved())
|
||||
.containsExactly(DAB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER);
|
||||
.containsExactly(DAB_DMB_SID_EXT_IDENTIFIER, DAB_ENSEMBLE_IDENTIFIER);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -36,18 +36,18 @@ public final class ProgramSelectorTest {
|
||||
private static final long AM_FREQUENCY = 700;
|
||||
private static final ProgramSelector.Identifier FM_IDENTIFIER = new ProgramSelector.Identifier(
|
||||
ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, FM_FREQUENCY);
|
||||
private static final ProgramSelector.Identifier DAB_SID_EXT_IDENTIFIER_1 =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT,
|
||||
/* value= */ 0x1000011);
|
||||
private static final ProgramSelector.Identifier DAB_SID_EXT_IDENTIFIER_2 =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT,
|
||||
/* value= */ 0x10000112);
|
||||
private static final ProgramSelector.Identifier DAB_DMB_SID_EXT_IDENTIFIER_1 =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
|
||||
/* value= */ 0xA000000111L);
|
||||
private static final ProgramSelector.Identifier DAB_DMB_SID_EXT_IDENTIFIER_2 =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
|
||||
/* value= */ 0xA000000112L);
|
||||
private static final ProgramSelector.Identifier DAB_ENSEMBLE_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
|
||||
/* value= */ 0x1001);
|
||||
private static final ProgramSelector.Identifier DAB_FREQUENCY_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
|
||||
/* value= */ 94500);
|
||||
/* value= */ 220352);
|
||||
|
||||
@Test
|
||||
public void getType_forIdentifier() {
|
||||
@@ -80,13 +80,13 @@ public final class ProgramSelectorTest {
|
||||
@Test
|
||||
public void equals_withDifferentTypesForIdentifiers_returnsFalse() {
|
||||
assertWithMessage("Identifier with different identifier type")
|
||||
.that(FM_IDENTIFIER).isNotEqualTo(DAB_SID_EXT_IDENTIFIER_1);
|
||||
.that(FM_IDENTIFIER).isNotEqualTo(DAB_DMB_SID_EXT_IDENTIFIER_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equals_withDifferentValuesForIdentifiers_returnsFalse() {
|
||||
assertWithMessage("Identifier with different identifier value")
|
||||
.that(DAB_SID_EXT_IDENTIFIER_2).isNotEqualTo(DAB_SID_EXT_IDENTIFIER_1);
|
||||
.that(DAB_DMB_SID_EXT_IDENTIFIER_2).isNotEqualTo(DAB_DMB_SID_EXT_IDENTIFIER_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -168,19 +168,19 @@ public final class ProgramSelectorTest {
|
||||
@Test
|
||||
public void getFirstId_withIdInSelector() {
|
||||
ProgramSelector.Identifier[] secondaryIds = new ProgramSelector.Identifier[]{
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_SID_EXT_IDENTIFIER_2, DAB_FREQUENCY_IDENTIFIER};
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_DMB_SID_EXT_IDENTIFIER_2, DAB_FREQUENCY_IDENTIFIER};
|
||||
ProgramSelector selector = getDabSelector(secondaryIds, /* vendorIds= */ null);
|
||||
|
||||
long firstIdValue = selector.getFirstId(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT);
|
||||
long firstIdValue = selector.getFirstId(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT);
|
||||
|
||||
assertWithMessage("Value of the first DAB_SID_EXT identifier")
|
||||
.that(firstIdValue).isEqualTo(DAB_SID_EXT_IDENTIFIER_1.getValue());
|
||||
.that(firstIdValue).isEqualTo(DAB_DMB_SID_EXT_IDENTIFIER_1.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFirstId_withIdNotInSelector() {
|
||||
ProgramSelector.Identifier[] secondaryIds = new ProgramSelector.Identifier[]{
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_SID_EXT_IDENTIFIER_2};
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_DMB_SID_EXT_IDENTIFIER_2};
|
||||
ProgramSelector selector = getDabSelector(secondaryIds, /* vendorIds= */ null);
|
||||
|
||||
int idType = ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY;
|
||||
@@ -195,13 +195,13 @@ public final class ProgramSelectorTest {
|
||||
@Test
|
||||
public void getAllIds_withIdInSelector() {
|
||||
ProgramSelector.Identifier[] secondaryIds = new ProgramSelector.Identifier[]{
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_SID_EXT_IDENTIFIER_2, DAB_FREQUENCY_IDENTIFIER};
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_DMB_SID_EXT_IDENTIFIER_2, DAB_FREQUENCY_IDENTIFIER};
|
||||
ProgramSelector.Identifier[] allIdsExpected =
|
||||
{DAB_SID_EXT_IDENTIFIER_1, DAB_SID_EXT_IDENTIFIER_2};
|
||||
{DAB_DMB_SID_EXT_IDENTIFIER_1, DAB_DMB_SID_EXT_IDENTIFIER_2};
|
||||
ProgramSelector selector = getDabSelector(secondaryIds, /* vendorIds= */ null);
|
||||
|
||||
ProgramSelector.Identifier[] allIds =
|
||||
selector.getAllIds(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT);
|
||||
selector.getAllIds(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT);
|
||||
|
||||
assertWithMessage("All DAB_SID_EXT identifiers in selector")
|
||||
.that(allIds).isEqualTo(allIdsExpected);
|
||||
@@ -244,14 +244,14 @@ public final class ProgramSelectorTest {
|
||||
@Test
|
||||
public void withSecondaryPreferred() {
|
||||
ProgramSelector.Identifier[] secondaryIds = new ProgramSelector.Identifier[]{
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_SID_EXT_IDENTIFIER_2, DAB_FREQUENCY_IDENTIFIER};
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_DMB_SID_EXT_IDENTIFIER_2, DAB_FREQUENCY_IDENTIFIER};
|
||||
long[] vendorIdsExpected = {12345, 678};
|
||||
ProgramSelector selector = getDabSelector(secondaryIds, vendorIdsExpected);
|
||||
ProgramSelector.Identifier[] secondaryIdsExpected = new ProgramSelector.Identifier[]{
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_FREQUENCY_IDENTIFIER, DAB_SID_EXT_IDENTIFIER_1};
|
||||
DAB_ENSEMBLE_IDENTIFIER, DAB_FREQUENCY_IDENTIFIER, DAB_DMB_SID_EXT_IDENTIFIER_1};
|
||||
|
||||
ProgramSelector selectorPreferred =
|
||||
selector.withSecondaryPreferred(DAB_SID_EXT_IDENTIFIER_1);
|
||||
selector.withSecondaryPreferred(DAB_DMB_SID_EXT_IDENTIFIER_1);
|
||||
|
||||
assertWithMessage("Program type")
|
||||
.that(selectorPreferred.getProgramType()).isEqualTo(selector.getProgramType());
|
||||
@@ -458,7 +458,7 @@ public final class ProgramSelectorTest {
|
||||
|
||||
private ProgramSelector getDabSelector(@Nullable ProgramSelector.Identifier[] secondaryIds,
|
||||
@Nullable long[] vendorIds) {
|
||||
return new ProgramSelector(DAB_PROGRAM_TYPE, DAB_SID_EXT_IDENTIFIER_1, secondaryIds,
|
||||
return new ProgramSelector(DAB_PROGRAM_TYPE, DAB_DMB_SID_EXT_IDENTIFIER_1, secondaryIds,
|
||||
vendorIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,17 +105,17 @@ public final class RadioManagerTest {
|
||||
private static final int INFO_FLAGS = 0b110001;
|
||||
private static final int SIGNAL_QUALITY = 2;
|
||||
private static final ProgramSelector.Identifier DAB_SID_EXT_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT,
|
||||
/* value= */ 0x10000111);
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
|
||||
/* value= */ 0xA000000111L);
|
||||
private static final ProgramSelector.Identifier DAB_SID_EXT_IDENTIFIER_RELATED =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT,
|
||||
/* value= */ 0x10000113);
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
|
||||
/* value= */ 0xA000000113L);
|
||||
private static final ProgramSelector.Identifier DAB_ENSEMBLE_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
|
||||
/* value= */ 0x1013);
|
||||
private static final ProgramSelector.Identifier DAB_FREQUENCY_IDENTIFIER =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
|
||||
/* value= */ 95500);
|
||||
/* value= */ 220352);
|
||||
private static final ProgramSelector DAB_SELECTOR =
|
||||
new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB, DAB_SID_EXT_IDENTIFIER,
|
||||
new ProgramSelector.Identifier[]{
|
||||
@@ -859,13 +859,13 @@ public final class RadioManagerTest {
|
||||
@Test
|
||||
public void getLogicallyTunedTo_forProgramInfo() {
|
||||
assertWithMessage("Identifier logically tuned to in DAB program info")
|
||||
.that(DAB_PROGRAM_INFO.getLogicallyTunedTo()).isEqualTo(DAB_FREQUENCY_IDENTIFIER);
|
||||
.that(DAB_PROGRAM_INFO.getLogicallyTunedTo()).isEqualTo(DAB_SID_EXT_IDENTIFIER);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPhysicallyTunedTo_forProgramInfo() {
|
||||
assertWithMessage("Identifier physically tuned to DAB program info")
|
||||
.that(DAB_PROGRAM_INFO.getPhysicallyTunedTo()).isEqualTo(DAB_SID_EXT_IDENTIFIER);
|
||||
.that(DAB_PROGRAM_INFO.getPhysicallyTunedTo()).isEqualTo(DAB_FREQUENCY_IDENTIFIER);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1104,8 +1104,8 @@ public final class RadioManagerTest {
|
||||
}
|
||||
|
||||
private static RadioManager.ProgramInfo createDabProgramInfo(ProgramSelector selector) {
|
||||
return new RadioManager.ProgramInfo(selector, DAB_FREQUENCY_IDENTIFIER,
|
||||
DAB_SID_EXT_IDENTIFIER, Arrays.asList(DAB_SID_EXT_IDENTIFIER_RELATED), INFO_FLAGS,
|
||||
return new RadioManager.ProgramInfo(selector, DAB_SID_EXT_IDENTIFIER,
|
||||
DAB_FREQUENCY_IDENTIFIER, Arrays.asList(DAB_SID_EXT_IDENTIFIER_RELATED), INFO_FLAGS,
|
||||
SIGNAL_QUALITY, METADATA, /* vendorInfo= */ null);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,13 @@ final class AidlTestUtils {
|
||||
return makeProgramInfo(selector, signalQuality);
|
||||
}
|
||||
|
||||
static ProgramIdentifier makeHalIdentifier(@IdentifierType int type, long value) {
|
||||
ProgramIdentifier halDabId = new ProgramIdentifier();
|
||||
halDabId.type = type;
|
||||
halDabId.value = value;
|
||||
return halDabId;
|
||||
}
|
||||
|
||||
static ProgramSelector makeFmSelector(long freq) {
|
||||
return makeProgramSelector(ProgramSelector.PROGRAM_TYPE_FM,
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY,
|
||||
@@ -67,15 +74,17 @@ final class AidlTestUtils {
|
||||
}
|
||||
|
||||
static android.hardware.broadcastradio.ProgramSelector makeHalFmSelector(int freq) {
|
||||
ProgramIdentifier halId = new ProgramIdentifier();
|
||||
halId.type = IdentifierType.AMFM_FREQUENCY_KHZ;
|
||||
halId.value = freq;
|
||||
ProgramIdentifier halId = makeHalIdentifier(IdentifierType.AMFM_FREQUENCY_KHZ, freq);
|
||||
return makeHalSelector(halId, /* secondaryIds= */ new ProgramIdentifier[0]);
|
||||
}
|
||||
|
||||
android.hardware.broadcastradio.ProgramSelector halSelector =
|
||||
static android.hardware.broadcastradio.ProgramSelector makeHalSelector(
|
||||
ProgramIdentifier primaryId, ProgramIdentifier[] secondaryIds) {
|
||||
android.hardware.broadcastradio.ProgramSelector hwSelector =
|
||||
new android.hardware.broadcastradio.ProgramSelector();
|
||||
halSelector.primaryId = halId;
|
||||
halSelector.secondaryIds = new ProgramIdentifier[0];
|
||||
return halSelector;
|
||||
hwSelector.primaryId = primaryId;
|
||||
hwSelector.secondaryIds = secondaryIds;
|
||||
return hwSelector;
|
||||
}
|
||||
|
||||
static ProgramInfo programInfoToHalProgramInfo(RadioManager.ProgramInfo info) {
|
||||
@@ -95,10 +104,17 @@ final class AidlTestUtils {
|
||||
|
||||
static ProgramInfo makeHalProgramInfo(
|
||||
android.hardware.broadcastradio.ProgramSelector hwSel, int hwSignalQuality) {
|
||||
return makeHalProgramInfo(hwSel, hwSel.primaryId, hwSel.primaryId, hwSignalQuality);
|
||||
}
|
||||
|
||||
static ProgramInfo makeHalProgramInfo(
|
||||
android.hardware.broadcastradio.ProgramSelector hwSel,
|
||||
ProgramIdentifier logicallyTunedTo, ProgramIdentifier physicallyTunedTo,
|
||||
int hwSignalQuality) {
|
||||
ProgramInfo hwInfo = new ProgramInfo();
|
||||
hwInfo.selector = hwSel;
|
||||
hwInfo.logicallyTunedTo = hwSel.primaryId;
|
||||
hwInfo.physicallyTunedTo = hwSel.primaryId;
|
||||
hwInfo.logicallyTunedTo = logicallyTunedTo;
|
||||
hwInfo.physicallyTunedTo = physicallyTunedTo;
|
||||
hwInfo.signalQuality = hwSignalQuality;
|
||||
hwInfo.relatedContent = new ProgramIdentifier[]{};
|
||||
hwInfo.metadata = new Metadata[]{};
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.hardware.broadcastradio.AmFmBandRange;
|
||||
import android.hardware.broadcastradio.AmFmRegionConfig;
|
||||
import android.hardware.broadcastradio.DabTableEntry;
|
||||
import android.hardware.broadcastradio.IdentifierType;
|
||||
import android.hardware.broadcastradio.ProgramIdentifier;
|
||||
import android.hardware.broadcastradio.ProgramInfo;
|
||||
import android.hardware.broadcastradio.Properties;
|
||||
import android.hardware.broadcastradio.VendorKeyValue;
|
||||
import android.hardware.radio.Announcement;
|
||||
@@ -57,6 +59,27 @@ public final class ConversionUtilsTest {
|
||||
private static final String TEST_VERSION = "versionMock";
|
||||
private static final String TEST_SERIAL = "serialMock";
|
||||
|
||||
private static final int TEST_SIGNAL_QUALITY = 1;
|
||||
private static final long TEST_DAB_DMB_SID_EXT_VALUE = 0xA000000111L;
|
||||
private static final long TEST_DAB_ENSEMBLE_VALUE = 0x1001;
|
||||
private static final long TEST_DAB_FREQUENCY_VALUE = 220352;
|
||||
private static final ProgramSelector.Identifier TEST_DAB_SID_EXT_ID =
|
||||
new ProgramSelector.Identifier(
|
||||
ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT, TEST_DAB_DMB_SID_EXT_VALUE);
|
||||
private static final ProgramSelector.Identifier TEST_DAB_ENSEMBLE_ID =
|
||||
new ProgramSelector.Identifier(
|
||||
ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, TEST_DAB_ENSEMBLE_VALUE);
|
||||
private static final ProgramSelector.Identifier TEST_DAB_FREQUENCY_ID =
|
||||
new ProgramSelector.Identifier(
|
||||
ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, TEST_DAB_FREQUENCY_VALUE);
|
||||
private static final ProgramIdentifier TEST_HAL_DAB_SID_EXT_ID =
|
||||
AidlTestUtils.makeHalIdentifier(IdentifierType.DAB_SID_EXT, TEST_DAB_DMB_SID_EXT_VALUE);
|
||||
private static final ProgramIdentifier TEST_HAL_DAB_ENSEMBLE_ID =
|
||||
AidlTestUtils.makeHalIdentifier(IdentifierType.DAB_ENSEMBLE, TEST_DAB_ENSEMBLE_VALUE);
|
||||
private static final ProgramIdentifier TEST_HAL_DAB_FREQUENCY_ID =
|
||||
AidlTestUtils.makeHalIdentifier(IdentifierType.DAB_FREQUENCY_KHZ,
|
||||
TEST_DAB_FREQUENCY_VALUE);
|
||||
|
||||
private static final int TEST_ENABLED_TYPE = Announcement.TYPE_EMERGENCY;
|
||||
private static final int TEST_ANNOUNCEMENT_FREQUENCY = FM_LOWER_LIMIT + FM_SPACING;
|
||||
|
||||
@@ -158,6 +181,142 @@ public final class ConversionUtilsTest {
|
||||
.that(bands[1].getSpacing()).isEqualTo(AM_SPACING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void identifierToHalProgramIdentifier_withDabId() {
|
||||
ProgramIdentifier halDabId =
|
||||
ConversionUtils.identifierToHalProgramIdentifier(TEST_DAB_SID_EXT_ID);
|
||||
|
||||
expect.withMessage("Converted HAL DAB identifier").that(halDabId)
|
||||
.isEqualTo(TEST_HAL_DAB_SID_EXT_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void identifierFromHalProgramIdentifier_withDabId() {
|
||||
ProgramSelector.Identifier dabId =
|
||||
ConversionUtils.identifierFromHalProgramIdentifier(TEST_HAL_DAB_SID_EXT_ID);
|
||||
|
||||
expect.withMessage("Converted DAB identifier").that(dabId).isEqualTo(TEST_DAB_SID_EXT_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void programSelectorToHalProgramSelector_withValidSelector() {
|
||||
ProgramSelector dabSelector = new ProgramSelector(
|
||||
ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID,
|
||||
new ProgramSelector.Identifier[]{TEST_DAB_ENSEMBLE_ID, TEST_DAB_FREQUENCY_ID},
|
||||
new long[0]);
|
||||
|
||||
android.hardware.broadcastradio.ProgramSelector halDabSelector =
|
||||
ConversionUtils.programSelectorToHalProgramSelector(dabSelector);
|
||||
|
||||
expect.withMessage("Primary identifier of converted HAL DAB selector")
|
||||
.that(halDabSelector.primaryId).isEqualTo(TEST_HAL_DAB_SID_EXT_ID);
|
||||
expect.withMessage("Secondary identifiers of converted HAL DAB selector")
|
||||
.that(halDabSelector.secondaryIds).asList()
|
||||
.containsExactly(TEST_HAL_DAB_FREQUENCY_ID, TEST_HAL_DAB_ENSEMBLE_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void programSelectorToHalProgramSelector_withInvalidDabSelector_returnsNull() {
|
||||
ProgramSelector invalidDbSelector = new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB,
|
||||
TEST_DAB_SID_EXT_ID,
|
||||
new ProgramSelector.Identifier[0],
|
||||
new long[0]);
|
||||
|
||||
android.hardware.broadcastradio.ProgramSelector invalidHalDabSelector =
|
||||
ConversionUtils.programSelectorToHalProgramSelector(invalidDbSelector);
|
||||
|
||||
expect.withMessage("Invalid HAL DAB selector without required secondary ids")
|
||||
.that(invalidHalDabSelector).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void programSelectorFromHalProgramSelector_withValidSelector() {
|
||||
android.hardware.broadcastradio.ProgramSelector halDabSelector =
|
||||
AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
|
||||
TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID});
|
||||
|
||||
ProgramSelector dabSelector =
|
||||
ConversionUtils.programSelectorFromHalProgramSelector(halDabSelector);
|
||||
|
||||
expect.withMessage("Primary identifier of converted DAB selector")
|
||||
.that(dabSelector.getPrimaryId()).isEqualTo(TEST_DAB_SID_EXT_ID);
|
||||
expect.withMessage("Secondary identifiers of converted DAB selector")
|
||||
.that(dabSelector.getSecondaryIds()).asList()
|
||||
.containsExactly(TEST_DAB_FREQUENCY_ID, TEST_DAB_ENSEMBLE_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void programSelectorFromHalProgramSelector_withInvalidSelector_returnsNull() {
|
||||
android.hardware.broadcastradio.ProgramSelector invalidHalDabSelector =
|
||||
AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{});
|
||||
|
||||
ProgramSelector invalidDabSelector =
|
||||
ConversionUtils.programSelectorFromHalProgramSelector(invalidHalDabSelector);
|
||||
|
||||
expect.withMessage("Invalid DAB selector without required secondary ids")
|
||||
.that(invalidDabSelector).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void programInfoFromHalProgramInfo_withValidProgramInfo() {
|
||||
android.hardware.broadcastradio.ProgramSelector halDabSelector =
|
||||
AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID, new ProgramIdentifier[]{
|
||||
TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID});
|
||||
ProgramInfo halProgramInfo = AidlTestUtils.makeHalProgramInfo(halDabSelector,
|
||||
TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_FREQUENCY_ID, TEST_SIGNAL_QUALITY);
|
||||
|
||||
RadioManager.ProgramInfo programInfo =
|
||||
ConversionUtils.programInfoFromHalProgramInfo(halProgramInfo);
|
||||
|
||||
expect.withMessage("Primary id of selector of converted program info")
|
||||
.that(programInfo.getSelector().getPrimaryId()).isEqualTo(TEST_DAB_SID_EXT_ID);
|
||||
expect.withMessage("Secondary id of selector of converted program info")
|
||||
.that(programInfo.getSelector().getSecondaryIds()).asList()
|
||||
.containsExactly(TEST_DAB_ENSEMBLE_ID, TEST_DAB_FREQUENCY_ID);
|
||||
expect.withMessage("Logically tuned identifier of converted program info")
|
||||
.that(programInfo.getLogicallyTunedTo()).isEqualTo(TEST_DAB_SID_EXT_ID);
|
||||
expect.withMessage("Physically tuned identifier of converted program info")
|
||||
.that(programInfo.getPhysicallyTunedTo()).isEqualTo(TEST_DAB_FREQUENCY_ID);
|
||||
expect.withMessage("Signal quality of converted program info")
|
||||
.that(programInfo.getSignalStrength()).isEqualTo(TEST_SIGNAL_QUALITY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void programInfoFromHalProgramInfo_withInvalidDabProgramInfo() {
|
||||
android.hardware.broadcastradio.ProgramSelector invalidHalDabSelector =
|
||||
AidlTestUtils.makeHalSelector(TEST_HAL_DAB_SID_EXT_ID,
|
||||
new ProgramIdentifier[]{TEST_HAL_DAB_ENSEMBLE_ID, TEST_HAL_DAB_FREQUENCY_ID});
|
||||
ProgramInfo halProgramInfo = AidlTestUtils.makeHalProgramInfo(invalidHalDabSelector,
|
||||
TEST_HAL_DAB_SID_EXT_ID, TEST_HAL_DAB_ENSEMBLE_ID, TEST_SIGNAL_QUALITY);
|
||||
|
||||
RadioManager.ProgramInfo programInfo =
|
||||
ConversionUtils.programInfoFromHalProgramInfo(halProgramInfo);
|
||||
|
||||
expect.withMessage("Invalid DAB program info with incorrect type of physically tuned to id")
|
||||
.that(programInfo).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void programSelectorMeetsSdkVersionRequirement_withLowerVersionId_returnsFalse() {
|
||||
ProgramSelector dabSelector = new ProgramSelector(
|
||||
ProgramSelector.PROGRAM_TYPE_DAB, TEST_DAB_SID_EXT_ID,
|
||||
new ProgramSelector.Identifier[]{TEST_DAB_ENSEMBLE_ID, TEST_DAB_FREQUENCY_ID},
|
||||
new long[0]);
|
||||
|
||||
expect.withMessage("Selector %s not meeting required SDK version", dabSelector)
|
||||
.that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(dabSelector,
|
||||
Build.VERSION_CODES.TIRAMISU)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void programSelectorMeetsSdkVersionRequirement_withRequiredVersionId_returnsTrue() {
|
||||
ProgramSelector fmSelector = AidlTestUtils.makeFmSelector(/* freq= */ 97100);
|
||||
|
||||
expect.withMessage("Selector %s meeting required SDK version", fmSelector)
|
||||
.that(ConversionUtils.programSelectorMeetsSdkVersionRequirement(fmSelector,
|
||||
Build.VERSION_CODES.TIRAMISU)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void announcementFromHalAnnouncement_typesMatch() {
|
||||
expect.withMessage("Announcement type")
|
||||
|
||||
@@ -330,10 +330,17 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
|
||||
|
||||
@Test
|
||||
public void tune_withUnsupportedSelector_throwsException() throws Exception {
|
||||
ProgramSelector.Identifier dabPrimaryId =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT,
|
||||
/* value= */ 0xA000000111L);
|
||||
ProgramSelector.Identifier[] dabSecondaryIds = new ProgramSelector.Identifier[]{
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
|
||||
/* value= */ 1337),
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
|
||||
/* value= */ 225648)};
|
||||
ProgramSelector unsupportedSelector = new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB,
|
||||
dabPrimaryId, dabSecondaryIds, /* vendorIds= */ null);
|
||||
openAidlClients(/* numClients= */ 1);
|
||||
ProgramSelector unsupportedSelector = AidlTestUtils.makeProgramSelector(
|
||||
ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, new ProgramSelector.Identifier(
|
||||
ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, /* value= */ 300));
|
||||
|
||||
UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
|
||||
() -> mTunerSessions[0].tune(unsupportedSelector));
|
||||
@@ -342,6 +349,21 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
|
||||
.that(thrown).hasMessageThat().contains("tune: NOT_SUPPORTED");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tune_withInvalidSelector_throwsIllegalArgumentException() throws Exception {
|
||||
openAidlClients(/* numClients= */ 1);
|
||||
ProgramSelector.Identifier invalidDabId = new ProgramSelector.Identifier(
|
||||
ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE, /* value= */ 0x1001);
|
||||
ProgramSelector invalidSel = new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB,
|
||||
invalidDabId, new ProgramSelector.Identifier[0], new long[0]);
|
||||
|
||||
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
|
||||
() -> mTunerSessions[0].tune(invalidSel));
|
||||
|
||||
assertWithMessage("Exception for tuning on DAB selector without DAB_SID_EXT primary id")
|
||||
.that(thrown).hasMessageThat().contains("tune: INVALID_ARGUMENTS");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tune_forCurrentUser_doesNotTune() throws Exception {
|
||||
openAidlClients(/* numClients= */ 1);
|
||||
|
||||
@@ -324,10 +324,17 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
|
||||
|
||||
@Test
|
||||
public void tune_withUnsupportedSelector_throwsException() throws Exception {
|
||||
ProgramSelector.Identifier dabPrimaryId =
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_SID_EXT,
|
||||
/* value= */ 0xA00111);
|
||||
ProgramSelector.Identifier[] dabSecondaryIds = new ProgramSelector.Identifier[]{
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE,
|
||||
/* value= */ 1337),
|
||||
new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY,
|
||||
/* value= */ 225648)};
|
||||
ProgramSelector unsupportedSelector = new ProgramSelector(ProgramSelector.PROGRAM_TYPE_DAB,
|
||||
dabPrimaryId, dabSecondaryIds, /* vendorIds= */ null);
|
||||
openAidlClients(/* numClients= */ 1);
|
||||
ProgramSelector unsupportedSelector = TestUtils.makeProgramSelector(
|
||||
ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, new ProgramSelector.Identifier(
|
||||
ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY, /* value= */ 300));
|
||||
|
||||
UnsupportedOperationException thrown = assertThrows(UnsupportedOperationException.class,
|
||||
() -> mTunerSessions[0].tune(unsupportedSelector));
|
||||
|
||||
@@ -307,6 +307,9 @@ final class ConversionUtils {
|
||||
static ProgramIdentifier identifierToHalProgramIdentifier(ProgramSelector.Identifier id) {
|
||||
ProgramIdentifier hwId = new ProgramIdentifier();
|
||||
hwId.type = id.getType();
|
||||
if (hwId.type == ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT) {
|
||||
hwId.type = IdentifierType.DAB_SID_EXT;
|
||||
}
|
||||
hwId.value = id.getValue();
|
||||
return hwId;
|
||||
}
|
||||
@@ -317,9 +320,49 @@ final class ConversionUtils {
|
||||
if (id.type == IdentifierType.INVALID) {
|
||||
return null;
|
||||
}
|
||||
return new ProgramSelector.Identifier(id.type, id.value);
|
||||
int idType;
|
||||
if (id.type == IdentifierType.DAB_SID_EXT) {
|
||||
idType = ProgramSelector.IDENTIFIER_TYPE_DAB_DMB_SID_EXT;
|
||||
} else {
|
||||
idType = id.type;
|
||||
}
|
||||
return new ProgramSelector.Identifier(idType, id.value);
|
||||
}
|
||||
|
||||
private static boolean isVendorIdentifierType(int idType) {
|
||||
return idType >= IdentifierType.VENDOR_START && idType <= IdentifierType.VENDOR_END;
|
||||
}
|
||||
|
||||
private static boolean isValidHalProgramSelector(
|
||||
android.hardware.broadcastradio.ProgramSelector sel) {
|
||||
if (sel.primaryId.type != IdentifierType.AMFM_FREQUENCY_KHZ
|
||||
&& sel.primaryId.type != IdentifierType.RDS_PI
|
||||
&& sel.primaryId.type != IdentifierType.HD_STATION_ID_EXT
|
||||
&& sel.primaryId.type != IdentifierType.DAB_SID_EXT
|
||||
&& sel.primaryId.type != IdentifierType.DRMO_SERVICE_ID
|
||||
&& sel.primaryId.type != IdentifierType.SXM_SERVICE_ID
|
||||
&& !isVendorIdentifierType(sel.primaryId.type)) {
|
||||
return false;
|
||||
}
|
||||
if (sel.primaryId.type == IdentifierType.DAB_SID_EXT) {
|
||||
boolean hasEnsemble = false;
|
||||
boolean hasFrequency = false;
|
||||
for (int i = 0; i < sel.secondaryIds.length; i++) {
|
||||
if (sel.secondaryIds[i].type == IdentifierType.DAB_ENSEMBLE) {
|
||||
hasEnsemble = true;
|
||||
} else if (sel.secondaryIds[i].type == IdentifierType.DAB_FREQUENCY_KHZ) {
|
||||
hasFrequency = true;
|
||||
}
|
||||
if (hasEnsemble && hasFrequency) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static android.hardware.broadcastradio.ProgramSelector programSelectorToHalProgramSelector(
|
||||
ProgramSelector sel) {
|
||||
android.hardware.broadcastradio.ProgramSelector hwSel =
|
||||
@@ -332,6 +375,9 @@ final class ConversionUtils {
|
||||
secondaryIdList.add(identifierToHalProgramIdentifier(secondaryIds[i]));
|
||||
}
|
||||
hwSel.secondaryIds = secondaryIdList.toArray(ProgramIdentifier[]::new);
|
||||
if (!isValidHalProgramSelector(hwSel)) {
|
||||
return null;
|
||||
}
|
||||
return hwSel;
|
||||
}
|
||||
|
||||
@@ -344,7 +390,7 @@ final class ConversionUtils {
|
||||
@Nullable
|
||||
static ProgramSelector programSelectorFromHalProgramSelector(
|
||||
android.hardware.broadcastradio.ProgramSelector sel) {
|
||||
if (isEmpty(sel)) {
|
||||
if (isEmpty(sel) || !isValidHalProgramSelector(sel)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -432,7 +478,34 @@ final class ConversionUtils {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static boolean isValidLogicallyTunedTo(ProgramIdentifier id) {
|
||||
return id.type == IdentifierType.AMFM_FREQUENCY_KHZ || id.type == IdentifierType.RDS_PI
|
||||
|| id.type == IdentifierType.HD_STATION_ID_EXT
|
||||
|| id.type == IdentifierType.DAB_SID_EXT
|
||||
|| id.type == IdentifierType.DRMO_SERVICE_ID
|
||||
|| id.type == IdentifierType.SXM_SERVICE_ID
|
||||
|| isVendorIdentifierType(id.type);
|
||||
}
|
||||
|
||||
private static boolean isValidPhysicallyTunedTo(ProgramIdentifier id) {
|
||||
return id.type == IdentifierType.AMFM_FREQUENCY_KHZ
|
||||
|| id.type == IdentifierType.DAB_FREQUENCY_KHZ
|
||||
|| id.type == IdentifierType.DRMO_FREQUENCY_KHZ
|
||||
|| id.type == IdentifierType.SXM_CHANNEL
|
||||
|| isVendorIdentifierType(id.type);
|
||||
}
|
||||
|
||||
private static boolean isValidHalProgramInfo(ProgramInfo info) {
|
||||
return isValidHalProgramSelector(info.selector)
|
||||
&& isValidLogicallyTunedTo(info.logicallyTunedTo)
|
||||
&& isValidPhysicallyTunedTo(info.physicallyTunedTo);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static RadioManager.ProgramInfo programInfoFromHalProgramInfo(ProgramInfo info) {
|
||||
if (!isValidHalProgramInfo(info)) {
|
||||
return null;
|
||||
}
|
||||
Collection<ProgramSelector.Identifier> relatedContent = new ArrayList<>();
|
||||
if (info.relatedContent != null) {
|
||||
for (int i = 0; i < info.relatedContent.length; i++) {
|
||||
@@ -485,7 +558,14 @@ final class ConversionUtils {
|
||||
static ProgramList.Chunk chunkFromHalProgramListChunk(ProgramListChunk chunk) {
|
||||
Set<RadioManager.ProgramInfo> modified = new ArraySet<>(chunk.modified.length);
|
||||
for (int i = 0; i < chunk.modified.length; i++) {
|
||||
modified.add(programInfoFromHalProgramInfo(chunk.modified[i]));
|
||||
RadioManager.ProgramInfo modifiedInfo =
|
||||
programInfoFromHalProgramInfo(chunk.modified[i]);
|
||||
if (modifiedInfo == null) {
|
||||
Slogf.w(TAG, "Program info %s in program list chunk is not valid",
|
||||
chunk.modified[i]);
|
||||
continue;
|
||||
}
|
||||
modified.add(modifiedInfo);
|
||||
}
|
||||
Set<ProgramSelector.Identifier> removed = new ArraySet<>();
|
||||
if (chunk.removed != null) {
|
||||
@@ -558,7 +638,7 @@ final class ConversionUtils {
|
||||
Announcement hwAnnouncement) {
|
||||
return new android.hardware.radio.Announcement(
|
||||
Objects.requireNonNull(programSelectorFromHalProgramSelector(
|
||||
hwAnnouncement.selector)),
|
||||
hwAnnouncement.selector), "Program selector can not be null"),
|
||||
hwAnnouncement.type,
|
||||
vendorInfoFromHalVendorKeyValues(hwAnnouncement.vendorInfo)
|
||||
);
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.utils.Slogf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -37,6 +38,7 @@ import java.util.Set;
|
||||
*/
|
||||
final class ProgramInfoCache {
|
||||
|
||||
private static final String TAG = "BcRadioAidlSrv.cache";
|
||||
/**
|
||||
* Maximum number of {@link RadioManager#ProgramInfo} elements that will be put into a
|
||||
* ProgramList.Chunk.mModified array. Used to try to ensure a single ProgramList.Chunk
|
||||
@@ -124,6 +126,10 @@ final class ProgramInfoCache {
|
||||
for (int i = 0; i < chunk.modified.length; i++) {
|
||||
RadioManager.ProgramInfo programInfo =
|
||||
ConversionUtils.programInfoFromHalProgramInfo(chunk.modified[i]);
|
||||
if (programInfo == null) {
|
||||
Slogf.e(TAG, "Program info in program info %s in chunk is not valid",
|
||||
chunk.modified[i]);
|
||||
}
|
||||
mProgramInfoMap.put(programInfo.getSelector().getPrimaryId(), programInfo);
|
||||
}
|
||||
if (chunk.removed != null) {
|
||||
|
||||
@@ -97,10 +97,10 @@ final class RadioModule {
|
||||
|
||||
public void onTuneFailed(int result, ProgramSelector programSelector) {
|
||||
fireLater(() -> {
|
||||
android.hardware.radio.ProgramSelector csel =
|
||||
ConversionUtils.programSelectorFromHalProgramSelector(programSelector);
|
||||
int tunerResult = ConversionUtils.halResultToTunerResult(result);
|
||||
synchronized (mLock) {
|
||||
android.hardware.radio.ProgramSelector csel =
|
||||
ConversionUtils.programSelectorFromHalProgramSelector(programSelector);
|
||||
int tunerResult = ConversionUtils.halResultToTunerResult(result);
|
||||
fanoutAidlCallbackLocked((cb, sdkVersion) -> {
|
||||
if (csel != null && !ConversionUtils
|
||||
.programSelectorMeetsSdkVersionRequirement(csel, sdkVersion)) {
|
||||
@@ -117,10 +117,12 @@ final class RadioModule {
|
||||
@Override
|
||||
public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
|
||||
fireLater(() -> {
|
||||
RadioManager.ProgramInfo currentProgramInfo =
|
||||
ConversionUtils.programInfoFromHalProgramInfo(halProgramInfo);
|
||||
Objects.requireNonNull(currentProgramInfo,
|
||||
"Program info from AIDL HAL is invalid");
|
||||
synchronized (mLock) {
|
||||
mCurrentProgramInfo =
|
||||
ConversionUtils.programInfoFromHalProgramInfo(halProgramInfo);
|
||||
RadioManager.ProgramInfo currentProgramInfo = mCurrentProgramInfo;
|
||||
mCurrentProgramInfo = currentProgramInfo;
|
||||
fanoutAidlCallbackLocked((cb, sdkVersion) -> {
|
||||
if (!ConversionUtils.programInfoMeetsSdkVersionRequirement(
|
||||
currentProgramInfo, sdkVersion)) {
|
||||
|
||||
@@ -203,10 +203,15 @@ final class TunerSession extends ITuner.Stub {
|
||||
Slogf.w(TAG, "Cannot tune on AIDL HAL client from non-current user");
|
||||
return;
|
||||
}
|
||||
android.hardware.broadcastradio.ProgramSelector hwSel =
|
||||
ConversionUtils.programSelectorToHalProgramSelector(selector);
|
||||
if (hwSel == null) {
|
||||
throw new IllegalArgumentException("tune: INVALID_ARGUMENTS for program selector");
|
||||
}
|
||||
synchronized (mLock) {
|
||||
checkNotClosedLocked();
|
||||
try {
|
||||
mService.tune(ConversionUtils.programSelectorToHalProgramSelector(selector));
|
||||
mService.tune(hwSel);
|
||||
} catch (RuntimeException ex) {
|
||||
throw ConversionUtils.throwOnError(ex, /* action= */ "tune");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user