1 /* 2 * Copyright (C) 2014 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.cts; 18 19 import android.content.ComponentName; 20 import android.content.ContentResolver; 21 import android.content.ContentUris; 22 import android.content.ContentValues; 23 import android.content.res.AssetFileDescriptor; 24 import android.database.Cursor; 25 import android.graphics.Bitmap; 26 import android.graphics.BitmapFactory; 27 import android.media.tv.TvContentRating; 28 import android.media.tv.TvContract; 29 import android.net.Uri; 30 import android.test.AndroidTestCase; 31 32 import com.android.cts.tv.R; 33 34 import java.io.InputStream; 35 import java.io.OutputStream; 36 37 /** 38 * Test for {@link android.media.tv.TvContract}. 39 */ 40 public class TvContractTest extends AndroidTestCase { 41 private static final String[] CHANNELS_PROJECTION = { 42 TvContract.Channels._ID, 43 TvContract.Channels.COLUMN_INPUT_ID, 44 TvContract.Channels.COLUMN_TYPE, 45 TvContract.Channels.COLUMN_SERVICE_TYPE, 46 TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, 47 TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID, 48 TvContract.Channels.COLUMN_SERVICE_ID, 49 TvContract.Channels.COLUMN_DISPLAY_NUMBER, 50 TvContract.Channels.COLUMN_DISPLAY_NAME, 51 TvContract.Channels.COLUMN_NETWORK_AFFILIATION, 52 TvContract.Channels.COLUMN_DESCRIPTION, 53 TvContract.Channels.COLUMN_VIDEO_FORMAT, 54 TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA, 55 TvContract.Channels.COLUMN_VERSION_NUMBER, 56 }; 57 58 private static final String[] PROGRAMS_PROJECTION = { 59 TvContract.Programs._ID, 60 TvContract.Programs.COLUMN_CHANNEL_ID, 61 TvContract.Programs.COLUMN_TITLE, 62 TvContract.Programs.COLUMN_SEASON_NUMBER, 63 TvContract.Programs.COLUMN_EPISODE_NUMBER, 64 TvContract.Programs.COLUMN_EPISODE_TITLE, 65 TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, 66 TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, 67 TvContract.Programs.COLUMN_BROADCAST_GENRE, 68 TvContract.Programs.COLUMN_CANONICAL_GENRE, 69 TvContract.Programs.COLUMN_SHORT_DESCRIPTION, 70 TvContract.Programs.COLUMN_LONG_DESCRIPTION, 71 TvContract.Programs.COLUMN_VIDEO_WIDTH, 72 TvContract.Programs.COLUMN_VIDEO_HEIGHT, 73 TvContract.Programs.COLUMN_AUDIO_LANGUAGE, 74 TvContract.Programs.COLUMN_CONTENT_RATING, 75 TvContract.Programs.COLUMN_POSTER_ART_URI, 76 TvContract.Programs.COLUMN_THUMBNAIL_URI, 77 TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA, 78 TvContract.Programs.COLUMN_VERSION_NUMBER, 79 }; 80 81 private static long OPERATION_TIME = 1000l; 82 83 private String mInputId; 84 private ContentResolver mContentResolver; 85 private Uri mChannelsUri; 86 87 @Override 88 protected void setUp() throws Exception { 89 super.setUp(); 90 if (!Utils.hasTvInputFramework(getContext())) { 91 return; 92 } 93 mInputId = TvContract.buildInputId( 94 new ComponentName(getContext(), StubTunerTvInputService.class)); 95 mContentResolver = getContext().getContentResolver(); 96 mChannelsUri = TvContract.buildChannelsUriForInput(mInputId); 97 } 98 99 @Override 100 protected void tearDown() throws Exception { 101 if (!Utils.hasTvInputFramework(getContext())) { 102 super.tearDown(); 103 return; 104 } 105 // Clean up, just in case we failed to delete the entry when a test failed. 106 // The cotentUris are specific to this package, so this will delete only the 107 // entries inserted by this package. 108 String[] projection = { TvContract.Channels._ID }; 109 try (Cursor cursor = mContentResolver.query(mChannelsUri, projection, null, null, null)) { 110 while (cursor != null && cursor.moveToNext()) { 111 long channelId = cursor.getLong(0); 112 mContentResolver.delete( 113 TvContract.buildProgramsUriForChannel(channelId), null, null); 114 } 115 } 116 mContentResolver.delete(mChannelsUri, null, null); 117 super.tearDown(); 118 } 119 120 private static ContentValues createDummyChannelValues(String inputId) { 121 ContentValues values = new ContentValues(); 122 values.put(TvContract.Channels.COLUMN_INPUT_ID, inputId); 123 values.put(TvContract.Channels.COLUMN_TYPE, TvContract.Channels.TYPE_OTHER); 124 values.put(TvContract.Channels.COLUMN_SERVICE_TYPE, 125 TvContract.Channels.SERVICE_TYPE_AUDIO_VIDEO); 126 values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, "1"); 127 values.put(TvContract.Channels.COLUMN_VIDEO_FORMAT, TvContract.Channels.VIDEO_FORMAT_480P); 128 129 return values; 130 } 131 132 private static ContentValues createDummyProgramValues(long channelId) { 133 ContentValues values = new ContentValues(); 134 values.put(TvContract.Programs.COLUMN_CHANNEL_ID, channelId); 135 values.put(TvContract.Programs.COLUMN_EPISODE_TITLE, "Title"); 136 values.put(TvContract.Programs.COLUMN_CANONICAL_GENRE, TvContract.Programs.Genres.encode( 137 TvContract.Programs.Genres.MOVIES, TvContract.Programs.Genres.DRAMA)); 138 TvContentRating rating = TvContentRating.createRating("android.media.tv", "US_TVPG", 139 "US_TVPG_TV_MA", "US_TVPG_S", "US_TVPG_V"); 140 values.put(TvContract.Programs.COLUMN_CONTENT_RATING, rating.flattenToString()); 141 142 return values; 143 } 144 145 private static void verifyStringColumn(Cursor cursor, ContentValues expectedValues, 146 String columnName) { 147 if (expectedValues.containsKey(columnName)) { 148 assertEquals(expectedValues.getAsString(columnName), 149 cursor.getString(cursor.getColumnIndex(columnName))); 150 } 151 } 152 153 private static void verifyIntegerColumn(Cursor cursor, ContentValues expectedValues, 154 String columnName) { 155 if (expectedValues.containsKey(columnName)) { 156 assertEquals(expectedValues.getAsInteger(columnName).intValue(), 157 cursor.getInt(cursor.getColumnIndex(columnName))); 158 } 159 } 160 161 private static void verifyLongColumn(Cursor cursor, ContentValues expectedValues, 162 String columnName) { 163 if (expectedValues.containsKey(columnName)) { 164 assertEquals(expectedValues.getAsLong(columnName).longValue(), 165 cursor.getLong(cursor.getColumnIndex(columnName))); 166 } 167 } 168 169 private static void verifyBlobColumn(Cursor cursor, ContentValues expectedValues, 170 String columnName) { 171 if (expectedValues.containsKey(columnName)) { 172 byte[] expected = expectedValues.getAsByteArray(columnName); 173 byte[] actual = cursor.getBlob(cursor.getColumnIndex(columnName)); 174 assertEquals(expected.length, actual.length); 175 for (int i = 0; i < expected.length; ++i) { 176 assertEquals(expected[i], actual[i]); 177 } 178 } 179 } 180 181 private void verifyChannel(Uri channelUri, ContentValues expectedValues, long channelId) { 182 try (Cursor cursor = mContentResolver.query( 183 channelUri, CHANNELS_PROJECTION, null, null, null)) { 184 assertNotNull(cursor); 185 assertEquals(cursor.getCount(), 1); 186 assertTrue(cursor.moveToNext()); 187 assertEquals(channelId, cursor.getLong(cursor.getColumnIndex(TvContract.Channels._ID))); 188 verifyStringColumn(cursor, expectedValues, TvContract.Channels.COLUMN_INPUT_ID); 189 verifyStringColumn(cursor, expectedValues, TvContract.Channels.COLUMN_TYPE); 190 verifyStringColumn(cursor, expectedValues, TvContract.Channels.COLUMN_SERVICE_TYPE); 191 verifyIntegerColumn(cursor, expectedValues, 192 TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID); 193 verifyIntegerColumn(cursor, expectedValues, 194 TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID); 195 verifyIntegerColumn(cursor, expectedValues, 196 TvContract.Channels.COLUMN_SERVICE_ID); 197 verifyStringColumn(cursor, expectedValues, TvContract.Channels.COLUMN_DISPLAY_NUMBER); 198 verifyStringColumn(cursor, expectedValues, TvContract.Channels.COLUMN_DISPLAY_NAME); 199 verifyStringColumn(cursor, expectedValues, 200 TvContract.Channels.COLUMN_NETWORK_AFFILIATION); 201 verifyStringColumn(cursor, expectedValues, TvContract.Channels.COLUMN_DESCRIPTION); 202 verifyStringColumn(cursor, expectedValues, TvContract.Channels.COLUMN_VIDEO_FORMAT); 203 verifyBlobColumn(cursor, expectedValues, 204 TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA); 205 verifyIntegerColumn(cursor, expectedValues, TvContract.Channels.COLUMN_VERSION_NUMBER); 206 } 207 } 208 209 public void testChannelsTable() throws Exception { 210 if (!Utils.hasTvInputFramework(getContext())) { 211 return; 212 } 213 // Test: insert 214 ContentValues values = createDummyChannelValues(mInputId); 215 216 Uri rowUri = mContentResolver.insert(mChannelsUri, values); 217 long channelId = ContentUris.parseId(rowUri); 218 Uri channelUri = TvContract.buildChannelUri(channelId); 219 verifyChannel(channelUri, values, channelId); 220 221 // Test: update 222 values.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, "1-1"); 223 values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, "One dash one"); 224 values.put(TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA, "Coffee".getBytes()); 225 226 mContentResolver.update(channelUri, values, null, null); 227 verifyChannel(channelUri, values, channelId); 228 229 // Test: delete 230 mContentResolver.delete(mChannelsUri, null, null); 231 try (Cursor cursor = mContentResolver.query( 232 mChannelsUri, CHANNELS_PROJECTION, null, null, null)) { 233 assertEquals(0, cursor.getCount()); 234 } 235 } 236 237 private void verifyProgram(Uri programUri, ContentValues expectedValues, long programId) { 238 try (Cursor cursor = mContentResolver.query( 239 programUri, PROGRAMS_PROJECTION, null, null, null)) { 240 assertNotNull(cursor); 241 assertEquals(cursor.getCount(), 1); 242 assertTrue(cursor.moveToNext()); 243 assertEquals(programId, cursor.getLong(cursor.getColumnIndex(TvContract.Programs._ID))); 244 verifyLongColumn(cursor, expectedValues, TvContract.Programs.COLUMN_CHANNEL_ID); 245 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_TITLE); 246 verifyIntegerColumn(cursor, expectedValues, TvContract.Programs.COLUMN_SEASON_NUMBER); 247 verifyIntegerColumn(cursor, expectedValues, TvContract.Programs.COLUMN_EPISODE_NUMBER); 248 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_EPISODE_TITLE); 249 verifyLongColumn(cursor, expectedValues, 250 TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS); 251 verifyLongColumn(cursor, expectedValues, 252 TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS); 253 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_BROADCAST_GENRE); 254 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_CANONICAL_GENRE); 255 verifyStringColumn(cursor, expectedValues, 256 TvContract.Programs.COLUMN_SHORT_DESCRIPTION); 257 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_LONG_DESCRIPTION); 258 verifyIntegerColumn(cursor, expectedValues, TvContract.Programs.COLUMN_VIDEO_WIDTH); 259 verifyIntegerColumn(cursor, expectedValues, TvContract.Programs.COLUMN_VIDEO_HEIGHT); 260 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_AUDIO_LANGUAGE); 261 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_CONTENT_RATING); 262 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_POSTER_ART_URI); 263 verifyStringColumn(cursor, expectedValues, TvContract.Programs.COLUMN_THUMBNAIL_URI); 264 verifyBlobColumn(cursor, expectedValues, 265 TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA); 266 verifyIntegerColumn(cursor, expectedValues, TvContract.Programs.COLUMN_VERSION_NUMBER); 267 } 268 } 269 270 private void verifyLogoIsReadable(Uri logoUri) throws Exception { 271 try (AssetFileDescriptor fd = mContentResolver.openAssetFileDescriptor(logoUri, "r")) { 272 try (InputStream is = fd.createInputStream()) { 273 // Assure that the stream is decodable as a Bitmap. 274 BitmapFactory.decodeStream(is); 275 } 276 } 277 } 278 279 public void testChannelLogo() throws Exception { 280 if (!Utils.hasTvInputFramework(getContext())) { 281 return; 282 } 283 // Set-up: add a channel. 284 ContentValues values = createDummyChannelValues(mInputId); 285 Uri channelUri = mContentResolver.insert(mChannelsUri, values); 286 Uri logoUri = TvContract.buildChannelLogoUri(channelUri); 287 Bitmap logo = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.robot); 288 289 // Write 290 try (AssetFileDescriptor fd = mContentResolver.openAssetFileDescriptor(logoUri, "w")) { 291 try (OutputStream os = fd.createOutputStream()) { 292 logo.compress(Bitmap.CompressFormat.PNG, 100, os); 293 } 294 } 295 296 // Give some time for TvProvider to process the logo. 297 Thread.sleep(OPERATION_TIME); 298 299 // Read and verify 300 verifyLogoIsReadable(logoUri); 301 302 // Read and verify using alternative logo URI. 303 verifyLogoIsReadable(TvContract.buildChannelLogoUri(ContentUris.parseId(channelUri))); 304 } 305 306 public void verifyProgramsTable(Uri programsUri, long channelId) { 307 if (!Utils.hasTvInputFramework(getContext())) { 308 return; 309 } 310 // Test: insert 311 ContentValues values = createDummyProgramValues(channelId); 312 313 Uri rowUri = mContentResolver.insert(programsUri, values); 314 long programId = ContentUris.parseId(rowUri); 315 Uri programUri = TvContract.buildProgramUri(programId); 316 verifyProgram(programUri, values, programId); 317 318 // Test: update 319 values.put(TvContract.Programs.COLUMN_EPISODE_TITLE, "Sample title"); 320 values.put(TvContract.Programs.COLUMN_SHORT_DESCRIPTION, "Short description"); 321 values.put(TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA, "Coffee".getBytes()); 322 323 mContentResolver.update(programUri, values, null, null); 324 verifyProgram(programUri, values, programId); 325 326 // Test: delete 327 mContentResolver.delete(programsUri, null, null); 328 try (Cursor cursor = mContentResolver.query( 329 programsUri, PROGRAMS_PROJECTION, null, null, null)) { 330 assertEquals(0, cursor.getCount()); 331 } 332 } 333 334 public void testProgramsTable() throws Exception { 335 if (!Utils.hasTvInputFramework(getContext())) { 336 return; 337 } 338 // Set-up: add a channel. 339 ContentValues values = createDummyChannelValues(mInputId); 340 Uri channelUri = mContentResolver.insert(mChannelsUri, values); 341 long channelId = ContentUris.parseId(channelUri); 342 343 verifyProgramsTable(TvContract.buildProgramsUriForChannel(channelId), channelId); 344 verifyProgramsTable(TvContract.buildProgramsUriForChannel(channelUri), channelId); 345 } 346 347 private void verifyOverlap(long startMillis, long endMillis, int expectedCount, 348 long channelId, Uri channelUri) { 349 try (Cursor cursor = mContentResolver.query(TvContract.buildProgramsUriForChannel( 350 channelId, startMillis, endMillis), PROGRAMS_PROJECTION, null, null, null)) { 351 assertEquals(expectedCount, cursor.getCount()); 352 } 353 try (Cursor cursor = mContentResolver.query(TvContract.buildProgramsUriForChannel( 354 channelUri, startMillis, endMillis), PROGRAMS_PROJECTION, null, null, null)) { 355 assertEquals(expectedCount, cursor.getCount()); 356 } 357 } 358 359 public void testProgramsScheduleOverlap() throws Exception { 360 if (!Utils.hasTvInputFramework(getContext())) { 361 return; 362 } 363 final long programStartMillis = 1403712000000l; // Jun 25 2014 16:00 UTC 364 final long programEndMillis = 1403719200000l; // Jun 25 2014 18:00 UTC 365 final long hour = 3600000l; 366 367 // Set-up: add a channel and program. 368 ContentValues values = createDummyChannelValues(mInputId); 369 Uri channelUri = mContentResolver.insert(mChannelsUri, values); 370 long channelId = ContentUris.parseId(channelUri); 371 Uri programsUri = TvContract.buildProgramsUriForChannel(channelId); 372 values = createDummyProgramValues(channelId); 373 values.put(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, programStartMillis); 374 values.put(TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, programEndMillis); 375 mContentResolver.insert(programsUri, values); 376 377 // Overlap 1: starts early, ends early. 378 verifyOverlap(programStartMillis - hour, programEndMillis - hour, 1, channelId, channelUri); 379 380 // Overlap 2: starts early, ends late. 381 verifyOverlap(programStartMillis - hour, programEndMillis + hour, 1, channelId, channelUri); 382 383 // Overlap 3: starts early, ends late. 384 verifyOverlap(programStartMillis + hour / 2, programEndMillis - hour / 2, 1, 385 channelId, channelUri); 386 387 // Overlap 4: starts late, ends late. 388 verifyOverlap(programStartMillis + hour, programEndMillis + hour, 1, channelId, channelUri); 389 390 // Non-overlap 1: ends too early. 391 verifyOverlap(programStartMillis - hour, programStartMillis - hour / 2, 0, 392 channelId, channelUri); 393 394 // Non-overlap 2: starts too late 395 verifyOverlap(programEndMillis + hour, programEndMillis + hour * 2, 0, 396 channelId, channelUri); 397 } 398 399 private void verifyQueryWithSortOrder(Uri uri, final String[] projection, 400 String sortOrder) throws Exception { 401 try { 402 getContext().getContentResolver().query(uri, projection, null, null, sortOrder); 403 fail("Setting sortOrder should fail without ACCESS_ALL_EPG_DATA permission for " + uri); 404 } catch (SecurityException e) { 405 // Expected exception 406 } 407 } 408 409 private void verifyQueryWithSelection(Uri uri, final String[] projection, 410 String selection) throws Exception { 411 try { 412 getContext().getContentResolver().query(uri, projection, selection, null, null); 413 fail("Setting selection should fail without ACCESS_ALL_EPG_DATA permission for " + uri); 414 } catch (SecurityException e) { 415 // Expected exception 416 } 417 } 418 419 private void verifyUpdateWithSelection(Uri uri, String selection) throws Exception { 420 try { 421 ContentValues values = new ContentValues(); 422 getContext().getContentResolver().update(uri, values, selection, null); 423 fail("Setting selection should fail without ACCESS_ALL_EPG_DATA permission for " + uri); 424 } catch (SecurityException e) { 425 // Expected exception 426 } 427 } 428 429 private void verifyDeleteWithSelection(Uri uri, String selection) throws Exception { 430 try { 431 getContext().getContentResolver().delete(uri, selection, null); 432 fail("Setting selection should fail without ACCESS_ALL_EPG_DATA permission for " + uri); 433 } catch (SecurityException e) { 434 // Expected exception 435 } 436 } 437 438 public void testAllEpgPermissionBlocksSortOrderOnQuery_Channels() throws Exception { 439 if (!Utils.hasTvInputFramework(getContext())) { 440 return; 441 } 442 final String[] projection = { TvContract.Channels._ID }; 443 verifyQueryWithSortOrder(TvContract.Channels.CONTENT_URI, projection, 444 TvContract.Channels._ID + " ASC"); 445 } 446 447 public void testAllEpgPermissionBlocksSelectionOnQuery_Channels() throws Exception { 448 if (!Utils.hasTvInputFramework(getContext())) { 449 return; 450 } 451 final String[] projection = { TvContract.Channels._ID }; 452 verifyQueryWithSelection(TvContract.Channels.CONTENT_URI, projection, 453 TvContract.Channels._ID + ">0"); 454 } 455 456 public void testAllEpgPermissionBlocksSelectionOnUpdate_Channels() throws Exception { 457 if (!Utils.hasTvInputFramework(getContext())) { 458 return; 459 } 460 verifyUpdateWithSelection(TvContract.Channels.CONTENT_URI, 461 TvContract.Channels._ID + ">0"); 462 } 463 464 public void testAllEpgPermissionBlocksSelectionOnDelete_Channels() throws Exception { 465 if (!Utils.hasTvInputFramework(getContext())) { 466 return; 467 } 468 verifyDeleteWithSelection(TvContract.Channels.CONTENT_URI, 469 TvContract.Channels._ID + ">0"); 470 } 471 472 public void testAllEpgPermissionBlocksSortOrderOnQuery_Programs() throws Exception { 473 if (!Utils.hasTvInputFramework(getContext())) { 474 return; 475 } 476 final String[] projection = { TvContract.Programs._ID }; 477 verifyQueryWithSortOrder(TvContract.Programs.CONTENT_URI, projection, 478 TvContract.Programs._ID + " ASC"); 479 } 480 481 public void testAllEpgPermissionBlocksSelectionOnQuery_Programs() throws Exception { 482 if (!Utils.hasTvInputFramework(getContext())) { 483 return; 484 } 485 final String[] projection = { TvContract.Channels._ID }; 486 verifyQueryWithSelection(TvContract.Programs.CONTENT_URI, projection, 487 TvContract.Programs._ID + ">0"); 488 } 489 490 public void testAllEpgPermissionBlocksSelectionOnUpdate_Programs() throws Exception { 491 if (!Utils.hasTvInputFramework(getContext())) { 492 return; 493 } 494 verifyUpdateWithSelection(TvContract.Programs.CONTENT_URI, 495 TvContract.Programs._ID + ">0"); 496 } 497 498 public void testAllEpgPermissionBlocksSelectionOnDelete_Programs() throws Exception { 499 if (!Utils.hasTvInputFramework(getContext())) { 500 return; 501 } 502 verifyDeleteWithSelection(TvContract.Programs.CONTENT_URI, 503 TvContract.Programs._ID + ">0"); 504 } 505 506 public void testDefaultValues() throws Exception { 507 if (!Utils.hasTvInputFramework(getContext())) { 508 return; 509 } 510 ContentValues values = new ContentValues(); 511 values.put(TvContract.Channels.COLUMN_INPUT_ID, mInputId); 512 Uri channelUri = mContentResolver.insert(mChannelsUri, values); 513 assertNotNull(channelUri); 514 long channelId = ContentUris.parseId(channelUri); 515 try (Cursor cursor = mContentResolver.query( 516 channelUri, CHANNELS_PROJECTION, null, null, null)) { 517 cursor.moveToNext(); 518 assertEquals(TvContract.Channels.TYPE_OTHER, 519 cursor.getString(cursor.getColumnIndex(TvContract.Channels.COLUMN_TYPE))); 520 assertEquals(TvContract.Channels.SERVICE_TYPE_AUDIO_VIDEO, 521 cursor.getString(cursor.getColumnIndex( 522 TvContract.Channels.COLUMN_SERVICE_TYPE))); 523 } 524 values.clear(); 525 } 526 } 527