RadioTunerTest.java revision df77643cd8024b381c7df2f509175c7be719fae9
1/* 2 * Copyright (C) 2017 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 */ 16package android.hardware.radio.tests.functional; 17 18import android.Manifest; 19import android.content.Context; 20import android.content.pm.PackageManager; 21import android.hardware.radio.ProgramSelector; 22import android.hardware.radio.RadioManager; 23import android.hardware.radio.RadioTuner; 24import android.support.test.InstrumentationRegistry; 25import android.support.test.runner.AndroidJUnit4; 26import android.test.suitebuilder.annotation.MediumTest; 27import android.util.Log; 28 29import java.lang.reflect.Constructor; 30import java.util.ArrayList; 31import java.util.List; 32 33import org.junit.After; 34import org.junit.Before; 35import org.junit.Test; 36import org.junit.runner.RunWith; 37import org.mockito.ArgumentCaptor; 38import org.mockito.Mock; 39import org.mockito.Mockito; 40import org.mockito.MockitoAnnotations; 41 42import static org.junit.Assert.*; 43import static org.junit.Assume.*; 44import static org.mockito.Matchers.any; 45import static org.mockito.Matchers.anyInt; 46import static org.mockito.Mockito.after; 47import static org.mockito.Mockito.atLeast; 48import static org.mockito.Mockito.atMost; 49import static org.mockito.Mockito.never; 50import static org.mockito.Mockito.timeout; 51import static org.mockito.Mockito.times; 52import static org.mockito.Mockito.verify; 53import static org.mockito.Mockito.verifyNoMoreInteractions; 54import static org.testng.Assert.assertThrows; 55 56/** 57 * A test for broadcast radio API. 58 */ 59@RunWith(AndroidJUnit4.class) 60@MediumTest 61public class RadioTunerTest { 62 private static final String TAG = "BroadcastRadioTests.RadioTuner"; 63 64 public final Context mContext = InstrumentationRegistry.getContext(); 65 66 private final int kConfigCallbackTimeoutMs = 10000; 67 private final int kCancelTimeoutMs = 1000; 68 private final int kTuneCallbackTimeoutMs = 30000; 69 private final int kFullScanTimeoutMs = 60000; 70 71 private RadioManager mRadioManager; 72 private RadioTuner mRadioTuner; 73 private RadioManager.ModuleProperties mModule; 74 private final List<RadioManager.ModuleProperties> mModules = new ArrayList<>(); 75 @Mock private RadioTuner.Callback mCallback; 76 77 RadioManager.AmBandDescriptor mAmBandDescriptor; 78 RadioManager.FmBandDescriptor mFmBandDescriptor; 79 80 RadioManager.BandConfig mAmBandConfig; 81 RadioManager.BandConfig mFmBandConfig; 82 83 @Before 84 public void setup() { 85 MockitoAnnotations.initMocks(this); 86 87 // check if radio is supported and skip the test if it's not 88 PackageManager packageManager = mContext.getPackageManager(); 89 boolean isRadioSupported = packageManager.hasSystemFeature( 90 PackageManager.FEATURE_BROADCAST_RADIO); 91 assumeTrue(isRadioSupported); 92 93 // Check radio access permission 94 int res = mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_BROADCAST_RADIO); 95 assertEquals("ACCESS_BROADCAST_RADIO permission not granted", 96 PackageManager.PERMISSION_GRANTED, res); 97 98 mRadioManager = (RadioManager)mContext.getSystemService(Context.RADIO_SERVICE); 99 assertNotNull(mRadioManager); 100 101 int status = mRadioManager.listModules(mModules); 102 assertEquals(RadioManager.STATUS_OK, status); 103 assertFalse(mModules.isEmpty()); 104 } 105 106 @After 107 public void tearDown() { 108 mRadioManager = null; 109 mModules.clear(); 110 if (mRadioTuner != null) { 111 mRadioTuner.close(); 112 mRadioTuner = null; 113 } 114 resetCallback(); 115 } 116 117 private void openTuner() { 118 openTuner(true); 119 } 120 121 private void resetCallback() { 122 verify(mCallback, atLeast(0)).onMetadataChanged(any()); 123 verifyNoMoreInteractions(mCallback); 124 Mockito.reset(mCallback); 125 } 126 127 private void openTuner(boolean withAudio) { 128 assertNull(mRadioTuner); 129 130 // find FM band and build its config 131 mModule = mModules.get(0); 132 for (RadioManager.BandDescriptor band : mModule.getBands()) { 133 int bandType = band.getType(); 134 if (bandType == RadioManager.BAND_AM || bandType == RadioManager.BAND_AM_HD) { 135 mAmBandDescriptor = (RadioManager.AmBandDescriptor)band; 136 } 137 if (bandType == RadioManager.BAND_FM || bandType == RadioManager.BAND_FM_HD) { 138 mFmBandDescriptor = (RadioManager.FmBandDescriptor)band; 139 } 140 } 141 assertNotNull(mAmBandDescriptor); 142 assertNotNull(mFmBandDescriptor); 143 mAmBandConfig = new RadioManager.AmBandConfig.Builder(mAmBandDescriptor).build(); 144 mFmBandConfig = new RadioManager.FmBandConfig.Builder(mFmBandDescriptor).build(); 145 146 mRadioTuner = mRadioManager.openTuner(mModule.getId(), 147 mFmBandConfig, withAudio, mCallback, null); 148 assertNotNull(mRadioTuner); 149 verify(mCallback, timeout(kConfigCallbackTimeoutMs)).onConfigurationChanged(any()); 150 resetCallback(); 151 152 boolean isAntennaConnected = mRadioTuner.isAntennaConnected(); 153 assertTrue(isAntennaConnected); 154 } 155 156 @Test 157 public void testOpenTuner() { 158 openTuner(); 159 } 160 161 @Test 162 public void testReopenTuner() throws Throwable { 163 openTuner(); 164 mRadioTuner.close(); 165 mRadioTuner = null; 166 Thread.sleep(100); // TODO(b/36122635): force reopen 167 openTuner(); 168 } 169 170 @Test 171 public void testDoubleClose() { 172 openTuner(); 173 mRadioTuner.close(); 174 mRadioTuner.close(); 175 } 176 177 @Test 178 public void testUseAfterClose() { 179 openTuner(); 180 mRadioTuner.close(); 181 int ret = mRadioTuner.cancel(); 182 assertEquals(RadioManager.STATUS_INVALID_OPERATION, ret); 183 } 184 185 @Test 186 public void testSetAndGetConfiguration() { 187 openTuner(); 188 189 // set 190 int ret = mRadioTuner.setConfiguration(mAmBandConfig); 191 assertEquals(RadioManager.STATUS_OK, ret); 192 verify(mCallback, timeout(kConfigCallbackTimeoutMs)).onConfigurationChanged(any()); 193 194 // get 195 RadioManager.BandConfig[] config = new RadioManager.BandConfig[1]; 196 ret = mRadioTuner.getConfiguration(config); 197 assertEquals(RadioManager.STATUS_OK, ret); 198 199 assertEquals(mAmBandConfig, config[0]); 200 } 201 202 @Test 203 public void testSetBadConfiguration() throws Throwable { 204 openTuner(); 205 206 // set bad config 207 Constructor<RadioManager.AmBandConfig> configConstr = 208 RadioManager.AmBandConfig.class.getDeclaredConstructor( 209 int.class, int.class, int.class, int.class, int.class, boolean.class); 210 configConstr.setAccessible(true); 211 RadioManager.AmBandConfig badConfig = configConstr.newInstance( 212 0 /*region*/, RadioManager.BAND_AM /*type*/, 213 10000 /*lowerLimit*/, 1 /*upperLimit*/, 100 /*spacing*/, false /*stereo*/); 214 int ret = mRadioTuner.setConfiguration(badConfig); 215 assertEquals(RadioManager.STATUS_BAD_VALUE, ret); 216 verify(mCallback, never()).onConfigurationChanged(any()); 217 218 // set null config 219 ret = mRadioTuner.setConfiguration(null); 220 assertEquals(RadioManager.STATUS_BAD_VALUE, ret); 221 verify(mCallback, never()).onConfigurationChanged(any()); 222 223 // setting good config should recover 224 ret = mRadioTuner.setConfiguration(mAmBandConfig); 225 assertEquals(RadioManager.STATUS_OK, ret); 226 verify(mCallback, timeout(kConfigCallbackTimeoutMs)).onConfigurationChanged(any()); 227 } 228 229 @Test 230 public void testMute() { 231 openTuner(); 232 233 boolean isMuted = mRadioTuner.getMute(); 234 assertFalse(isMuted); 235 236 int ret = mRadioTuner.setMute(true); 237 assertEquals(RadioManager.STATUS_OK, ret); 238 isMuted = mRadioTuner.getMute(); 239 assertTrue(isMuted); 240 241 ret = mRadioTuner.setMute(false); 242 assertEquals(RadioManager.STATUS_OK, ret); 243 isMuted = mRadioTuner.getMute(); 244 assertFalse(isMuted); 245 } 246 247 @Test 248 public void testMuteNoAudio() { 249 openTuner(false); 250 251 int ret = mRadioTuner.setMute(false); 252 assertEquals(RadioManager.STATUS_ERROR, ret); 253 254 boolean isMuted = mRadioTuner.getMute(); 255 assertTrue(isMuted); 256 } 257 258 @Test 259 public void testStep() { 260 openTuner(); 261 262 int ret = mRadioTuner.step(RadioTuner.DIRECTION_DOWN, true); 263 assertEquals(RadioManager.STATUS_OK, ret); 264 verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(any()); 265 266 resetCallback(); 267 268 ret = mRadioTuner.step(RadioTuner.DIRECTION_UP, false); 269 assertEquals(RadioManager.STATUS_OK, ret); 270 verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(any()); 271 } 272 273 @Test 274 public void testTuneAndGetPI() { 275 openTuner(); 276 277 int channel = mFmBandConfig.getLowerLimit() + mFmBandConfig.getSpacing(); 278 279 // test tune 280 int ret = mRadioTuner.tune(channel, 0); 281 assertEquals(RadioManager.STATUS_OK, ret); 282 ArgumentCaptor<RadioManager.ProgramInfo> infoc = 283 ArgumentCaptor.forClass(RadioManager.ProgramInfo.class); 284 verify(mCallback, timeout(kTuneCallbackTimeoutMs)) 285 .onProgramInfoChanged(infoc.capture()); 286 assertEquals(channel, infoc.getValue().getChannel()); 287 288 // test getProgramInformation 289 RadioManager.ProgramInfo[] info = new RadioManager.ProgramInfo[1]; 290 ret = mRadioTuner.getProgramInformation(info); 291 assertEquals(RadioManager.STATUS_OK, ret); 292 assertNotNull(info[0]); 293 assertEquals(channel, info[0].getChannel()); 294 } 295 296 @Test 297 public void testDummyCancel() { 298 openTuner(); 299 300 int ret = mRadioTuner.cancel(); 301 assertEquals(RadioManager.STATUS_OK, ret); 302 } 303 304 @Test 305 public void testLateCancel() { 306 openTuner(); 307 308 int ret = mRadioTuner.step(RadioTuner.DIRECTION_DOWN, false); 309 assertEquals(RadioManager.STATUS_OK, ret); 310 verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(any()); 311 312 int cancelRet = mRadioTuner.cancel(); 313 assertEquals(RadioManager.STATUS_OK, cancelRet); 314 } 315 316 @Test 317 public void testScanAndCancel() { 318 openTuner(); 319 320 /* There is a possible race condition between scan and cancel commands - the scan may finish 321 * before cancel command is issued. Thus we accept both outcomes in this test. 322 */ 323 int scanRet = mRadioTuner.scan(RadioTuner.DIRECTION_DOWN, true); 324 int cancelRet = mRadioTuner.cancel(); 325 326 assertEquals(RadioManager.STATUS_OK, scanRet); 327 assertEquals(RadioManager.STATUS_OK, cancelRet); 328 329 verify(mCallback, after(kCancelTimeoutMs).atMost(1)).onError(RadioTuner.ERROR_CANCELLED); 330 verify(mCallback, atMost(1)).onProgramInfoChanged(any()); 331 } 332 333 @Test 334 public void testStartBackgroundScan() { 335 openTuner(); 336 337 boolean ret = mRadioTuner.startBackgroundScan(); 338 boolean isSupported = mModule.isBackgroundScanningSupported(); 339 assertEquals(isSupported, ret); 340 } 341 342 @Test 343 public void testGetProgramList() { 344 openTuner(); 345 346 try { 347 List<RadioManager.ProgramInfo> list = mRadioTuner.getProgramList(null); 348 assertNotNull(list); 349 } catch (IllegalStateException e) { 350 // the list may or may not be ready at this point 351 Log.i(TAG, "Background list is not ready"); 352 } 353 } 354 355 @Test 356 public void testTuneFromProgramList() { 357 openTuner(); 358 359 List<RadioManager.ProgramInfo> list; 360 361 try { 362 list = mRadioTuner.getProgramList(null); 363 assertNotNull(list); 364 } catch (IllegalStateException e) { 365 Log.i(TAG, "Background list is not ready, trying to fix it"); 366 367 boolean success = mRadioTuner.startBackgroundScan(); 368 assertTrue(success); 369 verify(mCallback, timeout(kFullScanTimeoutMs)).onBackgroundScanComplete(); 370 371 list = mRadioTuner.getProgramList(null); 372 assertNotNull(list); 373 } 374 375 if (list.isEmpty()) { 376 Log.i(TAG, "Program list is empty, can't test tune"); 377 return; 378 } 379 380 ProgramSelector sel = list.get(0).getSelector(); 381 mRadioTuner.tune(sel); 382 ArgumentCaptor<RadioManager.ProgramInfo> infoc = 383 ArgumentCaptor.forClass(RadioManager.ProgramInfo.class); 384 verify(mCallback, timeout(kTuneCallbackTimeoutMs)).onProgramInfoChanged(infoc.capture()); 385 assertEquals(sel, infoc.getValue().getSelector()); 386 } 387 388 @Test 389 public void testForcedAnalog() { 390 openTuner(); 391 392 boolean isSupported = true; 393 boolean isForced; 394 try { 395 isForced = mRadioTuner.isAnalogForced(); 396 assertFalse(isForced); 397 } catch (IllegalStateException ex) { 398 Log.i(TAG, "Forced analog switch is not supported by this tuner"); 399 isSupported = false; 400 } 401 402 if (isSupported) { 403 mRadioTuner.setAnalogForced(true); 404 isForced = mRadioTuner.isAnalogForced(); 405 assertTrue(isForced); 406 407 mRadioTuner.setAnalogForced(false); 408 isForced = mRadioTuner.isAnalogForced(); 409 assertFalse(isForced); 410 } else { 411 assertThrows(IllegalStateException.class, () -> mRadioTuner.setAnalogForced(true)); 412 } 413 } 414} 415