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