• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.data;
18 
19 import static android.support.test.InstrumentationRegistry.getInstrumentation;
20 import static android.support.test.InstrumentationRegistry.getTargetContext;
21 import static com.google.common.truth.Truth.assertThat;
22 import static com.google.common.truth.Truth.assertWithMessage;
23 
24 import android.content.ContentProvider;
25 import android.content.ContentUris;
26 import android.content.ContentValues;
27 import android.content.Context;
28 import android.database.ContentObserver;
29 import android.database.Cursor;
30 import android.media.tv.TvContract;
31 import android.media.tv.TvContract.Channels;
32 import android.net.Uri;
33 import android.os.AsyncTask;
34 import android.support.test.filters.SmallTest;
35 import android.support.test.runner.AndroidJUnit4;
36 import android.test.MoreAsserts;
37 import android.test.mock.MockContentProvider;
38 import android.test.mock.MockContentResolver;
39 import android.test.mock.MockCursor;
40 import android.text.TextUtils;
41 import android.util.Log;
42 import android.util.SparseArray;
43 import com.android.tv.data.api.Channel;
44 import com.android.tv.testing.constants.Constants;
45 import com.android.tv.testing.data.ChannelInfo;
46 import com.android.tv.util.TvInputManagerHelper;
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.List;
50 import java.util.concurrent.CountDownLatch;
51 import java.util.concurrent.TimeUnit;
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 import org.mockito.Matchers;
57 import org.mockito.Mockito;
58 
59 /**
60  * Test for {@link ChannelDataManager}
61  *
62  * <p>A test method may include tests for multiple methods to minimize the DB access. Note that all
63  * the methods of {@link ChannelDataManager} should be called from the UI thread.
64  */
65 @SmallTest
66 @RunWith(AndroidJUnit4.class)
67 public class ChannelDataManagerTest {
68     private static final boolean DEBUG = false;
69     private static final String TAG = "ChannelDataManagerTest";
70 
71     // Wait time for expected success.
72     private static final long WAIT_TIME_OUT_MS = 1000L;
73     private static final String DUMMY_INPUT_ID = "dummy";
74     private static final String COLUMN_BROWSABLE = "browsable";
75     private static final String COLUMN_LOCKED = "locked";
76 
77     private ChannelDataManager mChannelDataManager;
78     private TestChannelDataManagerListener mListener;
79     private FakeContentResolver mContentResolver;
80     private FakeContentProvider mContentProvider;
81 
82     @Before
setUp()83     public void setUp() {
84         assertWithMessage("More than 2 channels to test")
85                 .that(Constants.UNIT_TEST_CHANNEL_COUNT > 2)
86                 .isTrue();
87 
88         mContentProvider = new FakeContentProvider(getTargetContext());
89         mContentResolver = new FakeContentResolver();
90         mContentResolver.addProvider(TvContract.AUTHORITY, mContentProvider);
91         mListener = new TestChannelDataManagerListener();
92         getInstrumentation()
93                 .runOnMainSync(
94                         new Runnable() {
95                             @Override
96                             public void run() {
97                                 TvInputManagerHelper mockHelper =
98                                         Mockito.mock(TvInputManagerHelper.class);
99                                 Mockito.when(mockHelper.hasTvInputInfo(Matchers.anyString()))
100                                         .thenReturn(true);
101                                 mChannelDataManager =
102                                         new ChannelDataManager(
103                                                 getTargetContext(),
104                                                 mockHelper,
105                                                 AsyncTask.SERIAL_EXECUTOR,
106                                                 mContentResolver);
107                                 mChannelDataManager.addListener(mListener);
108                             }
109                         });
110     }
111 
112     @After
tearDown()113     public void tearDown() {
114         getInstrumentation()
115                 .runOnMainSync(
116                         new Runnable() {
117                             @Override
118                             public void run() {
119                                 mChannelDataManager.stop();
120                             }
121                         });
122     }
123 
startAndWaitForComplete()124     private void startAndWaitForComplete() throws InterruptedException {
125         getInstrumentation()
126                 .runOnMainSync(
127                         new Runnable() {
128                             @Override
129                             public void run() {
130                                 mChannelDataManager.start();
131                             }
132                         });
133         assertThat(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
134                 .isTrue();
135     }
136 
restart()137     private void restart() throws InterruptedException {
138         getInstrumentation()
139                 .runOnMainSync(
140                         new Runnable() {
141                             @Override
142                             public void run() {
143                                 mChannelDataManager.stop();
144                                 mListener.reset();
145                             }
146                         });
147         startAndWaitForComplete();
148     }
149 
150     @Test
testIsDbLoadFinished()151     public void testIsDbLoadFinished() throws InterruptedException {
152         startAndWaitForComplete();
153         assertThat(mChannelDataManager.isDbLoadFinished()).isTrue();
154     }
155 
156     /**
157      * Test for following methods - {@link ChannelDataManager#getChannelCount} - {@link
158      * ChannelDataManager#getChannelList} - {@link ChannelDataManager#getChannel}
159      */
160     @Test
testGetChannels()161     public void testGetChannels() throws InterruptedException {
162         startAndWaitForComplete();
163 
164         // Test {@link ChannelDataManager#getChannelCount}
165         assertThat(mChannelDataManager.getChannelCount())
166                 .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT);
167 
168         // Test {@link ChannelDataManager#getChannelList}
169         List<ChannelInfo> channelInfoList = new ArrayList<>();
170         for (int i = 1; i <= Constants.UNIT_TEST_CHANNEL_COUNT; i++) {
171             channelInfoList.add(ChannelInfo.create(getTargetContext(), i));
172         }
173         List<Channel> channelList = mChannelDataManager.getChannelList();
174         for (Channel channel : channelList) {
175             boolean found = false;
176             for (ChannelInfo channelInfo : channelInfoList) {
177                 if (TextUtils.equals(channelInfo.name, channel.getDisplayName())) {
178                     found = true;
179                     channelInfoList.remove(channelInfo);
180                     break;
181                 }
182             }
183             assertWithMessage("Cannot find (" + channel + ")").that(found).isTrue();
184         }
185 
186         // Test {@link ChannelDataManager#getChannelIndex()}
187         for (Channel channel : channelList) {
188             assertThat(mChannelDataManager.getChannel(channel.getId())).isEqualTo(channel);
189         }
190     }
191 
192     /** Test for {@link ChannelDataManager#getChannelCount} when no channel is available. */
193     @Test
testGetChannels_noChannels()194     public void testGetChannels_noChannels() throws InterruptedException {
195         mContentProvider.clear();
196         startAndWaitForComplete();
197         assertThat(mChannelDataManager.getChannelCount()).isEqualTo(0);
198     }
199 
200     /**
201      * Test for following methods and channel listener with notifying change. - {@link
202      * ChannelDataManager#updateBrowsable} - {@link ChannelDataManager#applyUpdatedValuesToDb}
203      */
204     @Test
testBrowsable()205     public void testBrowsable() throws InterruptedException {
206         startAndWaitForComplete();
207 
208         // Test if all channels are browsable
209         List<Channel> channelList = mChannelDataManager.getChannelList();
210         List<Channel> browsableChannelList = mChannelDataManager.getBrowsableChannelList();
211         for (Channel browsableChannel : browsableChannelList) {
212             boolean found = channelList.remove(browsableChannel);
213             assertWithMessage("Cannot find (" + browsableChannel + ")").that(found).isTrue();
214         }
215         assertThat(channelList).isEmpty();
216 
217         // Prepare for next tests.
218         channelList = mChannelDataManager.getChannelList();
219         TestChannelDataManagerChannelListener channelListener =
220                 new TestChannelDataManagerChannelListener();
221         Channel channel1 = channelList.get(0);
222         mChannelDataManager.addChannelListener(channel1.getId(), channelListener);
223 
224         // Test {@link ChannelDataManager#updateBrowsable} & notification.
225         mChannelDataManager.updateBrowsable(channel1.getId(), false, false);
226         assertThat(mListener.channelBrowsableChangedCalled).isTrue();
227         assertThat(mChannelDataManager.getBrowsableChannelList()).doesNotContain(channel1);
228         MoreAsserts.assertContentsInAnyOrder(channelListener.updatedChannels, channel1);
229         channelListener.reset();
230 
231         // Test {@link ChannelDataManager#applyUpdatedValuesToDb}
232         // Disable the update notification to avoid the unwanted call of "onLoadFinished".
233         mContentResolver.mNotifyDisabled = true;
234         mChannelDataManager.applyUpdatedValuesToDb();
235         restart();
236         browsableChannelList = mChannelDataManager.getBrowsableChannelList();
237         assertThat(browsableChannelList).hasSize(Constants.UNIT_TEST_CHANNEL_COUNT - 1);
238         assertThat(browsableChannelList).doesNotContain(channel1);
239     }
240 
241     /**
242      * Test for following methods and channel listener without notifying change. - {@link
243      * ChannelDataManager#updateBrowsable} - {@link ChannelDataManager#applyUpdatedValuesToDb}
244      */
245     @Test
testBrowsable_skipNotification()246     public void testBrowsable_skipNotification() throws InterruptedException {
247         startAndWaitForComplete();
248 
249         List<Channel> channels = mChannelDataManager.getChannelList();
250         // Prepare for next tests.
251         TestChannelDataManagerChannelListener channelListener =
252                 new TestChannelDataManagerChannelListener();
253         Channel channel1 = channels.get(0);
254         Channel channel2 = channels.get(1);
255         mChannelDataManager.addChannelListener(channel1.getId(), channelListener);
256         mChannelDataManager.addChannelListener(channel2.getId(), channelListener);
257 
258         // Test {@link ChannelDataManager#updateBrowsable} & skip notification.
259         mChannelDataManager.updateBrowsable(channel1.getId(), false, true);
260         mChannelDataManager.updateBrowsable(channel2.getId(), false, true);
261         mChannelDataManager.updateBrowsable(channel1.getId(), true, true);
262         assertThat(mListener.channelBrowsableChangedCalled).isFalse();
263         List<Channel> browsableChannelList = mChannelDataManager.getBrowsableChannelList();
264         assertThat(browsableChannelList).contains(channel1);
265         assertThat(browsableChannelList).doesNotContain(channel2);
266 
267         // Test {@link ChannelDataManager#applyUpdatedValuesToDb}
268         // Disable the update notification to avoid the unwanted call of "onLoadFinished".
269         mContentResolver.mNotifyDisabled = true;
270         mChannelDataManager.applyUpdatedValuesToDb();
271         restart();
272         browsableChannelList = mChannelDataManager.getBrowsableChannelList();
273         assertThat(browsableChannelList).hasSize(Constants.UNIT_TEST_CHANNEL_COUNT - 1);
274         assertThat(browsableChannelList).doesNotContain(channel2);
275     }
276 
277     /**
278      * Test for following methods and channel listener. - {@link ChannelDataManager#updateLocked} -
279      * {@link ChannelDataManager#applyUpdatedValuesToDb}
280      */
281     @Test
testLocked()282     public void testLocked() throws InterruptedException {
283         startAndWaitForComplete();
284 
285         // Test if all channels aren't locked at the first time.
286         List<Channel> channelList = mChannelDataManager.getChannelList();
287         for (Channel channel : channelList) {
288             assertWithMessage(channel + " is locked").that(channel.isLocked()).isFalse();
289         }
290 
291         // Prepare for next tests.
292         Channel channel = mChannelDataManager.getChannelList().get(0);
293 
294         // Test {@link ChannelDataManager#updateLocked}
295         mChannelDataManager.updateLocked(channel.getId(), true);
296         assertThat(mChannelDataManager.getChannel(channel.getId()).isLocked()).isTrue();
297 
298         // Test {@link ChannelDataManager#applyUpdatedValuesToDb}.
299         // Disable the update notification to avoid the unwanted call of "onLoadFinished".
300         mContentResolver.mNotifyDisabled = true;
301         mChannelDataManager.applyUpdatedValuesToDb();
302         restart();
303         assertThat(mChannelDataManager.getChannel(channel.getId()).isLocked()).isTrue();
304 
305         // Cleanup
306         mChannelDataManager.updateLocked(channel.getId(), false);
307     }
308 
309     /** Test ChannelDataManager when channels in TvContract are updated, removed, or added. */
310     @Test
testChannelListChanged()311     public void testChannelListChanged() throws InterruptedException {
312         startAndWaitForComplete();
313 
314         // Test channel add.
315         mListener.reset();
316         long testChannelId = Constants.UNIT_TEST_CHANNEL_COUNT + 1;
317         ChannelInfo testChannelInfo = ChannelInfo.create(getTargetContext(), (int) testChannelId);
318         testChannelId = Constants.UNIT_TEST_CHANNEL_COUNT + 1;
319         mContentProvider.simulateInsert(testChannelInfo);
320         assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
321                 .isTrue();
322         assertThat(mChannelDataManager.getChannelCount())
323                 .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT + 1);
324 
325         // Test channel update
326         mListener.reset();
327         TestChannelDataManagerChannelListener channelListener =
328                 new TestChannelDataManagerChannelListener();
329         mChannelDataManager.addChannelListener(testChannelId, channelListener);
330         String newName = testChannelInfo.name + "_test";
331         mContentProvider.simulateUpdate(testChannelId, newName);
332         assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
333                 .isTrue();
334         assertThat(
335                         channelListener.channelChangedLatch.await(
336                                 WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
337                 .isTrue();
338         assertThat(channelListener.removedChannels).isEmpty();
339         assertThat(channelListener.updatedChannels).hasSize(1);
340         Channel updatedChannel = channelListener.updatedChannels.get(0);
341         assertThat(updatedChannel.getId()).isEqualTo(testChannelId);
342         assertThat(updatedChannel.getDisplayNumber()).isEqualTo(testChannelInfo.number);
343         assertThat(updatedChannel.getDisplayName()).isEqualTo(newName);
344         assertThat(mChannelDataManager.getChannelCount())
345                 .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT + 1);
346 
347         // Test channel remove.
348         mListener.reset();
349         channelListener.reset();
350         mContentProvider.simulateDelete(testChannelId);
351         assertThat(mListener.channelListUpdatedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
352                 .isTrue();
353         assertThat(
354                         channelListener.channelChangedLatch.await(
355                                 WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS))
356                 .isTrue();
357         assertThat(channelListener.removedChannels).hasSize(1);
358         assertThat(channelListener.updatedChannels).isEmpty();
359         Channel removedChannel = channelListener.removedChannels.get(0);
360         assertThat(removedChannel.getDisplayName()).isEqualTo(newName);
361         assertThat(removedChannel.getDisplayNumber()).isEqualTo(testChannelInfo.number);
362         assertThat(mChannelDataManager.getChannelCount())
363                 .isEqualTo(Constants.UNIT_TEST_CHANNEL_COUNT);
364     }
365 
366     private static class ChannelInfoWrapper {
367         public ChannelInfo channelInfo;
368         public boolean browsable;
369         public boolean locked;
370 
ChannelInfoWrapper(ChannelInfo channelInfo)371         public ChannelInfoWrapper(ChannelInfo channelInfo) {
372             this.channelInfo = channelInfo;
373             browsable = true;
374             locked = false;
375         }
376     }
377 
378     private class FakeContentResolver extends MockContentResolver {
379         boolean mNotifyDisabled;
380 
381         @Override
notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork)382         public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
383             super.notifyChange(uri, observer, syncToNetwork);
384             if (DEBUG) {
385                 Log.d(
386                         TAG,
387                         "onChanged(uri="
388                                 + uri
389                                 + ", observer="
390                                 + observer
391                                 + ") - Notification "
392                                 + (mNotifyDisabled ? "disabled" : "enabled"));
393             }
394             if (mNotifyDisabled) {
395                 return;
396             }
397             // Do not call {@link ContentObserver#onChange} directly to run it on the correct
398             // thread.
399             if (observer != null) {
400                 observer.dispatchChange(false, uri);
401             } else {
402                 mChannelDataManager.getContentObserver().dispatchChange(false, uri);
403             }
404         }
405     }
406 
407     // This implements the minimal methods in content resolver
408     // and detailed assumptions are written in each method.
409     private class FakeContentProvider extends MockContentProvider {
410         private final SparseArray<ChannelInfoWrapper> mChannelInfoList = new SparseArray<>();
411 
FakeContentProvider(Context context)412         public FakeContentProvider(Context context) {
413             super(context);
414             for (int i = 1; i <= Constants.UNIT_TEST_CHANNEL_COUNT; i++) {
415                 mChannelInfoList.put(
416                         i, new ChannelInfoWrapper(ChannelInfo.create(getTargetContext(), i)));
417             }
418         }
419 
420         /**
421          * Implementation of {@link ContentProvider#query}. This assumes that {@link
422          * ChannelDataManager} queries channels with empty {@code selection}. (i.e. channels are
423          * always queries for all)
424          */
425         @Override
query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)426         public Cursor query(
427                 Uri uri,
428                 String[] projection,
429                 String selection,
430                 String[] selectionArgs,
431                 String sortOrder) {
432             if (DEBUG) {
433                 Log.d(TAG, "dump query");
434                 Log.d(TAG, "  uri=" + uri);
435                 Log.d(TAG, "  projection=" + Arrays.toString(projection));
436                 Log.d(TAG, "  selection=" + selection);
437             }
438             assertChannelUri(uri);
439             return new FakeCursor(projection);
440         }
441 
442         /**
443          * Implementation of {@link ContentProvider#update}. This assumes that {@link
444          * ChannelDataManager} update channels only for changing browsable and locked.
445          */
446         @Override
update(Uri uri, ContentValues values, String selection, String[] selectionArgs)447         public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
448             if (DEBUG) Log.d(TAG, "update(uri=" + uri + ", selection=" + selection);
449             assertChannelUri(uri);
450             List<Long> channelIds = new ArrayList<>();
451             try {
452                 long channelId = ContentUris.parseId(uri);
453                 channelIds.add(channelId);
454             } catch (NumberFormatException e) {
455                 // Update for multiple channels.
456                 if (TextUtils.isEmpty(selection)) {
457                     for (int i = 0; i < mChannelInfoList.size(); i++) {
458                         channelIds.add((long) mChannelInfoList.keyAt(i));
459                     }
460                 } else {
461                     // See {@link Utils#buildSelectionForIds} for the syntax.
462                     String selectionForId =
463                             selection.substring(
464                                     selection.indexOf("(") + 1, selection.lastIndexOf(")"));
465                     String[] ids = selectionForId.split(", ");
466                     if (ids != null) {
467                         for (String id : ids) {
468                             channelIds.add(Long.parseLong(id));
469                         }
470                     }
471                 }
472             }
473             int updateCount = 0;
474             for (long channelId : channelIds) {
475                 boolean updated = false;
476                 ChannelInfoWrapper channel = mChannelInfoList.get((int) channelId);
477                 if (channel == null) {
478                     return 0;
479                 }
480                 if (values.containsKey(COLUMN_BROWSABLE)) {
481                     updated = true;
482                     channel.browsable = (values.getAsInteger(COLUMN_BROWSABLE) == 1);
483                 }
484                 if (values.containsKey(COLUMN_LOCKED)) {
485                     updated = true;
486                     channel.locked = (values.getAsInteger(COLUMN_LOCKED) == 1);
487                 }
488                 updateCount += updated ? 1 : 0;
489             }
490             if (updateCount > 0) {
491                 if (channelIds.size() == 1) {
492                     mContentResolver.notifyChange(uri, null);
493                 } else {
494                     mContentResolver.notifyChange(Channels.CONTENT_URI, null);
495                 }
496             } else {
497                 if (DEBUG) {
498                     Log.d(TAG, "Update to channel(uri=" + uri + ") is ignored for " + values);
499                 }
500             }
501             return updateCount;
502         }
503 
504         /**
505          * Simulates channel data insert. This assigns original network ID (the same with channel
506          * number) to channel ID.
507          */
simulateInsert(ChannelInfo testChannelInfo)508         public void simulateInsert(ChannelInfo testChannelInfo) {
509             long channelId = testChannelInfo.originalNetworkId;
510             mChannelInfoList.put(
511                     (int) channelId,
512                     new ChannelInfoWrapper(
513                             ChannelInfo.create(getTargetContext(), (int) channelId)));
514             mContentResolver.notifyChange(TvContract.buildChannelUri(channelId), null);
515         }
516 
517         /** Simulates channel data delete. */
simulateDelete(long channelId)518         public void simulateDelete(long channelId) {
519             mChannelInfoList.remove((int) channelId);
520             mContentResolver.notifyChange(TvContract.buildChannelUri(channelId), null);
521         }
522 
523         /** Simulates channel data update. */
simulateUpdate(long channelId, String newName)524         public void simulateUpdate(long channelId, String newName) {
525             ChannelInfoWrapper channel = mChannelInfoList.get((int) channelId);
526             ChannelInfo.Builder builder = new ChannelInfo.Builder(channel.channelInfo);
527             builder.setName(newName);
528             channel.channelInfo = builder.build();
529             mContentResolver.notifyChange(TvContract.buildChannelUri(channelId), null);
530         }
531 
assertChannelUri(Uri uri)532         private void assertChannelUri(Uri uri) {
533             assertWithMessage("Uri(" + uri + ") isn't channel uri")
534                     .that(uri.toString().startsWith(Channels.CONTENT_URI.toString()))
535                     .isTrue();
536         }
537 
clear()538         public void clear() {
539             mChannelInfoList.clear();
540         }
541 
get(int position)542         public ChannelInfoWrapper get(int position) {
543             return mChannelInfoList.get(mChannelInfoList.keyAt(position));
544         }
545 
getCount()546         public int getCount() {
547             return mChannelInfoList.size();
548         }
549 
keyAt(int position)550         public long keyAt(int position) {
551             return mChannelInfoList.keyAt(position);
552         }
553     }
554 
555     private class FakeCursor extends MockCursor {
556         private final String[] allColumns = {
557             Channels._ID,
558             Channels.COLUMN_DISPLAY_NAME,
559             Channels.COLUMN_DISPLAY_NUMBER,
560             Channels.COLUMN_INPUT_ID,
561             Channels.COLUMN_VIDEO_FORMAT,
562             Channels.COLUMN_ORIGINAL_NETWORK_ID,
563             COLUMN_BROWSABLE,
564             COLUMN_LOCKED
565         };
566         private final String[] mColumns;
567         private int mPosition;
568 
FakeCursor(String[] columns)569         public FakeCursor(String[] columns) {
570             mColumns = (columns == null) ? allColumns : columns;
571             mPosition = -1;
572         }
573 
574         @Override
getColumnName(int columnIndex)575         public String getColumnName(int columnIndex) {
576             return mColumns[columnIndex];
577         }
578 
579         @Override
getColumnIndex(String columnName)580         public int getColumnIndex(String columnName) {
581             for (int i = 0; i < mColumns.length; i++) {
582                 if (mColumns[i].equalsIgnoreCase(columnName)) {
583                     return i;
584                 }
585             }
586             return -1;
587         }
588 
589         @Override
getLong(int columnIndex)590         public long getLong(int columnIndex) {
591             String columnName = getColumnName(columnIndex);
592             switch (columnName) {
593                 case Channels._ID:
594                     return mContentProvider.keyAt(mPosition);
595                 default: // fall out
596             }
597             if (DEBUG) {
598                 Log.d(TAG, "Column (" + columnName + ") is ignored in getLong()");
599             }
600             return 0;
601         }
602 
603         @Override
getString(int columnIndex)604         public String getString(int columnIndex) {
605             String columnName = getColumnName(columnIndex);
606             ChannelInfoWrapper channel = mContentProvider.get(mPosition);
607             switch (columnName) {
608                 case Channels.COLUMN_DISPLAY_NAME:
609                     return channel.channelInfo.name;
610                 case Channels.COLUMN_DISPLAY_NUMBER:
611                     return channel.channelInfo.number;
612                 case Channels.COLUMN_INPUT_ID:
613                     return DUMMY_INPUT_ID;
614                 case Channels.COLUMN_VIDEO_FORMAT:
615                     return channel.channelInfo.getVideoFormat();
616                 default: // fall out
617             }
618             if (DEBUG) {
619                 Log.d(TAG, "Column (" + columnName + ") is ignored in getString()");
620             }
621             return null;
622         }
623 
624         @Override
getInt(int columnIndex)625         public int getInt(int columnIndex) {
626             String columnName = getColumnName(columnIndex);
627             ChannelInfoWrapper channel = mContentProvider.get(mPosition);
628             switch (columnName) {
629                 case Channels.COLUMN_ORIGINAL_NETWORK_ID:
630                     return channel.channelInfo.originalNetworkId;
631                 case COLUMN_BROWSABLE:
632                     return channel.browsable ? 1 : 0;
633                 case COLUMN_LOCKED:
634                     return channel.locked ? 1 : 0;
635                 default: // fall out
636             }
637             if (DEBUG) {
638                 Log.d(TAG, "Column (" + columnName + ") is ignored in getInt()");
639             }
640             return 0;
641         }
642 
643         @Override
getCount()644         public int getCount() {
645             return mContentProvider.getCount();
646         }
647 
648         @Override
moveToNext()649         public boolean moveToNext() {
650             return ++mPosition < mContentProvider.getCount();
651         }
652 
653         @Override
close()654         public void close() {
655             // No-op.
656         }
657     }
658 
659     private static class TestChannelDataManagerListener implements ChannelDataManager.Listener {
660         public CountDownLatch loadFinishedLatch = new CountDownLatch(1);
661         public CountDownLatch channelListUpdatedLatch = new CountDownLatch(1);
662         public boolean channelBrowsableChangedCalled;
663 
664         @Override
onLoadFinished()665         public void onLoadFinished() {
666             loadFinishedLatch.countDown();
667         }
668 
669         @Override
onChannelListUpdated()670         public void onChannelListUpdated() {
671             channelListUpdatedLatch.countDown();
672         }
673 
674         @Override
onChannelBrowsableChanged()675         public void onChannelBrowsableChanged() {
676             channelBrowsableChangedCalled = true;
677         }
678 
reset()679         public void reset() {
680             loadFinishedLatch = new CountDownLatch(1);
681             channelListUpdatedLatch = new CountDownLatch(1);
682             channelBrowsableChangedCalled = false;
683         }
684     }
685 
686     private static class TestChannelDataManagerChannelListener
687             implements ChannelDataManager.ChannelListener {
688         public CountDownLatch channelChangedLatch = new CountDownLatch(1);
689         public final List<Channel> removedChannels = new ArrayList<>();
690         public final List<Channel> updatedChannels = new ArrayList<>();
691 
692         @Override
onChannelRemoved(Channel channel)693         public void onChannelRemoved(Channel channel) {
694             removedChannels.add(channel);
695             channelChangedLatch.countDown();
696         }
697 
698         @Override
onChannelUpdated(Channel channel)699         public void onChannelUpdated(Channel channel) {
700             updatedChannels.add(channel);
701             channelChangedLatch.countDown();
702         }
703 
reset()704         public void reset() {
705             channelChangedLatch = new CountDownLatch(1);
706             removedChannels.clear();
707             updatedChannels.clear();
708         }
709     }
710 }
711