Loading core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java +208 −3 Original line number Diff line number Diff line Loading @@ -20,13 +20,26 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import android.annotation.Nullable; import android.app.compat.CompatChanges; import android.hardware.broadcastradio.Alert; import android.hardware.broadcastradio.AlertArea; import android.hardware.broadcastradio.AlertCategory; import android.hardware.broadcastradio.AlertCertainty; import android.hardware.broadcastradio.AlertInfo; import android.hardware.broadcastradio.AlertMessageType; import android.hardware.broadcastradio.AlertSeverity; import android.hardware.broadcastradio.AlertStatus; import android.hardware.broadcastradio.AlertUrgency; import android.hardware.broadcastradio.AmFmBandRange; import android.hardware.broadcastradio.AmFmRegionConfig; import android.hardware.broadcastradio.ConfigFlag; import android.hardware.broadcastradio.Coordinate; import android.hardware.broadcastradio.DabTableEntry; import android.hardware.broadcastradio.Geocode; import android.hardware.broadcastradio.IdentifierType; import android.hardware.broadcastradio.Metadata; import android.hardware.broadcastradio.Polygon; import android.hardware.broadcastradio.ProgramFilter; import android.hardware.broadcastradio.ProgramIdentifier; import android.hardware.broadcastradio.ProgramInfo; Loading @@ -37,10 +50,13 @@ import android.hardware.radio.Announcement; import android.hardware.radio.Flags; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioAlert; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; import android.hardware.radio.UniqueProgramIdentifier; import android.os.ServiceSpecificException; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.util.ArrayMap; import android.util.ArraySet; Loading Loading @@ -148,6 +164,9 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { private static final ProgramIdentifier TEST_HAL_HD_STATION_LOCATION_ID = AidlTestUtils.makeHalIdentifier(IdentifierType.HD_STATION_LOCATION, TEST_HD_LOCATION_VALUE); private static final ProgramIdentifier TEST_HAL_HD_FM_FREQUENCY_ID = AidlTestUtils.makeHalIdentifier(IdentifierType.AMFM_FREQUENCY_KHZ, TEST_HD_FREQUENCY_VALUE); private static final UniqueProgramIdentifier TEST_DAB_UNIQUE_ID = new UniqueProgramIdentifier( TEST_DAB_SELECTOR); Loading @@ -173,6 +192,57 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { private static final Metadata TEST_HAL_HD_SUBCHANNELS = Metadata.hdSubChannelsAvailable( TEST_HD_SUBCHANNELS); private static final int TEST_STATUS = RadioAlert.STATUS_ACTUAL; private static final int TEST_HAL_STATUS = AlertStatus.ACTUAL; private static final int TEST_TYPE = RadioAlert.MESSAGE_TYPE_ALERT; private static final int TEST_HAL_TYPE = AlertMessageType.ALERT; private static final int[] TEST_CATEGORY_ARRAY = new int[]{RadioAlert.CATEGORY_CBRNE, RadioAlert.CATEGORY_GEO}; private static final int[] TEST_HAL_CATEGORY_LIST = new int[]{AlertCategory.CBRNE, AlertCategory.GEO}; private static final int TEST_URGENCY = RadioAlert.URGENCY_FUTURE; private static final int TEST_HAL_URGENCY = AlertUrgency.FUTURE; private static final int TEST_SEVERITY = RadioAlert.SEVERITY_MINOR; private static final int TEST_HAL_SEVERITY = AlertSeverity.MINOR; private static final int TEST_CERTAINTY = RadioAlert.CERTAINTY_UNLIKELY; private static final int TEST_HAL_CERTAINTY = AlertCertainty.UNLIKELY; private static final String TEST_DESCRIPTION_MESSAGE = "Test Alert Description Message."; private static final String TEST_GEOCODE_VALUE_NAME = "ZIP"; private static final String TEST_GEOCODE_VALUE_1 = "10001"; private static final String TEST_GEOCODE_VALUE_2 = "10002"; private static final double TEST_POLYGON_LATITUDE_START = -38.47; private static final double TEST_POLYGON_LONGITUDE_START = -120.14; private static final RadioAlert.Coordinate TEST_POLYGON_COORDINATE_START = new RadioAlert.Coordinate(TEST_POLYGON_LATITUDE_START, TEST_POLYGON_LONGITUDE_START); private static final List<RadioAlert.Coordinate> TEST_COORDINATES = List.of( TEST_POLYGON_COORDINATE_START, new RadioAlert.Coordinate(38.34, -119.95), new RadioAlert.Coordinate(38.52, -119.74), new RadioAlert.Coordinate(38.62, -119.89), TEST_POLYGON_COORDINATE_START); private static final RadioAlert.Polygon TEST_POLYGON = new RadioAlert.Polygon(TEST_COORDINATES); private static final Polygon TEST_HAL_POLYGON = createHalPolygon(TEST_COORDINATES); private static final RadioAlert.Geocode TEST_GEOCODE_1 = new RadioAlert.Geocode( TEST_GEOCODE_VALUE_NAME, TEST_GEOCODE_VALUE_1); private static final RadioAlert.Geocode TEST_GEOCODE_2 = new RadioAlert.Geocode( TEST_GEOCODE_VALUE_NAME, TEST_GEOCODE_VALUE_2); private static final RadioAlert.AlertArea TEST_AREA = new RadioAlert.AlertArea( List.of(TEST_POLYGON), List.of(TEST_GEOCODE_1, TEST_GEOCODE_2)); private static final AlertArea TEST_HAL_ALERT_AREA = createHalAlertArea( new Polygon[]{TEST_HAL_POLYGON}, new Geocode[]{ createHalGeocode(TEST_GEOCODE_VALUE_NAME, TEST_GEOCODE_VALUE_1), createHalGeocode(TEST_GEOCODE_VALUE_NAME, TEST_GEOCODE_VALUE_2)}); private static final String TEST_LANGUAGE = "en-US"; private static final RadioAlert.AlertInfo TEST_ALERT_INFO_1 = new RadioAlert.AlertInfo( TEST_CATEGORY_ARRAY, TEST_URGENCY, TEST_SEVERITY, TEST_CERTAINTY, TEST_DESCRIPTION_MESSAGE, List.of(TEST_AREA), TEST_LANGUAGE); private static final AlertInfo TEST_HAL_ALERT_INFO = createHalAlertInfo( TEST_HAL_CATEGORY_LIST, TEST_HAL_URGENCY, TEST_HAL_SEVERITY, TEST_HAL_CERTAINTY, TEST_DESCRIPTION_MESSAGE, new AlertArea[]{TEST_HAL_ALERT_AREA}, TEST_LANGUAGE); private static final RadioAlert TEST_ALERT = new RadioAlert(TEST_STATUS, TEST_TYPE, List.of(TEST_ALERT_INFO_1)); private static final Alert TEST_HAL_ALERT = createHalAlert(TEST_HAL_STATUS, TEST_HAL_TYPE, new AlertInfo[]{TEST_HAL_ALERT_INFO}); @Rule public final Expect expect = Expect.create(); @Rule Loading Loading @@ -575,6 +645,42 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { .that(programInfo).isNull(); } @Test @EnableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void programInfoFromHalProgramInfo_withAlertMessageAndFlagEnabled() { android.hardware.broadcastradio.ProgramSelector halHdSelector = AidlTestUtils.makeHalSelector(TEST_HAL_HD_STATION_EXT_ID, new ProgramIdentifier[]{}); ProgramInfo halHdProgramInfo = AidlTestUtils.makeHalProgramInfo(halHdSelector, TEST_HAL_HD_STATION_EXT_ID, TEST_HAL_HD_FM_FREQUENCY_ID, TEST_SIGNAL_QUALITY, new ProgramIdentifier[]{}, new Metadata[]{}); halHdProgramInfo.emergencyAlert = TEST_HAL_ALERT; RadioManager.ProgramInfo programInfo = ConversionUtils.programInfoFromHalProgramInfo(halHdProgramInfo); expect.withMessage("Alert of converted HD program info with alert and enabled flag") .that(programInfo.getAlert()).isEqualTo(TEST_ALERT); } @Test @DisableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void programInfoFromHalProgramInfo_withAlertMessageAndFlagDisabled() { android.hardware.broadcastradio.ProgramSelector halHdSelector = AidlTestUtils.makeHalSelector(TEST_HAL_HD_STATION_EXT_ID, new ProgramIdentifier[]{}); ProgramInfo halHdProgramInfo = AidlTestUtils.makeHalProgramInfo(halHdSelector, TEST_HAL_HD_STATION_EXT_ID, TEST_HAL_HD_FM_FREQUENCY_ID, TEST_SIGNAL_QUALITY, new ProgramIdentifier[]{}, new Metadata[]{}); halHdProgramInfo.emergencyAlert = TEST_HAL_ALERT; RadioManager.ProgramInfo programInfo = ConversionUtils.programInfoFromHalProgramInfo(halHdProgramInfo); expect.withMessage("Alert of converted HD program info with alert and disabled flag") .that(programInfo.getAlert()).isNull(); } @Test public void tunedProgramInfoFromHalProgramInfo_withInvalidDabProgramInfo() { android.hardware.broadcastradio.ProgramSelector invalidHalDabSelector = Loading Loading @@ -851,7 +957,7 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { } @Test public void radioMetadataFromHalMetadata_withHdMedatadataAndFlagEnabled() { public void radioMetadataFromHalMetadata_withHdMetadataAndFlagEnabled() { mSetFlagsRule.enableFlags(Flags.FLAG_HD_RADIO_IMPROVED); String genreValue = "genreTest"; String commentShortDescriptionValue = "commentShortDescriptionTest"; Loading Loading @@ -973,6 +1079,57 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { .isEmpty(); } @Test @EnableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void radioAlertFromHalAlert() { RadioAlert convertedAlert = ConversionUtils.radioAlertFromHalAlert(TEST_HAL_ALERT); expect.withMessage("Converted alert").that(convertedAlert) .isEqualTo(TEST_ALERT); } @Test @EnableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void radioAlertFromHalAlert_withLowThanFourCoordinates() { Polygon invalidPolygon = createHalPolygon(List.of( TEST_POLYGON_COORDINATE_START, new RadioAlert.Coordinate(38.34, -119.95), TEST_POLYGON_COORDINATE_START)); AlertInfo halAlertInfo = createHalAlertInfo(TEST_HAL_CATEGORY_LIST, TEST_HAL_URGENCY, TEST_HAL_SEVERITY, TEST_HAL_CERTAINTY, TEST_DESCRIPTION_MESSAGE, new AlertArea[]{createHalAlertArea(new Polygon[]{invalidPolygon}, new Geocode[]{})}, TEST_LANGUAGE); Alert halAlert = createHalAlert(TEST_HAL_STATUS, TEST_HAL_TYPE, new AlertInfo[]{halAlertInfo }); RadioAlert convertedAlert = ConversionUtils.radioAlertFromHalAlert(halAlert); expect.withMessage("Empty polygon list with less than 4 coordinates") .that(convertedAlert.getInfoList().get(0).getAreas().get(0).getPolygons()) .isEmpty(); } @Test @EnableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void radioAlertFromHalAlert_withDifferentFirstAndLastCoordinate() { Polygon invalidPolygon = createHalPolygon(List.of( TEST_POLYGON_COORDINATE_START, new RadioAlert.Coordinate(38.34, -119.95), new RadioAlert.Coordinate(38.52, -119.74), new RadioAlert.Coordinate(38.62, -119.89), new RadioAlert.Coordinate(38.42, -120.14))); AlertInfo halAlertInfo = createHalAlertInfo(TEST_HAL_CATEGORY_LIST, TEST_HAL_URGENCY, TEST_HAL_SEVERITY, TEST_HAL_CERTAINTY, TEST_DESCRIPTION_MESSAGE, new AlertArea[]{createHalAlertArea(new Polygon[]{invalidPolygon}, new Geocode[]{})}, TEST_LANGUAGE); Alert halAlert = createHalAlert(TEST_HAL_STATUS, TEST_HAL_TYPE, new AlertInfo[]{halAlertInfo}); RadioAlert convertedAlert = ConversionUtils.radioAlertFromHalAlert(halAlert); expect.withMessage("Empty polygon list with different first and last coordinates") .that(convertedAlert.getInfoList().get(0).getAreas().get(0).getPolygons()) .isEmpty(); } private static RadioManager.ModuleProperties createModuleProperties() { AmFmRegionConfig amFmConfig = createAmFmRegionConfig(); DabTableEntry[] dabTableEntries = new DabTableEntry[]{ Loading Loading @@ -1028,14 +1185,62 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { return halProperties; } private ProgramSelector.Identifier createHdStationLocationIdWithFlagEnabled() { private static ProgramSelector.Identifier createHdStationLocationIdWithFlagEnabled() { return new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_HD_STATION_LOCATION, TEST_HD_LOCATION_VALUE); } private ProgramSelector createHdSelectorWithFlagEnabled() { private static ProgramSelector createHdSelectorWithFlagEnabled() { return new ProgramSelector(ProgramSelector.PROGRAM_TYPE_FM_HD, TEST_HD_STATION_EXT_ID, new ProgramSelector.Identifier[]{createHdStationLocationIdWithFlagEnabled()}, /* vendorIds= */ null); } private static Alert createHalAlert(int status, int messageType, AlertInfo[] alertInfos) { Alert halAlert = new Alert(); halAlert.status = status; halAlert.messageType = messageType; halAlert.infoArray = alertInfos; return halAlert; } private static AlertInfo createHalAlertInfo(int[] categoryArray, int urgency, int severity, int certainty, String description, AlertArea[] areas, @Nullable String language) { AlertInfo info = new AlertInfo(); info.categoryArray = categoryArray; info.urgency = urgency; info.severity = severity; info.certainty = certainty; info.description = description; info.areas = areas; info.language = language; return info; } private static AlertArea createHalAlertArea(Polygon[] polygons, Geocode[] geocodes) { AlertArea area = new AlertArea(); area.polygons = polygons; area.geocodes = geocodes; return area; } private static Polygon createHalPolygon(List<RadioAlert.Coordinate> coordinates) { Coordinate[] halCoordinates = new Coordinate[coordinates.size()]; for (int idx = 0; idx < coordinates.size(); idx++) { Coordinate halCoordinate = new Coordinate(); halCoordinate.latitude = coordinates.get(idx).getLatitude(); halCoordinate.longitude = coordinates.get(idx).getLongitude(); halCoordinates[idx] = halCoordinate; } Polygon polygon = new Polygon(); polygon.coordinates = halCoordinates; return polygon; } private static Geocode createHalGeocode(String valueName, String value) { Geocode halGeocode = new Geocode(); halGeocode.valueName = valueName; halGeocode.value = value; return halGeocode; } } services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java +96 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.SuppressLint; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.hardware.broadcastradio.Alert; import android.hardware.broadcastradio.AmFmRegionConfig; import android.hardware.broadcastradio.Announcement; import android.hardware.broadcastradio.ConfigFlag; Loading @@ -36,6 +37,7 @@ import android.hardware.broadcastradio.VendorKeyValue; import android.hardware.radio.Flags; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioAlert; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; import android.hardware.radio.RadioTuner; Loading Loading @@ -573,6 +575,86 @@ final class ConversionUtils { return builder.build(); } @Nullable private static RadioAlert.Polygon polygonFromHalPolygon( android.hardware.broadcastradio.Polygon halPolygon) { if (halPolygon.coordinates.length < 4) { Slogf.e(TAG, "Number of coordinates in alert polygon cannot be less than 4"); return null; } else if (halPolygon.coordinates[0].latitude != halPolygon.coordinates[halPolygon.coordinates.length - 1].latitude || halPolygon.coordinates[0].longitude != halPolygon.coordinates[halPolygon.coordinates.length - 1].longitude) { Slogf.e(TAG, "The first and the last coordinate in alert polygon cannot be different"); return null; } List<RadioAlert.Coordinate> coordinates = new ArrayList<>(halPolygon.coordinates.length); for (int idx = 0; idx < halPolygon.coordinates.length; idx++) { coordinates.add(new RadioAlert.Coordinate(halPolygon.coordinates[idx].latitude, halPolygon.coordinates[idx].longitude)); } return new RadioAlert.Polygon(coordinates); } private static RadioAlert.Geocode geocodeFromHalGeocode( android.hardware.broadcastradio.Geocode geocode) { return new RadioAlert.Geocode(geocode.valueName, geocode.value); } private static RadioAlert.AlertArea alertAreaFromHalAlertArea( android.hardware.broadcastradio.AlertArea halAlertArea) { List<RadioAlert.Polygon> polygonList = new ArrayList<>(); for (int idx = 0; idx < halAlertArea.polygons.length; idx++) { RadioAlert.Polygon polygon = polygonFromHalPolygon(halAlertArea.polygons[idx]); if (polygon != null) { polygonList.add(polygon); } } List<RadioAlert.Geocode> geocodeList = new ArrayList<>(halAlertArea.geocodes.length); for (int idx = 0; idx < halAlertArea.geocodes.length; idx++) { geocodeList.add(geocodeFromHalGeocode(halAlertArea.geocodes[idx])); } return new RadioAlert.AlertArea(polygonList, geocodeList); } private static RadioAlert.AlertInfo alertInfoFromHalAlertInfo( android.hardware.broadcastradio.AlertInfo halAlertInfo) { int[] categoryArray = new int[halAlertInfo.categoryArray.length]; for (int idx = 0; idx < halAlertInfo.categoryArray.length; idx++) { // Integer values in android.hardware.radio.RadioAlert.AlertCategory and // android.hardware.broadcastradio.AlertCategory match. categoryArray[idx] = halAlertInfo.categoryArray[idx]; } List<RadioAlert.AlertArea> alertAreaList = new ArrayList<>(); for (int idx = 0; idx < halAlertInfo.areas.length; idx++) { alertAreaList.add(alertAreaFromHalAlertArea(halAlertInfo.areas[idx])); } // Integer values in android.hardware.radio.RadioAlert.AlertUrgency and // android.hardware.broadcastradio.AlertUrgency match. // Integer values in android.hardware.radio.RadioAlert.AlertSeverity and // android.hardware.broadcastradio.AlertSeverity match. // Integer values in android.hardware.radio.RadioAlert.AlertCertainty and // android.hardware.broadcastradio.AlertCertainty match. return new RadioAlert.AlertInfo(categoryArray, halAlertInfo.urgency, halAlertInfo.severity, halAlertInfo.certainty, halAlertInfo.description, alertAreaList, halAlertInfo.language); } @VisibleForTesting @Nullable static RadioAlert radioAlertFromHalAlert(Alert halAlert) { if (halAlert == null) { return null; } List<RadioAlert.AlertInfo> alertInfo = new ArrayList<>(halAlert.infoArray.length); for (int idx = 0; idx < halAlert.infoArray.length; idx++) { alertInfo.add(alertInfoFromHalAlertInfo(halAlert.infoArray[idx])); } // Integer values in android.hardware.radio.RadioAlert.AlertStatus and // android.hardware.broadcastradio.AlertStatus match. // Integer values in android.hardware.radio.RadioAlert.AlertMessageType and // android.hardware.broadcastradio.AlertMessageType match. return new RadioAlert(halAlert.status, halAlert.messageType, alertInfo); } 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 Loading Loading @@ -605,7 +687,7 @@ final class ConversionUtils { } } } if (!Flags.hdRadioEmergencyAlertSystem()) { return new RadioManager.ProgramInfo( Objects.requireNonNull(programSelectorFromHalProgramSelector(info.selector)), identifierFromHalProgramIdentifier(info.logicallyTunedTo), Loading @@ -617,6 +699,18 @@ final class ConversionUtils { vendorInfoFromHalVendorKeyValues(info.vendorInfo) ); } return new RadioManager.ProgramInfo( Objects.requireNonNull(programSelectorFromHalProgramSelector(info.selector)), identifierFromHalProgramIdentifier(info.logicallyTunedTo), identifierFromHalProgramIdentifier(info.physicallyTunedTo), relatedContent, info.infoFlags, info.signalQuality, radioMetadataFromHalMetadata(info.metadata), vendorInfoFromHalVendorKeyValues(info.vendorInfo), radioAlertFromHalAlert(info.emergencyAlert) ); } @Nullable static RadioManager.ProgramInfo tunedProgramInfoFromHalProgramInfo(ProgramInfo info) { Loading Loading
core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/ConversionUtilsTest.java +208 −3 Original line number Diff line number Diff line Loading @@ -20,13 +20,26 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import android.annotation.Nullable; import android.app.compat.CompatChanges; import android.hardware.broadcastradio.Alert; import android.hardware.broadcastradio.AlertArea; import android.hardware.broadcastradio.AlertCategory; import android.hardware.broadcastradio.AlertCertainty; import android.hardware.broadcastradio.AlertInfo; import android.hardware.broadcastradio.AlertMessageType; import android.hardware.broadcastradio.AlertSeverity; import android.hardware.broadcastradio.AlertStatus; import android.hardware.broadcastradio.AlertUrgency; import android.hardware.broadcastradio.AmFmBandRange; import android.hardware.broadcastradio.AmFmRegionConfig; import android.hardware.broadcastradio.ConfigFlag; import android.hardware.broadcastradio.Coordinate; import android.hardware.broadcastradio.DabTableEntry; import android.hardware.broadcastradio.Geocode; import android.hardware.broadcastradio.IdentifierType; import android.hardware.broadcastradio.Metadata; import android.hardware.broadcastradio.Polygon; import android.hardware.broadcastradio.ProgramFilter; import android.hardware.broadcastradio.ProgramIdentifier; import android.hardware.broadcastradio.ProgramInfo; Loading @@ -37,10 +50,13 @@ import android.hardware.radio.Announcement; import android.hardware.radio.Flags; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioAlert; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; import android.hardware.radio.UniqueProgramIdentifier; import android.os.ServiceSpecificException; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.util.ArrayMap; import android.util.ArraySet; Loading Loading @@ -148,6 +164,9 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { private static final ProgramIdentifier TEST_HAL_HD_STATION_LOCATION_ID = AidlTestUtils.makeHalIdentifier(IdentifierType.HD_STATION_LOCATION, TEST_HD_LOCATION_VALUE); private static final ProgramIdentifier TEST_HAL_HD_FM_FREQUENCY_ID = AidlTestUtils.makeHalIdentifier(IdentifierType.AMFM_FREQUENCY_KHZ, TEST_HD_FREQUENCY_VALUE); private static final UniqueProgramIdentifier TEST_DAB_UNIQUE_ID = new UniqueProgramIdentifier( TEST_DAB_SELECTOR); Loading @@ -173,6 +192,57 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { private static final Metadata TEST_HAL_HD_SUBCHANNELS = Metadata.hdSubChannelsAvailable( TEST_HD_SUBCHANNELS); private static final int TEST_STATUS = RadioAlert.STATUS_ACTUAL; private static final int TEST_HAL_STATUS = AlertStatus.ACTUAL; private static final int TEST_TYPE = RadioAlert.MESSAGE_TYPE_ALERT; private static final int TEST_HAL_TYPE = AlertMessageType.ALERT; private static final int[] TEST_CATEGORY_ARRAY = new int[]{RadioAlert.CATEGORY_CBRNE, RadioAlert.CATEGORY_GEO}; private static final int[] TEST_HAL_CATEGORY_LIST = new int[]{AlertCategory.CBRNE, AlertCategory.GEO}; private static final int TEST_URGENCY = RadioAlert.URGENCY_FUTURE; private static final int TEST_HAL_URGENCY = AlertUrgency.FUTURE; private static final int TEST_SEVERITY = RadioAlert.SEVERITY_MINOR; private static final int TEST_HAL_SEVERITY = AlertSeverity.MINOR; private static final int TEST_CERTAINTY = RadioAlert.CERTAINTY_UNLIKELY; private static final int TEST_HAL_CERTAINTY = AlertCertainty.UNLIKELY; private static final String TEST_DESCRIPTION_MESSAGE = "Test Alert Description Message."; private static final String TEST_GEOCODE_VALUE_NAME = "ZIP"; private static final String TEST_GEOCODE_VALUE_1 = "10001"; private static final String TEST_GEOCODE_VALUE_2 = "10002"; private static final double TEST_POLYGON_LATITUDE_START = -38.47; private static final double TEST_POLYGON_LONGITUDE_START = -120.14; private static final RadioAlert.Coordinate TEST_POLYGON_COORDINATE_START = new RadioAlert.Coordinate(TEST_POLYGON_LATITUDE_START, TEST_POLYGON_LONGITUDE_START); private static final List<RadioAlert.Coordinate> TEST_COORDINATES = List.of( TEST_POLYGON_COORDINATE_START, new RadioAlert.Coordinate(38.34, -119.95), new RadioAlert.Coordinate(38.52, -119.74), new RadioAlert.Coordinate(38.62, -119.89), TEST_POLYGON_COORDINATE_START); private static final RadioAlert.Polygon TEST_POLYGON = new RadioAlert.Polygon(TEST_COORDINATES); private static final Polygon TEST_HAL_POLYGON = createHalPolygon(TEST_COORDINATES); private static final RadioAlert.Geocode TEST_GEOCODE_1 = new RadioAlert.Geocode( TEST_GEOCODE_VALUE_NAME, TEST_GEOCODE_VALUE_1); private static final RadioAlert.Geocode TEST_GEOCODE_2 = new RadioAlert.Geocode( TEST_GEOCODE_VALUE_NAME, TEST_GEOCODE_VALUE_2); private static final RadioAlert.AlertArea TEST_AREA = new RadioAlert.AlertArea( List.of(TEST_POLYGON), List.of(TEST_GEOCODE_1, TEST_GEOCODE_2)); private static final AlertArea TEST_HAL_ALERT_AREA = createHalAlertArea( new Polygon[]{TEST_HAL_POLYGON}, new Geocode[]{ createHalGeocode(TEST_GEOCODE_VALUE_NAME, TEST_GEOCODE_VALUE_1), createHalGeocode(TEST_GEOCODE_VALUE_NAME, TEST_GEOCODE_VALUE_2)}); private static final String TEST_LANGUAGE = "en-US"; private static final RadioAlert.AlertInfo TEST_ALERT_INFO_1 = new RadioAlert.AlertInfo( TEST_CATEGORY_ARRAY, TEST_URGENCY, TEST_SEVERITY, TEST_CERTAINTY, TEST_DESCRIPTION_MESSAGE, List.of(TEST_AREA), TEST_LANGUAGE); private static final AlertInfo TEST_HAL_ALERT_INFO = createHalAlertInfo( TEST_HAL_CATEGORY_LIST, TEST_HAL_URGENCY, TEST_HAL_SEVERITY, TEST_HAL_CERTAINTY, TEST_DESCRIPTION_MESSAGE, new AlertArea[]{TEST_HAL_ALERT_AREA}, TEST_LANGUAGE); private static final RadioAlert TEST_ALERT = new RadioAlert(TEST_STATUS, TEST_TYPE, List.of(TEST_ALERT_INFO_1)); private static final Alert TEST_HAL_ALERT = createHalAlert(TEST_HAL_STATUS, TEST_HAL_TYPE, new AlertInfo[]{TEST_HAL_ALERT_INFO}); @Rule public final Expect expect = Expect.create(); @Rule Loading Loading @@ -575,6 +645,42 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { .that(programInfo).isNull(); } @Test @EnableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void programInfoFromHalProgramInfo_withAlertMessageAndFlagEnabled() { android.hardware.broadcastradio.ProgramSelector halHdSelector = AidlTestUtils.makeHalSelector(TEST_HAL_HD_STATION_EXT_ID, new ProgramIdentifier[]{}); ProgramInfo halHdProgramInfo = AidlTestUtils.makeHalProgramInfo(halHdSelector, TEST_HAL_HD_STATION_EXT_ID, TEST_HAL_HD_FM_FREQUENCY_ID, TEST_SIGNAL_QUALITY, new ProgramIdentifier[]{}, new Metadata[]{}); halHdProgramInfo.emergencyAlert = TEST_HAL_ALERT; RadioManager.ProgramInfo programInfo = ConversionUtils.programInfoFromHalProgramInfo(halHdProgramInfo); expect.withMessage("Alert of converted HD program info with alert and enabled flag") .that(programInfo.getAlert()).isEqualTo(TEST_ALERT); } @Test @DisableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void programInfoFromHalProgramInfo_withAlertMessageAndFlagDisabled() { android.hardware.broadcastradio.ProgramSelector halHdSelector = AidlTestUtils.makeHalSelector(TEST_HAL_HD_STATION_EXT_ID, new ProgramIdentifier[]{}); ProgramInfo halHdProgramInfo = AidlTestUtils.makeHalProgramInfo(halHdSelector, TEST_HAL_HD_STATION_EXT_ID, TEST_HAL_HD_FM_FREQUENCY_ID, TEST_SIGNAL_QUALITY, new ProgramIdentifier[]{}, new Metadata[]{}); halHdProgramInfo.emergencyAlert = TEST_HAL_ALERT; RadioManager.ProgramInfo programInfo = ConversionUtils.programInfoFromHalProgramInfo(halHdProgramInfo); expect.withMessage("Alert of converted HD program info with alert and disabled flag") .that(programInfo.getAlert()).isNull(); } @Test public void tunedProgramInfoFromHalProgramInfo_withInvalidDabProgramInfo() { android.hardware.broadcastradio.ProgramSelector invalidHalDabSelector = Loading Loading @@ -851,7 +957,7 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { } @Test public void radioMetadataFromHalMetadata_withHdMedatadataAndFlagEnabled() { public void radioMetadataFromHalMetadata_withHdMetadataAndFlagEnabled() { mSetFlagsRule.enableFlags(Flags.FLAG_HD_RADIO_IMPROVED); String genreValue = "genreTest"; String commentShortDescriptionValue = "commentShortDescriptionTest"; Loading Loading @@ -973,6 +1079,57 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { .isEmpty(); } @Test @EnableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void radioAlertFromHalAlert() { RadioAlert convertedAlert = ConversionUtils.radioAlertFromHalAlert(TEST_HAL_ALERT); expect.withMessage("Converted alert").that(convertedAlert) .isEqualTo(TEST_ALERT); } @Test @EnableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void radioAlertFromHalAlert_withLowThanFourCoordinates() { Polygon invalidPolygon = createHalPolygon(List.of( TEST_POLYGON_COORDINATE_START, new RadioAlert.Coordinate(38.34, -119.95), TEST_POLYGON_COORDINATE_START)); AlertInfo halAlertInfo = createHalAlertInfo(TEST_HAL_CATEGORY_LIST, TEST_HAL_URGENCY, TEST_HAL_SEVERITY, TEST_HAL_CERTAINTY, TEST_DESCRIPTION_MESSAGE, new AlertArea[]{createHalAlertArea(new Polygon[]{invalidPolygon}, new Geocode[]{})}, TEST_LANGUAGE); Alert halAlert = createHalAlert(TEST_HAL_STATUS, TEST_HAL_TYPE, new AlertInfo[]{halAlertInfo }); RadioAlert convertedAlert = ConversionUtils.radioAlertFromHalAlert(halAlert); expect.withMessage("Empty polygon list with less than 4 coordinates") .that(convertedAlert.getInfoList().get(0).getAreas().get(0).getPolygons()) .isEmpty(); } @Test @EnableFlags(Flags.FLAG_HD_RADIO_EMERGENCY_ALERT_SYSTEM) public void radioAlertFromHalAlert_withDifferentFirstAndLastCoordinate() { Polygon invalidPolygon = createHalPolygon(List.of( TEST_POLYGON_COORDINATE_START, new RadioAlert.Coordinate(38.34, -119.95), new RadioAlert.Coordinate(38.52, -119.74), new RadioAlert.Coordinate(38.62, -119.89), new RadioAlert.Coordinate(38.42, -120.14))); AlertInfo halAlertInfo = createHalAlertInfo(TEST_HAL_CATEGORY_LIST, TEST_HAL_URGENCY, TEST_HAL_SEVERITY, TEST_HAL_CERTAINTY, TEST_DESCRIPTION_MESSAGE, new AlertArea[]{createHalAlertArea(new Polygon[]{invalidPolygon}, new Geocode[]{})}, TEST_LANGUAGE); Alert halAlert = createHalAlert(TEST_HAL_STATUS, TEST_HAL_TYPE, new AlertInfo[]{halAlertInfo}); RadioAlert convertedAlert = ConversionUtils.radioAlertFromHalAlert(halAlert); expect.withMessage("Empty polygon list with different first and last coordinates") .that(convertedAlert.getInfoList().get(0).getAreas().get(0).getPolygons()) .isEmpty(); } private static RadioManager.ModuleProperties createModuleProperties() { AmFmRegionConfig amFmConfig = createAmFmRegionConfig(); DabTableEntry[] dabTableEntries = new DabTableEntry[]{ Loading Loading @@ -1028,14 +1185,62 @@ public final class ConversionUtilsTest extends ExtendedRadioMockitoTestCase { return halProperties; } private ProgramSelector.Identifier createHdStationLocationIdWithFlagEnabled() { private static ProgramSelector.Identifier createHdStationLocationIdWithFlagEnabled() { return new ProgramSelector.Identifier(ProgramSelector.IDENTIFIER_TYPE_HD_STATION_LOCATION, TEST_HD_LOCATION_VALUE); } private ProgramSelector createHdSelectorWithFlagEnabled() { private static ProgramSelector createHdSelectorWithFlagEnabled() { return new ProgramSelector(ProgramSelector.PROGRAM_TYPE_FM_HD, TEST_HD_STATION_EXT_ID, new ProgramSelector.Identifier[]{createHdStationLocationIdWithFlagEnabled()}, /* vendorIds= */ null); } private static Alert createHalAlert(int status, int messageType, AlertInfo[] alertInfos) { Alert halAlert = new Alert(); halAlert.status = status; halAlert.messageType = messageType; halAlert.infoArray = alertInfos; return halAlert; } private static AlertInfo createHalAlertInfo(int[] categoryArray, int urgency, int severity, int certainty, String description, AlertArea[] areas, @Nullable String language) { AlertInfo info = new AlertInfo(); info.categoryArray = categoryArray; info.urgency = urgency; info.severity = severity; info.certainty = certainty; info.description = description; info.areas = areas; info.language = language; return info; } private static AlertArea createHalAlertArea(Polygon[] polygons, Geocode[] geocodes) { AlertArea area = new AlertArea(); area.polygons = polygons; area.geocodes = geocodes; return area; } private static Polygon createHalPolygon(List<RadioAlert.Coordinate> coordinates) { Coordinate[] halCoordinates = new Coordinate[coordinates.size()]; for (int idx = 0; idx < coordinates.size(); idx++) { Coordinate halCoordinate = new Coordinate(); halCoordinate.latitude = coordinates.get(idx).getLatitude(); halCoordinate.longitude = coordinates.get(idx).getLongitude(); halCoordinates[idx] = halCoordinate; } Polygon polygon = new Polygon(); polygon.coordinates = halCoordinates; return polygon; } private static Geocode createHalGeocode(String valueName, String value) { Geocode halGeocode = new Geocode(); halGeocode.valueName = valueName; halGeocode.value = value; return halGeocode; } }
services/core/java/com/android/server/broadcastradio/aidl/ConversionUtils.java +96 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.SuppressLint; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.hardware.broadcastradio.Alert; import android.hardware.broadcastradio.AmFmRegionConfig; import android.hardware.broadcastradio.Announcement; import android.hardware.broadcastradio.ConfigFlag; Loading @@ -36,6 +37,7 @@ import android.hardware.broadcastradio.VendorKeyValue; import android.hardware.radio.Flags; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioAlert; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioMetadata; import android.hardware.radio.RadioTuner; Loading Loading @@ -573,6 +575,86 @@ final class ConversionUtils { return builder.build(); } @Nullable private static RadioAlert.Polygon polygonFromHalPolygon( android.hardware.broadcastradio.Polygon halPolygon) { if (halPolygon.coordinates.length < 4) { Slogf.e(TAG, "Number of coordinates in alert polygon cannot be less than 4"); return null; } else if (halPolygon.coordinates[0].latitude != halPolygon.coordinates[halPolygon.coordinates.length - 1].latitude || halPolygon.coordinates[0].longitude != halPolygon.coordinates[halPolygon.coordinates.length - 1].longitude) { Slogf.e(TAG, "The first and the last coordinate in alert polygon cannot be different"); return null; } List<RadioAlert.Coordinate> coordinates = new ArrayList<>(halPolygon.coordinates.length); for (int idx = 0; idx < halPolygon.coordinates.length; idx++) { coordinates.add(new RadioAlert.Coordinate(halPolygon.coordinates[idx].latitude, halPolygon.coordinates[idx].longitude)); } return new RadioAlert.Polygon(coordinates); } private static RadioAlert.Geocode geocodeFromHalGeocode( android.hardware.broadcastradio.Geocode geocode) { return new RadioAlert.Geocode(geocode.valueName, geocode.value); } private static RadioAlert.AlertArea alertAreaFromHalAlertArea( android.hardware.broadcastradio.AlertArea halAlertArea) { List<RadioAlert.Polygon> polygonList = new ArrayList<>(); for (int idx = 0; idx < halAlertArea.polygons.length; idx++) { RadioAlert.Polygon polygon = polygonFromHalPolygon(halAlertArea.polygons[idx]); if (polygon != null) { polygonList.add(polygon); } } List<RadioAlert.Geocode> geocodeList = new ArrayList<>(halAlertArea.geocodes.length); for (int idx = 0; idx < halAlertArea.geocodes.length; idx++) { geocodeList.add(geocodeFromHalGeocode(halAlertArea.geocodes[idx])); } return new RadioAlert.AlertArea(polygonList, geocodeList); } private static RadioAlert.AlertInfo alertInfoFromHalAlertInfo( android.hardware.broadcastradio.AlertInfo halAlertInfo) { int[] categoryArray = new int[halAlertInfo.categoryArray.length]; for (int idx = 0; idx < halAlertInfo.categoryArray.length; idx++) { // Integer values in android.hardware.radio.RadioAlert.AlertCategory and // android.hardware.broadcastradio.AlertCategory match. categoryArray[idx] = halAlertInfo.categoryArray[idx]; } List<RadioAlert.AlertArea> alertAreaList = new ArrayList<>(); for (int idx = 0; idx < halAlertInfo.areas.length; idx++) { alertAreaList.add(alertAreaFromHalAlertArea(halAlertInfo.areas[idx])); } // Integer values in android.hardware.radio.RadioAlert.AlertUrgency and // android.hardware.broadcastradio.AlertUrgency match. // Integer values in android.hardware.radio.RadioAlert.AlertSeverity and // android.hardware.broadcastradio.AlertSeverity match. // Integer values in android.hardware.radio.RadioAlert.AlertCertainty and // android.hardware.broadcastradio.AlertCertainty match. return new RadioAlert.AlertInfo(categoryArray, halAlertInfo.urgency, halAlertInfo.severity, halAlertInfo.certainty, halAlertInfo.description, alertAreaList, halAlertInfo.language); } @VisibleForTesting @Nullable static RadioAlert radioAlertFromHalAlert(Alert halAlert) { if (halAlert == null) { return null; } List<RadioAlert.AlertInfo> alertInfo = new ArrayList<>(halAlert.infoArray.length); for (int idx = 0; idx < halAlert.infoArray.length; idx++) { alertInfo.add(alertInfoFromHalAlertInfo(halAlert.infoArray[idx])); } // Integer values in android.hardware.radio.RadioAlert.AlertStatus and // android.hardware.broadcastradio.AlertStatus match. // Integer values in android.hardware.radio.RadioAlert.AlertMessageType and // android.hardware.broadcastradio.AlertMessageType match. return new RadioAlert(halAlert.status, halAlert.messageType, alertInfo); } 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 Loading Loading @@ -605,7 +687,7 @@ final class ConversionUtils { } } } if (!Flags.hdRadioEmergencyAlertSystem()) { return new RadioManager.ProgramInfo( Objects.requireNonNull(programSelectorFromHalProgramSelector(info.selector)), identifierFromHalProgramIdentifier(info.logicallyTunedTo), Loading @@ -617,6 +699,18 @@ final class ConversionUtils { vendorInfoFromHalVendorKeyValues(info.vendorInfo) ); } return new RadioManager.ProgramInfo( Objects.requireNonNull(programSelectorFromHalProgramSelector(info.selector)), identifierFromHalProgramIdentifier(info.logicallyTunedTo), identifierFromHalProgramIdentifier(info.physicallyTunedTo), relatedContent, info.infoFlags, info.signalQuality, radioMetadataFromHalMetadata(info.metadata), vendorInfoFromHalVendorKeyValues(info.vendorInfo), radioAlertFromHalAlert(info.emergencyAlert) ); } @Nullable static RadioManager.ProgramInfo tunedProgramInfoFromHalProgramInfo(ProgramInfo info) { Loading