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