1 /* 2 * Copyright (C) 2016 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.common.recording; 18 19 import static android.media.tv.TvContract.RecordedPrograms; 20 21 import android.content.ContentUris; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.database.Cursor; 25 import android.media.tv.TvContract; 26 import android.net.Uri; 27 import android.support.annotation.Nullable; 28 import android.text.TextUtils; 29 30 import com.android.tv.common.R; 31 32 import java.util.Arrays; 33 import java.util.Comparator; 34 import java.util.Objects; 35 36 /** 37 * Immutable instance of {@link android.media.tv.TvContract.RecordedPrograms}. 38 */ 39 public class RecordedProgram { 40 public static final int ID_NOT_SET = -1; 41 42 public final static String[] PROJECTION = { 43 // These are in exactly the order listed in RecordedPrograms 44 RecordedPrograms._ID, 45 RecordedPrograms.COLUMN_INPUT_ID, 46 RecordedPrograms.COLUMN_CHANNEL_ID, 47 RecordedPrograms.COLUMN_TITLE, 48 RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, 49 RecordedPrograms.COLUMN_SEASON_TITLE, 50 RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, 51 RecordedPrograms.COLUMN_EPISODE_TITLE, 52 RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, 53 RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, 54 RecordedPrograms.COLUMN_BROADCAST_GENRE, 55 RecordedPrograms.COLUMN_CANONICAL_GENRE, 56 RecordedPrograms.COLUMN_SHORT_DESCRIPTION, 57 RecordedPrograms.COLUMN_LONG_DESCRIPTION, 58 RecordedPrograms.COLUMN_VIDEO_WIDTH, 59 RecordedPrograms.COLUMN_VIDEO_HEIGHT, 60 RecordedPrograms.COLUMN_AUDIO_LANGUAGE, 61 RecordedPrograms.COLUMN_CONTENT_RATING, 62 RecordedPrograms.COLUMN_POSTER_ART_URI, 63 RecordedPrograms.COLUMN_THUMBNAIL_URI, 64 RecordedPrograms.COLUMN_SEARCHABLE, 65 RecordedPrograms.COLUMN_RECORDING_DATA_URI, 66 RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, 67 RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, 68 RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, 69 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, 70 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, 71 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, 72 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, 73 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, 74 RecordedPrograms.COLUMN_VERSION_NUMBER, 75 }; 76 fromCursor(Cursor cursor)77 public static final RecordedProgram fromCursor(Cursor cursor) { 78 int index = 0; 79 return builder() 80 .setId(cursor.getLong(index++)) 81 .setInputId(cursor.getString(index++)) 82 .setChannelId(cursor.getLong(index++)) 83 .setTitle(cursor.getString(index++)) 84 .setSeasonNumber(cursor.getString(index++)) 85 .setSeasonTitle(cursor.getString(index++)) 86 .setEpisodeNumber(cursor.getString(index++)) 87 .setEpisodeTitle(cursor.getString(index++)) 88 .setStartTimeUtcMillis(cursor.getLong(index++)) 89 .setEndTimeUtcMillis(cursor.getLong(index++)) 90 .setBroadcastGenres(cursor.getString(index++)) 91 .setCanonicalGenres(cursor.getString(index++)) 92 .setShortDescription(cursor.getString(index++)) 93 .setLongDescription(cursor.getString(index++)) 94 .setVideoWidth(cursor.getInt(index++)) 95 .setVideoHeight(cursor.getInt(index++)) 96 .setAudioLanguage(cursor.getString(index++)) 97 .setContentRating(cursor.getString(index++)) 98 .setPosterArt(cursor.getString(index++)) 99 .setThumbnail(cursor.getString(index++)) 100 .setSearchable(cursor.getInt(index++) == 1) 101 .setDataUri(cursor.getString(index++)) 102 .setDataBytes(cursor.getLong(index++)) 103 .setDurationMillis(cursor.getLong(index++)) 104 .setExpireTimeUtcMillis(cursor.getLong(index++)) 105 .setInternalProviderData(cursor.getBlob(index++)) 106 .setInternalProviderFlag1(cursor.getInt(index++)) 107 .setInternalProviderFlag2(cursor.getInt(index++)) 108 .setInternalProviderFlag3(cursor.getInt(index++)) 109 .setInternalProviderFlag4(cursor.getInt(index++)) 110 .setVersionNumber(cursor.getInt(index++)) 111 .build(); 112 } 113 toValues(RecordedProgram recordedProgram)114 public static ContentValues toValues(RecordedProgram recordedProgram) { 115 ContentValues values = new ContentValues(); 116 if (recordedProgram.mId != ID_NOT_SET) { 117 values.put(RecordedPrograms._ID, recordedProgram.mId); 118 } 119 values.put(RecordedPrograms.COLUMN_INPUT_ID, recordedProgram.mInputId); 120 values.put(RecordedPrograms.COLUMN_CHANNEL_ID, recordedProgram.mChannelId); 121 values.put(RecordedPrograms.COLUMN_TITLE, recordedProgram.mTitle); 122 values.put(RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, recordedProgram.mSeasonNumber); 123 values.put(RecordedPrograms.COLUMN_SEASON_TITLE, recordedProgram.mSeasonTitle); 124 values.put(RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, recordedProgram.mEpisodeNumber); 125 values.put(RecordedPrograms.COLUMN_EPISODE_TITLE, recordedProgram.mTitle); 126 values.put(RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, 127 recordedProgram.mStartTimeUtcMillis); 128 values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, recordedProgram.mEndTimeUtcMillis); 129 values.put(RecordedPrograms.COLUMN_BROADCAST_GENRE, 130 safeEncode(recordedProgram.mBroadcastGenres)); 131 values.put(RecordedPrograms.COLUMN_CANONICAL_GENRE, 132 safeEncode(recordedProgram.mCanonicalGenres)); 133 values.put(RecordedPrograms.COLUMN_SHORT_DESCRIPTION, recordedProgram.mShortDescription); 134 values.put(RecordedPrograms.COLUMN_LONG_DESCRIPTION, recordedProgram.mLongDescription); 135 if (recordedProgram.mVideoWidth == 0) { 136 values.putNull(RecordedPrograms.COLUMN_VIDEO_WIDTH); 137 } else { 138 values.put(RecordedPrograms.COLUMN_VIDEO_WIDTH, recordedProgram.mVideoWidth); 139 } 140 if (recordedProgram.mVideoHeight == 0) { 141 values.putNull(RecordedPrograms.COLUMN_VIDEO_HEIGHT); 142 } else { 143 values.put(RecordedPrograms.COLUMN_VIDEO_HEIGHT, recordedProgram.mVideoHeight); 144 } 145 values.put(RecordedPrograms.COLUMN_AUDIO_LANGUAGE, recordedProgram.mAudioLanguage); 146 values.put(RecordedPrograms.COLUMN_CONTENT_RATING, recordedProgram.mContentRating); 147 values.put(RecordedPrograms.COLUMN_POSTER_ART_URI, 148 safeToString(recordedProgram.mPosterArt)); 149 values.put(RecordedPrograms.COLUMN_THUMBNAIL_URI, safeToString(recordedProgram.mThumbnail)); 150 values.put(RecordedPrograms.COLUMN_SEARCHABLE, recordedProgram.mSearchable ? 1 : 0); 151 values.put(RecordedPrograms.COLUMN_RECORDING_DATA_URI, 152 safeToString(recordedProgram.mDataUri)); 153 values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, recordedProgram.mDataBytes); 154 values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, 155 recordedProgram.mDurationMillis); 156 values.put(RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, 157 recordedProgram.mExpireTimeUtcMillis); 158 values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, 159 recordedProgram.mInternalProviderData); 160 values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, 161 recordedProgram.mInternalProviderFlag1); 162 values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, 163 recordedProgram.mInternalProviderFlag2); 164 values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, 165 recordedProgram.mInternalProviderFlag3); 166 values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, 167 recordedProgram.mInternalProviderFlag4); 168 values.put(RecordedPrograms.COLUMN_VERSION_NUMBER, recordedProgram.mVersionNumber); 169 return values; 170 } 171 172 public static class Builder{ 173 private long mId = ID_NOT_SET; 174 private String mInputId; 175 private long mChannelId; 176 private String mTitle; 177 private String mSeasonNumber; 178 private String mSeasonTitle; 179 private String mEpisodeNumber; 180 private String mEpisodeTitle; 181 private long mStartTimeUtcMillis; 182 private long mEndTimeUtcMillis; 183 private String[] mBroadcastGenres; 184 private String[] mCanonicalGenres; 185 private String mShortDescription; 186 private String mLongDescription; 187 private int mVideoWidth; 188 private int mVideoHeight; 189 private String mAudioLanguage; 190 private String mContentRating; 191 private Uri mPosterArt; 192 private Uri mThumbnail; 193 private boolean mSearchable = true; 194 private Uri mDataUri; 195 private long mDataBytes; 196 private long mDurationMillis; 197 private long mExpireTimeUtcMillis; 198 private byte[] mInternalProviderData; 199 private int mInternalProviderFlag1; 200 private int mInternalProviderFlag2; 201 private int mInternalProviderFlag3; 202 private int mInternalProviderFlag4; 203 private int mVersionNumber; 204 setId(long id)205 public Builder setId(long id) { 206 mId = id; 207 return this; 208 } 209 setInputId(String inputId)210 public Builder setInputId(String inputId) { 211 mInputId = inputId; 212 return this; 213 } 214 setChannelId(long channelId)215 public Builder setChannelId(long channelId) { 216 mChannelId = channelId; 217 return this; 218 } 219 setTitle(String title)220 public Builder setTitle(String title) { 221 mTitle = title; 222 return this; 223 } 224 setSeasonNumber(String seasonNumber)225 public Builder setSeasonNumber(String seasonNumber) { 226 mSeasonNumber = seasonNumber; 227 return this; 228 } 229 setSeasonTitle(String seasonTitle)230 public Builder setSeasonTitle(String seasonTitle) { 231 mSeasonTitle = seasonTitle; 232 return this; 233 } 234 setEpisodeNumber(String episodeNumber)235 public Builder setEpisodeNumber(String episodeNumber) { 236 mEpisodeNumber = episodeNumber; 237 return this; 238 } 239 setEpisodeTitle(String episodeTitle)240 public Builder setEpisodeTitle(String episodeTitle) { 241 mEpisodeTitle = episodeTitle; 242 return this; 243 } 244 setStartTimeUtcMillis(long startTimeUtcMillis)245 public Builder setStartTimeUtcMillis(long startTimeUtcMillis) { 246 mStartTimeUtcMillis = startTimeUtcMillis; 247 return this; 248 } 249 setEndTimeUtcMillis(long endTimeUtcMillis)250 public Builder setEndTimeUtcMillis(long endTimeUtcMillis) { 251 mEndTimeUtcMillis = endTimeUtcMillis; 252 return this; 253 } 254 setBroadcastGenres(String broadcastGenres)255 public Builder setBroadcastGenres(String broadcastGenres) { 256 if (TextUtils.isEmpty(broadcastGenres)) { 257 mBroadcastGenres = null; 258 return this; 259 } 260 return setBroadcastGenres(TvContract.Programs.Genres.decode(broadcastGenres)); 261 } 262 setBroadcastGenres(String[] broadcastGenres)263 private Builder setBroadcastGenres(String[] broadcastGenres) { 264 mBroadcastGenres = broadcastGenres; 265 return this; 266 } 267 setCanonicalGenres(String canonicalGenres)268 public Builder setCanonicalGenres(String canonicalGenres) { 269 if (TextUtils.isEmpty(canonicalGenres)) { 270 mCanonicalGenres = null; 271 return this; 272 } 273 return setCanonicalGenres(TvContract.Programs.Genres.decode(canonicalGenres)); 274 } 275 setCanonicalGenres(String[] canonicalGenres)276 private Builder setCanonicalGenres(String[] canonicalGenres) { 277 mCanonicalGenres = canonicalGenres; 278 return this; 279 } 280 setShortDescription(String shortDescription)281 public Builder setShortDescription(String shortDescription) { 282 mShortDescription = shortDescription; 283 return this; 284 } 285 setLongDescription(String longDescription)286 public Builder setLongDescription(String longDescription) { 287 mLongDescription = longDescription; 288 return this; 289 } 290 setVideoWidth(int videoWidth)291 public Builder setVideoWidth(int videoWidth) { 292 mVideoWidth = videoWidth; 293 return this; 294 } 295 setVideoHeight(int videoHeight)296 public Builder setVideoHeight(int videoHeight) { 297 mVideoHeight = videoHeight; 298 return this; 299 } 300 setAudioLanguage(String audioLanguage)301 public Builder setAudioLanguage(String audioLanguage) { 302 mAudioLanguage = audioLanguage; 303 return this; 304 } 305 setContentRating(String contentRating)306 public Builder setContentRating(String contentRating) { 307 mContentRating = contentRating; 308 return this; 309 } 310 toUri(String uriString)311 private Uri toUri(String uriString) { 312 try { 313 return uriString == null ? null : Uri.parse(uriString); 314 } catch (Exception e) { 315 return null; 316 } 317 } 318 setPosterArt(String posterArtUri)319 public Builder setPosterArt(String posterArtUri) { 320 return setPosterArt(toUri(posterArtUri)); 321 } 322 setPosterArt(Uri posterArt)323 public Builder setPosterArt(Uri posterArt) { 324 mPosterArt = posterArt; 325 return this; 326 } 327 setThumbnail(String thumbnailUri)328 public Builder setThumbnail(String thumbnailUri) { 329 return setThumbnail(toUri(thumbnailUri)); 330 } 331 setThumbnail(Uri thumbnail)332 public Builder setThumbnail(Uri thumbnail) { 333 mThumbnail = thumbnail; 334 return this; 335 } 336 setSearchable(boolean searchable)337 public Builder setSearchable(boolean searchable) { 338 mSearchable = searchable; 339 return this; 340 } 341 setDataUri(String dataUri)342 public Builder setDataUri(String dataUri) { 343 return setDataUri(toUri(dataUri)); 344 } 345 setDataUri(Uri dataUri)346 public Builder setDataUri(Uri dataUri) { 347 mDataUri = dataUri; 348 return this; 349 } 350 setDataBytes(long dataBytes)351 public Builder setDataBytes(long dataBytes) { 352 mDataBytes = dataBytes; 353 return this; 354 } 355 setDurationMillis(long durationMillis)356 public Builder setDurationMillis(long durationMillis) { 357 mDurationMillis = durationMillis; 358 return this; 359 } 360 setExpireTimeUtcMillis(long expireTimeUtcMillis)361 public Builder setExpireTimeUtcMillis(long expireTimeUtcMillis) { 362 mExpireTimeUtcMillis = expireTimeUtcMillis; 363 return this; 364 } 365 setInternalProviderData(byte[] internalProviderData)366 public Builder setInternalProviderData(byte[] internalProviderData) { 367 mInternalProviderData = internalProviderData; 368 return this; 369 } 370 setInternalProviderFlag1(int internalProviderFlag1)371 public Builder setInternalProviderFlag1(int internalProviderFlag1) { 372 mInternalProviderFlag1 = internalProviderFlag1; 373 return this; 374 } 375 setInternalProviderFlag2(int internalProviderFlag2)376 public Builder setInternalProviderFlag2(int internalProviderFlag2) { 377 mInternalProviderFlag2 = internalProviderFlag2; 378 return this; 379 } 380 setInternalProviderFlag3(int internalProviderFlag3)381 public Builder setInternalProviderFlag3(int internalProviderFlag3) { 382 mInternalProviderFlag3 = internalProviderFlag3; 383 return this; 384 } 385 setInternalProviderFlag4(int internalProviderFlag4)386 public Builder setInternalProviderFlag4(int internalProviderFlag4) { 387 mInternalProviderFlag4 = internalProviderFlag4; 388 return this; 389 } 390 setVersionNumber(int versionNumber)391 public Builder setVersionNumber(int versionNumber) { 392 mVersionNumber = versionNumber; 393 return this; 394 } 395 build()396 public RecordedProgram build() { 397 return new RecordedProgram(mId, mInputId, mChannelId, mTitle, mSeasonNumber, 398 mSeasonTitle, mEpisodeNumber, mEpisodeTitle, mStartTimeUtcMillis, 399 mEndTimeUtcMillis, mBroadcastGenres, mCanonicalGenres, mShortDescription, 400 mLongDescription, mVideoWidth, mVideoHeight, mAudioLanguage, mContentRating, 401 mPosterArt, mThumbnail, mSearchable, mDataUri, mDataBytes, mDurationMillis, 402 mExpireTimeUtcMillis, mInternalProviderData, mInternalProviderFlag1, 403 mInternalProviderFlag2, mInternalProviderFlag3, mInternalProviderFlag4, 404 mVersionNumber); 405 } 406 } 407 builder()408 public static Builder builder() { return new Builder(); } 409 buildFrom(RecordedProgram orig)410 public static Builder buildFrom(RecordedProgram orig) { 411 return builder() 412 .setId(orig.getId()) 413 .setInputId(orig.getInputId()) 414 .setChannelId(orig.getChannelId()) 415 .setTitle(orig.getTitle()) 416 .setSeasonNumber(orig.getSeasonNumber()) 417 .setSeasonTitle(orig.getSeasonTitle()) 418 .setEpisodeNumber(orig.getEpisodeNumber()) 419 .setEpisodeTitle(orig.getEpisodeTitle()) 420 .setStartTimeUtcMillis(orig.getStartTimeUtcMillis()) 421 .setEndTimeUtcMillis(orig.getEndTimeUtcMillis()) 422 .setBroadcastGenres(orig.getBroadcastGenres()) 423 .setCanonicalGenres(orig.getCanonicalGenres()) 424 .setShortDescription(orig.getShortDescription()) 425 .setLongDescription(orig.getLongDescription()) 426 .setVideoWidth(orig.getVideoWidth()) 427 .setVideoHeight(orig.getVideoHeight()) 428 .setAudioLanguage(orig.getAudioLanguage()) 429 .setContentRating(orig.getContentRating()) 430 .setPosterArt(orig.getPosterArt()) 431 .setThumbnail(orig.getThumbnail()) 432 .setSearchable(orig.isSearchable()) 433 .setInternalProviderData(orig.getInternalProviderData()) 434 .setInternalProviderFlag1(orig.getInternalProviderFlag1()) 435 .setInternalProviderFlag2(orig.getInternalProviderFlag2()) 436 .setInternalProviderFlag3(orig.getInternalProviderFlag3()) 437 .setInternalProviderFlag4(orig.getInternalProviderFlag4()) 438 .setVersionNumber(orig.getVersionNumber()); 439 } 440 441 public static final Comparator<RecordedProgram> START_TIME_THEN_ID_COMPARATOR 442 = new Comparator<RecordedProgram>() { 443 @Override 444 public int compare(RecordedProgram lhs, RecordedProgram rhs) { 445 int res = Long.compare(lhs.getStartTimeUtcMillis(), rhs.getStartTimeUtcMillis()); 446 if (res != 0) { 447 return res; 448 } 449 return Long.compare(lhs.mId, rhs.mId); 450 } 451 }; 452 453 private final long mId; 454 private final String mInputId; 455 private final long mChannelId; 456 private final String mTitle; 457 private final String mSeasonNumber; 458 private final String mSeasonTitle; 459 private final String mEpisodeNumber; 460 private final String mEpisodeTitle; 461 private final long mStartTimeUtcMillis; 462 private final long mEndTimeUtcMillis; 463 private final String[] mBroadcastGenres; 464 private final String[] mCanonicalGenres; 465 private final String mShortDescription; 466 private final String mLongDescription; 467 private final int mVideoWidth; 468 private final int mVideoHeight; 469 private final String mAudioLanguage; 470 private final String mContentRating; 471 private final Uri mPosterArt; 472 private final Uri mThumbnail; 473 private final boolean mSearchable; 474 private final Uri mDataUri; 475 private final long mDataBytes; 476 private final long mDurationMillis; 477 private final long mExpireTimeUtcMillis; 478 private final byte[] mInternalProviderData; 479 private final int mInternalProviderFlag1; 480 private final int mInternalProviderFlag2; 481 private final int mInternalProviderFlag3; 482 private final int mInternalProviderFlag4; 483 private final int mVersionNumber; 484 RecordedProgram(long id, String inputId, long channelId, String title, String seasonNumber, String seasonTitle, String episodeNumber, String episodeTitle, long startTimeUtcMillis, long endTimeUtcMillis, String[] broadcastGenres, String[] canonicalGenres, String shortDescription, String longDescription, int videoWidth, int videoHeight, String audioLanguage, String contentRating, Uri posterArt, Uri thumbnail, boolean searchable, Uri dataUri, long dataBytes, long durationMillis, long expireTimeUtcMillis, byte[] internalProviderData, int internalProviderFlag1, int internalProviderFlag2, int internalProviderFlag3, int internalProviderFlag4, int versionNumber)485 private RecordedProgram(long id, String inputId, long channelId, String title, 486 String seasonNumber, String seasonTitle, String episodeNumber, String episodeTitle, 487 long startTimeUtcMillis, long endTimeUtcMillis, String[] broadcastGenres, 488 String[] canonicalGenres, String shortDescription, String longDescription, 489 int videoWidth, int videoHeight, String audioLanguage, String contentRating, 490 Uri posterArt, Uri thumbnail, boolean searchable, Uri dataUri, long dataBytes, 491 long durationMillis, long expireTimeUtcMillis, byte[] internalProviderData, 492 int internalProviderFlag1, int internalProviderFlag2, int internalProviderFlag3, 493 int internalProviderFlag4, int versionNumber) { 494 mId = id; 495 mInputId = inputId; 496 mChannelId = channelId; 497 mTitle = title; 498 mSeasonNumber = seasonNumber; 499 mSeasonTitle = seasonTitle; 500 mEpisodeNumber = episodeNumber; 501 mEpisodeTitle = episodeTitle; 502 mStartTimeUtcMillis = startTimeUtcMillis; 503 mEndTimeUtcMillis = endTimeUtcMillis; 504 mBroadcastGenres = broadcastGenres; 505 mCanonicalGenres = canonicalGenres; 506 mShortDescription = shortDescription; 507 mLongDescription = longDescription; 508 mVideoWidth = videoWidth; 509 mVideoHeight = videoHeight; 510 511 mAudioLanguage = audioLanguage; 512 mContentRating = contentRating; 513 mPosterArt = posterArt; 514 mThumbnail = thumbnail; 515 mSearchable = searchable; 516 mDataUri = dataUri; 517 mDataBytes = dataBytes; 518 mDurationMillis = durationMillis; 519 mExpireTimeUtcMillis = expireTimeUtcMillis; 520 mInternalProviderData = internalProviderData; 521 mInternalProviderFlag1 = internalProviderFlag1; 522 mInternalProviderFlag2 = internalProviderFlag2; 523 mInternalProviderFlag3 = internalProviderFlag3; 524 mInternalProviderFlag4 = internalProviderFlag4; 525 mVersionNumber = versionNumber; 526 } 527 getAudioLanguage()528 public String getAudioLanguage() { 529 return mAudioLanguage; 530 } 531 getBroadcastGenres()532 public String[] getBroadcastGenres() { 533 return mBroadcastGenres; 534 } 535 getCanonicalGenres()536 public String[] getCanonicalGenres() { 537 return mCanonicalGenres; 538 } 539 getChannelId()540 public long getChannelId() { 541 return mChannelId; 542 } 543 getContentRating()544 public String getContentRating() { 545 return mContentRating; 546 } 547 getDataUri()548 public Uri getDataUri() { 549 return mDataUri; 550 } 551 getDataBytes()552 public long getDataBytes() { 553 return mDataBytes; 554 } 555 getDurationMillis()556 public long getDurationMillis() { 557 return mDurationMillis; 558 } 559 getEndTimeUtcMillis()560 public long getEndTimeUtcMillis() { 561 return mEndTimeUtcMillis; 562 } 563 getEpisodeNumber()564 public String getEpisodeNumber() { 565 return mEpisodeNumber; 566 } 567 getEpisodeTitle()568 public String getEpisodeTitle() { 569 return mEpisodeTitle; 570 } 571 getEpisodeDisplayTitle(Context context)572 public String getEpisodeDisplayTitle(Context context) { 573 if (!TextUtils.isEmpty(mSeasonNumber) && !TextUtils.isEmpty(mEpisodeNumber) 574 && !TextUtils.isEmpty(mEpisodeTitle)) { 575 return String.format(context.getResources().getString(R.string.episode_format), 576 mSeasonNumber, mEpisodeNumber, mEpisodeTitle); 577 } 578 return mEpisodeTitle; 579 } 580 getExpireTimeUtcMillis()581 public long getExpireTimeUtcMillis() { 582 return mExpireTimeUtcMillis; 583 } 584 getId()585 public long getId() { 586 return mId; 587 } 588 getInputId()589 public String getInputId() { 590 return mInputId; 591 } 592 getInternalProviderData()593 public byte[] getInternalProviderData() { 594 return mInternalProviderData; 595 } 596 getInternalProviderFlag1()597 public int getInternalProviderFlag1() { 598 return mInternalProviderFlag1; 599 } 600 getInternalProviderFlag2()601 public int getInternalProviderFlag2() { 602 return mInternalProviderFlag2; 603 } 604 getInternalProviderFlag3()605 public int getInternalProviderFlag3() { 606 return mInternalProviderFlag3; 607 } 608 getInternalProviderFlag4()609 public int getInternalProviderFlag4() { 610 return mInternalProviderFlag4; 611 } 612 getLongDescription()613 public String getLongDescription() { 614 return mLongDescription; 615 } 616 getPosterArt()617 public Uri getPosterArt() { 618 return mPosterArt; 619 } 620 isSearchable()621 public boolean isSearchable() { 622 return mSearchable; 623 } 624 getSeasonNumber()625 public String getSeasonNumber() { 626 return mSeasonNumber; 627 } 628 getSeasonTitle()629 public String getSeasonTitle() { 630 return mSeasonTitle; 631 } 632 getShortDescription()633 public String getShortDescription() { 634 return mShortDescription; 635 } 636 getStartTimeUtcMillis()637 public long getStartTimeUtcMillis() { 638 return mStartTimeUtcMillis; 639 } 640 getThumbnail()641 public Uri getThumbnail() { 642 return mThumbnail; 643 } 644 getTitle()645 public String getTitle() { 646 return mTitle; 647 } 648 getUri()649 public Uri getUri() { 650 return ContentUris.withAppendedId(RecordedPrograms.CONTENT_URI, mId); 651 } 652 getVersionNumber()653 public int getVersionNumber() { 654 return mVersionNumber; 655 } 656 getVideoHeight()657 public int getVideoHeight() { 658 return mVideoHeight; 659 } 660 getVideoWidth()661 public int getVideoWidth() { 662 return mVideoWidth; 663 } 664 665 /** 666 * Compares everything except {@link #getInternalProviderData()} 667 */ 668 @Override equals(Object o)669 public boolean equals(Object o) { 670 if (this == o) return true; 671 if (o == null || getClass() != o.getClass()) return false; 672 RecordedProgram that = (RecordedProgram) o; 673 return Objects.equals(mId, that.mId) && 674 Objects.equals(mChannelId, that.mChannelId) && 675 Objects.equals(mSeasonNumber, that.mSeasonNumber) && 676 Objects.equals(mSeasonTitle, that.mSeasonTitle) && 677 Objects.equals(mEpisodeNumber, that.mEpisodeNumber) && 678 Objects.equals(mStartTimeUtcMillis, that.mStartTimeUtcMillis) && 679 Objects.equals(mEndTimeUtcMillis, that.mEndTimeUtcMillis) && 680 Objects.equals(mVideoWidth, that.mVideoWidth) && 681 Objects.equals(mVideoHeight, that.mVideoHeight) && 682 Objects.equals(mSearchable, that.mSearchable) && 683 Objects.equals(mDataBytes, that.mDataBytes) && 684 Objects.equals(mDurationMillis, that.mDurationMillis) && 685 Objects.equals(mExpireTimeUtcMillis, that.mExpireTimeUtcMillis) && 686 Objects.equals(mInternalProviderFlag1, that.mInternalProviderFlag1) && 687 Objects.equals(mInternalProviderFlag2, that.mInternalProviderFlag2) && 688 Objects.equals(mInternalProviderFlag3, that.mInternalProviderFlag3) && 689 Objects.equals(mInternalProviderFlag4, that.mInternalProviderFlag4) && 690 Objects.equals(mVersionNumber, that.mVersionNumber) && 691 Objects.equals(mTitle, that.mTitle) && 692 Objects.equals(mEpisodeTitle, that.mEpisodeTitle) && 693 Arrays.equals(mBroadcastGenres, that.mBroadcastGenres) && 694 Arrays.equals(mCanonicalGenres, that.mCanonicalGenres) && 695 Objects.equals(mShortDescription, that.mShortDescription) && 696 Objects.equals(mLongDescription, that.mLongDescription) && 697 Objects.equals(mAudioLanguage, that.mAudioLanguage) && 698 Objects.equals(mContentRating, that.mContentRating) && 699 Objects.equals(mPosterArt, that.mPosterArt) && 700 Objects.equals(mThumbnail, that.mThumbnail); 701 } 702 703 /** 704 * Hashes based on the ID. 705 */ 706 @Override hashCode()707 public int hashCode() { 708 return Objects.hash(mId); 709 } 710 711 @Override toString()712 public String toString() { 713 return "RecordedProgram" 714 + "[" + mId + 715 "]{ mInputId=" + mInputId + 716 ", mChannelId='" + mChannelId + '\'' + 717 ", mTitle='" + mTitle + '\'' + 718 ", mEpisodeNumber=" + mEpisodeNumber + 719 ", mEpisodeTitle='" + mEpisodeTitle + '\'' + 720 ", mStartTimeUtcMillis=" + mStartTimeUtcMillis + 721 ", mEndTimeUtcMillis=" + mEndTimeUtcMillis + 722 ", mBroadcastGenres=" + 723 (mBroadcastGenres != null ? Arrays.toString(mBroadcastGenres) : "null") + 724 ", mCanonicalGenres=" + 725 (mCanonicalGenres != null ? Arrays.toString(mCanonicalGenres) : "null") + 726 ", mShortDescription='" + mShortDescription + '\'' + 727 ", mLongDescription='" + mLongDescription + '\'' + 728 ", mVideoHeight=" + mVideoHeight + 729 ", mVideoWidth=" + mVideoWidth + 730 ", mAudioLanguage='" + mAudioLanguage + '\'' + 731 ", mContentRating='" + mContentRating + '\'' + 732 ", mPosterArt=" + mPosterArt + 733 ", mThumbnail=" + mThumbnail + 734 ", mSearchable=" + mSearchable + 735 ", mDataUri=" + mDataUri + 736 ", mDataBytes=" + mDataBytes + 737 ", mDurationMillis=" + mDurationMillis + 738 ", mExpireTimeUtcMillis=" + mExpireTimeUtcMillis + 739 ", mInternalProviderData.length=" + 740 (mInternalProviderData == null ? "null" : mInternalProviderData.length) + 741 ", mInternalProviderFlag1=" + mInternalProviderFlag1 + 742 ", mInternalProviderFlag2=" + mInternalProviderFlag2 + 743 ", mInternalProviderFlag3=" + mInternalProviderFlag3 + 744 ", mInternalProviderFlag4=" + mInternalProviderFlag4 + 745 ", mSeasonNumber=" + mSeasonNumber + 746 ", mSeasonTitle=" + mSeasonTitle + 747 ", mVersionNumber=" + mVersionNumber + 748 '}'; 749 } 750 751 @Nullable safeToString(@ullable Object o)752 private static String safeToString(@Nullable Object o) { 753 return o == null ? null : o.toString(); 754 } 755 756 @Nullable safeEncode(@ullable String[] genres)757 private static String safeEncode(@Nullable String[] genres) { 758 return genres == null ? null : TvContract.Programs.Genres.encode(genres); 759 } 760 } 761