1 /* 2 * Copyright (C) 2017 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 package androidx.tvprovider.media.tv; 17 18 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 19 20 import android.content.ContentValues; 21 import android.content.Intent; 22 import android.database.Cursor; 23 import android.net.Uri; 24 import android.os.Build; 25 26 import androidx.annotation.RestrictTo; 27 import androidx.tvprovider.media.tv.TvContractCompat.Channels; 28 import androidx.tvprovider.media.tv.TvContractCompat.Channels.ServiceType; 29 import androidx.tvprovider.media.tv.TvContractCompat.Channels.Type; 30 import androidx.tvprovider.media.tv.TvContractCompat.Channels.VideoFormat; 31 32 import java.net.URISyntaxException; 33 import java.nio.charset.Charset; 34 35 /** 36 * A convenience class to access {@link TvContractCompat.Channels} entries in the system content 37 * provider. 38 * 39 * <p>This class makes it easy to insert or retrieve a channel from the system content provider, 40 * which is defined in {@link TvContractCompat}. 41 * 42 * <p>Usage example when inserting a channel: 43 * <pre> 44 * Channel channel = new Channel.Builder() 45 * .setDisplayName("Channel Name") 46 * .setDescription("Channel description") 47 * .setType(Channels.TYPE_PREVIEW) 48 * // Set more attributes... 49 * .build(); 50 * Uri channelUri = getContentResolver().insert(Channels.CONTENT_URI, channel.toContentValues()); 51 * </pre> 52 * 53 * <p>Usage example when retrieving a channel: 54 * <pre> 55 * Channel channel; 56 * try (Cursor cursor = resolver.query(channelUri, null, null, null, null)) { 57 * if (cursor != null && cursor.getCount() != 0) { 58 * cursor.moveToNext(); 59 * channel = Channel.fromCursor(cursor); 60 * } 61 * } 62 * </pre> 63 * 64 * <p>Usage example when updating an existing channel: 65 * <pre> 66 * Channel updatedChannel = new Channel.Builder(channel) 67 * .setDescription("New channel description") 68 * .build(); 69 * getContentResolver().update(TvContractCompat.buildChannelUri(updatedChannel.getId()), 70 * updatedChannel.toContentValues(), null, null); 71 * </pre> 72 * 73 * <p>Usage example when deleting a channel: 74 * <pre> 75 * getContentResolver().delete( 76 * TvContractCompat.buildChannelUri(existingChannel.getId()), null, null); 77 * </pre> 78 */ 79 public final class Channel { 80 /** 81 * @hide 82 */ 83 @RestrictTo(LIBRARY_GROUP) 84 public static final String[] PROJECTION = getProjection(); 85 86 private static final long INVALID_CHANNEL_ID = -1; 87 private static final int INVALID_INT_VALUE = -1; 88 private static final int IS_SEARCHABLE = 1; 89 private static final int IS_TRANSIENT = 1; 90 private static final int IS_BROWSABLE = 1; 91 private static final int IS_SYSTEM_APPROVED = 1; 92 private static final int IS_LOCKED = 1; 93 94 private ContentValues mValues; 95 96 private Channel(Builder builder) { 97 mValues = builder.mValues; 98 } 99 100 /** 101 * @return The value of {@link Channels#_ID} for the channel. 102 */ 103 public long getId() { 104 Long l = mValues.getAsLong(Channels._ID); 105 return l == null ? INVALID_CHANNEL_ID : l; 106 } 107 108 /** 109 * @return The value of {@link Channels#COLUMN_PACKAGE_NAME} for the channel. 110 */ 111 public String getPackageName() { 112 return mValues.getAsString(Channels.COLUMN_PACKAGE_NAME); 113 } 114 115 /** 116 * @return The value of {@link Channels#COLUMN_INPUT_ID} for the channel. 117 */ 118 public String getInputId() { 119 return mValues.getAsString(Channels.COLUMN_INPUT_ID); 120 } 121 122 /** 123 * @return The value of {@link Channels#COLUMN_TYPE} for the channel. 124 */ 125 public @Type String getType() { 126 return mValues.getAsString(Channels.COLUMN_TYPE); 127 } 128 129 /** 130 * @return The value of {@link Channels#COLUMN_DISPLAY_NUMBER} for the channel. 131 */ 132 public String getDisplayNumber() { 133 return mValues.getAsString(Channels.COLUMN_DISPLAY_NUMBER); 134 } 135 136 /** 137 * @return The value of {@link Channels#COLUMN_DISPLAY_NAME} for the channel. 138 */ 139 public String getDisplayName() { 140 return mValues.getAsString(Channels.COLUMN_DISPLAY_NAME); 141 } 142 143 /** 144 * @return The value of {@link Channels#COLUMN_DESCRIPTION} for the channel. 145 */ 146 public String getDescription() { 147 return mValues.getAsString(Channels.COLUMN_DESCRIPTION); 148 } 149 150 /** 151 * @return The value of {@link Channels#COLUMN_VIDEO_FORMAT} for the channel. 152 */ 153 public @VideoFormat String getVideoFormat() { 154 return mValues.getAsString(Channels.COLUMN_VIDEO_FORMAT); 155 } 156 157 /** 158 * @return The value of {@link Channels#COLUMN_ORIGINAL_NETWORK_ID} for the channel. 159 */ 160 public int getOriginalNetworkId() { 161 Integer i = mValues.getAsInteger(Channels.COLUMN_ORIGINAL_NETWORK_ID); 162 return i == null ? INVALID_INT_VALUE : i; 163 } 164 165 /** 166 * @return The value of {@link Channels#COLUMN_TRANSPORT_STREAM_ID} for the channel. 167 */ 168 public int getTransportStreamId() { 169 Integer i = mValues.getAsInteger(Channels.COLUMN_TRANSPORT_STREAM_ID); 170 return i == null ? INVALID_INT_VALUE : i; 171 } 172 173 /** 174 * @return The value of {@link Channels#COLUMN_SERVICE_ID} for the channel. 175 */ 176 public int getServiceId() { 177 Integer i = mValues.getAsInteger(Channels.COLUMN_SERVICE_ID); 178 return i == null ? INVALID_INT_VALUE : i; 179 } 180 181 /** 182 * @return The value of {@link Channels#COLUMN_APP_LINK_TEXT} for the channel. 183 */ 184 public String getAppLinkText() { 185 return mValues.getAsString(Channels.COLUMN_APP_LINK_TEXT); 186 } 187 188 /** 189 * @return The value of {@link Channels#COLUMN_APP_LINK_COLOR} for the channel. 190 */ 191 public int getAppLinkColor() { 192 Integer i = mValues.getAsInteger(Channels.COLUMN_APP_LINK_COLOR); 193 return i == null ? INVALID_INT_VALUE : i; 194 } 195 196 /** 197 * @return The value of {@link Channels#COLUMN_APP_LINK_ICON_URI} for the channel. 198 */ 199 public Uri getAppLinkIconUri() { 200 String uri = mValues.getAsString(Channels.COLUMN_APP_LINK_ICON_URI); 201 return uri == null ? null : Uri.parse(uri); 202 } 203 204 /** 205 * @return The value of {@link Channels#COLUMN_APP_LINK_POSTER_ART_URI} for the channel. 206 */ 207 public Uri getAppLinkPosterArtUri() { 208 String uri = mValues.getAsString(Channels.COLUMN_APP_LINK_POSTER_ART_URI); 209 return uri == null ? null : Uri.parse(uri); 210 } 211 212 /** 213 * @return The value of {@link Channels#COLUMN_APP_LINK_INTENT_URI} for the channel. 214 */ 215 public Uri getAppLinkIntentUri() { 216 String uri = mValues.getAsString(Channels.COLUMN_APP_LINK_INTENT_URI); 217 return uri == null ? null : Uri.parse(uri); 218 } 219 220 /** 221 * @return The value of {@link Channels#COLUMN_APP_LINK_INTENT_URI} for the program. 222 */ 223 public Intent getAppLinkIntent() throws URISyntaxException { 224 String uri = mValues.getAsString(Channels.COLUMN_APP_LINK_INTENT_URI); 225 return uri == null ? null : Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME); 226 } 227 228 /** 229 * @return The value of {@link Channels#COLUMN_NETWORK_AFFILIATION} for the channel. 230 */ 231 public String getNetworkAffiliation() { 232 return mValues.getAsString(Channels.COLUMN_NETWORK_AFFILIATION); 233 } 234 235 /** 236 * @return The value of {@link Channels#COLUMN_SEARCHABLE} for the channel. 237 */ 238 public boolean isSearchable() { 239 Integer i = mValues.getAsInteger(Channels.COLUMN_SEARCHABLE); 240 return i == null || i == IS_SEARCHABLE; 241 } 242 243 /** 244 * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_DATA} for the channel. 245 */ 246 public byte[] getInternalProviderDataByteArray() { 247 return mValues.getAsByteArray(Channels.COLUMN_INTERNAL_PROVIDER_DATA); 248 } 249 250 /** 251 * @return The value of {@link Channels#COLUMN_SERVICE_TYPE} for the channel. 252 * 253 * <p>Returns {@link Channels#SERVICE_TYPE_AUDIO}, {@link Channels#SERVICE_TYPE_AUDIO_VIDEO}, or 254 * {@link Channels#SERVICE_TYPE_OTHER}. 255 */ 256 public @ServiceType String getServiceType() { 257 return mValues.getAsString(Channels.COLUMN_SERVICE_TYPE); 258 } 259 260 /** 261 * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG1} for the channel. 262 */ 263 public Long getInternalProviderFlag1() { 264 return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1); 265 } 266 267 /** 268 * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG2} for the channel. 269 */ 270 public Long getInternalProviderFlag2() { 271 return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2); 272 } 273 274 /** 275 * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG3} for the channel. 276 */ 277 public Long getInternalProviderFlag3() { 278 return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3); 279 } 280 281 /** 282 * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG4} for the channel. 283 */ 284 public Long getInternalProviderFlag4() { 285 return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4); 286 } 287 288 /** 289 * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_ID} for the channel. 290 */ 291 public String getInternalProviderId() { 292 return mValues.getAsString(Channels.COLUMN_INTERNAL_PROVIDER_ID); 293 } 294 295 /** 296 * @return The value of {@link Channels#COLUMN_TRANSIENT} for the channel. 297 */ 298 public boolean isTransient() { 299 Integer i = mValues.getAsInteger(Channels.COLUMN_TRANSIENT); 300 return i != null && i == IS_TRANSIENT; 301 } 302 303 /** 304 * @return The value of {@link Channels#COLUMN_BROWSABLE} for the channel. 305 */ 306 public boolean isBrowsable() { 307 Integer i = mValues.getAsInteger(Channels.COLUMN_BROWSABLE); 308 return i != null && i == IS_BROWSABLE; 309 } 310 311 /** 312 * @return The value of {@link Channels#COLUMN_SYSTEM_APPROVED} for the channel. 313 * @hide 314 */ 315 @RestrictTo(LIBRARY_GROUP) 316 public boolean isSystemApproved() { 317 Integer i = mValues.getAsInteger(Channels.COLUMN_SYSTEM_APPROVED); 318 return i != null && i == IS_SYSTEM_APPROVED; 319 } 320 321 /** 322 * @return The value of {@link Channels#COLUMN_CONFIGURATION_DISPLAY_ORDER} for the channel. 323 */ 324 public int getConfigurationDisplayOrder() { 325 return mValues.getAsInteger(Channels.COLUMN_CONFIGURATION_DISPLAY_ORDER); 326 } 327 328 /** 329 * @return The value of {@link Channels#COLUMN_SYSTEM_CHANNEL_KEY} for the channel. 330 */ 331 public String getSystemChannelKey() { 332 return mValues.getAsString(Channels.COLUMN_SYSTEM_CHANNEL_KEY); 333 } 334 335 /** 336 * @return The value of {@link Channels#COLUMN_LOCKED} for the channel. 337 */ 338 public boolean isLocked() { 339 Integer i = mValues.getAsInteger(Channels.COLUMN_LOCKED); 340 return i != null && i == IS_LOCKED; 341 } 342 343 @Override 344 public int hashCode() { 345 return mValues.hashCode(); 346 } 347 348 @Override 349 public boolean equals(Object other) { 350 if (!(other instanceof Channel)) { 351 return false; 352 } 353 return mValues.equals(((Channel) other).mValues); 354 } 355 @Override 356 public String toString() { 357 return "Channel{" + mValues.toString() + "}"; 358 } 359 360 /** 361 * @return The fields of the Channel in the ContentValues format to be easily inserted into the 362 * TV Input Framework database. 363 */ 364 public ContentValues toContentValues() { 365 return toContentValues(false); 366 } 367 368 /** 369 * Returns fields of the Channel in the ContentValues format to be easily inserted into the 370 * TV Input Framework database. 371 * 372 * @param includeProtectedFields Whether the fields protected by system is included or not. 373 * @hide 374 */ 375 @RestrictTo(LIBRARY_GROUP) 376 public ContentValues toContentValues(boolean includeProtectedFields) { 377 ContentValues values = new ContentValues(mValues); 378 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { 379 values.remove(Channels.COLUMN_APP_LINK_COLOR); 380 values.remove(Channels.COLUMN_APP_LINK_TEXT); 381 values.remove(Channels.COLUMN_APP_LINK_ICON_URI); 382 values.remove(Channels.COLUMN_APP_LINK_POSTER_ART_URI); 383 values.remove(Channels.COLUMN_APP_LINK_INTENT_URI); 384 values.remove(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1); 385 values.remove(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2); 386 values.remove(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3); 387 values.remove(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4); 388 } 389 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { 390 values.remove(Channels.COLUMN_INTERNAL_PROVIDER_ID); 391 values.remove(Channels.COLUMN_TRANSIENT); 392 values.remove(Channels.COLUMN_CONFIGURATION_DISPLAY_ORDER); 393 values.remove(Channels.COLUMN_SYSTEM_CHANNEL_KEY); 394 } 395 396 if (!includeProtectedFields) { 397 values.remove(Channels.COLUMN_BROWSABLE); 398 values.remove(Channels.COLUMN_LOCKED); 399 } 400 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !includeProtectedFields) { 401 values.remove(Channels.COLUMN_SYSTEM_APPROVED); 402 } 403 return values; 404 } 405 406 /** 407 * Creates a Channel object from a cursor including the fields defined in {@link Channels}. 408 * 409 * @param cursor A row from the TV Input Framework database. 410 * @return A channel with the values taken from the cursor. 411 */ 412 public static Channel fromCursor(Cursor cursor) { 413 // TODO: Add additional API which does not use costly getColumnIndex(). 414 Builder builder = new Builder(); 415 int index; 416 if ((index = cursor.getColumnIndex(Channels._ID)) >= 0 && !cursor.isNull(index)) { 417 builder.setId(cursor.getLong(index)); 418 } 419 if ((index = cursor.getColumnIndex(Channels.COLUMN_DESCRIPTION)) >= 0 420 && !cursor.isNull(index)) { 421 builder.setDescription(cursor.getString(index)); 422 } 423 if ((index = cursor.getColumnIndex(Channels.COLUMN_DISPLAY_NAME)) >= 0 424 && !cursor.isNull(index)) { 425 builder.setDisplayName(cursor.getString(index)); 426 } 427 if ((index = cursor.getColumnIndex(Channels.COLUMN_DISPLAY_NUMBER)) >= 0 428 && !cursor.isNull(index)) { 429 builder.setDisplayNumber(cursor.getString(index)); 430 } 431 if ((index = cursor.getColumnIndex(Channels.COLUMN_INPUT_ID)) >= 0 432 && !cursor.isNull(index)) { 433 builder.setInputId(cursor.getString(index)); 434 } 435 if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_DATA)) >= 0 436 && !cursor.isNull(index)) { 437 builder.setInternalProviderData(cursor.getBlob(index)); 438 } 439 if ((index = cursor.getColumnIndex(Channels.COLUMN_NETWORK_AFFILIATION)) >= 0 440 && !cursor.isNull(index)) { 441 builder.setNetworkAffiliation(cursor.getString(index)); 442 } 443 if ((index = cursor.getColumnIndex(Channels.COLUMN_ORIGINAL_NETWORK_ID)) >= 0 444 && !cursor.isNull(index)) { 445 builder.setOriginalNetworkId(cursor.getInt(index)); 446 } 447 if ((index = cursor.getColumnIndex(Channels.COLUMN_PACKAGE_NAME)) >= 0 448 && !cursor.isNull(index)) { 449 builder.setPackageName(cursor.getString(index)); 450 } 451 if ((index = cursor.getColumnIndex(Channels.COLUMN_SEARCHABLE)) >= 0 452 && !cursor.isNull(index)) { 453 builder.setSearchable(cursor.getInt(index) == IS_SEARCHABLE); 454 } 455 if ((index = cursor.getColumnIndex(Channels.COLUMN_SERVICE_ID)) >= 0 456 && !cursor.isNull(index)) { 457 builder.setServiceId(cursor.getInt(index)); 458 } 459 if ((index = cursor.getColumnIndex(Channels.COLUMN_SERVICE_TYPE)) >= 0 460 && !cursor.isNull(index)) { 461 builder.setServiceType(cursor.getString(index)); 462 } 463 if ((index = cursor.getColumnIndex(Channels.COLUMN_TRANSPORT_STREAM_ID)) >= 0 464 && !cursor.isNull(index)) { 465 builder.setTransportStreamId(cursor.getInt(index)); 466 } 467 if ((index = cursor.getColumnIndex(Channels.COLUMN_TYPE)) >= 0 && !cursor.isNull(index)) { 468 builder.setType(cursor.getString(index)); 469 } 470 if ((index = cursor.getColumnIndex(Channels.COLUMN_VIDEO_FORMAT)) >= 0 471 && !cursor.isNull(index)) { 472 builder.setVideoFormat(cursor.getString(index)); 473 } 474 if ((index = cursor.getColumnIndex(Channels.COLUMN_BROWSABLE)) >= 0 475 && !cursor.isNull(index)) { 476 builder.setBrowsable(cursor.getInt(index) == IS_BROWSABLE); 477 } 478 if ((index = cursor.getColumnIndex(Channels.COLUMN_LOCKED)) >= 0 479 && !cursor.isNull(index)) { 480 builder.setLocked(cursor.getInt(index) == IS_LOCKED); 481 } 482 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 483 if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_COLOR)) >= 0 484 && !cursor.isNull(index)) { 485 builder.setAppLinkColor(cursor.getInt(index)); 486 } 487 if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_ICON_URI)) >= 0 488 && !cursor.isNull(index)) { 489 builder.setAppLinkIconUri(Uri.parse(cursor.getString(index))); 490 } 491 if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_INTENT_URI)) >= 0 492 && !cursor.isNull(index)) { 493 builder.setAppLinkIntentUri(Uri.parse(cursor.getString(index))); 494 } 495 if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_POSTER_ART_URI)) >= 0 496 && !cursor.isNull(index)) { 497 builder.setAppLinkPosterArtUri(Uri.parse(cursor.getString(index))); 498 } 499 if ((index = cursor.getColumnIndex(Channels.COLUMN_APP_LINK_TEXT)) >= 0 500 && !cursor.isNull(index)) { 501 builder.setAppLinkText(cursor.getString(index)); 502 } 503 if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1)) >= 0 504 && !cursor.isNull(index)) { 505 builder.setInternalProviderFlag1(cursor.getLong(index)); 506 } 507 if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2)) >= 0 508 && !cursor.isNull(index)) { 509 builder.setInternalProviderFlag2(cursor.getLong(index)); 510 } 511 if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3)) >= 0 512 && !cursor.isNull(index)) { 513 builder.setInternalProviderFlag3(cursor.getLong(index)); 514 } 515 if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4)) >= 0 516 && !cursor.isNull(index)) { 517 builder.setInternalProviderFlag4(cursor.getLong(index)); 518 } 519 } 520 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 521 if ((index = cursor.getColumnIndex(Channels.COLUMN_INTERNAL_PROVIDER_ID)) >= 0 522 && !cursor.isNull(index)) { 523 builder.setInternalProviderId(cursor.getString(index)); 524 } 525 if ((index = cursor.getColumnIndex(Channels.COLUMN_TRANSIENT)) >= 0 526 && !cursor.isNull(index)) { 527 builder.setTransient(cursor.getInt(index) == IS_TRANSIENT); 528 } 529 if ((index = cursor.getColumnIndex(Channels.COLUMN_SYSTEM_APPROVED)) >= 0 530 && !cursor.isNull(index)) { 531 builder.setSystemApproved(cursor.getInt(index) == IS_SYSTEM_APPROVED); 532 } 533 if ((index = cursor.getColumnIndex(Channels.COLUMN_CONFIGURATION_DISPLAY_ORDER)) >= 0 534 && !cursor.isNull(index)) { 535 builder.setConfigurationDisplayOrder(cursor.getInt(index)); 536 } 537 if ((index = cursor.getColumnIndex(Channels.COLUMN_SYSTEM_CHANNEL_KEY)) >= 0 538 && !cursor.isNull(index)) { 539 builder.setSystemChannelKey(cursor.getString(index)); 540 } 541 } 542 return builder.build(); 543 } 544 545 private static String[] getProjection() { 546 String[] baseColumns = new String[] { 547 Channels._ID, 548 Channels.COLUMN_DESCRIPTION, 549 Channels.COLUMN_DISPLAY_NAME, 550 Channels.COLUMN_DISPLAY_NUMBER, 551 Channels.COLUMN_INPUT_ID, 552 Channels.COLUMN_INTERNAL_PROVIDER_DATA, 553 Channels.COLUMN_NETWORK_AFFILIATION, 554 Channels.COLUMN_ORIGINAL_NETWORK_ID, 555 Channels.COLUMN_PACKAGE_NAME, 556 Channels.COLUMN_SEARCHABLE, 557 Channels.COLUMN_SERVICE_ID, 558 Channels.COLUMN_SERVICE_TYPE, 559 Channels.COLUMN_TRANSPORT_STREAM_ID, 560 Channels.COLUMN_TYPE, 561 Channels.COLUMN_VIDEO_FORMAT, 562 Channels.COLUMN_BROWSABLE, 563 Channels.COLUMN_LOCKED, 564 }; 565 String[] marshmallowColumns = new String[] { 566 Channels.COLUMN_APP_LINK_COLOR, 567 Channels.COLUMN_APP_LINK_ICON_URI, 568 Channels.COLUMN_APP_LINK_INTENT_URI, 569 Channels.COLUMN_APP_LINK_POSTER_ART_URI, 570 Channels.COLUMN_APP_LINK_TEXT, 571 Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, 572 Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, 573 Channels.COLUMN_INTERNAL_PROVIDER_FLAG3, 574 Channels.COLUMN_INTERNAL_PROVIDER_FLAG4, 575 }; 576 String[] oReleaseColumns = new String[] { 577 Channels.COLUMN_INTERNAL_PROVIDER_ID, 578 Channels.COLUMN_TRANSIENT, 579 Channels.COLUMN_SYSTEM_APPROVED, 580 Channels.COLUMN_CONFIGURATION_DISPLAY_ORDER, 581 Channels.COLUMN_SYSTEM_CHANNEL_KEY 582 }; 583 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 584 return CollectionUtils.concatAll(baseColumns, marshmallowColumns, oReleaseColumns); 585 } 586 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 587 return CollectionUtils.concatAll(baseColumns, marshmallowColumns); 588 } 589 return baseColumns; 590 } 591 592 /** 593 * The builder class that makes it easy to chain setters to create a {@link Channel} object. 594 */ 595 public static final class Builder { 596 private ContentValues mValues; 597 598 public Builder() { 599 mValues = new ContentValues(); 600 } 601 602 public Builder(Channel other) { 603 mValues = new ContentValues(other.mValues); 604 } 605 606 /** 607 * Sets the ID of the Channel. 608 * 609 * @param id The value of {@link Channels#_ID} for the channel. 610 * @return This Builder object to allow for chaining of calls to builder methods. 611 */ 612 private Builder setId(long id) { 613 mValues.put(Channels._ID, id); 614 return this; 615 } 616 617 /** 618 * Sets the package name of the Channel. 619 * 620 * @param packageName The value of {@link Channels#COLUMN_PACKAGE_NAME} for the channel. 621 * @return This Builder object to allow for chaining of calls to builder methods. 622 * @hide 623 */ 624 @RestrictTo(LIBRARY_GROUP) 625 Builder setPackageName(String packageName) { 626 mValues.put(Channels.COLUMN_PACKAGE_NAME, packageName); 627 return this; 628 } 629 630 /** 631 * Sets the input id of the Channel. 632 * 633 * @param inputId The value of {@link Channels#COLUMN_INPUT_ID} for the channel. 634 * @return This Builder object to allow for chaining of calls to builder methods. 635 */ 636 public Builder setInputId(String inputId) { 637 mValues.put(Channels.COLUMN_INPUT_ID, inputId); 638 return this; 639 } 640 641 /** 642 * Sets the broadcast standard of the Channel. 643 * 644 * @param type The value of {@link Channels#COLUMN_TYPE} for the channel. 645 * @return This Builder object to allow for chaining of calls to builder methods. 646 */ 647 public Builder setType(@Type String type) { 648 mValues.put(Channels.COLUMN_TYPE, type); 649 return this; 650 } 651 652 /** 653 * Sets the display number of the Channel. 654 * 655 * @param displayNumber The value of {@link Channels#COLUMN_DISPLAY_NUMBER} for the channel. 656 * @return This Builder object to allow for chaining of calls to builder methods. 657 */ 658 public Builder setDisplayNumber(String displayNumber) { 659 mValues.put(Channels.COLUMN_DISPLAY_NUMBER, displayNumber); 660 return this; 661 } 662 663 /** 664 * Sets the name to be displayed for the Channel. 665 * 666 * @param displayName The value of {@link Channels#COLUMN_DISPLAY_NAME} for the channel. 667 * @return This Builder object to allow for chaining of calls to builder methods. 668 */ 669 public Builder setDisplayName(String displayName) { 670 mValues.put(Channels.COLUMN_DISPLAY_NAME, displayName); 671 return this; 672 } 673 674 /** 675 * Sets the description of the Channel. 676 * 677 * @param description The value of {@link Channels#COLUMN_DESCRIPTION} for the channel. 678 * @return This Builder object to allow for chaining of calls to builder methods. 679 */ 680 public Builder setDescription(String description) { 681 mValues.put(Channels.COLUMN_DESCRIPTION, description); 682 return this; 683 } 684 685 /** 686 * Sets the video format of the Channel. 687 * 688 * @param videoFormat The value of {@link Channels#COLUMN_VIDEO_FORMAT} for the channel. 689 * @return This Builder object to allow for chaining of calls to builder methods. 690 */ 691 public Builder setVideoFormat(@VideoFormat String videoFormat) { 692 mValues.put(Channels.COLUMN_VIDEO_FORMAT, videoFormat); 693 return this; 694 } 695 696 /** 697 * Sets the original network id of the Channel. 698 * 699 * @param originalNetworkId The value of {@link Channels#COLUMN_ORIGINAL_NETWORK_ID} for the 700 * channel. 701 * @return This Builder object to allow for chaining of calls to builder methods. 702 */ 703 public Builder setOriginalNetworkId(int originalNetworkId) { 704 mValues.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, originalNetworkId); 705 return this; 706 } 707 708 /** 709 * Sets the transport stream id of the Channel. 710 * 711 * @param transportStreamId The value of {@link Channels#COLUMN_TRANSPORT_STREAM_ID} for the 712 * channel. 713 * @return This Builder object to allow for chaining of calls to builder methods. 714 */ 715 public Builder setTransportStreamId(int transportStreamId) { 716 mValues.put(Channels.COLUMN_TRANSPORT_STREAM_ID, transportStreamId); 717 return this; 718 } 719 720 /** 721 * Sets the service id of the Channel. 722 * 723 * @param serviceId The value of {@link Channels#COLUMN_SERVICE_ID} for the channel. 724 * @return This Builder object to allow for chaining of calls to builder methods. 725 */ 726 public Builder setServiceId(int serviceId) { 727 mValues.put(Channels.COLUMN_SERVICE_ID, serviceId); 728 return this; 729 } 730 731 /** 732 * Sets the internal provider data of the channel. 733 * 734 * @param internalProviderData The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_DATA} 735 * for the channel. 736 * @return This Builder object to allow for chaining of calls to builder methods. 737 */ 738 public Builder setInternalProviderData(byte[] internalProviderData) { 739 mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_DATA, internalProviderData); 740 return this; 741 } 742 743 /** 744 * Sets the internal provider data of the channel. 745 * 746 * @param internalProviderData The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_DATA} 747 * for the channel. 748 * @return This Builder object to allow for chaining of calls to builder methods. 749 */ 750 public Builder setInternalProviderData(String internalProviderData) { 751 mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_DATA, 752 internalProviderData.getBytes(Charset.defaultCharset())); 753 return this; 754 } 755 756 /** 757 * Sets the text to be displayed in the App Linking card. 758 * 759 * @param appLinkText The value of {@link Channels#COLUMN_APP_LINK_TEXT} for the channel. 760 * @return This Builder object to allow for chaining of calls to builder methods. 761 */ 762 public Builder setAppLinkText(String appLinkText) { 763 mValues.put(Channels.COLUMN_APP_LINK_TEXT, appLinkText); 764 return this; 765 } 766 767 /** 768 * Sets the background color of the App Linking card. 769 * 770 * @param appLinkColor The value of {@link Channels#COLUMN_APP_LINK_COLOR} for the channel. 771 * @return This Builder object to allow for chaining of calls to builder methods. 772 */ 773 public Builder setAppLinkColor(int appLinkColor) { 774 mValues.put(Channels.COLUMN_APP_LINK_COLOR, appLinkColor); 775 return this; 776 } 777 778 /** 779 * Sets the icon to be displayed next to the text of the App Linking card. 780 * 781 * @param appLinkIconUri The value of {@link Channels#COLUMN_APP_LINK_ICON_URI} for the 782 * channel. 783 * @return This Builder object to allow for chaining of calls to builder methods. 784 */ 785 public Builder setAppLinkIconUri(Uri appLinkIconUri) { 786 mValues.put(Channels.COLUMN_APP_LINK_ICON_URI, 787 appLinkIconUri == null ? null : appLinkIconUri.toString()); 788 return this; 789 } 790 791 /** 792 * Sets the background image of the App Linking card. 793 * 794 * @param appLinkPosterArtUri The value of {@link Channels#COLUMN_APP_LINK_POSTER_ART_URI} 795 * for the channel. 796 * @return This Builder object to allow for chaining of calls to builder methods. 797 */ 798 public Builder setAppLinkPosterArtUri(Uri appLinkPosterArtUri) { 799 mValues.put(Channels.COLUMN_APP_LINK_POSTER_ART_URI, 800 appLinkPosterArtUri == null ? null : appLinkPosterArtUri.toString()); 801 return this; 802 } 803 804 /** 805 * Sets the App Linking Intent. 806 * 807 * @param appLinkIntent The Intent to be executed when the App Linking card is selected 808 * @return This Builder object to allow for chaining of calls to builder methods. 809 */ 810 public Builder setAppLinkIntent(Intent appLinkIntent) { 811 return setAppLinkIntentUri(Uri.parse(appLinkIntent.toUri(Intent.URI_INTENT_SCHEME))); 812 } 813 814 /** 815 * Sets the App Linking Intent. 816 * 817 * @param appLinkIntentUri The Intent that should be executed when the App Linking card is 818 * selected. Use the method toUri(Intent.URI_INTENT_SCHEME) on your 819 * Intent to turn it into a String. See 820 * {@link Channels#COLUMN_APP_LINK_INTENT_URI}. 821 * @return This Builder object to allow for chaining of calls to builder methods. 822 */ 823 public Builder setAppLinkIntentUri(Uri appLinkIntentUri) { 824 mValues.put(Channels.COLUMN_APP_LINK_INTENT_URI, 825 appLinkIntentUri == null ? null : appLinkIntentUri.toString()); 826 return this; 827 } 828 829 /** 830 * Sets the network name for the channel, which may be different from its display name. 831 * 832 * @param networkAffiliation The value of 833 * {@link Channels#COLUMN_NETWORK_AFFILIATION} for the channel. 834 * @return This Builder object to allow for chaining of calls to builder methods. 835 */ 836 public Builder setNetworkAffiliation(String networkAffiliation) { 837 mValues.put(Channels.COLUMN_NETWORK_AFFILIATION, networkAffiliation); 838 return this; 839 } 840 841 /** 842 * Sets whether this channel can be searched for in other applications. 843 * 844 * @param searchable The value of {@link Channels#COLUMN_SEARCHABLE} for the channel. 845 * @return This Builder object to allow for chaining of calls to builder methods. 846 */ 847 public Builder setSearchable(boolean searchable) { 848 mValues.put(Channels.COLUMN_SEARCHABLE, searchable ? IS_SEARCHABLE : 0); 849 return this; 850 } 851 852 /** 853 * Sets the type of content that will appear on this channel. This could refer to the 854 * underlying broadcast standard or refer to {@link Channels#SERVICE_TYPE_AUDIO}, 855 * {@link Channels#SERVICE_TYPE_AUDIO_VIDEO}, or {@link Channels#SERVICE_TYPE_OTHER}. 856 * 857 * @param serviceType The value of {@link Channels#COLUMN_SERVICE_TYPE} for the channel. 858 * @return This Builder object to allow for chaining of calls to builder methods. 859 */ 860 public Builder setServiceType(@ServiceType String serviceType) { 861 mValues.put(Channels.COLUMN_SERVICE_TYPE, serviceType); 862 return this; 863 } 864 865 /** 866 * Sets the internal provider flag1 for the channel. 867 * 868 * @param flag The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG1} for the program. 869 * @return This Builder object to allow for chaining of calls to builder methods. 870 */ 871 public Builder setInternalProviderFlag1(long flag) { 872 mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, flag); 873 return this; 874 } 875 876 /** 877 * Sets the internal provider flag2 for the channel. 878 * 879 * @param flag The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG2} for the program. 880 * @return This Builder object to allow for chaining of calls to builder methods. 881 */ 882 public Builder setInternalProviderFlag2(long flag) { 883 mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, flag); 884 return this; 885 } 886 887 /** 888 * Sets the internal provider flag3 for the channel. 889 * 890 * @param flag The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG3} for the program. 891 * @return This Builder object to allow for chaining of calls to builder methods. 892 */ 893 public Builder setInternalProviderFlag3(long flag) { 894 mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3, flag); 895 return this; 896 } 897 898 /** 899 * Sets the internal provider flag4 for the channel. 900 * 901 * @param flag The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG4} for the program. 902 * @return This Builder object to allow for chaining of calls to builder methods. 903 */ 904 public Builder setInternalProviderFlag4(long flag) { 905 mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4, flag); 906 return this; 907 } 908 909 /** 910 * Sets the internal provider ID for the channel. 911 * 912 * @param internalProviderId The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_ID} 913 * for the program. 914 * @return This Builder object to allow for chaining of calls to builder methods. 915 */ 916 public Builder setInternalProviderId(String internalProviderId) { 917 mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_ID, internalProviderId); 918 return this; 919 } 920 921 /** 922 * Sets whether this channel is transient or not. 923 * 924 * @param value The value of {@link Channels#COLUMN_TRANSIENT} for the channel. 925 * @return This Builder object to allow for chaining of calls to builder methods. 926 */ 927 public Builder setTransient(boolean value) { 928 mValues.put(Channels.COLUMN_TRANSIENT, value ? IS_TRANSIENT : 0); 929 return this; 930 } 931 932 /** 933 * Sets whether this channel is browsable or not. 934 * 935 * @param value The value of {@link Channels#COLUMN_BROWSABLE} for the channel. 936 * @return This Builder object to allow for chaining of calls to builder methods. 937 * @hide 938 */ 939 @RestrictTo(LIBRARY_GROUP) 940 public Builder setBrowsable(boolean value) { 941 mValues.put(Channels.COLUMN_BROWSABLE, value ? IS_BROWSABLE : 0); 942 return this; 943 } 944 945 /** 946 * Sets whether system approved this channel or not. 947 * 948 * @param value The value of {@link Channels#COLUMN_SYSTEM_APPROVED} for the channel. 949 * @return This Builder object to allow for chaining of calls to builder methods. 950 * @hide 951 */ 952 @RestrictTo(LIBRARY_GROUP) 953 public Builder setSystemApproved(boolean value) { 954 mValues.put(Channels.COLUMN_SYSTEM_APPROVED, value ? IS_SYSTEM_APPROVED : 0); 955 return this; 956 } 957 958 /** 959 * Sets the configuration display order for this channel. This value will be used to 960 * order channels within the configure channels menu. 961 * 962 * @param value The value of {@link Channels#COLUMN_CONFIGURATION_DISPLAY_ORDER} for the 963 * channel 964 * @return This Builder object to allow for chaining of calls to builder methods. 965 */ 966 public Builder setConfigurationDisplayOrder(int value) { 967 mValues.put(Channels.COLUMN_CONFIGURATION_DISPLAY_ORDER, value); 968 return this; 969 } 970 971 /** 972 * Sets the system channel key for this channel. This identifier helps OEM differentiate 973 * among the app's channels. This identifier should be unique per channel for each app, and 974 * should be agreed between the app and the OEM. It is up to the OEM on how they use this 975 * identifier for customization purposes. 976 * 977 * @param value The value of {@link Channels#COLUMN_SYSTEM_CHANNEL_KEY} for the channel. 978 * @return This Builder object to allow for chaining of calls to builder methods. 979 */ 980 public Builder setSystemChannelKey(String value) { 981 mValues.put(Channels.COLUMN_SYSTEM_CHANNEL_KEY, value); 982 return this; 983 } 984 985 /** 986 * Sets whether this channel is locked or not. 987 * 988 * @param value The value of {@link Channels#COLUMN_LOCKED} for the channel. 989 * @return This Builder object to allow for chaining of calls to builder methods. 990 * @hide 991 */ 992 @RestrictTo(LIBRARY_GROUP) 993 public Builder setLocked(boolean value) { 994 mValues.put(Channels.COLUMN_LOCKED, value ? IS_LOCKED : 0); 995 return this; 996 } 997 998 /** 999 * Takes the values of the Builder object and creates a Channel object. 1000 * @return Channel object with values from the Builder. 1001 */ 1002 public Channel build() { 1003 return new Channel(this); 1004 } 1005 } 1006 } 1007