• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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 android.media.tv.tuner.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotEquals;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertTrue;
25 import static org.junit.Assert.fail;
26 
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.content.ServiceConnection;
31 import android.content.pm.PackageManager;
32 import android.media.tv.tuner.DemuxCapabilities;
33 import android.media.tv.tuner.Descrambler;
34 import android.media.tv.tuner.Lnb;
35 import android.media.tv.tuner.LnbCallback;
36 import android.media.tv.tuner.Tuner;
37 import android.media.tv.tuner.TunerVersionChecker;
38 import android.media.tv.tuner.dvr.DvrPlayback;
39 import android.media.tv.tuner.dvr.DvrRecorder;
40 import android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener;
41 import android.media.tv.tuner.dvr.OnRecordStatusChangedListener;
42 import android.media.tv.tuner.filter.AlpFilterConfiguration;
43 import android.media.tv.tuner.filter.AudioDescriptor;
44 import android.media.tv.tuner.filter.AvSettings;
45 import android.media.tv.tuner.filter.DownloadEvent;
46 import android.media.tv.tuner.filter.DownloadSettings;
47 import android.media.tv.tuner.filter.Filter;
48 import android.media.tv.tuner.filter.FilterCallback;
49 import android.media.tv.tuner.filter.FilterConfiguration;
50 import android.media.tv.tuner.filter.FilterEvent;
51 import android.media.tv.tuner.filter.IpCidChangeEvent;
52 import android.media.tv.tuner.filter.IpFilterConfiguration;
53 import android.media.tv.tuner.filter.IpPayloadEvent;
54 import android.media.tv.tuner.filter.MediaEvent;
55 import android.media.tv.tuner.filter.MmtpFilterConfiguration;
56 import android.media.tv.tuner.filter.MmtpRecordEvent;
57 import android.media.tv.tuner.filter.PesEvent;
58 import android.media.tv.tuner.filter.PesSettings;
59 import android.media.tv.tuner.filter.RecordSettings;
60 import android.media.tv.tuner.filter.RestartEvent;
61 import android.media.tv.tuner.filter.ScramblingStatusEvent;
62 import android.media.tv.tuner.filter.SectionEvent;
63 import android.media.tv.tuner.filter.SectionSettingsWithSectionBits;
64 import android.media.tv.tuner.filter.SectionSettingsWithTableInfo;
65 import android.media.tv.tuner.filter.Settings;
66 import android.media.tv.tuner.filter.SharedFilter;
67 import android.media.tv.tuner.filter.SharedFilterCallback;
68 import android.media.tv.tuner.filter.TemiEvent;
69 import android.media.tv.tuner.filter.TimeFilter;
70 import android.media.tv.tuner.filter.TlvFilterConfiguration;
71 import android.media.tv.tuner.filter.TsFilterConfiguration;
72 import android.media.tv.tuner.filter.TsRecordEvent;
73 import android.media.tv.tuner.frontend.AnalogFrontendCapabilities;
74 import android.media.tv.tuner.frontend.AnalogFrontendSettings;
75 import android.media.tv.tuner.frontend.Atsc3FrontendCapabilities;
76 import android.media.tv.tuner.frontend.Atsc3FrontendSettings;
77 import android.media.tv.tuner.frontend.Atsc3PlpInfo;
78 import android.media.tv.tuner.frontend.AtscFrontendCapabilities;
79 import android.media.tv.tuner.frontend.AtscFrontendSettings;
80 import android.media.tv.tuner.frontend.DtmbFrontendCapabilities;
81 import android.media.tv.tuner.frontend.DtmbFrontendSettings;
82 import android.media.tv.tuner.frontend.DvbcFrontendCapabilities;
83 import android.media.tv.tuner.frontend.DvbcFrontendSettings;
84 import android.media.tv.tuner.frontend.DvbsFrontendCapabilities;
85 import android.media.tv.tuner.frontend.DvbsFrontendSettings;
86 import android.media.tv.tuner.frontend.DvbtFrontendCapabilities;
87 import android.media.tv.tuner.frontend.DvbtFrontendSettings;
88 import android.media.tv.tuner.frontend.FrontendCapabilities;
89 import android.media.tv.tuner.frontend.FrontendInfo;
90 import android.media.tv.tuner.frontend.FrontendSettings;
91 import android.media.tv.tuner.frontend.FrontendStatus;
92 import android.media.tv.tuner.frontend.FrontendStatus.Atsc3PlpTuningInfo;
93 import android.media.tv.tuner.frontend.FrontendStatusReadiness;
94 import android.media.tv.tuner.frontend.Isdbs3FrontendCapabilities;
95 import android.media.tv.tuner.frontend.Isdbs3FrontendSettings;
96 import android.media.tv.tuner.frontend.IsdbsFrontendCapabilities;
97 import android.media.tv.tuner.frontend.IsdbsFrontendSettings;
98 import android.media.tv.tuner.frontend.IsdbtFrontendCapabilities;
99 import android.media.tv.tuner.frontend.IsdbtFrontendSettings;
100 import android.media.tv.tuner.frontend.OnTuneEventListener;
101 import android.media.tv.tuner.frontend.ScanCallback;
102 import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
103 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
104 import android.media.tv.tunerresourcemanager.TunerResourceManager;
105 import android.os.ConditionVariable;
106 import android.os.Handler;
107 import android.os.IBinder;
108 import android.os.Looper;
109 import android.os.Message;
110 
111 import androidx.test.InstrumentationRegistry;
112 import androidx.test.filters.SmallTest;
113 import androidx.test.runner.AndroidJUnit4;
114 
115 import com.android.compatibility.common.util.RequiredFeatureRule;
116 
117 import org.junit.After;
118 import org.junit.Before;
119 import org.junit.Rule;
120 import org.junit.Test;
121 import org.junit.runner.RunWith;
122 
123 import java.time.Duration;
124 import java.time.Instant;
125 import java.util.List;
126 import java.util.concurrent.BlockingQueue;
127 import java.util.concurrent.CountDownLatch;
128 import java.util.concurrent.Executor;
129 import java.util.concurrent.LinkedBlockingQueue;
130 import java.util.concurrent.TimeUnit;
131 import java.util.concurrent.locks.ReentrantLock;
132 
133 @RunWith(AndroidJUnit4.class)
134 @SmallTest
135 public class TunerTest {
136     private static final String TAG = "MediaTunerTest";
137 
138     @Rule
139     public RequiredFeatureRule featureRule = new RequiredFeatureRule(
140             PackageManager.FEATURE_TUNER);
141 
142     private static final int TIMEOUT_MS = 10 * 1000;  // 10 seconds
143     private static final int SCAN_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
144     private static final long TIMEOUT_BINDER_SERVICE_SEC = 2;
145 
146     private Context mContext;
147     private Tuner mTuner;
148     private CountDownLatch mLockLatch = new CountDownLatch(1);
149     private TunerResourceManager mTunerResourceManager = null;
150     private TestServiceConnection mConnection;
151     private ISharedFilterTestServer mSharedFilterTestServer;
152 
153     private class TestServiceConnection implements ServiceConnection {
154         private BlockingQueue<IBinder> mBlockingQueue = new LinkedBlockingQueue<>();
155 
onServiceConnected(ComponentName componentName, IBinder service)156         public void onServiceConnected(ComponentName componentName, IBinder service) {
157             mBlockingQueue.offer(service);
158         }
159 
onServiceDisconnected(ComponentName componentName)160         public void onServiceDisconnected(ComponentName componentName) {}
161 
getService()162         public IBinder getService() throws Exception {
163             final IBinder service =
164                     mBlockingQueue.poll(TIMEOUT_BINDER_SERVICE_SEC, TimeUnit.SECONDS);
165             return service;
166         }
167     }
168 
169     private class TunerResourceTestServiceConnection implements ServiceConnection {
170         private BlockingQueue<IBinder> mBlockingQueue = new LinkedBlockingQueue<>();
171 
172         @Override
onServiceConnected(ComponentName componentName, IBinder service)173         public void onServiceConnected(ComponentName componentName, IBinder service) {
174             mBlockingQueue.offer(service);
175         }
176 
177         @Override
onServiceDisconnected(ComponentName componentName)178         public void onServiceDisconnected(ComponentName componentName){}
179 
getService()180         public ITunerResourceTestServer getService() throws Exception {
181             final IBinder service =
182                     mBlockingQueue.poll(TIMEOUT_BINDER_SERVICE_SEC, TimeUnit.SECONDS);
183             return ITunerResourceTestServer.Stub.asInterface(service);
184         }
185     }
186 
187     private class TunerTestOnTuneEventListener implements OnTuneEventListener {
188         public static final int INVALID_TUNE_EVENT = -1;
189         private static final int SLEEP_TIME_MS = 100;
190         private static final int TIMEOUT_MS = 500;
191         private final ReentrantLock mLock = new ReentrantLock();
192         private final ConditionVariable mCV = new ConditionVariable();
193         private int mLastTuneEvent = INVALID_TUNE_EVENT;
194 
195         @Override
onTuneEvent(int tuneEvent)196         public void onTuneEvent(int tuneEvent) {
197             synchronized (mLock) {
198                 mLastTuneEvent = tuneEvent;
199                 mCV.open();
200             }
201         }
202 
resetLastTuneEvent()203         public void resetLastTuneEvent() {
204             synchronized (mLock) {
205                 mLastTuneEvent = INVALID_TUNE_EVENT;
206             }
207         }
208 
getLastTuneEvent()209         public int getLastTuneEvent() {
210             try {
211                 // yield to let the callback handling execute
212                 Thread.sleep(SLEEP_TIME_MS);
213             } catch (Exception e) {
214                 // ignore exception
215             }
216             synchronized (mLock) {
217                 mCV.block(TIMEOUT_MS);
218                 mCV.close();
219                 return mLastTuneEvent;
220             }
221         }
222     }
223 
224     private class TunerTestLnbCallback implements LnbCallback {
225         public static final int INVALID_LNB_EVENT = -1;
226         private static final int SLEEP_TIME_MS = 100;
227         private static final int TIMEOUT_MS = 500;
228         private final ReentrantLock mDMLock = new ReentrantLock();
229         private final ConditionVariable mDMCV = new ConditionVariable();
230         private boolean mOnDiseqcMessageCalled = false;
231 
232         // will not test this as there is no good way to trigger this
233         @Override
onEvent(int lnbEventType)234         public void onEvent(int lnbEventType) {}
235 
236         // will test this instead
237         @Override
onDiseqcMessage(byte[] diseqcMessage)238         public void onDiseqcMessage(byte[] diseqcMessage) {
239             synchronized (mDMLock) {
240                 mOnDiseqcMessageCalled = true;
241                 mDMCV.open();
242             }
243         }
244 
resetOnDiseqcMessageCalled()245         public void resetOnDiseqcMessageCalled() {
246             synchronized (mDMLock) {
247                 mOnDiseqcMessageCalled = false;
248             }
249         }
250 
getOnDiseqcMessageCalled()251         public boolean getOnDiseqcMessageCalled() {
252             try {
253                 // yield to let the callback handling execute
254                 Thread.sleep(SLEEP_TIME_MS);
255             } catch (Exception e) {
256                 // ignore exception
257             }
258 
259             synchronized (mDMLock) {
260                 mDMCV.block(TIMEOUT_MS);
261                 mDMCV.close();
262                 return mOnDiseqcMessageCalled;
263             }
264         }
265     }
266 
267     @Before
setUp()268     public void setUp() throws Exception {
269         mContext = InstrumentationRegistry.getTargetContext();
270         InstrumentationRegistry
271                 .getInstrumentation().getUiAutomation().adoptShellPermissionIdentity();
272         mTuner = new Tuner(mContext, null, 100);
273     }
274 
275     @After
tearDown()276     public void tearDown() {
277         if (mTuner != null) {
278           mTuner.close();
279           mTuner = null;
280         }
281     }
282 
283     @Test
testTunerConstructor()284     public void testTunerConstructor() throws Exception {
285         assertNotNull(mTuner);
286     }
287 
288     @Test
testTunerVersion()289     public void testTunerVersion() {
290         assertNotNull(mTuner);
291         int version = TunerVersionChecker.getTunerVersion();
292         assertTrue(version >= TunerVersionChecker.TUNER_VERSION_1_0);
293         assertTrue(version <= TunerVersionChecker.TUNER_VERSION_2_0);
294     }
295 
296     @Test
testFrontendHardwareInfo()297     public void testFrontendHardwareInfo() throws Exception {
298         String hwInfo = null;
299         try {
300             hwInfo = mTuner.getCurrentFrontendHardwareInfo();
301             if (TunerVersionChecker.isHigherOrEqualVersionTo(
302                     TunerVersionChecker.TUNER_VERSION_2_0)) {
303                 fail("Get Frontend hardware info should throw IllegalStateException.");
304             } else {
305                 assertNull(hwInfo);
306             }
307         } catch (IllegalStateException e) {
308             // pass
309         }
310 
311         List<Integer> ids = mTuner.getFrontendIds();
312         if (ids == null) return;
313         assertFalse(ids.isEmpty());
314 
315         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
316         int res = mTuner.tune(createFrontendSettings(info));
317         hwInfo = mTuner.getCurrentFrontendHardwareInfo();
318         if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) {
319             assertNotNull(hwInfo);
320             assertFalse(hwInfo.isEmpty());
321         } else {
322             assertNull(hwInfo);
323         }
324         res = mTuner.cancelTuning();
325         assertEquals(Tuner.RESULT_SUCCESS, res);
326     }
327 
328     @Test
testTuning()329     public void testTuning() throws Exception {
330         List<Integer> ids = mTuner.getFrontendIds();
331         if (ids == null) return;
332         assertFalse(ids.isEmpty());
333 
334         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
335         int res = mTuner.tune(createFrontendSettings(info));
336         assertEquals(Tuner.RESULT_SUCCESS, res);
337         res = mTuner.setLnaEnabled(false);
338         assertTrue((res == Tuner.RESULT_SUCCESS) || (res == Tuner.RESULT_UNAVAILABLE));
339         res = mTuner.cancelTuning();
340         assertEquals(Tuner.RESULT_SUCCESS, res);
341     }
342 
343     @Test
testMultiTuning()344     public void testMultiTuning() throws Exception {
345         List<Integer> ids = mTuner.getFrontendIds();
346         if (ids == null) return;
347         assertFalse(ids.isEmpty());
348 
349         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
350         int res = mTuner.tune(createFrontendSettings(info));
351         assertEquals(Tuner.RESULT_SUCCESS, res);
352         res = mTuner.cancelTuning();
353         assertEquals(Tuner.RESULT_SUCCESS, res);
354 
355         // Tune again with the same frontend.
356         mTuner.tune(createFrontendSettings(info));
357         assertEquals(Tuner.RESULT_SUCCESS, res);
358         res = mTuner.cancelTuning();
359         assertEquals(Tuner.RESULT_SUCCESS, res);
360 
361         for (int i = 1; i < ids.size(); i++) {
362             FrontendInfo info2 = mTuner.getFrontendInfoById(ids.get(i));
363             if (info2.getType() != info.getType()) {
364                 res = mTuner.tune(createFrontendSettings(info2));
365                 assertEquals(Tuner.RESULT_INVALID_STATE, res);
366             }
367         }
368     }
369 
370     @Test
testScanning()371     public void testScanning() throws Exception {
372         // Use the same test approach as testTune since it is not possible to test all frontends on
373         // one signal source
374         List<Integer> ids = mTuner.getFrontendIds();
375         if (ids == null) return;
376         assertFalse(ids.isEmpty());
377 
378         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
379         int res = mTuner.scan(
380                         createFrontendSettings(info),
381                         Tuner.SCAN_TYPE_AUTO,
382                         getExecutor(),
383                         getScanCallback());
384         assertEquals(Tuner.RESULT_SUCCESS, res);
385         res = mTuner.cancelScanning();
386         assertEquals(Tuner.RESULT_SUCCESS, res);
387     }
388 
389     @Test
testFrontendStatus()390     public void testFrontendStatus() throws Exception {
391         List<Integer> ids = mTuner.getFrontendIds();
392         if (ids == null) return;
393         assertFalse(ids.isEmpty());
394 
395         for (int id : ids) {
396             Tuner tuner = new Tuner(mContext, null, 100);
397             FrontendInfo info = tuner.getFrontendInfoById(id);
398             int res = tuner.tune(createFrontendSettings(info));
399 
400             int[] statusCapabilities = info.getStatusCapabilities();
401             assertNotNull(statusCapabilities);
402             FrontendStatus status = tuner.getFrontendStatus(statusCapabilities);
403             assertNotNull(status);
404 
405             for (int i = 0; i < statusCapabilities.length; i++) {
406                 switch (statusCapabilities[i]) {
407                     case FrontendStatus.FRONTEND_STATUS_TYPE_DEMOD_LOCK:
408                         status.isDemodLocked();
409                         break;
410                     case FrontendStatus.FRONTEND_STATUS_TYPE_SNR:
411                         status.getSnr();
412                         break;
413                     case FrontendStatus.FRONTEND_STATUS_TYPE_BER:
414                         status.getBer();
415                         break;
416                     case FrontendStatus.FRONTEND_STATUS_TYPE_PER:
417                         status.getPer();
418                         break;
419                     case FrontendStatus.FRONTEND_STATUS_TYPE_PRE_BER:
420                         status.getPerBer();
421                         break;
422                     case FrontendStatus.FRONTEND_STATUS_TYPE_SIGNAL_QUALITY:
423                         status.getSignalQuality();
424                         break;
425                     case FrontendStatus.FRONTEND_STATUS_TYPE_SIGNAL_STRENGTH:
426                         status.getSignalStrength();
427                         break;
428                     case FrontendStatus.FRONTEND_STATUS_TYPE_SYMBOL_RATE:
429                         status.getSymbolRate();
430                         break;
431                     case FrontendStatus.FRONTEND_STATUS_TYPE_FEC:
432                         status.getInnerFec();
433                         break;
434                     case FrontendStatus.FRONTEND_STATUS_TYPE_MODULATION:
435                         if (info.getType() != FrontendSettings.TYPE_DVBT)
436                             status.getModulation();
437                         break;
438                     case FrontendStatus.FRONTEND_STATUS_TYPE_SPECTRAL:
439                         status.getSpectralInversion();
440                         break;
441                     case FrontendStatus.FRONTEND_STATUS_TYPE_LNB_VOLTAGE:
442                         status.getLnbVoltage();
443                         break;
444                     case FrontendStatus.FRONTEND_STATUS_TYPE_PLP_ID:
445                         status.getPlpId();
446                         break;
447                     case FrontendStatus.FRONTEND_STATUS_TYPE_EWBS:
448                         status.isEwbs();
449                         break;
450                     case FrontendStatus.FRONTEND_STATUS_TYPE_AGC:
451                         status.getAgc();
452                         break;
453                     case FrontendStatus.FRONTEND_STATUS_TYPE_LNA:
454                         status.isLnaOn();
455                         break;
456                     case FrontendStatus.FRONTEND_STATUS_TYPE_LAYER_ERROR:
457                         boolean[] r = status.getLayerErrors();
458                         assertNotNull(r);
459                         break;
460                     case FrontendStatus.FRONTEND_STATUS_TYPE_MER:
461                         status.getMer();
462                         break;
463                     case FrontendStatus.FRONTEND_STATUS_TYPE_FREQ_OFFSET:
464                         status.getFreqOffsetLong();
465                         status.getFreqOffset();
466                         break;
467                     case FrontendStatus.FRONTEND_STATUS_TYPE_HIERARCHY:
468                         status.getHierarchy();
469                         break;
470                     case FrontendStatus.FRONTEND_STATUS_TYPE_RF_LOCK:
471                         status.isRfLocked();
472                         break;
473                     case FrontendStatus.FRONTEND_STATUS_TYPE_ATSC3_PLP_INFO:
474                         Atsc3PlpTuningInfo[] tuningInfos = status.getAtsc3PlpTuningInfo();
475                         if (tuningInfos != null) {
476                             for (Atsc3PlpTuningInfo tuningInfo : tuningInfos) {
477                                 tuningInfo.getPlpId();
478                                 tuningInfo.isLocked();
479                                 tuningInfo.getUec();
480                             }
481                         }
482                         break;
483                     case FrontendStatus.FRONTEND_STATUS_TYPE_BERS:
484                         int[] b = status.getBers();
485                         assertNotNull(b);
486                         break;
487                     case FrontendStatus.FRONTEND_STATUS_TYPE_CODERATES:
488                         int[] c = status.getCodeRates();
489                         assertNotNull(c);
490                         break;
491                     case FrontendStatus.FRONTEND_STATUS_TYPE_BANDWIDTH:
492                         status.getBandwidth();
493                         break;
494                     case FrontendStatus.FRONTEND_STATUS_TYPE_GUARD_INTERVAL:
495                         status.getGuardInterval();
496                         break;
497                     case FrontendStatus.FRONTEND_STATUS_TYPE_TRANSMISSION_MODE:
498                         status.getTransmissionMode();
499                         break;
500                     case FrontendStatus.FRONTEND_STATUS_TYPE_UEC:
501                         status.getUec();
502                         break;
503                     case FrontendStatus.FRONTEND_STATUS_TYPE_T2_SYSTEM_ID:
504                         status.getSystemId();
505                         break;
506                     case FrontendStatus.FRONTEND_STATUS_TYPE_INTERLEAVINGS:
507                         int[] l = status.getInterleaving();
508                         assertNotNull(l);
509                         break;
510                     case FrontendStatus.FRONTEND_STATUS_TYPE_ISDBT_SEGMENTS:
511                         int[] segment = status.getIsdbtSegment();
512                         assertNotNull(segment);
513                         break;
514                     case FrontendStatus.FRONTEND_STATUS_TYPE_TS_DATA_RATES:
515                         int[] rates = status.getTsDataRate();
516                         assertNotNull(rates);
517                         break;
518                     case FrontendStatus.FRONTEND_STATUS_TYPE_MODULATIONS_EXT:
519                         int[] modulations = status.getExtendedModulations();
520                         assertNotNull(modulations);
521                         break;
522                     case FrontendStatus.FRONTEND_STATUS_TYPE_ROLL_OFF:
523                         status.getRollOff();
524                         break;
525                     case FrontendStatus.FRONTEND_STATUS_TYPE_IS_MISO_ENABLED:
526                         status.isMisoEnabled();
527                         break;
528                     case FrontendStatus.FRONTEND_STATUS_TYPE_IS_LINEAR:
529                         status.isLinear();
530                         break;
531                     case FrontendStatus.FRONTEND_STATUS_TYPE_IS_SHORT_FRAMES_ENABLED:
532                         status.isShortFramesEnabled();
533                         break;
534                     case FrontendStatus.FRONTEND_STATUS_TYPE_ISDBT_MODE:
535                         status.getIsdbtMode();
536                         break;
537                     case FrontendStatus.FRONTEND_STATUS_TYPE_ISDBT_PARTIAL_RECEPTION_FLAG:
538                         status.getIsdbtPartialReceptionFlag();
539                         break;
540                     case FrontendStatus.FRONTEND_STATUS_TYPE_STREAM_IDS:
541                         int[] streamIds = status.getStreamIds();
542                         assertNotNull(streamIds);
543                         break;
544                     case FrontendStatus.FRONTEND_STATUS_TYPE_DVBT_CELL_IDS:
545                         int[] cellIds = status.getDvbtCellIds();
546                         assertNotNull(cellIds);
547                         break;
548                     case FrontendStatus.FRONTEND_STATUS_TYPE_ATSC3_ALL_PLP_INFO:
549                         List<Atsc3PlpInfo> plps = status.getAllAtsc3PlpInfo();
550                         assertFalse(plps.isEmpty());
551                         break;
552                 }
553             }
554             tuner.close();
555             tuner = null;
556         }
557     }
558 
559     @Test
testFrontendStatusReadiness()560     public void testFrontendStatusReadiness() throws Exception {
561         // Test w/o active frontend
562         try {
563             int[] caps = {0};
564             List<FrontendStatusReadiness> readiness = mTuner.getFrontendStatusReadiness(caps);
565             if (TunerVersionChecker.isHigherOrEqualVersionTo(
566                         TunerVersionChecker.TUNER_VERSION_2_0)) {
567                 fail("Get Frontend Status Readiness should throw IllegalStateException.");
568             } else {
569                 assertTrue(readiness.isEmpty());
570             }
571         } catch (IllegalStateException e) {
572             // pass
573         }
574 
575         List<Integer> ids = mTuner.getFrontendIds();
576         if (ids == null)
577             return;
578         assertFalse(ids.isEmpty());
579 
580         for (int id : ids) {
581             Tuner tuner = new Tuner(mContext, null, 100);
582             FrontendInfo info = tuner.getFrontendInfoById(id);
583             int res = tuner.tune(createFrontendSettings(info));
584 
585             int[] statusCapabilities = info.getStatusCapabilities();
586             assertNotNull(statusCapabilities);
587             List<FrontendStatusReadiness> readiness =
588                     tuner.getFrontendStatusReadiness(statusCapabilities);
589             if (TunerVersionChecker.isHigherOrEqualVersionTo(
590                         TunerVersionChecker.TUNER_VERSION_2_0)) {
591                 assertEquals(readiness.size(), statusCapabilities.length);
592                 for (int i = 0; i < readiness.size(); i++) {
593                     assertEquals(readiness.get(i).getStatusType(), statusCapabilities[i]);
594                     int r = readiness.get(i).getStatusReadiness();
595                     if (r == FrontendStatusReadiness.FRONTEND_STATUS_READINESS_UNAVAILABLE
596                             || r == FrontendStatusReadiness.FRONTEND_STATUS_READINESS_UNSTABLE
597                             || r == FrontendStatusReadiness.FRONTEND_STATUS_READINESS_STABLE) {
598                         // pass
599                     } else {
600                         fail("Get Frontend Status Readiness returned wrong readiness " + r);
601                     }
602                 }
603             } else {
604                 assertTrue(readiness.isEmpty());
605             }
606             tuner.cancelTuning();
607             tuner.close();
608             tuner = null;
609         }
610     }
611 
612     @Test
testLnb()613     public void testLnb() throws Exception {
614         Lnb lnb = mTuner.openLnb(getExecutor(), getLnbCallback());
615         if (lnb == null) return;
616         assertEquals(lnb.setVoltage(Lnb.VOLTAGE_5V), Tuner.RESULT_SUCCESS);
617         assertEquals(lnb.setTone(Lnb.TONE_NONE), Tuner.RESULT_SUCCESS);
618         assertEquals(
619                 lnb.setSatellitePosition(Lnb.POSITION_A), Tuner.RESULT_SUCCESS);
620         lnb.sendDiseqcMessage(new byte[] {1, 2});
621         lnb.close();
622     }
623 
624     @Test
testLnbAddAndRemoveCallback()625     public void testLnbAddAndRemoveCallback() throws Exception {
626         TunerTestLnbCallback lnbCB1 = new TunerTestLnbCallback();
627         Lnb lnb = mTuner.openLnb(getExecutor(), lnbCB1);
628         if (lnb == null) {
629             return;
630         }
631 
632         assertEquals(lnb.setVoltage(Lnb.VOLTAGE_5V), Tuner.RESULT_SUCCESS);
633         assertEquals(lnb.setTone(Lnb.TONE_NONE), Tuner.RESULT_SUCCESS);
634         assertEquals(
635                 lnb.setSatellitePosition(Lnb.POSITION_A), Tuner.RESULT_SUCCESS);
636         lnb.sendDiseqcMessage(new byte[] {1, 2});
637         assertTrue(lnbCB1.getOnDiseqcMessageCalled());
638         lnbCB1.resetOnDiseqcMessageCalled();
639 
640         List<Integer> ids = mTuner.getFrontendIds();
641         assertFalse(ids.isEmpty());
642         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
643         FrontendSettings feSettings = createFrontendSettings(info);
644         int res = mTuner.tune(feSettings);
645         assertEquals(Tuner.RESULT_SUCCESS, res);
646 
647         // create sharee
648         Tuner sharee = new Tuner(mContext, null, 100);
649         sharee.shareFrontendFromTuner(mTuner);
650         TunerTestLnbCallback lnbCB2 = new TunerTestLnbCallback();
651 
652         // add it as sharee
653         lnb.addCallback(getExecutor(), lnbCB2);
654 
655         // check callback
656         lnb.sendDiseqcMessage(new byte[] {1, 2});
657         assertTrue(lnbCB1.getOnDiseqcMessageCalled());
658         lnbCB1.resetOnDiseqcMessageCalled();
659         assertTrue(lnbCB2.getOnDiseqcMessageCalled());
660         lnbCB2.resetOnDiseqcMessageCalled();
661 
662         // remove sharee the sharee (should succeed)
663         assertTrue(lnb.removeCallback(lnbCB2));
664 
665         // check callback (only the original owner gets callback
666         lnb.sendDiseqcMessage(new byte[] {1, 2});
667         assertTrue(lnbCB1.getOnDiseqcMessageCalled());
668         lnbCB1.resetOnDiseqcMessageCalled();
669         assertFalse(lnbCB2.getOnDiseqcMessageCalled());
670         lnbCB2.resetOnDiseqcMessageCalled();
671 
672         sharee.close();
673     }
674 
675     @Test
testOpenLnbByname()676     public void testOpenLnbByname() throws Exception {
677         Lnb lnb = mTuner.openLnbByName("default", getExecutor(), getLnbCallback());
678         if (lnb != null) {
679             lnb.close();
680         }
681     }
682 
683     @Test
testCiCam()684     public void testCiCam() throws Exception {
685     // open filter to get demux resource
686         mTuner.openFilter(
687                 Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
688 
689         mTuner.connectCiCam(1);
690         mTuner.disconnectCiCam();
691     }
692 
693     @Test
testFrontendToCiCam()694     public void testFrontendToCiCam() throws Exception {
695         // tune to get frontend resource
696         List<Integer> ids = mTuner.getFrontendIds();
697         if (ids == null) return;
698         assertFalse(ids.isEmpty());
699         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
700         int res = mTuner.tune(createFrontendSettings(info));
701         assertEquals(Tuner.RESULT_SUCCESS, res);
702 
703         if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
704             // TODO: get real CiCam id from MediaCas
705             // only tuner hal1.1 support CiCam
706             res = mTuner.connectFrontendToCiCam(0);
707             if (res != Tuner.INVALID_LTS_ID)
708                 assertEquals(mTuner.disconnectFrontendToCiCam(0), Tuner.RESULT_SUCCESS);
709         }
710     }
711 
712     @Test
testRemoveOutputPid()713     public void testRemoveOutputPid() throws Exception {
714         // Test w/o active frontend
715         try {
716             int status = mTuner.removeOutputPid(10);
717             if (TunerVersionChecker.isHigherOrEqualVersionTo(
718                         TunerVersionChecker.TUNER_VERSION_2_0)) {
719                 fail("Remove output PID should throw IllegalStateException.");
720             } else {
721                 assertEquals(status, Tuner.RESULT_UNAVAILABLE);
722             }
723         } catch (IllegalStateException e) {
724             // pass
725         }
726 
727         // tune to get frontend resource
728         List<Integer> ids = mTuner.getFrontendIds();
729         if (ids == null)
730             return;
731         assertFalse(ids.isEmpty());
732         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
733         int res = mTuner.tune(createFrontendSettings(info));
734         assertEquals(Tuner.RESULT_SUCCESS, res);
735 
736         if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
737             // TODO: get real CiCam id from MediaCas
738             res = mTuner.connectFrontendToCiCam(0);
739         } else {
740             assertEquals(Tuner.INVALID_LTS_ID, mTuner.connectFrontendToCiCam(0));
741         }
742 
743         int status = mTuner.removeOutputPid(10);
744         if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) {
745             if (status != Tuner.RESULT_SUCCESS) {
746                 assertEquals(status, Tuner.RESULT_UNAVAILABLE);
747             }
748         } else {
749             assertEquals(status, Tuner.RESULT_UNAVAILABLE);
750         }
751 
752         if (res != Tuner.INVALID_LTS_ID) {
753             assertEquals(mTuner.disconnectFrontendToCiCam(0), Tuner.RESULT_SUCCESS);
754         } else {
755             // Make sure the connectFrontendToCiCam only fails because the current device
756             // does not support connecting frontend to cicam
757             assertEquals(mTuner.disconnectFrontendToCiCam(0), Tuner.RESULT_UNAVAILABLE);
758         }
759     }
760 
761     @Test
testAvSyncId()762     public void testAvSyncId() throws Exception {
763     // open filter to get demux resource
764         Filter f = mTuner.openFilter(
765                 Filter.TYPE_TS, Filter.SUBTYPE_AUDIO, 1000, getExecutor(), getFilterCallback());
766         assertNotNull(f);
767         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
768         Settings settings = AvSettings
769                 .builder(Filter.TYPE_TS, true)
770                 .setPassthrough(false)
771                 .setUseSecureMemory(false)
772                 .setAudioStreamType(AvSettings.AUDIO_STREAM_TYPE_MPEG1)
773                 .build();
774         FilterConfiguration config = TsFilterConfiguration
775                 .builder()
776                 .setTpid(10)
777                 .setSettings(settings)
778                 .build();
779         f.configure(config);
780         int id = mTuner.getAvSyncHwId(f);
781         if (id != Tuner.INVALID_AV_SYNC_ID) {
782             assertNotEquals(Tuner.INVALID_TIMESTAMP, mTuner.getAvSyncTime(id));
783         }
784     }
785 
786     @Test
testReadFilter()787     public void testReadFilter() throws Exception {
788         Filter f = mTuner.openFilter(
789                 Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
790         assertNotNull(f);
791         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
792         if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
793             assertNotEquals(Tuner.INVALID_FILTER_ID_LONG, f.getIdLong());
794         } else {
795             assertEquals(Tuner.INVALID_FILTER_ID_LONG, f.getIdLong());
796         }
797 
798         Settings settings = SectionSettingsWithTableInfo
799                 .builder(Filter.TYPE_TS)
800                 .setTableId(2)
801                 .setVersion(1)
802                 .setCrcEnabled(true)
803                 .setRaw(false)
804                 .setRepeat(false)
805                 .build();
806         FilterConfiguration config = TsFilterConfiguration
807                 .builder()
808                 .setTpid(10)
809                 .setSettings(settings)
810                 .build();
811         f.configure(config);
812         f.setMonitorEventMask(
813                 Filter.MONITOR_EVENT_SCRAMBLING_STATUS | Filter.MONITOR_EVENT_IP_CID_CHANGE);
814 
815         // Tune a frontend before start the filter
816         List<Integer> ids = mTuner.getFrontendIds();
817         if (ids == null) return;
818         assertFalse(ids.isEmpty());
819 
820         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
821         int res = mTuner.tune(createFrontendSettings(info));
822         assertEquals(Tuner.RESULT_SUCCESS, res);
823 
824         f.start();
825         f.flush();
826         f.read(new byte[3], 0, 3);
827         f.stop();
828         f.close();
829 
830         res = mTuner.cancelTuning();
831         assertEquals(Tuner.RESULT_SUCCESS, res);
832     }
833 
834     @Test
testAudioFilterStreamTypeConfig()835     public void testAudioFilterStreamTypeConfig() throws Exception {
836         Filter f = mTuner.openFilter(
837                 Filter.TYPE_TS, Filter.SUBTYPE_AUDIO, 1000, getExecutor(), getFilterCallback());
838         assertNotNull(f);
839         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
840 
841         Settings settings = AvSettings
842                 .builder(Filter.TYPE_TS, true)
843                 .setPassthrough(false)
844                 .setUseSecureMemory(false)
845                 .setAudioStreamType(AvSettings.AUDIO_STREAM_TYPE_MPEG1)
846                 .build();
847         FilterConfiguration config = TsFilterConfiguration
848                 .builder()
849                 .setTpid(10)
850                 .setSettings(settings)
851                 .build();
852         f.configure(config);
853 
854         // Tune a frontend before start the filter
855         List<Integer> ids = mTuner.getFrontendIds();
856         if (ids == null) return;
857         assertFalse(ids.isEmpty());
858 
859         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
860         int res = mTuner.tune(createFrontendSettings(info));
861         assertEquals(Tuner.RESULT_SUCCESS, res);
862 
863         f.start();
864         f.flush();
865         f.stop();
866         f.close();
867 
868         res = mTuner.cancelTuning();
869         assertEquals(Tuner.RESULT_SUCCESS, res);
870     }
871 
872     @Test
testTimeFilter()873     public void testTimeFilter() throws Exception {
874         if (!mTuner.getDemuxCapabilities().isTimeFilterSupported()) return;
875         TimeFilter f = mTuner.openTimeFilter();
876         assertNotNull(f);
877         f.setCurrentTimestamp(0);
878         assertNotEquals(Tuner.INVALID_TIMESTAMP, f.getTimeStamp());
879         assertNotEquals(Tuner.INVALID_TIMESTAMP, f.getSourceTime());
880         f.clearTimestamp();
881         f.close();
882     }
883 
884     @Test
testIpFilter()885     public void testIpFilter() throws Exception {
886         Filter f = mTuner.openFilter(
887                 Filter.TYPE_IP, Filter.SUBTYPE_IP, 1000, getExecutor(), getFilterCallback());
888         if (f == null) return;
889         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
890 
891         FilterConfiguration config = IpFilterConfiguration
892                 .builder()
893                 .setSrcIpAddress(new byte[] {(byte) 0xC0, (byte) 0xA8, 0, 1})
894                 .setDstIpAddress(new byte[] {(byte) 0xC0, (byte) 0xA8, 3, 4})
895                 .setSrcPort(33)
896                 .setDstPort(23)
897                 .setPassthrough(false)
898                 .setSettings(null)
899                 .setIpFilterContextId(1)
900                 .build();
901         f.configure(config);
902 
903         // Tune a frontend before start the filter
904         List<Integer> ids = mTuner.getFrontendIds();
905         if (ids == null) return;
906         assertFalse(ids.isEmpty());
907 
908         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
909         int res = mTuner.tune(createFrontendSettings(info));
910         assertEquals(Tuner.RESULT_SUCCESS, res);
911 
912         f.start();
913         f.stop();
914         f.close();
915 
916         res = mTuner.cancelTuning();
917         assertEquals(Tuner.RESULT_SUCCESS, res);
918     }
919 
920     @Test
testAlpSectionFilterConfig()921     public void testAlpSectionFilterConfig() throws Exception {
922         Filter f = mTuner.openFilter(
923                 Filter.TYPE_ALP, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
924         if (f == null) return;
925         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
926 
927         SectionSettingsWithSectionBits settings =
928                 SectionSettingsWithSectionBits
929                         .builder(Filter.TYPE_TS)
930                         .setCrcEnabled(true)
931                         .setRepeat(false)
932                         .setRaw(false)
933                         .setFilter(new byte[]{2, 3, 4})
934                         .setMask(new byte[]{7, 6, 5, 4})
935                         .setMode(new byte[]{22, 55, 33})
936                         .build();
937         AlpFilterConfiguration config =
938                 AlpFilterConfiguration
939                         .builder()
940                         .setPacketType(AlpFilterConfiguration.PACKET_TYPE_COMPRESSED)
941                         .setLengthType(AlpFilterConfiguration.LENGTH_TYPE_WITH_ADDITIONAL_HEADER)
942                         .setSettings(settings)
943                         .build();
944         f.configure(config);
945         f.start();
946         f.stop();
947         f.close();
948     }
949 
950     @Test
testMmtpPesFilterConfig()951     public void testMmtpPesFilterConfig() throws Exception {
952         Filter f = mTuner.openFilter(
953                 Filter.TYPE_MMTP, Filter.SUBTYPE_PES, 1000, getExecutor(), getFilterCallback());
954         if (f == null) return;
955         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
956 
957         PesSettings settings =
958                 PesSettings
959                         .builder(Filter.TYPE_TS)
960                         .setStreamId(3)
961                         .setRaw(false)
962                         .build();
963         MmtpFilterConfiguration config =
964                 MmtpFilterConfiguration
965                         .builder()
966                         .setMmtpPacketId(3)
967                         .setSettings(settings)
968                         .build();
969         f.configure(config);
970         f.start();
971         f.stop();
972         f.close();
973     }
974 
975     @Test
testMmtpDownloadFilterConfig()976     public void testMmtpDownloadFilterConfig() throws Exception {
977         Filter f = mTuner.openFilter(
978                 Filter.TYPE_MMTP, Filter.SUBTYPE_DOWNLOAD,
979                 1000, getExecutor(), getFilterCallback());
980         if (f == null) return;
981         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
982 
983         DownloadSettings.Builder builder = DownloadSettings.builder(Filter.TYPE_MMTP);
984         if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
985             builder.setUseDownloadId(true);
986         }
987         builder.setDownloadId(2);
988         DownloadSettings settings = builder.build();
989         if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
990             assertEquals(settings.useDownloadId(), true);
991         } else {
992             assertEquals(settings.useDownloadId(), false);
993         }
994         assertEquals(settings.getDownloadId(), 2);
995 
996         MmtpFilterConfiguration config =
997                 MmtpFilterConfiguration
998                         .builder()
999                         .setMmtpPacketId(3)
1000                         .setSettings(settings)
1001                         .build();
1002         f.configure(config);
1003         f.start();
1004         f.stop();
1005         f.close();
1006     }
1007 
1008     @Test
testTsAvFilterConfig()1009     public void testTsAvFilterConfig() throws Exception {
1010         Filter f = mTuner.openFilter(
1011                 Filter.TYPE_TS, Filter.SUBTYPE_AUDIO, 1000, getExecutor(), getFilterCallback());
1012         assertNotNull(f);
1013         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
1014 
1015         AvSettings settings =
1016                 AvSettings
1017                         .builder(Filter.TYPE_TS, true) // is Audio
1018                         .setPassthrough(false)
1019                         .setUseSecureMemory(false)
1020                         .setAudioStreamType(AvSettings.AUDIO_STREAM_TYPE_MPEG1)
1021                         .build();
1022         TsFilterConfiguration config =
1023                 TsFilterConfiguration
1024                         .builder()
1025                         .setTpid(521)
1026                         .setSettings(settings)
1027                         .build();
1028         f.configure(config);
1029         f.start();
1030         f.stop();
1031         f.close();
1032     }
1033 
1034     @Test
testTsRecordFilterConfig()1035     public void testTsRecordFilterConfig() throws Exception {
1036         Filter f = mTuner.openFilter(
1037                 Filter.TYPE_TS, Filter.SUBTYPE_RECORD, 1000, getExecutor(), getFilterCallback());
1038         assertNotNull(f);
1039         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
1040 
1041         RecordSettings settings =
1042                 RecordSettings
1043                         .builder(Filter.TYPE_TS)
1044                         .setTsIndexMask(
1045                                 RecordSettings.TS_INDEX_FIRST_PACKET
1046                                         | RecordSettings.TS_INDEX_PRIVATE_DATA)
1047                         .setScIndexType(RecordSettings.INDEX_TYPE_SC)
1048                         .setScIndexMask(RecordSettings.SC_INDEX_B_SLICE)
1049                         .build();
1050         TsFilterConfiguration config =
1051                 TsFilterConfiguration
1052                         .builder()
1053                         .setTpid(521)
1054                         .setSettings(settings)
1055                         .build();
1056         f.configure(config);
1057         f.start();
1058         f.stop();
1059         f.close();
1060     }
1061 
1062     @Test
testTlvTlvFilterConfig()1063     public void testTlvTlvFilterConfig() throws Exception {
1064         Filter f = mTuner.openFilter(
1065                 Filter.TYPE_TLV, Filter.SUBTYPE_TLV, 1000, getExecutor(), getFilterCallback());
1066         if (f == null) return;
1067         assertNotEquals(Tuner.INVALID_FILTER_ID, f.getId());
1068 
1069         TlvFilterConfiguration config =
1070                 TlvFilterConfiguration
1071                         .builder()
1072                         .setPacketType(TlvFilterConfiguration.PACKET_TYPE_IPV4)
1073                         .setCompressedIpPacket(true)
1074                         .setPassthrough(false)
1075                         .setSettings(null)
1076                         .build();
1077         f.configure(config);
1078         f.start();
1079         f.stop();
1080         f.close();
1081     }
1082 
1083     @Test
testDescrambler()1084     public void testDescrambler() throws Exception {
1085         Descrambler d = mTuner.openDescrambler();
1086         byte[] keyToken = new byte[] {1, 3, 2};
1087         assertNotNull(d);
1088         Filter f = mTuner.openFilter(
1089                 Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
1090         assertTrue(d.isValidKeyToken(keyToken));
1091         d.setKeyToken(keyToken);
1092         d.addPid(Descrambler.PID_TYPE_T, 1, f);
1093         d.removePid(Descrambler.PID_TYPE_T, 1, f);
1094         f.close();
1095         d.close();
1096     }
1097 
1098     @Test
testDescramblerKeyTokenValidator()1099     public void testDescramblerKeyTokenValidator() throws Exception {
1100         byte[] invalidToken = new byte[17];
1101         byte[] validToken = new byte[] {1, 3, 2};
1102         assertTrue(Descrambler.isValidKeyToken(validToken));
1103         assertTrue(Descrambler.isValidKeyToken(Tuner.VOID_KEYTOKEN));
1104         assertFalse(Descrambler.isValidKeyToken(invalidToken));
1105     }
1106 
1107     @Test
testOpenDvrRecorder()1108     public void testOpenDvrRecorder() throws Exception {
1109         DvrRecorder d = mTuner.openDvrRecorder(100, getExecutor(), getRecordListener());
1110         assertNotNull(d);
1111         d.close();
1112     }
1113 
1114     @Test
testOpenDvPlayback()1115     public void testOpenDvPlayback() throws Exception {
1116         DvrPlayback d = mTuner.openDvrPlayback(100, getExecutor(), getPlaybackListener());
1117         assertNotNull(d);
1118         d.close();
1119     }
1120 
1121     @Test
testDemuxCapabilities()1122     public void testDemuxCapabilities() throws Exception {
1123         DemuxCapabilities d = mTuner.getDemuxCapabilities();
1124         assertNotNull(d);
1125 
1126         d.getDemuxCount();
1127         d.getRecordCount();
1128         d.getPlaybackCount();
1129         d.getTsFilterCount();
1130         d.getSectionFilterCount();
1131         d.getAudioFilterCount();
1132         d.getVideoFilterCount();
1133         d.getPesFilterCount();
1134         d.getPcrFilterCount();
1135         d.getSectionFilterLength();
1136         d.getFilterCapabilities();
1137         d.getLinkCapabilities();
1138         d.isTimeFilterSupported();
1139     }
1140 
1141     @Test
testResourceLostListener()1142     public void testResourceLostListener() throws Exception {
1143         mTuner.setResourceLostListener(getExecutor(), new Tuner.OnResourceLostListener() {
1144             @Override
1145             public void onResourceLost(Tuner tuner) {
1146             }
1147         });
1148         mTuner.clearResourceLostListener();
1149     }
1150 
1151     @Test
testOnTuneEventListener()1152     public void testOnTuneEventListener() throws Exception {
1153         mTuner.setOnTuneEventListener(getExecutor(), new OnTuneEventListener() {
1154             @Override
1155             public void onTuneEvent(int tuneEvent) {
1156             }
1157         });
1158         mTuner.clearOnTuneEventListener();
1159     }
1160 
1161     @Test
testUpdateResourcePriority()1162     public void testUpdateResourcePriority() throws Exception {
1163         mTuner.updateResourcePriority(100, 20);
1164     }
1165 
1166     @Test
testResourceReclaimed()1167     public void testResourceReclaimed() throws Exception {
1168         List<Integer> ids = mTuner.getFrontendIds();
1169         assertFalse(ids.isEmpty());
1170         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
1171         FrontendSettings feSettings = createFrontendSettings(info);
1172 
1173         // first tune with mTuner to acquire resource
1174         int res = mTuner.tune(feSettings);
1175         assertEquals(Tuner.RESULT_SUCCESS, res);
1176         assertNotNull(mTuner.getFrontendInfo());
1177 
1178         // now tune with a higher priority tuner to have mTuner's resource reclaimed
1179         Tuner higherPrioTuner = new Tuner(mContext, null, 200);
1180         res = higherPrioTuner.tune(feSettings);
1181         assertEquals(Tuner.RESULT_SUCCESS, res);
1182         assertNotNull(higherPrioTuner.getFrontendInfo());
1183 
1184         higherPrioTuner.close();
1185     }
1186 
1187     // TODO: change this to use ITunerResourceTestServer
1188     @Test
testResourceReclaimedDifferentThread()1189     public void testResourceReclaimedDifferentThread() throws Exception {
1190         List<Integer> ids = mTuner.getFrontendIds();
1191         assertFalse(ids.isEmpty());
1192         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
1193         FrontendSettings feSettings = createFrontendSettings(info);
1194 
1195         // first tune with mTuner to acquire resource
1196         int res = mTuner.tune(feSettings);
1197         assertEquals(Tuner.RESULT_SUCCESS, res);
1198         assertNotNull(mTuner.getFrontendInfo());
1199 
1200         // now tune with a higher priority tuner to have mTuner's resource reclaimed
1201         TunerHandler tunerHandler = createTunerHandler(null);
1202         Message msgCreate = new Message();
1203         msgCreate.what = MSG_TUNER_HANDLER_CREATE;
1204         msgCreate.arg1 = 200;
1205         tunerHandler.sendMessage(msgCreate);
1206         mTunerHandlerTaskComplete.block();
1207         mTunerHandlerTaskComplete.close();
1208 
1209         Message msgTune = new Message();
1210         msgTune.what = MSG_TUNER_HANDLER_TUNE;
1211         msgTune.obj = (Object) feSettings;
1212         tunerHandler.sendMessage(msgTune);
1213 
1214         // call mTuner.close in parallel
1215         int sleepMS = 1;
1216         //int sleepMS = (int) (Math.random() * 3.);
1217         try {
1218             Thread.sleep(sleepMS);
1219         } catch (Exception e) { } // ignore
1220         mTuner.close();
1221         mTuner = null;
1222 
1223         mTunerHandlerTaskComplete.block();
1224         mTunerHandlerTaskComplete.close();
1225         res = tunerHandler.getResult();
1226         assertEquals(Tuner.RESULT_SUCCESS, res);
1227 
1228         Tuner higherPrioTuner = tunerHandler.getTuner();
1229         assertNotNull(higherPrioTuner.getFrontendInfo());
1230 
1231         Message msgClose = new Message();
1232         msgClose.what = MSG_TUNER_HANDLER_CLOSE;
1233         tunerHandler.sendMessage(msgClose);
1234 
1235     }
1236 
1237     @Test
testResourceReclaimedDifferentProcess()1238     public void testResourceReclaimedDifferentProcess() throws Exception {
1239         List<Integer> ids = mTuner.getFrontendIds();
1240         int frontendIndex = 0;
1241         assertFalse(ids.isEmpty());
1242         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(frontendIndex));
1243         FrontendSettings feSettings = createFrontendSettings(info);
1244 
1245         // set up the test server
1246         TunerResourceTestServiceConnection connection = new TunerResourceTestServiceConnection();
1247         ITunerResourceTestServer tunerResourceTestServer = null;
1248         Intent intent = new Intent(mContext, TunerResourceTestService.class);
1249 
1250         // get the TunerResourceTestService
1251         mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
1252         tunerResourceTestServer = connection.getService();
1253 
1254         // CASE1 - normal reclaim
1255         //
1256         // first tune with mTuner to acquire resource
1257         int res = mTuner.tune(feSettings);
1258         boolean tunerReclaimed = false;
1259         assertEquals(Tuner.RESULT_SUCCESS, res);
1260         assertNotNull(mTuner.getFrontendInfo());
1261 
1262         // now tune with a higher priority tuner to have mTuner's resource reclaimed
1263 
1264         // create higher priority tuner
1265         tunerResourceTestServer.createTuner(200);
1266 
1267         // now tune on higher priority tuner to get mTuner reclaimed
1268         res = tunerResourceTestServer.tune(frontendIndex);
1269         assertEquals(Tuner.RESULT_SUCCESS, res);
1270 
1271         try {
1272             int[] statusCapabilities = info.getStatusCapabilities();
1273             mTuner.getFrontendStatus(statusCapabilities);
1274 
1275         } catch (IllegalStateException e) {
1276             tunerReclaimed = true;
1277             mTuner.close();
1278             mTuner = null;
1279         }
1280 
1281         // confirm if the mTuner is reclaimed
1282         assertTrue(tunerReclaimed);
1283 
1284         tunerResourceTestServer.closeTuner();
1285         assertTrue(tunerResourceTestServer.verifyTunerIsNull());
1286 
1287 
1288         // CASE2 - race between Tuner#close() and reclaim
1289         mTuner = new Tuner(mContext, null, 100);
1290         res = mTuner.tune(feSettings);
1291         assertEquals(Tuner.RESULT_SUCCESS, res);
1292         assertNotNull(mTuner.getFrontendInfo());
1293 
1294         tunerResourceTestServer.createTuner(200);
1295         tunerResourceTestServer.tuneAsync(frontendIndex);
1296 
1297         // adjust timing to induce race/deadlock
1298         int sleepMS = 4;
1299         //int sleepMS = (int) (Math.random() * 5.);
1300         try {
1301             Thread.sleep(sleepMS);
1302         } catch (Exception e) { } // ignore
1303         mTuner.close();
1304         mTuner = null;
1305 
1306         tunerResourceTestServer.closeTuner();
1307 
1308         // unbind
1309         mContext.unbindService(connection);
1310     }
1311 
1312     @Test
testShareFrontendFromTuner()1313     public void testShareFrontendFromTuner() throws Exception {
1314         Tuner tuner100 = new Tuner(mContext, null, 100);
1315         List<Integer> ids = tuner100.getFrontendIds();
1316         assertFalse(ids.isEmpty());
1317         FrontendInfo info = tuner100.getFrontendInfoById(ids.get(0));
1318         FrontendSettings feSettings = createFrontendSettings(info);
1319         int[] statusTypes = {1};
1320         boolean exceptionThrown = false;
1321         int res;
1322 
1323         // CASE1: check resource reclaim while sharee's priority < owner's priority
1324         // let tuner100 share from tuner200
1325         Tuner tuner200 = new Tuner(mContext, null, 200);
1326         res = tuner200.tune(feSettings);
1327         assertEquals(Tuner.RESULT_SUCCESS, res);
1328 
1329         info = tuner200.getFrontendInfoById(ids.get(0));
1330         res = tuner200.tune(feSettings);
1331         assertEquals(Tuner.RESULT_SUCCESS, res);
1332 
1333         tuner100 = new Tuner(mContext, null, 100);
1334         tuner100.shareFrontendFromTuner(tuner200);
1335         // call openFilter to trigger ITunerDemux.setFrontendDataSourceById()
1336         Filter f = tuner100.openFilter(
1337                 Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
1338         assertNotNull(f);
1339 
1340         // setup onTuneCallback
1341         TunerTestOnTuneEventListener cb100 = new TunerTestOnTuneEventListener();
1342         TunerTestOnTuneEventListener cb200 = new TunerTestOnTuneEventListener();
1343 
1344         // tune again on the owner
1345         info = tuner200.getFrontendInfoById(ids.get(1));
1346         tuner100.setOnTuneEventListener(getExecutor(), cb100);
1347         tuner200.setOnTuneEventListener(getExecutor(), cb200);
1348         res = tuner200.tune(feSettings);
1349         assertEquals(Tuner.RESULT_SUCCESS, res);
1350         assertEquals(OnTuneEventListener.SIGNAL_LOCKED, cb100.getLastTuneEvent());
1351         assertEquals(OnTuneEventListener.SIGNAL_LOCKED, cb200.getLastTuneEvent());
1352         tuner100.clearOnTuneEventListener();
1353         tuner200.clearOnTuneEventListener();
1354 
1355         // now let the higher priority tuner steal the resource
1356         Tuner tuner300 = new Tuner(mContext, null, 300);
1357         res = tuner300.tune(feSettings);
1358         assertEquals(Tuner.RESULT_SUCCESS, res);
1359 
1360         // confirm owner & sharee's resource gets reclaimed by confirming an exception is thrown
1361         exceptionThrown = false;
1362         try {
1363             tuner200.getFrontendStatus(statusTypes);
1364         } catch (Exception e) {
1365             exceptionThrown = true;
1366         }
1367         assertTrue(exceptionThrown);
1368 
1369         exceptionThrown = false;
1370         try {
1371             tuner100.getFrontendStatus(statusTypes);
1372         } catch (Exception e) {
1373             exceptionThrown = true;
1374         }
1375         assertTrue(exceptionThrown);
1376 
1377         tuner100.close();
1378         tuner200.close();
1379         tuner300.close();
1380 
1381 
1382         // CASE2: check resource reclaim fail when sharee's priority > new requester
1383         tuner100 = new Tuner(mContext, null, 100);
1384         res = tuner100.tune(feSettings);
1385         assertEquals(Tuner.RESULT_SUCCESS, res);
1386 
1387         tuner300 = new Tuner(mContext, null, 300);
1388         tuner300.shareFrontendFromTuner(tuner100);
1389         f = tuner100.openFilter(
1390                 Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, getExecutor(), getFilterCallback());
1391         assertNotNull(f);
1392 
1393         tuner200 = new Tuner(mContext, null, 200);
1394         res = tuner200.tune(feSettings);
1395         assertNotEquals(Tuner.RESULT_SUCCESS, res);
1396 
1397         // confirm the original tuner is still intact
1398         res = tuner100.tune(feSettings);
1399         assertEquals(Tuner.RESULT_SUCCESS, res);
1400 
1401         tuner100.close();
1402         tuner200.close();
1403         tuner300.close();
1404     }
1405 
testTransferFeOwnershipSingleTuner()1406     private void testTransferFeOwnershipSingleTuner() {
1407         List<Integer> ids = mTuner.getFrontendIds();
1408         if (ids == null) {
1409             return;
1410         }
1411         assertFalse(ids.isEmpty());
1412         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
1413         FrontendSettings feSettings = createFrontendSettings(info);
1414 
1415         // SCENARIO 1 - transfer and close the previous owner
1416 
1417         // First create a tuner and tune() to acquire frontend resource
1418         Tuner tunerA = new Tuner(mContext, null, 100);
1419         int res = tunerA.tune(feSettings);
1420         assertEquals(Tuner.RESULT_SUCCESS, res);
1421 
1422         // Create another tuner and share frontend from tunerA
1423         Tuner tunerB = new Tuner(mContext, null, 500);
1424         tunerB.shareFrontendFromTuner(tunerA);
1425         DvrRecorder d = tunerB.openDvrRecorder(100, getExecutor(), getRecordListener());
1426         assertNotNull(d);
1427 
1428         // Call transferOwner in the wrong configurations and confirm it fails
1429         assertEquals(Tuner.RESULT_INVALID_STATE, tunerB.transferOwner(tunerA));
1430         Tuner nonSharee = new Tuner(mContext, null, 300);
1431         assertEquals(Tuner.RESULT_INVALID_STATE, tunerA.transferOwner(nonSharee));
1432         nonSharee.close();
1433 
1434         // Now call it correctly to transfer ownership from tunerA to tunerB
1435         assertEquals(Tuner.RESULT_SUCCESS, tunerA.transferOwner(tunerB));
1436 
1437         // Close the original owner (tunerA)
1438         tunerA.close();
1439 
1440         // Confirm the new owner (tunerB) is still functional
1441         assertNotNull(tunerB.getFrontendInfo());
1442 
1443         // Close the new owner (tunerB)
1444         d.close();
1445         tunerB.close();
1446 
1447         // SCENARIO 2 - transfer and closeFrontend and tune on the previous owner
1448 
1449         // First create a tuner and tune() to acquire frontend resource
1450         tunerA = new Tuner(mContext, null, 200);
1451         res = tunerA.tune(feSettings);
1452         assertEquals(Tuner.RESULT_SUCCESS, res);
1453 
1454         // Create another tuner and share frontend from tunerA
1455         tunerB = new Tuner(mContext, null, 100);
1456         tunerB.shareFrontendFromTuner(tunerA);
1457         assertNotNull(tunerB.getFrontendInfo());
1458 
1459         // Transfer ownership from tunerA to tunerB
1460         assertEquals(Tuner.RESULT_SUCCESS, tunerA.transferOwner(tunerB));
1461 
1462         // Close frontend for the original owner (tunerA)
1463         tunerA.closeFrontend();
1464 
1465         // Confirm tune works without going through Tuner.close() even after transferOwner()
1466         // The purpose isn't to get tunerB's frontend revoked, but doing so as singletuner
1467         // based test has wider coverage
1468         res = tunerA.tune(feSettings); // this should reclaim tunerB
1469         assertEquals(Tuner.RESULT_SUCCESS, res);
1470 
1471         // Confirm tuberB is revoked
1472         assertNull(tunerB.getFrontendInfo());
1473 
1474         // Close tunerA
1475         tunerA.close();
1476 
1477         // close TunerB just in case
1478         tunerB.close();
1479     }
1480 
testTransferFeAndCiCamOwnership()1481     private void testTransferFeAndCiCamOwnership() {
1482         List<Integer> ids = mTuner.getFrontendIds();
1483         assertNotNull(ids);
1484         assertFalse(ids.isEmpty());
1485         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
1486         FrontendSettings feSettings = createFrontendSettings(info);
1487 
1488         // Create tuner and tune to get frontend resource
1489         Tuner tunerA = new Tuner(mContext, null, 100);
1490         assertEquals(Tuner.RESULT_SUCCESS, tunerA.tune(feSettings));
1491 
1492         int ciCamId = 0;
1493         boolean linkCiCamToFrontendSupported = false;
1494 
1495         // connect CiCam to Frontend
1496         if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
1497             // TODO: get real CiCam id from MediaCas
1498             assertEquals(Tuner.RESULT_SUCCESS, tunerA.connectFrontendToCiCam(ciCamId));
1499             linkCiCamToFrontendSupported = true;
1500         } else {
1501             assertEquals(Tuner.INVALID_LTS_ID, tunerA.connectFrontendToCiCam(ciCamId));
1502         }
1503 
1504         // connect CiCam to Demux
1505         assertEquals(Tuner.RESULT_SUCCESS, tunerA.connectCiCam(ciCamId));
1506 
1507         // start another tuner and connect the same CiCam to its own demux
1508         Tuner tunerB = new Tuner(mContext, null, 400);
1509         tunerB.shareFrontendFromTuner(tunerA);
1510         assertNotNull(tunerB.getFrontendInfo());
1511         assertEquals(Tuner.RESULT_SUCCESS, tunerB.connectCiCam(ciCamId));
1512 
1513         // unlink CiCam to Demux in tunerA and transfer ownership
1514         assertEquals(Tuner.RESULT_SUCCESS, tunerA.disconnectCiCam());
1515         assertEquals(Tuner.RESULT_SUCCESS, tunerA.transferOwner(tunerB));
1516 
1517         // close the original owner
1518         tunerA.close();
1519 
1520         // disconnect CiCam from demux
1521         assertEquals(Tuner.RESULT_SUCCESS, tunerB.disconnectCiCam());
1522 
1523         // let Tuner.close() handle the release of CiCam
1524         tunerB.close();
1525 
1526         // now that the CiCam is released, disconnectFrontendToCiCam() should fail
1527         assertEquals(Tuner.RESULT_UNAVAILABLE, tunerB.disconnectFrontendToCiCam(ciCamId));
1528 
1529         // see if tune still works just in case
1530         tunerA = new Tuner(mContext, null, 100);
1531         assertEquals(Tuner.RESULT_SUCCESS, tunerA.tune(feSettings));
1532         tunerA.close();
1533     }
1534 
testTransferFeAndLnbOwnership()1535     private void testTransferFeAndLnbOwnership() {
1536         List<Integer> ids = mTuner.getFrontendIds();
1537         assertNotNull(ids);
1538         assertFalse(ids.isEmpty());
1539         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
1540         FrontendSettings feSettings = createFrontendSettings(info);
1541 
1542         // Create tuner and tune to acquire frontend resource
1543         Tuner tunerA = new Tuner(mContext, null, 100);
1544         assertEquals(Tuner.RESULT_SUCCESS, tunerA.tune(feSettings));
1545 
1546         // Open Lnb and check the callback
1547         TunerTestLnbCallback lnbCB1 = new TunerTestLnbCallback();
1548         Lnb lnbA = tunerA.openLnb(getExecutor(), lnbCB1);
1549         assertNotNull(lnbA);
1550         lnbA.setVoltage(Lnb.VOLTAGE_5V);
1551         lnbA.setTone(Lnb.TONE_CONTINUOUS);
1552         lnbA.sendDiseqcMessage(new byte[] {1, 2});
1553         assertTrue(lnbCB1.getOnDiseqcMessageCalled());
1554         lnbCB1.resetOnDiseqcMessageCalled();
1555 
1556         // Create another tuner and share from tunerB
1557         Tuner tunerB = new Tuner(mContext, null, 300);
1558         tunerB.shareFrontendFromTuner(tunerA);
1559 
1560         // add sharee and check the callback
1561         TunerTestLnbCallback lnbCB2 = new TunerTestLnbCallback();
1562         lnbA.addCallback(getExecutor(), lnbCB2);
1563         lnbA.sendDiseqcMessage(new byte[] {1, 2});
1564         assertTrue(lnbCB1.getOnDiseqcMessageCalled());
1565         lnbCB1.resetOnDiseqcMessageCalled();
1566         assertTrue(lnbCB2.getOnDiseqcMessageCalled());
1567         lnbCB2.resetOnDiseqcMessageCalled();
1568 
1569         // transfer owner and check callback
1570         assertEquals(Tuner.RESULT_SUCCESS, tunerA.transferOwner(tunerB));
1571         lnbA.sendDiseqcMessage(new byte[] {1, 2});
1572         assertTrue(lnbCB1.getOnDiseqcMessageCalled());
1573         lnbCB1.resetOnDiseqcMessageCalled();
1574         assertTrue(lnbCB2.getOnDiseqcMessageCalled());
1575         lnbCB2.resetOnDiseqcMessageCalled();
1576 
1577         // remove the owner callback (just for testing)
1578         assertTrue(lnbA.removeCallback(lnbCB2));
1579 
1580         // remove sharee and check callback
1581         assertTrue(lnbA.removeCallback(lnbCB1));
1582         lnbA.sendDiseqcMessage(new byte[] {1, 2});
1583         assertFalse(lnbCB1.getOnDiseqcMessageCalled());
1584         lnbCB1.resetOnDiseqcMessageCalled();
1585         assertFalse(lnbCB2.getOnDiseqcMessageCalled());
1586         lnbCB2.resetOnDiseqcMessageCalled();
1587 
1588         // close the original owner
1589         tunerA.close();
1590 
1591         // confirm the new owner is still intact
1592         int[] statusCapabilities = info.getStatusCapabilities();
1593         assertNotNull(statusCapabilities);
1594         FrontendStatus status = tunerB.getFrontendStatus(statusCapabilities);
1595         assertNotNull(status);
1596 
1597         tunerB.close();
1598     }
1599 
1600     @Test
testTransferOwner()1601     public void testTransferOwner() throws Exception {
1602         testTransferFeOwnershipSingleTuner();
1603         testTransferFeAndCiCamOwnership();
1604         testTransferFeAndLnbOwnership();
1605     }
1606 
1607     @Test
testClose()1608     public void testClose() throws Exception {
1609         Tuner other = new Tuner(mContext, null, 100);
1610 
1611         List<Integer> ids = other.getFrontendIds();
1612         if (ids == null) return;
1613         assertFalse(ids.isEmpty());
1614         FrontendInfo info = other.getFrontendInfoById(ids.get(0));
1615 
1616         FrontendSettings feSettings = createFrontendSettings(info);
1617         int res = other.tune(feSettings);
1618         assertEquals(Tuner.RESULT_SUCCESS, res);
1619         assertNotNull(other.getFrontendInfo());
1620 
1621         other.close();
1622 
1623         // make sure pre-existing tuner is still functional
1624         res = mTuner.tune(feSettings);
1625         assertEquals(Tuner.RESULT_SUCCESS, res);
1626         assertNotNull(mTuner.getFrontendInfo());
1627 
1628         // Frontend sharing scenario 1: close owner first
1629         // create sharee
1630         Tuner sharee = new Tuner(mContext, null, 100);
1631         sharee.shareFrontendFromTuner(mTuner);
1632 
1633         // close the owner
1634         mTuner.close();
1635         mTuner = null;
1636 
1637         // check the frontend of sharee is also released
1638         assertNull(sharee.getFrontendInfo());
1639 
1640         sharee.close();
1641 
1642         // Frontend sharing scenario 2: close sharee first
1643         // create owner first
1644         mTuner = new Tuner(mContext, null, 100);
1645         res = mTuner.tune(feSettings);
1646         assertEquals(Tuner.RESULT_SUCCESS, res);
1647 
1648         // create sharee
1649         sharee = new Tuner(mContext, null, 100);
1650         sharee.shareFrontendFromTuner(mTuner);
1651 
1652         // close sharee
1653         sharee.close();
1654 
1655         // confirm owner is still intact
1656         int[] statusCapabilities = info.getStatusCapabilities();
1657         assertNotNull(statusCapabilities);
1658         FrontendStatus status = mTuner.getFrontendStatus(statusCapabilities);
1659         assertNotNull(status);
1660     }
1661 
1662     @Test
testCloseFrontend()1663     public void testCloseFrontend() throws Exception {
1664         List<Integer> ids = mTuner.getFrontendIds();
1665         if (ids == null) {
1666             return;
1667         }
1668 
1669         // SCENARIO 1 - without Lnb
1670         assertFalse(ids.isEmpty());
1671         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
1672         FrontendSettings feSettings = createFrontendSettings(info);
1673         int res = mTuner.tune(feSettings);
1674         assertEquals(Tuner.RESULT_SUCCESS, res);
1675         assertNotNull(mTuner.getFrontendInfo());
1676 
1677         // now close frontend
1678         mTuner.closeFrontend();
1679 
1680         // confirm frontend is closed
1681         int[] statusCapabilities = info.getStatusCapabilities();
1682         boolean frontendClosed = false;
1683         try {
1684             mTuner.getFrontendStatus(statusCapabilities);
1685 
1686         } catch (IllegalStateException e) {
1687             frontendClosed = true;
1688         }
1689         assertTrue(frontendClosed);
1690 
1691         // now tune to a different setting
1692         info = mTuner.getFrontendInfoById(ids.get(1));
1693         feSettings = createFrontendSettings(info);
1694         mTuner.tune(feSettings);
1695         assertEquals(Tuner.RESULT_SUCCESS, res);
1696         assertNotNull(mTuner.getFrontendInfo());
1697         FrontendStatus status = mTuner.getFrontendStatus(statusCapabilities);
1698         assertNotNull(status);
1699 
1700         // SCENARIO 2 - with Lnb
1701 
1702         TunerTestLnbCallback lnbCB1 = new TunerTestLnbCallback();
1703         Lnb lnb = mTuner.openLnb(getExecutor(), lnbCB1);
1704         if (lnb == null) {
1705             return;
1706         }
1707 
1708         mTuner.closeFrontend();
1709         // confirm frontend is closed
1710         statusCapabilities = info.getStatusCapabilities();
1711         frontendClosed = false;
1712         try {
1713             mTuner.getFrontendStatus(statusCapabilities);
1714 
1715         } catch (IllegalStateException e) {
1716             frontendClosed = true;
1717         }
1718         assertTrue(frontendClosed);
1719 
1720         info = mTuner.getFrontendInfoById(ids.get(0));
1721         feSettings = createFrontendSettings(info);
1722         mTuner.tune(feSettings);
1723         assertEquals(Tuner.RESULT_SUCCESS, res);
1724         assertNotNull(mTuner.getFrontendInfo());
1725         status = mTuner.getFrontendStatus(statusCapabilities);
1726         assertNotNull(status);
1727     }
1728 
1729     @Test
testHasUnusedFrontend1()1730     public void testHasUnusedFrontend1() throws Exception {
1731         prepTRMCustomFeResourceMapTest();
1732 
1733         // Use try block to ensure restoring the TunerResourceManager
1734         // Note: the handles will be changed from the original value, but should be OK
1735         try {
1736             TunerFrontendInfo[] infos = new TunerFrontendInfo[6];
1737             // tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
1738             infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
1739             infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
1740             infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBS, 1);
1741             infos[3] = tunerFrontendInfo(4, FrontendSettings.TYPE_DVBT, 2);
1742             infos[4] = tunerFrontendInfo(5, FrontendSettings.TYPE_DVBC, 2);
1743             infos[5] = tunerFrontendInfo(6, FrontendSettings.TYPE_DVBS, 2);
1744 
1745             mTunerResourceManager.setFrontendInfoList(infos);
1746 
1747             Tuner A = new Tuner(mContext, null, 100);
1748             Tuner B = new Tuner(mContext, null, 100);
1749             Tuner C = new Tuner(mContext, null, 100);
1750 
1751             // check before anyone holds resource
1752             assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_UNDEFINED));
1753             assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_ATSC));
1754             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1755             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
1756             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
1757 
1758             // let B hold resource
1759             assignFeResource(B.getClientId(), FrontendSettings.TYPE_DVBT,
1760                              true /* expectedResult */, 1 /* expectedHandle */);
1761 
1762             // check when one of the two exclusive groups are held
1763             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1764             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
1765             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
1766 
1767             assertTrue(B.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1768 
1769             // let C hold the resource
1770             assignFeResource(C.getClientId(), FrontendSettings.TYPE_DVBC,
1771                              true /* expectedResult */, 5 /* expectedHandle */);
1772 
1773             assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1774             assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
1775             assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
1776 
1777             assertFalse(B.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1778             assertFalse(C.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1779 
1780             // let go of B's resource
1781             B.close();
1782 
1783             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1784             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
1785             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
1786 
1787             assertTrue(B.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1788             assertTrue(C.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1789 
1790             C.close();
1791             A.close();
1792         } catch (Exception e) {
1793             throw (e);
1794         } finally {
1795             cleanupTRMCustomFeResourceMapTest();
1796         }
1797     }
1798 
1799     @Test
testHasUnusedFrontend2()1800     public void testHasUnusedFrontend2() throws Exception {
1801         prepTRMCustomFeResourceMapTest();
1802 
1803         // Use try block to ensure restoring the TunerResourceManager
1804         // Note: the handles will be changed from the original value, but should be OK
1805         try {
1806             TunerFrontendInfo[] infos = new TunerFrontendInfo[5];
1807             // tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
1808             infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
1809             infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
1810             infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBT, 2);
1811             infos[3] = tunerFrontendInfo(4, FrontendSettings.TYPE_DVBC, 2);
1812             infos[4] = tunerFrontendInfo(5, FrontendSettings.TYPE_DVBS, 3);
1813 
1814             mTunerResourceManager.setFrontendInfoList(infos);
1815 
1816             Tuner A = new Tuner(mContext, null, 100);
1817             Tuner B = new Tuner(mContext, null, 100);
1818             Tuner C = new Tuner(mContext, null, 100);
1819 
1820             // let B hold resource
1821             assignFeResource(B.getClientId(), FrontendSettings.TYPE_DVBT,
1822                              true /* expectedResult */, 1 /* expectedHandle */);
1823 
1824             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1825             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
1826             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
1827 
1828             // let C hold the resource
1829             assignFeResource(C.getClientId(), FrontendSettings.TYPE_DVBC,
1830                              true /* expectedResult */, 4 /* expectedHandle */);
1831 
1832             assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1833             assertFalse(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
1834             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
1835 
1836             B.close();
1837             C.close();
1838         } catch (Exception e) {
1839             throw (e);
1840         } finally {
1841             cleanupTRMCustomFeResourceMapTest();
1842         }
1843     }
1844 
1845     @Test
testHasUnusedFrontend3()1846     public void testHasUnusedFrontend3() throws Exception {
1847         prepTRMCustomFeResourceMapTest();
1848 
1849         // Use try block to ensure restoring the TunerResourceManager
1850         // Note: the handles will be changed from the original value, but should be OK
1851         try {
1852             TunerFrontendInfo[] infos = new TunerFrontendInfo[6];
1853             // tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
1854             infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
1855             infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
1856             infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBS, 1);
1857             infos[3] = tunerFrontendInfo(4, FrontendSettings.TYPE_DVBT, 2);
1858             infos[4] = tunerFrontendInfo(5, FrontendSettings.TYPE_DVBC, 2);
1859             infos[5] = tunerFrontendInfo(6, FrontendSettings.TYPE_DVBS, 2);
1860 
1861             mTunerResourceManager.setFrontendInfoList(infos);
1862 
1863             Tuner A = new Tuner(mContext, null, 100);
1864             Tuner B = new Tuner(mContext, null, 100);
1865             Tuner C = new Tuner(mContext, null, 100);
1866 
1867             // let B hold resource
1868             assignFeResource(B.getClientId(), FrontendSettings.TYPE_DVBT,
1869                              true /* expectedResult */, 1 /* expectedHandle */);
1870 
1871             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1872             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
1873             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
1874 
1875             // let C share from B
1876             mTunerResourceManager.shareFrontend(C.getClientId(), B.getClientId());
1877 
1878             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBT));
1879             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBC));
1880             assertTrue(A.hasUnusedFrontend(FrontendSettings.TYPE_DVBS));
1881 
1882             A.close();
1883             C.close();
1884             B.close();
1885         } catch (Exception e) {
1886             throw (e);
1887         } finally {
1888             cleanupTRMCustomFeResourceMapTest();
1889         }
1890     }
1891 
1892     @Test
testIsLowestPriorityCornerCases()1893     public void testIsLowestPriorityCornerCases() throws Exception {
1894         prepTRMCustomFeResourceMapTest();
1895 
1896         // Use try block to ensure restoring the TunerResourceManager
1897         // Note: the handles will be changed from the original value, but should be OK
1898         try {
1899             setupSingleTunerSetupForIsLowestPriority();
1900 
1901             // must return true when non existing frontend type is specified
1902             assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_UNDEFINED));
1903             assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_ATSC));
1904 
1905             // must return true when no one is holding the resource
1906             assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBT));
1907             assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBC));
1908             assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBT));
1909 
1910             // must return true when the callee is the only one holding the resource
1911             assignFeResource(mTuner.getClientId(), FrontendSettings.TYPE_DVBT,
1912                              true /* expectedResult */, 1 /* expectedHandle */);
1913             assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBT));
1914             assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBC));
1915             assertTrue(mTuner.isLowestPriority(FrontendSettings.TYPE_DVBT));
1916 
1917         } catch (Exception e) {
1918             throw (e);
1919         } finally {
1920             cleanupTRMCustomFeResourceMapTest();
1921         }
1922     }
1923 
1924     @Test
testIsLowestPriorityTwoClients()1925     public void testIsLowestPriorityTwoClients() throws Exception {
1926         prepTRMCustomFeResourceMapTest();
1927 
1928         // Use try block to ensure restoring the TunerResourceManager
1929         // Note: the handles will be changed from the original value, but should be OK
1930         try {
1931             setupSingleTunerSetupForIsLowestPriority();
1932             testTwoClientsForIsLowestPriority(200, 100); // A > B
1933             testTwoClientsForIsLowestPriority(100, 200); // A < B
1934             testTwoClientsForIsLowestPriority(100, 100); // A = B
1935 
1936             setupDualTunerSetupForIsLowestPriority();
1937             testTwoClientsForIsLowestPriority(200, 100); // A > B
1938             testTwoClientsForIsLowestPriority(100, 200); // A < B
1939             testTwoClientsForIsLowestPriority(100, 100); // A = B
1940         } catch (Exception e) {
1941             throw (e);
1942         } finally {
1943             cleanupTRMCustomFeResourceMapTest();
1944         }
1945     }
1946 
1947     @Test
testIsLowestPriorityThreeClients()1948     public void testIsLowestPriorityThreeClients() throws Exception {
1949         prepTRMCustomFeResourceMapTest();
1950 
1951         // Use try block to ensure restoring the TunerResourceManager
1952         // Note: the handles will be changed from the original value, but should be OK
1953         try {
1954             setupDualTunerSetupForIsLowestPriority();
1955             testThreeClientsForIsLowestPriority(300, 200, 100); // A > B > C
1956             testThreeClientsForIsLowestPriority(300, 100, 200); // A > C > B
1957             testThreeClientsForIsLowestPriority(200, 300, 100); // B > A > C
1958             testThreeClientsForIsLowestPriority(200, 100, 300); // C > A > B
1959             testThreeClientsForIsLowestPriority(100, 300, 200); // B > C > A
1960             testThreeClientsForIsLowestPriority(100, 200, 300); // C > B > A
1961             testThreeClientsForIsLowestPriority(100, 100, 100); // A = B = C
1962             testThreeClientsForIsLowestPriority(200, 200, 100); // A = B > C
1963             testThreeClientsForIsLowestPriority(200, 100, 100); // A > B = C
1964             testThreeClientsForIsLowestPriority(200, 100, 200); // A = C > B
1965             testThreeClientsForIsLowestPriority(200, 300, 200); // B > A = C
1966             testThreeClientsForIsLowestPriority(100, 100, 200); // C > A = B
1967             testThreeClientsForIsLowestPriority(100, 200, 200); // B = C > A
1968         } catch (Exception e) {
1969             throw (e);
1970         } finally {
1971             cleanupTRMCustomFeResourceMapTest();
1972         }
1973     }
1974 
tunerFrontendInfo( int handle, int frontendType, int exclusiveGroupId)1975     private TunerFrontendInfo tunerFrontendInfo(
1976             int handle, int frontendType, int exclusiveGroupId) {
1977         TunerFrontendInfo info = new TunerFrontendInfo();
1978         info.handle = handle;
1979         info.type = frontendType;
1980         info.exclusiveGroupId = exclusiveGroupId;
1981         return info;
1982     }
1983 
1984     /**
1985      * Prep function for TunerTest that requires custom frontend resource map
1986      */
prepTRMCustomFeResourceMapTest()1987     private void prepTRMCustomFeResourceMapTest() {
1988         if (mTunerResourceManager == null) {
1989             mTunerResourceManager = (TunerResourceManager)
1990                     mContext.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
1991         }
1992         mTunerResourceManager.storeResourceMap(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
1993         mTunerResourceManager.clearResourceMap(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
1994     }
1995 
1996     /**
1997      * Clean up function for TunerTest that requires custom frontend resource map
1998      */
cleanupTRMCustomFeResourceMapTest()1999     private void cleanupTRMCustomFeResourceMapTest() {
2000         // first close mTuner in case a frontend resource is opened
2001         if (mTuner != null) {
2002             mTuner.close();
2003             mTuner = null;
2004         }
2005 
2006         // now restore the original frontend resource map
2007         if (mTunerResourceManager != null) {
2008             mTunerResourceManager.restoreResourceMap(
2009                     TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
2010         }
2011     }
2012 
clearFrontendInfoList()2013     private void clearFrontendInfoList() {
2014         if (mTunerResourceManager != null) {
2015             mTunerResourceManager.clearResourceMap(
2016                     TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND);
2017         }
2018     }
2019 
assignFeResource(int clientId, int frontendType, boolean expectedResult, int expectedHandle)2020     private void assignFeResource(int clientId, int frontendType,
2021                                   boolean expectedResult, int expectedHandle) {
2022         int[] feHandle = new int[1];
2023         TunerFrontendRequest request = new TunerFrontendRequest();
2024         request.clientId = clientId;
2025         request.frontendType = frontendType;
2026         boolean granted = mTunerResourceManager.requestFrontend(request, feHandle);
2027         assertEquals(granted, expectedResult);
2028         assertEquals(feHandle[0], expectedHandle);
2029     }
2030 
setupSingleTunerSetupForIsLowestPriority()2031     private void setupSingleTunerSetupForIsLowestPriority() {
2032         // first clear the frontend resource to register new set of resources
2033         clearFrontendInfoList();
2034 
2035         TunerFrontendInfo[] infos = new TunerFrontendInfo[3];
2036         // tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
2037         infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
2038         infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
2039         infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBS, 1);
2040 
2041         mTunerResourceManager.setFrontendInfoList(infos);
2042     }
2043 
setupDualTunerSetupForIsLowestPriority()2044     private void setupDualTunerSetupForIsLowestPriority() {
2045         // first clear the frontend resource to register new set of resources
2046         clearFrontendInfoList();
2047 
2048         TunerFrontendInfo[] infos = new TunerFrontendInfo[6];
2049         // tunerFrontendInfo(handle, FrontendSettings.TYPE_*, exclusiveGroupId
2050         infos[0] = tunerFrontendInfo(1, FrontendSettings.TYPE_DVBT, 1);
2051         infos[1] = tunerFrontendInfo(2, FrontendSettings.TYPE_DVBC, 1);
2052         infos[2] = tunerFrontendInfo(3, FrontendSettings.TYPE_DVBS, 1);
2053         infos[3] = tunerFrontendInfo(4, FrontendSettings.TYPE_DVBT, 2);
2054         infos[4] = tunerFrontendInfo(5, FrontendSettings.TYPE_DVBC, 2);
2055         infos[5] = tunerFrontendInfo(6, FrontendSettings.TYPE_DVBS, 2);
2056 
2057         mTunerResourceManager.setFrontendInfoList(infos);
2058     }
2059 
2060 
testTwoClientsForIsLowestPriority(int prioA, int prioB)2061     private void testTwoClientsForIsLowestPriority(int prioA, int prioB) {
2062 
2063         Tuner A = new Tuner(mContext, null, prioA);
2064         Tuner B = new Tuner(mContext, null, prioB);
2065 
2066         // all should return true
2067         assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBT));
2068         assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBC));
2069 
2070         // let A hold resource
2071         assignFeResource(A.getClientId(), FrontendSettings.TYPE_DVBT,
2072                          true /* expectedResult */, 1 /* expectedHandle */);
2073 
2074         // should return true for A as A is the sole holder
2075         assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBT));
2076         // should return false for B only if A < B
2077         if ( prioA < prioB ) {
2078             assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBC));
2079         } else {
2080             assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBC));
2081         }
2082 
2083         A.close();
2084         B.close();
2085     }
2086 
testThreeClientsForIsLowestPriority(int prioA, int prioB, int prioC)2087     private void testThreeClientsForIsLowestPriority(int prioA, int prioB, int prioC) {
2088 
2089         Tuner A = new Tuner(mContext, null, prioA);
2090         Tuner B = new Tuner(mContext, null, prioB);
2091         Tuner C = new Tuner(mContext, null, prioC);
2092 
2093         // all should return true
2094         assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBT));
2095         assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBC));
2096         assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBS));
2097 
2098         // let A & C hold resource
2099         assignFeResource(A.getClientId(), FrontendSettings.TYPE_DVBT,
2100                          true /* expectedResult */, 1 /* expectedHandle */);
2101 
2102         assignFeResource(C.getClientId(), FrontendSettings.TYPE_DVBC,
2103                          true /* expectedResult */, 5 /* expectedHandle */);
2104 
2105         // should return false for B only if A < B
2106         if (prioA > prioB && prioB > prioC) {
2107             assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2108             assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2109             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2110         } else if (prioA > prioC && prioC > prioB) {
2111             assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2112             assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2113             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2114         } else if (prioA > prioC && prioC > prioB) {
2115             assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2116             assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2117             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2118         } else if (prioB > prioA && prioA > prioC) {
2119             assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2120             assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2121             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2122         } else if (prioC > prioA && prioA > prioB) {
2123             assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2124             assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2125             assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2126         } else if (prioB > prioC && prioC > prioA) {
2127             assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2128             assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2129             assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2130         } else if (prioC > prioB && prioB > prioA) {
2131             assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2132             assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2133             assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2134         } else if (prioA == prioB && prioB == prioC) {
2135             assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2136             assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2137             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2138         } else if (prioA == prioB && prioB > prioC) {
2139             assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2140             assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2141             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2142         } else if (prioA > prioB && prioB == prioC) {
2143             assertFalse(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2144             assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2145             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2146         } else if (prioA == prioC && prioC > prioB) {
2147             assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2148             assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2149             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2150         } else if (prioB > prioA && prioA == prioC) {
2151             assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2152             assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2153             assertTrue(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2154         } else if (prioC > prioA && prioA == prioB) {
2155             assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2156             assertTrue(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2157             assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2158         } else if (prioB == prioC && prioC > prioA) {
2159             assertTrue(A.isLowestPriority(FrontendSettings.TYPE_DVBC));
2160             assertFalse(B.isLowestPriority(FrontendSettings.TYPE_DVBS));
2161             assertFalse(C.isLowestPriority(FrontendSettings.TYPE_DVBT));
2162         }
2163 
2164         A.close();
2165         B.close();
2166         C.close();
2167     }
2168 
2169     @Test
testSharedFilterOneProcess()2170     public void testSharedFilterOneProcess() throws Exception {
2171         Filter f = createTsSectionFilter(mTuner, getExecutor(), getFilterCallback());
2172         assertTrue(f != null);
2173 
2174         String token1 = f.acquireSharedFilterToken();
2175         assertTrue(token1 != null);
2176 
2177         String token2 = f.acquireSharedFilterToken();
2178         assertTrue(token2 == null);
2179 
2180         // Tune a frontend before start the filter
2181         List<Integer> ids = mTuner.getFrontendIds();
2182         assertFalse(ids.isEmpty());
2183 
2184         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
2185         int res = mTuner.tune(createFrontendSettings(info));
2186         assertEquals(Tuner.RESULT_SUCCESS, res);
2187 
2188         Settings settings = SectionSettingsWithTableInfo
2189                 .builder(Filter.TYPE_TS)
2190                 .setTableId(2)
2191                 .setVersion(1)
2192                 .setCrcEnabled(true)
2193                 .setRaw(false)
2194                 .setRepeat(false)
2195                 .build();
2196         FilterConfiguration config = TsFilterConfiguration
2197                 .builder()
2198                 .setTpid(10)
2199                 .setSettings(settings)
2200                 .build();
2201 
2202         assertEquals(f.configure(config), Tuner.RESULT_INVALID_STATE);
2203         assertEquals(f.setMonitorEventMask(Filter.MONITOR_EVENT_SCRAMBLING_STATUS),
2204                 Tuner.RESULT_INVALID_STATE);
2205         assertEquals(f.setDataSource(null), Tuner.RESULT_INVALID_STATE);
2206         assertEquals(f.start(), Tuner.RESULT_INVALID_STATE);
2207         assertEquals(f.flush(), Tuner.RESULT_INVALID_STATE);
2208         assertEquals(f.read(new byte[3], 0, 3), 0);
2209         assertEquals(f.stop(), Tuner.RESULT_INVALID_STATE);
2210 
2211         res = mTuner.cancelTuning();
2212         assertEquals(Tuner.RESULT_SUCCESS, res);
2213 
2214         f.freeSharedFilterToken(token1);
2215         f.close();
2216         f = null;
2217     }
2218 
2219     @Test
testSharedFilterTwoProcessesCloseInSharedFilter()2220     public void testSharedFilterTwoProcessesCloseInSharedFilter() throws Exception {
2221         mConnection = new TestServiceConnection();
2222         mContext.bindService(new Intent(mContext, SharedFilterTestService.class), mConnection,
2223                 Context.BIND_AUTO_CREATE);
2224         mSharedFilterTestServer =
2225                 ISharedFilterTestServer.Stub.asInterface(mConnection.getService());
2226 
2227         String token = mSharedFilterTestServer.acquireSharedFilterToken();
2228         assertTrue(token != null);
2229         SharedFilter f =
2230                 Tuner.openSharedFilter(mContext, token, getExecutor(), getSharedFilterCallback());
2231         assertTrue(f != null);
2232 
2233         assertEquals(f.start(), Tuner.RESULT_SUCCESS);
2234         assertEquals(f.flush(), Tuner.RESULT_SUCCESS);
2235         int size = f.read(new byte[3], 0, 3);
2236         assertTrue(size >= 0 && size <= 3);
2237         assertEquals(f.stop(), Tuner.RESULT_SUCCESS);
2238 
2239         mLockLatch = new CountDownLatch(1);
2240         f.close();
2241         f = null;
2242         mSharedFilterTestServer.closeFilter();
2243         Thread.sleep(2000);
2244         assertEquals(mLockLatch.getCount(), 1);
2245         mLockLatch = null;
2246 
2247         mContext.unbindService(mConnection);
2248     }
2249 
2250     @Test
testSharedFilterTwoProcessesCloseInFilter()2251     public void testSharedFilterTwoProcessesCloseInFilter() throws Exception {
2252         mConnection = new TestServiceConnection();
2253         mContext.bindService(new Intent(mContext, SharedFilterTestService.class), mConnection,
2254                 Context.BIND_AUTO_CREATE);
2255         mSharedFilterTestServer =
2256                 ISharedFilterTestServer.Stub.asInterface(mConnection.getService());
2257 
2258         String token = mSharedFilterTestServer.acquireSharedFilterToken();
2259         assertTrue(token != null);
2260 
2261         SharedFilter f =
2262                 Tuner.openSharedFilter(mContext, token, getExecutor(), getSharedFilterCallback());
2263         assertTrue(f != null);
2264 
2265         assertEquals(f.start(), Tuner.RESULT_SUCCESS);
2266         assertEquals(f.flush(), Tuner.RESULT_SUCCESS);
2267         int size = f.read(new byte[3], 0, 3);
2268         assertTrue(size >= 0 && size <= 3);
2269         assertEquals(f.stop(), Tuner.RESULT_SUCCESS);
2270 
2271         mLockLatch = new CountDownLatch(1);
2272         mSharedFilterTestServer.closeFilter();
2273         assertTrue(mLockLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
2274         mLockLatch = null;
2275         f.close();
2276         f = null;
2277 
2278         mContext.unbindService(mConnection);
2279     }
2280 
2281     @Test
testSharedFilterTwoProcessesReleaseInFilter()2282     public void testSharedFilterTwoProcessesReleaseInFilter() throws Exception {
2283         mConnection = new TestServiceConnection();
2284         mContext.bindService(new Intent(mContext, SharedFilterTestService.class), mConnection,
2285                 Context.BIND_AUTO_CREATE);
2286         mSharedFilterTestServer =
2287                 ISharedFilterTestServer.Stub.asInterface(mConnection.getService());
2288 
2289         String token = mSharedFilterTestServer.acquireSharedFilterToken();
2290         assertTrue(token != null);
2291 
2292         SharedFilter f =
2293                 Tuner.openSharedFilter(mContext, token, getExecutor(), getSharedFilterCallback());
2294         assertTrue(f != null);
2295 
2296         assertEquals(f.start(), Tuner.RESULT_SUCCESS);
2297         assertEquals(f.flush(), Tuner.RESULT_SUCCESS);
2298         int size = f.read(new byte[3], 0, 3);
2299         assertTrue(size >= 0 && size <= 3);
2300         assertEquals(f.stop(), Tuner.RESULT_SUCCESS);
2301 
2302         mLockLatch = new CountDownLatch(1);
2303         mSharedFilterTestServer.freeSharedFilterToken(token);
2304         assertTrue(mLockLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
2305         mLockLatch = null;
2306 
2307         mSharedFilterTestServer.closeFilter();
2308         f.close();
2309         f = null;
2310 
2311         mContext.unbindService(mConnection);
2312     }
2313 
2314     @Test
testSharedFilterTwoProcessesVerifySharedFilter()2315     public void testSharedFilterTwoProcessesVerifySharedFilter() throws Exception {
2316         mConnection = new TestServiceConnection();
2317         mContext.bindService(new Intent(mContext, SharedFilterTestService.class), mConnection,
2318                 Context.BIND_AUTO_CREATE);
2319         mSharedFilterTestServer =
2320                 ISharedFilterTestServer.Stub.asInterface(mConnection.getService());
2321 
2322         Filter f = createTsSectionFilter(mTuner, getExecutor(), getFilterCallback());
2323         assertTrue(f != null);
2324 
2325         String token = f.acquireSharedFilterToken();
2326         assertTrue(token != null);
2327 
2328         // Tune a frontend before start the shared filter
2329         List<Integer> ids = mTuner.getFrontendIds();
2330         assertFalse(ids.isEmpty());
2331 
2332         FrontendInfo info = mTuner.getFrontendInfoById(ids.get(0));
2333         int res = mTuner.tune(createFrontendSettings(info));
2334         assertEquals(Tuner.RESULT_SUCCESS, res);
2335         assertTrue(mSharedFilterTestServer.verifySharedFilter(token));
2336 
2337         res = mTuner.cancelTuning();
2338         assertEquals(Tuner.RESULT_SUCCESS, res);
2339 
2340         f.freeSharedFilterToken(token);
2341         f.close();
2342         f = null;
2343 
2344         mContext.unbindService(mConnection);
2345     }
2346 
2347     @Test
testFilterTimeDelay()2348     public void testFilterTimeDelay() throws Exception {
2349         Filter f = createTsSectionFilter(mTuner, getExecutor(), getFilterCallback());
2350 
2351         int timeDelayInMs = 5000;
2352         Instant start = Instant.now();
2353         int status = f.delayCallbackForDurationMillis(timeDelayInMs);
2354 
2355         if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) {
2356             // start / stop prevents initial race condition after first setting the time delay.
2357             f.start();
2358             f.stop();
2359 
2360             mLockLatch = new CountDownLatch(1);
2361             f.start();
2362             assertTrue(mLockLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
2363 
2364             Instant finish = Instant.now();
2365             Duration timeElapsed = Duration.between(start, finish);
2366             assertTrue(timeElapsed.toMillis() >= timeDelayInMs);
2367         } else {
2368             assertEquals(Tuner.RESULT_UNAVAILABLE, status);
2369         }
2370         f.close();
2371         f = null;
2372     }
2373 
2374     @Test
testFilterDataSizeDelay()2375     public void testFilterDataSizeDelay() throws Exception {
2376         Filter f = createTsSectionFilter(mTuner, getExecutor(), getFilterCallback());
2377         int status = f.delayCallbackUntilBytesAccumulated(5000);
2378         if (TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_2_0)) {
2379             assertEquals(Tuner.RESULT_SUCCESS, status);
2380         } else {
2381             assertEquals(Tuner.RESULT_UNAVAILABLE, status);
2382         }
2383         f.close();
2384     }
2385 
2386     @Test
testMaxNumberOfFrontends()2387     public void testMaxNumberOfFrontends() throws Exception {
2388         List<Integer> ids = mTuner.getFrontendIds();
2389         assertFalse(ids.isEmpty());
2390         for (int i = 0; i < ids.size(); i++) {
2391             int type = mTuner.getFrontendInfoById(ids.get(i)).getType();
2392             if (TunerVersionChecker.isHigherOrEqualVersionTo(
2393                         TunerVersionChecker.TUNER_VERSION_2_0)) {
2394                 int defaultMax = -1;
2395                 int status;
2396                 // Check default value
2397                 defaultMax = mTuner.getMaxNumberOfFrontends(type);
2398                 assertTrue(defaultMax > 0);
2399                 // Set to -1
2400                 status = mTuner.setMaxNumberOfFrontends(type, -1);
2401                 assertEquals(Tuner.RESULT_INVALID_ARGUMENT, status);
2402                 // Set to defaultMax + 1
2403                 status = mTuner.setMaxNumberOfFrontends(type, defaultMax + 1);
2404                 assertEquals(Tuner.RESULT_INVALID_ARGUMENT, status);
2405                 // Set to 0
2406                 status = mTuner.setMaxNumberOfFrontends(type, 0);
2407                 assertEquals(Tuner.RESULT_SUCCESS, status);
2408                 // Check after set
2409                 int currentMax = -1;
2410                 currentMax = mTuner.getMaxNumberOfFrontends(type);
2411                 assertEquals(currentMax, 0);
2412                 // Reset to default
2413                 status = mTuner.setMaxNumberOfFrontends(type, defaultMax);
2414                 assertEquals(Tuner.RESULT_SUCCESS, status);
2415                 currentMax = mTuner.getMaxNumberOfFrontends(type);
2416                 assertEquals(defaultMax, currentMax);
2417             } else {
2418                 int defaultMax = mTuner.getMaxNumberOfFrontends(type);
2419                 assertEquals(defaultMax, -1);
2420                 int status = mTuner.setMaxNumberOfFrontends(type, 0);
2421                 assertEquals(Tuner.RESULT_UNAVAILABLE, status);
2422             }
2423         }
2424         // validate the behavior of tune
2425         FrontendInfo info1 = mTuner.getFrontendInfoById(ids.get(0));
2426         FrontendSettings feSettings1 = createFrontendSettings(info1);
2427         int type1 = info1.getType();
2428         if (ids.size() >= 1) {
2429             int originalMax1 = mTuner.getMaxNumberOfFrontends(type1);
2430             assertEquals(Tuner.RESULT_SUCCESS, mTuner.tune(feSettings1));
2431             assertNotNull(mTuner.getFrontendInfo());
2432 
2433             // validate that set max cannot be set to lower value than current usage
2434             assertEquals(Tuner.RESULT_INVALID_ARGUMENT,
2435                     mTuner.setMaxNumberOfFrontends(type1, 0));
2436 
2437             // validate max value is reflected in the tune behavior
2438             mTuner.closeFrontend();
2439             assertEquals(Tuner.RESULT_SUCCESS,
2440                     mTuner.setMaxNumberOfFrontends(type1, 0));
2441             assertEquals(Tuner.RESULT_UNAVAILABLE,
2442                     mTuner.tune(feSettings1));
2443 
2444             assertEquals(Tuner.RESULT_SUCCESS,
2445                     mTuner.setMaxNumberOfFrontends(type1, originalMax1));
2446             assertEquals(Tuner.RESULT_SUCCESS, mTuner.tune(feSettings1));
2447             assertNotNull(mTuner.getFrontendInfo());
2448             mTuner.closeFrontend();
2449         }
2450 
2451         // validate max number on one frontend type has no impact on other
2452         if (ids.size() >= 2) {
2453             FrontendInfo info2 = mTuner.getFrontendInfoById(ids.get(1));
2454             int type2 = info2.getType();
2455             int originalMax2 = mTuner.getMaxNumberOfFrontends(type2);
2456 
2457             assertEquals(Tuner.RESULT_SUCCESS,
2458                     mTuner.setMaxNumberOfFrontends(type2, 0));
2459             assertEquals(Tuner.RESULT_SUCCESS,
2460                     mTuner.tune(feSettings1));
2461             assertNotNull(mTuner.getFrontendInfo());
2462 
2463             // set it back to the original max
2464             assertEquals(Tuner.RESULT_SUCCESS,
2465                     mTuner.setMaxNumberOfFrontends(type2, originalMax2));
2466             mTuner.closeFrontend();
2467 
2468         }
2469     }
2470 
createTsSectionFilter( Tuner tuner, Executor e, FilterCallback cb)2471     public static Filter createTsSectionFilter(
2472             Tuner tuner, Executor e, FilterCallback cb) {
2473         Filter f = tuner.openFilter(Filter.TYPE_TS, Filter.SUBTYPE_SECTION, 1000, e, cb);
2474         Settings settings = SectionSettingsWithTableInfo
2475                 .builder(Filter.TYPE_TS)
2476                 .setTableId(2)
2477                 .setVersion(1)
2478                 .setCrcEnabled(true)
2479                 .setRaw(false)
2480                 .setRepeat(false)
2481                 .build();
2482         FilterConfiguration config = TsFilterConfiguration
2483                 .builder()
2484                 .setTpid(10)
2485                 .setSettings(settings)
2486                 .build();
2487         f.configure(config);
2488         f.setMonitorEventMask(
2489                 Filter.MONITOR_EVENT_SCRAMBLING_STATUS | Filter.MONITOR_EVENT_IP_CID_CHANGE);
2490 
2491         return f;
2492     }
2493 
hasTuner()2494     private boolean hasTuner() {
2495         return mContext.getPackageManager().hasSystemFeature("android.hardware.tv.tuner");
2496     }
2497 
getExecutor()2498     private Executor getExecutor() {
2499         return Runnable::run;
2500     }
2501 
getLnbCallback()2502     private LnbCallback getLnbCallback() {
2503         return new LnbCallback() {
2504             @Override
2505             public void onEvent(int lnbEventType) {}
2506             @Override
2507             public void onDiseqcMessage(byte[] diseqcMessage) {}
2508         };
2509     }
2510 
getFilterCallback()2511     private FilterCallback getFilterCallback() {
2512         return new FilterCallback() {
2513             @Override
2514             public void onFilterEvent(Filter filter, FilterEvent[] events) {
2515                 for (FilterEvent e : events) {
2516                     if (e instanceof DownloadEvent) {
2517                         testDownloadEvent(filter, (DownloadEvent) e);
2518                     } else if (e instanceof IpPayloadEvent) {
2519                         testIpPayloadEvent(filter, (IpPayloadEvent) e);
2520                     } else if (e instanceof MediaEvent) {
2521                         testMediaEvent(filter, (MediaEvent) e);
2522                     } else if (e instanceof MmtpRecordEvent) {
2523                         testMmtpRecordEvent(filter, (MmtpRecordEvent) e);
2524                     } else if (e instanceof PesEvent) {
2525                         testPesEvent(filter, (PesEvent) e);
2526                     } else if (e instanceof SectionEvent) {
2527                         testSectionEvent(filter, (SectionEvent) e);
2528                     } else if (e instanceof TemiEvent) {
2529                         testTemiEvent(filter, (TemiEvent) e);
2530                     } else if (e instanceof TsRecordEvent) {
2531                         testTsRecordEvent(filter, (TsRecordEvent) e);
2532                     } else if (e instanceof ScramblingStatusEvent) {
2533                         testScramblingStatusEvent(filter, (ScramblingStatusEvent) e);
2534                     } else if (e instanceof IpCidChangeEvent) {
2535                         testIpCidChangeEvent(filter, (IpCidChangeEvent) e);
2536                     } else if (e instanceof RestartEvent) {
2537                         testRestartEvent(filter, (RestartEvent) e);
2538                     }
2539                 }
2540                 if (mLockLatch != null) {
2541                     mLockLatch.countDown();
2542                 }
2543             }
2544             @Override
2545             public void onFilterStatusChanged(Filter filter, int status) {}
2546         };
2547     }
2548 
2549     private SharedFilterCallback getSharedFilterCallback() {
2550         return new SharedFilterCallback() {
2551             @Override
2552             public void onFilterEvent(SharedFilter filter, FilterEvent[] events) {}
2553             @Override
2554             public void onFilterStatusChanged(SharedFilter filter, int status) {
2555                 if (status == SharedFilter.STATUS_INACCESSIBLE) {
2556                     if (mLockLatch != null) {
2557                         mLockLatch.countDown();
2558                     }
2559                 }
2560             }
2561         };
2562     }
2563 
2564     private void testDownloadEvent(Filter filter, DownloadEvent e) {
2565         e.getItemId();
2566         e.getDownloadId();
2567         e.getMpuSequenceNumber();
2568         e.getItemFragmentIndex();
2569         e.getLastItemFragmentIndex();
2570         long length = e.getDataLength();
2571         if (length > 0) {
2572             byte[] buffer = new byte[(int) length];
2573             assertNotEquals(0, filter.read(buffer, 0, length));
2574         }
2575     }
2576 
2577     private void testIpPayloadEvent(Filter filter, IpPayloadEvent e) {
2578         long length = e.getDataLength();
2579         if (length > 0) {
2580             byte[] buffer = new byte[(int) length];
2581             assertNotEquals(0, filter.read(buffer, 0, length));
2582         }
2583     }
2584 
2585     private void testMediaEvent(Filter filter, MediaEvent e) {
2586         e.getStreamId();
2587         e.isPtsPresent();
2588         e.getPts();
2589         e.isDtsPresent();
2590         e.getDts();
2591         e.getDataLength();
2592         e.getOffset();
2593         e.getLinearBlock();
2594         e.isSecureMemory();
2595         e.getAvDataId();
2596         e.getAudioHandle();
2597         e.getMpuSequenceNumber();
2598         e.isPrivateData();
2599         e.getScIndexMask();
2600         AudioDescriptor ad = e.getExtraMetaData();
2601         if (ad != null) {
2602             ad.getAdFade();
2603             ad.getAdPan();
2604             ad.getAdVersionTextTag();
2605             ad.getAdGainCenter();
2606             ad.getAdGainFront();
2607             ad.getAdGainSurround();
2608         }
2609         e.release();
2610     }
2611 
2612     private void testMmtpRecordEvent(Filter filter, MmtpRecordEvent e) {
2613         e.getScHevcIndexMask();
2614         e.getDataLength();
2615         int mpuSequenceNumber = e.getMpuSequenceNumber();
2616         long pts = e.getPts();
2617         int firstMbInSlice = e.getFirstMacroblockInSlice();
2618         int tsIndexMask = e.getTsIndexMask();
2619         if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
2620             assertEquals(mpuSequenceNumber, Tuner.INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM);
2621             assertEquals(pts, Tuner.INVALID_TIMESTAMP);
2622             assertEquals(firstMbInSlice, Tuner.INVALID_FIRST_MACROBLOCK_IN_SLICE);
2623             assertEquals(tsIndexMask, 0);
2624         }
2625     }
2626 
2627     private void testPesEvent(Filter filter, PesEvent e) {
2628         e.getStreamId();
2629         e.getMpuSequenceNumber();
2630         long length = e.getDataLength();
2631         if (length > 0) {
2632             byte[] buffer = new byte[(int) length];
2633             assertNotEquals(0, filter.read(buffer, 0, length));
2634         }
2635     }
2636 
2637     private void testSectionEvent(Filter filter, SectionEvent e) {
2638         e.getTableId();
2639         e.getVersion();
2640         e.getSectionNumber();
2641         e.getDataLength();
2642         long length = e.getDataLengthLong();
2643         if (length > 0) {
2644             byte[] buffer = new byte[(int) length];
2645             assertNotEquals(0, filter.read(buffer, 0, length));
2646         }
2647     }
2648 
2649     private void testTemiEvent(Filter filter, TemiEvent e) {
2650         e.getPts();
2651         e.getDescriptorTag();
2652         e.getDescriptorData();
2653     }
2654 
2655     private void testTsRecordEvent(Filter filter, TsRecordEvent e) {
2656         e.getPacketId();
2657         e.getTsIndexMask();
2658         e.getScIndexMask();
2659         e.getDataLength();
2660         long pts = e.getPts();
2661         int firstMbInSlice = e.getFirstMacroblockInSlice();
2662         if (!TunerVersionChecker.isHigherOrEqualVersionTo(TunerVersionChecker.TUNER_VERSION_1_1)) {
2663             assertEquals(pts, Tuner.INVALID_TIMESTAMP);
2664             assertEquals(firstMbInSlice, Tuner.INVALID_FIRST_MACROBLOCK_IN_SLICE);
2665         }
2666     }
2667 
2668     private void testScramblingStatusEvent(Filter filter, ScramblingStatusEvent e) {
2669         e.getScramblingStatus();
2670     }
2671 
2672     private void testIpCidChangeEvent(Filter filter, IpCidChangeEvent e) {
2673         e.getIpCid();
2674     }
2675 
2676     private void testRestartEvent(Filter filter, RestartEvent e) {
2677         e.getStartId();
2678     }
2679 
2680     private OnRecordStatusChangedListener getRecordListener() {
2681         return new OnRecordStatusChangedListener() {
2682             @Override
2683             public void onRecordStatusChanged(int status) {}
2684         };
2685     }
2686 
2687     private OnPlaybackStatusChangedListener getPlaybackListener() {
2688         return new OnPlaybackStatusChangedListener() {
2689             @Override
2690             public void onPlaybackStatusChanged(int status) {}
2691         };
2692     }
2693 
2694     static public FrontendSettings createFrontendSettings(FrontendInfo info) {
2695             FrontendCapabilities caps = info.getFrontendCapabilities();
2696             long minFreq = info.getFrequencyRangeLong().getLower();
2697             long maxFreq = info.getFrequencyRangeLong().getUpper();
2698             FrontendCapabilities feCaps = info.getFrontendCapabilities();
2699             switch(info.getType()) {
2700                 case FrontendSettings.TYPE_ANALOG: {
2701                     AnalogFrontendCapabilities analogCaps = (AnalogFrontendCapabilities) caps;
2702                     int signalType = getFirstCapable(analogCaps.getSignalTypeCapability());
2703                     int sif = getFirstCapable(analogCaps.getSifStandardCapability());
2704                     return AnalogFrontendSettings
2705                             .builder()
2706                             .setFrequencyLong(55250000) //2nd freq of VHF
2707                             .setSignalType(signalType)
2708                             .setSifStandard(sif)
2709                             .build();
2710                 }
2711                 case FrontendSettings.TYPE_ATSC3: {
2712                     Atsc3FrontendCapabilities atsc3Caps = (Atsc3FrontendCapabilities) caps;
2713                     int bandwidth = getFirstCapable(atsc3Caps.getBandwidthCapability());
2714                     int demod = getFirstCapable(atsc3Caps.getDemodOutputFormatCapability());
2715                     Atsc3FrontendSettings settings =
2716                             Atsc3FrontendSettings
2717                                     .builder()
2718                                     .setFrequencyLong(473000000) // 1st freq of UHF
2719                                     .setBandwidth(bandwidth)
2720                                     .setDemodOutputFormat(demod)
2721                                     .build();
2722                     settings.setEndFrequencyLong(maxFreq);
2723                     return settings;
2724                 }
2725                 case FrontendSettings.TYPE_ATSC: {
2726                     AtscFrontendCapabilities atscCaps = (AtscFrontendCapabilities) caps;
2727                     int modulation = getFirstCapable(atscCaps.getModulationCapability());
2728                     return AtscFrontendSettings
2729                             .builder()
2730                             .setFrequencyLong(479000000) // 2nd freq of UHF
2731                             .setModulation(modulation)
2732                             .build();
2733                 }
2734                 case FrontendSettings.TYPE_DVBC: {
2735                     DvbcFrontendCapabilities dvbcCaps = (DvbcFrontendCapabilities) caps;
2736                     int modulation = getFirstCapable(dvbcCaps.getModulationCapability());
2737                     int fec = getFirstCapable(dvbcCaps.getFecCapability());
2738                     int annex = getFirstCapable(dvbcCaps.getAnnexCapability());
2739                     DvbcFrontendSettings settings =
2740                             DvbcFrontendSettings
2741                                     .builder()
2742                                     .setFrequencyLong(490000000)
2743                                     .setModulation(modulation)
2744                                     .setInnerFec(fec)
2745                                     .setAnnex(annex)
2746                                     .build();
2747                     settings.setEndFrequencyLong(maxFreq);
2748                     return settings;
2749                 }
2750                 case FrontendSettings.TYPE_DVBS: {
2751                     DvbsFrontendCapabilities dvbsCaps = (DvbsFrontendCapabilities) caps;
2752                     int modulation = getFirstCapable(dvbsCaps.getModulationCapability());
2753                     int standard = getFirstCapable(dvbsCaps.getStandardCapability());
2754                     DvbsFrontendSettings settings =
2755                             DvbsFrontendSettings
2756                                     .builder()
2757                                     .setFrequencyLong(950000000) //950Mhz
2758                                     .setModulation(modulation)
2759                                     .setStandard(standard)
2760                                     .build();
2761                     settings.setEndFrequencyLong(maxFreq);
2762                     return settings;
2763                 }
2764                 case FrontendSettings.TYPE_DVBT: {
2765                     DvbtFrontendCapabilities dvbtCaps = (DvbtFrontendCapabilities) caps;
2766                     int transmission = getFirstCapable(dvbtCaps.getTransmissionModeCapability());
2767                     int bandwidth = getFirstCapable(dvbtCaps.getBandwidthCapability());
2768                     int constellation = getFirstCapable(dvbtCaps.getConstellationCapability());
2769                     int codeRate = getFirstCapable(dvbtCaps.getCodeRateCapability());
2770                     int hierarchy = getFirstCapable(dvbtCaps.getHierarchyCapability());
2771                     int guardInterval = getFirstCapable(dvbtCaps.getGuardIntervalCapability());
2772                     DvbtFrontendSettings settings = DvbtFrontendSettings
2773                             .builder()
2774                             .setFrequencyLong(498000000)
2775                             .setTransmissionMode(transmission)
2776                             .setBandwidth(bandwidth)
2777                             .setConstellation(constellation)
2778                             .setHierarchy(hierarchy)
2779                             .setHighPriorityCodeRate(codeRate)
2780                             .setLowPriorityCodeRate(codeRate)
2781                             .setGuardInterval(guardInterval)
2782                             .setStandard(DvbtFrontendSettings.STANDARD_T)
2783                             .setMiso(false)
2784                             .build();
2785                     settings.setEndFrequencyLong(maxFreq);
2786                     return settings;
2787                 }
2788                 case FrontendSettings.TYPE_ISDBS3: {
2789                     Isdbs3FrontendCapabilities isdbs3Caps = (Isdbs3FrontendCapabilities) caps;
2790                     int modulation = getFirstCapable(isdbs3Caps.getModulationCapability());
2791                     int codeRate = getFirstCapable(isdbs3Caps.getCodeRateCapability());
2792                     Isdbs3FrontendSettings settings = Isdbs3FrontendSettings
2793                             .builder()
2794                             .setFrequencyLong(1000000000) //1000 Mhz
2795                             .setModulation(modulation)
2796                             .setCodeRate(codeRate)
2797                             .build();
2798                     settings.setEndFrequencyLong(maxFreq);
2799                     return settings;
2800                 }
2801                 case FrontendSettings.TYPE_ISDBS: {
2802                     IsdbsFrontendCapabilities isdbsCaps = (IsdbsFrontendCapabilities) caps;
2803                     int modulation = getFirstCapable(isdbsCaps.getModulationCapability());
2804                     int codeRate = getFirstCapable(isdbsCaps.getCodeRateCapability());
2805                     IsdbsFrontendSettings settings = IsdbsFrontendSettings
2806                             .builder()
2807                             .setFrequencyLong(1050000000) //1050 Mhz
2808                             .setModulation(modulation)
2809                             .setCodeRate(codeRate)
2810                             .build();
2811                     settings.setEndFrequencyLong(maxFreq);
2812                     return settings;
2813                 }
2814                 case FrontendSettings.TYPE_ISDBT: {
2815                     IsdbtFrontendCapabilities isdbtCaps = (IsdbtFrontendCapabilities) caps;
2816                     int mode = getFirstCapable(isdbtCaps.getModeCapability());
2817                     int bandwidth = getFirstCapable(isdbtCaps.getBandwidthCapability());
2818                     int modulation = getFirstCapable(isdbtCaps.getModulationCapability());
2819                     int codeRate = getFirstCapable(isdbtCaps.getCodeRateCapability());
2820                     int guardInterval = getFirstCapable(isdbtCaps.getGuardIntervalCapability());
2821                     int timeInterleaveMode =
2822                             getFirstCapable(isdbtCaps.getTimeInterleaveModeCapability());
2823                     boolean isSegmentAutoSupported = isdbtCaps.isSegmentAutoSupported();
2824                     boolean isFullSegmentSupported = isdbtCaps.isFullSegmentSupported();
2825 
2826                     IsdbtFrontendSettings.Builder builder = IsdbtFrontendSettings.builder();
2827                     builder.setFrequencyLong(527143000); //22 ch    527.143 MHz
2828                     builder.setBandwidth(bandwidth);
2829                     builder.setMode(mode);
2830                     builder.setGuardInterval(guardInterval);
2831 
2832                     if (!TunerVersionChecker.isHigherOrEqualVersionTo(
2833                                 TunerVersionChecker.TUNER_VERSION_2_0)) {
2834                         builder.setModulation(modulation);
2835                         builder.setCodeRate(codeRate);
2836                     } else {
2837                         IsdbtFrontendSettings.IsdbtLayerSettings.Builder layerBuilder =
2838                                 IsdbtFrontendSettings.IsdbtLayerSettings.builder();
2839                         layerBuilder.setTimeInterleaveMode(timeInterleaveMode);
2840                         layerBuilder.setModulation(modulation);
2841                         layerBuilder.setCodeRate(codeRate);
2842                         if (isSegmentAutoSupported) {
2843                             layerBuilder.setNumberOfSegments(0xFF);
2844                         } else {
2845                             if (isFullSegmentSupported) {
2846                                 layerBuilder.setNumberOfSegments(13);
2847                             } else {
2848                                 layerBuilder.setNumberOfSegments(1);
2849                             }
2850                         }
2851                         IsdbtFrontendSettings.IsdbtLayerSettings layer = layerBuilder.build();
2852                         builder.setLayerSettings(
2853                                 new IsdbtFrontendSettings.IsdbtLayerSettings[] {layer});
2854                         builder.setPartialReceptionFlag(
2855                                 IsdbtFrontendSettings.PARTIAL_RECEPTION_FLAG_TRUE);
2856                     }
2857                     IsdbtFrontendSettings settings = builder.build();
2858                     settings.setEndFrequencyLong(maxFreq);
2859                     return settings;
2860                 }
2861                 case FrontendSettings.TYPE_DTMB: {
2862                     DtmbFrontendCapabilities dtmbCaps = (DtmbFrontendCapabilities) caps;
2863                     int modulation = getFirstCapable(dtmbCaps.getModulationCapability());
2864                     int transmissionMode = getFirstCapable(
2865                             dtmbCaps.getTransmissionModeCapability());
2866                     int guardInterval = getFirstCapable(dtmbCaps.getGuardIntervalCapability());
2867                     int timeInterleaveMode = getFirstCapable(
2868                             dtmbCaps.getTimeInterleaveModeCapability());
2869                     int codeRate = getFirstCapable(dtmbCaps.getCodeRateCapability());
2870                     int bandwidth = getFirstCapable(dtmbCaps.getBandwidthCapability());
2871                     DtmbFrontendSettings settings =
2872                             DtmbFrontendSettings
2873                                     .builder()
2874                                     .setFrequencyLong(506000000)
2875                                     .setModulation(modulation)
2876                                     .setTransmissionMode(transmissionMode)
2877                                     .setBandwidth(bandwidth)
2878                                     .setCodeRate(codeRate)
2879                                     .setGuardInterval(guardInterval)
2880                                     .setTimeInterleaveMode(timeInterleaveMode)
2881                                     .build();
2882                     settings.setEndFrequencyLong(maxFreq);
2883                     return settings;
2884                 }
2885                 default:
2886                     break;
2887             }
2888         return null;
2889     }
2890 
2891     static public int getFirstCapable(int caps) {
2892         if (caps == 0) return 0;
2893         int mask = 1;
2894         while ((mask & caps) == 0) {
2895             mask = mask << 1;
2896         }
2897         return (mask & caps);
2898     }
2899 
2900     static public long getFirstCapable(long caps) {
2901         if (caps == 0) return 0;
2902         long mask = 1;
2903         while ((mask & caps) == 0) {
2904             mask = mask << 1;
2905         }
2906         return (mask & caps);
2907     }
2908 
2909     private ScanCallback getScanCallback() {
2910         return new ScanCallback() {
2911             @Override
2912             public void onLocked() {
2913                 if (mLockLatch != null) {
2914                     mLockLatch.countDown();
2915                 }
2916             }
2917 
2918             @Override
2919             public void onUnlocked() {
2920                 ScanCallback.super.onUnlocked();
2921                 if (mLockLatch != null) {
2922                     mLockLatch.countDown();
2923                 }
2924             }
2925 
2926             @Override
2927             public void onScanStopped() {}
2928 
2929             @Override
2930             public void onProgress(int percent) {}
2931 
2932             @Override
2933             public void onFrequenciesReported(int[] frequency) {}
2934 
2935             @Override
2936             public void onFrequenciesLongReported(long[] frequencies) {
2937                 ScanCallback.super.onFrequenciesLongReported(frequencies);
2938             }
2939 
2940             @Override
2941             public void onSymbolRatesReported(int[] rate) {}
2942 
2943             @Override
2944             public void onPlpIdsReported(int[] plpIds) {}
2945 
2946             @Override
2947             public void onGroupIdsReported(int[] groupIds) {}
2948 
2949             @Override
2950             public void onInputStreamIdsReported(int[] inputStreamIds) {}
2951 
2952             @Override
2953             public void onDvbsStandardReported(int dvbsStandard) {}
2954 
2955             @Override
2956             public void onDvbtStandardReported(int dvbtStandard) {}
2957 
2958             @Override
2959             public void onAnalogSifStandardReported(int sif) {}
2960 
2961             @Override
2962             public void onAtsc3PlpInfosReported(Atsc3PlpInfo[] atsc3PlpInfos) {
2963                 for (Atsc3PlpInfo info : atsc3PlpInfos) {
2964                     if (info != null) {
2965                         info.getPlpId();
2966                         info.getLlsFlag();
2967                     }
2968                 }
2969             }
2970 
2971             @Override
2972             public void onHierarchyReported(int hierarchy) {}
2973 
2974             @Override
2975             public void onSignalTypeReported(int signalType) {}
2976 
2977             @Override
2978             public void onModulationReported(int modulation) {
2979                 ScanCallback.super.onModulationReported(modulation);
2980             }
2981 
2982             @Override
2983             public void onPriorityReported(boolean isHighPriority) {
2984                 ScanCallback.super.onPriorityReported(isHighPriority);
2985             }
2986 
2987             @Override
2988             public void onDvbcAnnexReported(int dvbcAnnext) {
2989                 ScanCallback.super.onDvbcAnnexReported(dvbcAnnext);
2990             }
2991 
2992             @Override
2993             public void onDvbtCellIdsReported(int[] dvbtCellIds) {
2994                 ScanCallback.super.onDvbtCellIdsReported(dvbtCellIds);
2995             }
2996         };
2997     }
2998 
2999     // TunerHandler utility for testing Tuner api calls in a different thread
3000     private static final int MSG_TUNER_HANDLER_CREATE = 1;
3001     private static final int MSG_TUNER_HANDLER_TUNE = 2;
3002     private static final int MSG_TUNER_HANDLER_CLOSE = 3;
3003 
3004     private ConditionVariable mTunerHandlerTaskComplete = new ConditionVariable();
3005 
3006     private TunerHandler createTunerHandler(Looper looper) {
3007         if (looper != null) {
3008             return new TunerHandler(looper);
3009         } else if ((looper = Looper.myLooper()) != null) {
3010             return new TunerHandler(looper);
3011         } else if ((looper = Looper.getMainLooper()) != null) {
3012             return new TunerHandler(looper);
3013         }
3014         return null;
3015     }
3016 
3017     private class TunerHandler extends Handler {
3018         Object mLock = new Object();
3019         Tuner mHandlersTuner;
3020         int mResult;
3021 
3022         private TunerHandler(Looper looper) {
3023             super(looper);
3024         }
3025 
3026         public Tuner getTuner() {
3027             synchronized (mLock) {
3028                 return mHandlersTuner;
3029             }
3030         }
3031 
3032         public int getResult() {
3033             synchronized (mLock) {
3034                 return mResult;
3035             }
3036         }
3037 
3038         @Override
3039         public void handleMessage(Message msg) {
3040             switch (msg.what) {
3041                 case MSG_TUNER_HANDLER_CREATE: {
3042                     synchronized (mLock) {
3043                         int useCase = msg.arg1;
3044                         mHandlersTuner = new Tuner(mContext, null, useCase);
3045                     }
3046                     break;
3047                 }
3048                 case MSG_TUNER_HANDLER_TUNE: {
3049                     synchronized (mLock) {
3050                         FrontendSettings feSettings = (FrontendSettings) msg.obj;
3051                         mResult = mHandlersTuner.tune(feSettings);
3052                     }
3053                     break;
3054                 }
3055                 case MSG_TUNER_HANDLER_CLOSE: {
3056                     synchronized (mLock) {
3057                         mHandlersTuner.close();
3058                     }
3059                     break;
3060                 }
3061                 default:
3062                     break;
3063             }
3064             mTunerHandlerTaskComplete.open();
3065         }
3066     }
3067 }
3068