1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.broadcastradio.hal2; 18 19 import static org.junit.Assert.assertThrows; 20 21 import android.hardware.broadcastradio.V2_0.AmFmBandRange; 22 import android.hardware.broadcastradio.V2_0.AmFmRegionConfig; 23 import android.hardware.broadcastradio.V2_0.DabTableEntry; 24 import android.hardware.broadcastradio.V2_0.IdentifierType; 25 import android.hardware.broadcastradio.V2_0.Metadata; 26 import android.hardware.broadcastradio.V2_0.MetadataKey; 27 import android.hardware.broadcastradio.V2_0.ProgramInfo; 28 import android.hardware.broadcastradio.V2_0.Properties; 29 import android.hardware.broadcastradio.V2_0.Result; 30 import android.hardware.broadcastradio.V2_0.VendorKeyValue; 31 import android.hardware.radio.Announcement; 32 import android.hardware.radio.ProgramSelector; 33 import android.hardware.radio.RadioManager; 34 import android.hardware.radio.RadioMetadata; 35 import android.util.ArrayMap; 36 37 import com.google.common.truth.Expect; 38 39 import org.junit.Rule; 40 import org.junit.Test; 41 42 import java.util.ArrayList; 43 import java.util.Arrays; 44 import java.util.List; 45 import java.util.Map; 46 47 public final class ConvertTest { 48 49 private static final int FM_LOWER_LIMIT = 87500; 50 private static final int FM_UPPER_LIMIT = 108000; 51 private static final int FM_SPACING = 200; 52 private static final int AM_LOWER_LIMIT = 540; 53 private static final int AM_UPPER_LIMIT = 1700; 54 private static final int AM_SPACING = 10; 55 private static final String DAB_ENTRY_LABEL_1 = "5A"; 56 private static final int DAB_ENTRY_FREQUENCY_1 = 174928; 57 private static final String DAB_ENTRY_LABEL_2 = "12D"; 58 private static final int DAB_ENTRY_FREQUENCY_2 = 229072; 59 private static final String VENDOR_INFO_KEY_1 = "vendorKey1"; 60 private static final String VENDOR_INFO_VALUE_1 = "vendorValue1"; 61 private static final String VENDOR_INFO_KEY_2 = "vendorKey2"; 62 private static final String VENDOR_INFO_VALUE_2 = "vendorValue2"; 63 private static final String TEST_SERVICE_NAME = "serviceMock"; 64 private static final int TEST_ID = 1; 65 private static final String TEST_MAKER = "makerMock"; 66 private static final String TEST_PRODUCT = "productMock"; 67 private static final String TEST_VERSION = "versionMock"; 68 private static final String TEST_SERIAL = "serialMock"; 69 70 private static final int TEST_ENABLED_TYPE = Announcement.TYPE_EMERGENCY; 71 private static final int TEST_ANNOUNCEMENT_FREQUENCY = FM_LOWER_LIMIT + FM_SPACING; 72 73 private static final RadioManager.ModuleProperties MODULE_PROPERTIES = 74 convertToModuleProperties(); 75 private static final Announcement ANNOUNCEMENT = 76 Convert.announcementFromHal( 77 TestUtils.makeAnnouncement(TEST_ENABLED_TYPE, TEST_ANNOUNCEMENT_FREQUENCY)); 78 79 @Rule 80 public final Expect expect = Expect.create(); 81 82 @Test throwOnError()83 public void throwOnError() { 84 IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> 85 Convert.throwOnError("tune", Result.INVALID_ARGUMENTS)); 86 87 expect.withMessage("Exception for illegeal argument").that(thrown) 88 .hasMessageThat().contains("INVALID_ARGUMENTS"); 89 } 90 91 @Test propertiesFromHalProperties_idsMatch()92 public void propertiesFromHalProperties_idsMatch() { 93 expect.withMessage("Properties id") 94 .that(MODULE_PROPERTIES.getId()).isEqualTo(TEST_ID); 95 } 96 97 @Test propertiesFromHalProperties_serviceNamesMatch()98 public void propertiesFromHalProperties_serviceNamesMatch() { 99 expect.withMessage("Service name") 100 .that(MODULE_PROPERTIES.getServiceName()).isEqualTo(TEST_SERVICE_NAME); 101 } 102 103 @Test propertiesFromHalProperties_implementorsMatch()104 public void propertiesFromHalProperties_implementorsMatch() { 105 expect.withMessage("Implementor") 106 .that(MODULE_PROPERTIES.getImplementor()).isEqualTo(TEST_MAKER); 107 } 108 109 110 @Test propertiesFromHalProperties_productsMatch()111 public void propertiesFromHalProperties_productsMatch() { 112 expect.withMessage("Product") 113 .that(MODULE_PROPERTIES.getProduct()).isEqualTo(TEST_PRODUCT); 114 } 115 116 @Test propertiesFromHalProperties_versionsMatch()117 public void propertiesFromHalProperties_versionsMatch() { 118 expect.withMessage("Version") 119 .that(MODULE_PROPERTIES.getVersion()).isEqualTo(TEST_VERSION); 120 } 121 122 @Test propertiesFromHalProperties_serialsMatch()123 public void propertiesFromHalProperties_serialsMatch() { 124 expect.withMessage("Serial") 125 .that(MODULE_PROPERTIES.getSerial()).isEqualTo(TEST_SERIAL); 126 } 127 128 @Test propertiesFromHalProperties_dabTableInfoMatch()129 public void propertiesFromHalProperties_dabTableInfoMatch() { 130 Map<String, Integer> dabTableExpected = Map.of(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1, 131 DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2); 132 133 expect.withMessage("Supported program types") 134 .that(MODULE_PROPERTIES.getDabFrequencyTable()) 135 .containsExactlyEntriesIn(dabTableExpected); 136 } 137 138 @Test propertiesFromHalProperties_vendorInfoMatch()139 public void propertiesFromHalProperties_vendorInfoMatch() { 140 Map<String, String> vendorInfoExpected = Map.of(VENDOR_INFO_KEY_1, VENDOR_INFO_VALUE_1, 141 VENDOR_INFO_KEY_2, VENDOR_INFO_VALUE_2); 142 143 expect.withMessage("Vendor info").that(MODULE_PROPERTIES.getVendorInfo()) 144 .containsExactlyEntriesIn(vendorInfoExpected); 145 } 146 147 @Test propertiesFromHalProperties_bandsMatch()148 public void propertiesFromHalProperties_bandsMatch() { 149 RadioManager.BandDescriptor[] bands = MODULE_PROPERTIES.getBands(); 150 151 expect.withMessage("Band descriptors").that(bands).hasLength(2); 152 153 expect.withMessage("FM band frequency lower limit") 154 .that(bands[0].getLowerLimit()).isEqualTo(FM_LOWER_LIMIT); 155 expect.withMessage("FM band frequency upper limit") 156 .that(bands[0].getUpperLimit()).isEqualTo(FM_UPPER_LIMIT); 157 expect.withMessage("FM band frequency spacing") 158 .that(bands[0].getSpacing()).isEqualTo(FM_SPACING); 159 160 expect.withMessage("AM band frequency lower limit") 161 .that(bands[1].getLowerLimit()).isEqualTo(AM_LOWER_LIMIT); 162 expect.withMessage("AM band frequency upper limit") 163 .that(bands[1].getUpperLimit()).isEqualTo(AM_UPPER_LIMIT); 164 expect.withMessage("AM band frequency spacing") 165 .that(bands[1].getSpacing()).isEqualTo(AM_SPACING); 166 } 167 168 @Test propertiesFromHalProperties_withInvalidBand()169 public void propertiesFromHalProperties_withInvalidBand() { 170 AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig(); 171 amFmRegionConfig.ranges = new ArrayList<>(Arrays.asList(createAmFmBandRange( 172 /* lowerBound= */ 50000, /* upperBound= */ 60000, /* spacing= */ 10), 173 createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING))); 174 175 RadioManager.ModuleProperties properties = convertToModuleProperties(amFmRegionConfig, 176 new ArrayList<>()); 177 178 RadioManager.BandDescriptor[] bands = properties.getBands(); 179 expect.withMessage("Band descriptors").that(bands).hasLength(1); 180 expect.withMessage("FM band frequency lower limit") 181 .that(bands[0].getLowerLimit()).isEqualTo(FM_LOWER_LIMIT); 182 expect.withMessage("FM band frequency upper limit") 183 .that(bands[0].getUpperLimit()).isEqualTo(FM_UPPER_LIMIT); 184 expect.withMessage("FM band frequency spacing") 185 .that(bands[0].getSpacing()).isEqualTo(FM_SPACING); 186 } 187 188 @Test announcementFromHalAnnouncement_typesMatch()189 public void announcementFromHalAnnouncement_typesMatch() { 190 expect.withMessage("Announcement type") 191 .that(ANNOUNCEMENT.getType()).isEqualTo(TEST_ENABLED_TYPE); 192 } 193 194 @Test announcementFromHalAnnouncement_selectorsMatch()195 public void announcementFromHalAnnouncement_selectorsMatch() { 196 ProgramSelector.Identifier primaryIdExpected = new ProgramSelector.Identifier( 197 ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, TEST_ANNOUNCEMENT_FREQUENCY); 198 199 ProgramSelector selector = ANNOUNCEMENT.getSelector(); 200 201 expect.withMessage("Primary id of announcement selector") 202 .that(selector.getPrimaryId()).isEqualTo(primaryIdExpected); 203 expect.withMessage("Secondary ids of announcement selector") 204 .that(selector.getSecondaryIds()).isEmpty(); 205 } 206 207 @Test announcementFromHalAnnouncement_VendorInfoMatch()208 public void announcementFromHalAnnouncement_VendorInfoMatch() { 209 expect.withMessage("Announcement vendor info") 210 .that(ANNOUNCEMENT.getVendorInfo()).isEmpty(); 211 } 212 213 @Test getBands_withInvalidFrequency()214 public void getBands_withInvalidFrequency() { 215 expect.withMessage("Band for invalid frequency") 216 .that(Utils.getBand(/* freq= */ 110000)).isEqualTo(FrequencyBand.UNKNOWN); 217 } 218 219 @Test vendorInfoToHal_withNull()220 public void vendorInfoToHal_withNull() { 221 expect.withMessage("Null vendor info converted to HAL") 222 .that(Convert.vendorInfoToHal(/* info= */ null)).isEmpty(); 223 } 224 225 @Test vendorInfoToHal_withNullValue()226 public void vendorInfoToHal_withNullValue() { 227 Map<String, String> vendorInfo = new ArrayMap<>(); 228 vendorInfo.put(VENDOR_INFO_KEY_1, null); 229 230 expect.withMessage("Vendor info with null value converted to HAL") 231 .that(Convert.vendorInfoToHal(vendorInfo)).isEmpty(); 232 } 233 234 @Test vendorInfoFromHalVendorKeyValues_withNullElements()235 public void vendorInfoFromHalVendorKeyValues_withNullElements() { 236 VendorKeyValue halVendorInfo = new VendorKeyValue(); 237 halVendorInfo.key = null; 238 halVendorInfo.value = "VendorValue"; 239 List<VendorKeyValue> halVendorInfoArray = List.of(halVendorInfo); 240 241 expect.withMessage("Null vendor info converted from HAL") 242 .that(Convert.vendorInfoFromHal(halVendorInfoArray)).isEmpty(); 243 } 244 245 @Test programInfoFromHal_withMetadata()246 public void programInfoFromHal_withMetadata() { 247 int freq = 97900; 248 int signalQuality = 90; 249 String songTitle = "titleTest"; 250 int albumArt = 1; 251 android.hardware.broadcastradio.V2_0.ProgramSelector halSelector = 252 TestUtils.makeHalFmSelector(freq); 253 ArrayList<Metadata> metadata = new ArrayList<>(List.of( 254 createIntMetadata(MetadataKey.ALBUM_ART, albumArt), 255 createStringMetadata(MetadataKey.SONG_TITLE, songTitle), 256 createStringMetadata(/* key= */ 1000, "valueForInvalidMetadataType"))); 257 ProgramInfo halInfo = TestUtils.makeHalProgramInfo(halSelector, signalQuality, 258 /* relatedContent= */ new ArrayList<>(), metadata); 259 260 RadioManager.ProgramInfo info = Convert.programInfoFromHal(halInfo); 261 262 RadioMetadata convertedMetadata = info.getMetadata(); 263 expect.withMessage("Metadata converted from HAL") 264 .that(convertedMetadata.size()).isEqualTo(2); 265 expect.withMessage("Song title") 266 .that(convertedMetadata.getString(RadioMetadata.METADATA_KEY_TITLE)) 267 .isEqualTo(songTitle); 268 expect.withMessage("Album art") 269 .that(convertedMetadata.getInt(RadioMetadata.METADATA_KEY_ART)) 270 .isEqualTo(albumArt); 271 } 272 convertToModuleProperties()273 private static RadioManager.ModuleProperties convertToModuleProperties() { 274 AmFmRegionConfig amFmConfig = createAmFmRegionConfig(); 275 List<DabTableEntry> dabTableEntries = Arrays.asList( 276 createDabTableEntry(DAB_ENTRY_LABEL_1, DAB_ENTRY_FREQUENCY_1), 277 createDabTableEntry(DAB_ENTRY_LABEL_2, DAB_ENTRY_FREQUENCY_2)); 278 279 return convertToModuleProperties(amFmConfig, dabTableEntries); 280 } 281 convertToModuleProperties( AmFmRegionConfig amFmConfig, List<DabTableEntry> dabTableEntries)282 private static RadioManager.ModuleProperties convertToModuleProperties( 283 AmFmRegionConfig amFmConfig, List<DabTableEntry> dabTableEntries) { 284 Properties properties = createHalProperties(); 285 return Convert.propertiesFromHal(TEST_ID, TEST_SERVICE_NAME, properties, 286 amFmConfig, dabTableEntries); 287 } 288 createAmFmRegionConfig()289 private static AmFmRegionConfig createAmFmRegionConfig() { 290 AmFmRegionConfig amFmRegionConfig = new AmFmRegionConfig(); 291 amFmRegionConfig.ranges = new ArrayList<>(Arrays.asList( 292 createAmFmBandRange(FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING), 293 createAmFmBandRange(AM_LOWER_LIMIT, AM_UPPER_LIMIT, AM_SPACING))); 294 return amFmRegionConfig; 295 } 296 createAmFmBandRange(int lowerBound, int upperBound, int spacing)297 private static AmFmBandRange createAmFmBandRange(int lowerBound, int upperBound, int spacing) { 298 AmFmBandRange bandRange = new AmFmBandRange(); 299 bandRange.lowerBound = lowerBound; 300 bandRange.upperBound = upperBound; 301 bandRange.spacing = spacing; 302 bandRange.scanSpacing = bandRange.spacing; 303 return bandRange; 304 } 305 createDabTableEntry(String label, int value)306 private static DabTableEntry createDabTableEntry(String label, int value) { 307 DabTableEntry dabTableEntry = new DabTableEntry(); 308 dabTableEntry.label = label; 309 dabTableEntry.frequency = value; 310 return dabTableEntry; 311 } 312 createHalProperties()313 private static Properties createHalProperties() { 314 Properties halProperties = new Properties(); 315 halProperties.supportedIdentifierTypes = new ArrayList<Integer>(Arrays.asList( 316 IdentifierType.AMFM_FREQUENCY, IdentifierType.RDS_PI, IdentifierType.DAB_SID_EXT, 317 IdentifierType.HD_STATION_ID_EXT, IdentifierType.DRMO_SERVICE_ID)); 318 halProperties.maker = TEST_MAKER; 319 halProperties.product = TEST_PRODUCT; 320 halProperties.version = TEST_VERSION; 321 halProperties.serial = TEST_SERIAL; 322 halProperties.vendorInfo = new ArrayList<>(Arrays.asList( 323 TestUtils.makeVendorKeyValue(VENDOR_INFO_KEY_1, VENDOR_INFO_VALUE_1), 324 TestUtils.makeVendorKeyValue(VENDOR_INFO_KEY_2, VENDOR_INFO_VALUE_2))); 325 return halProperties; 326 } 327 createStringMetadata(int key, String value)328 private Metadata createStringMetadata(int key, String value) { 329 Metadata metadata = new Metadata(); 330 metadata.key = key; 331 metadata.stringValue = value; 332 return metadata; 333 } 334 createIntMetadata(int key, int value)335 private Metadata createIntMetadata(int key, int value) { 336 Metadata metadata = new Metadata(); 337 metadata.key = key; 338 metadata.intValue = value; 339 return metadata; 340 } 341 } 342