diff options
Diffstat (limited to 'src/com/android/tv/dvr/data/RecordedProgram.java')
-rw-r--r-- | src/com/android/tv/dvr/data/RecordedProgram.java | 845 |
1 files changed, 845 insertions, 0 deletions
diff --git a/src/com/android/tv/dvr/data/RecordedProgram.java b/src/com/android/tv/dvr/data/RecordedProgram.java new file mode 100644 index 00000000..2e953a52 --- /dev/null +++ b/src/com/android/tv/dvr/data/RecordedProgram.java @@ -0,0 +1,845 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.tv.dvr.data; + +import android.annotation.TargetApi; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.media.tv.TvContentRating; +import android.media.tv.TvContract; +import android.media.tv.TvContract.RecordedPrograms; +import android.net.Uri; +import android.os.Build; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.android.tv.common.R; +import com.android.tv.common.TvContentRatingCache; +import com.android.tv.data.BaseProgram; +import com.android.tv.data.GenreItems; +import com.android.tv.data.InternalDataUtils; +import com.android.tv.util.Utils; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * Immutable instance of {@link android.media.tv.TvContract.RecordedPrograms}. + */ +@TargetApi(Build.VERSION_CODES.N) +public class RecordedProgram extends BaseProgram { + public static final int ID_NOT_SET = -1; + + public final static String[] PROJECTION = { + // These are in exactly the order listed in RecordedPrograms + RecordedPrograms._ID, + RecordedPrograms.COLUMN_PACKAGE_NAME, + RecordedPrograms.COLUMN_INPUT_ID, + RecordedPrograms.COLUMN_CHANNEL_ID, + RecordedPrograms.COLUMN_TITLE, + RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, + RecordedPrograms.COLUMN_SEASON_TITLE, + RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, + RecordedPrograms.COLUMN_EPISODE_TITLE, + RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, + RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, + RecordedPrograms.COLUMN_BROADCAST_GENRE, + RecordedPrograms.COLUMN_CANONICAL_GENRE, + RecordedPrograms.COLUMN_SHORT_DESCRIPTION, + RecordedPrograms.COLUMN_LONG_DESCRIPTION, + RecordedPrograms.COLUMN_VIDEO_WIDTH, + RecordedPrograms.COLUMN_VIDEO_HEIGHT, + RecordedPrograms.COLUMN_AUDIO_LANGUAGE, + RecordedPrograms.COLUMN_CONTENT_RATING, + RecordedPrograms.COLUMN_POSTER_ART_URI, + RecordedPrograms.COLUMN_THUMBNAIL_URI, + RecordedPrograms.COLUMN_SEARCHABLE, + RecordedPrograms.COLUMN_RECORDING_DATA_URI, + RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, + RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, + RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, + RecordedPrograms.COLUMN_VERSION_NUMBER, + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, + }; + + public static RecordedProgram fromCursor(Cursor cursor) { + int index = 0; + Builder builder = builder() + .setId(cursor.getLong(index++)) + .setPackageName(cursor.getString(index++)) + .setInputId(cursor.getString(index++)) + .setChannelId(cursor.getLong(index++)) + .setTitle(cursor.getString(index++)) + .setSeasonNumber(cursor.getString(index++)) + .setSeasonTitle(cursor.getString(index++)) + .setEpisodeNumber(cursor.getString(index++)) + .setEpisodeTitle(cursor.getString(index++)) + .setStartTimeUtcMillis(cursor.getLong(index++)) + .setEndTimeUtcMillis(cursor.getLong(index++)) + .setBroadcastGenres(cursor.getString(index++)) + .setCanonicalGenres(cursor.getString(index++)) + .setShortDescription(cursor.getString(index++)) + .setLongDescription(cursor.getString(index++)) + .setVideoWidth(cursor.getInt(index++)) + .setVideoHeight(cursor.getInt(index++)) + .setAudioLanguage(cursor.getString(index++)) + .setContentRatings( + TvContentRatingCache.getInstance().getRatings(cursor.getString(index++))) + .setPosterArtUri(cursor.getString(index++)) + .setThumbnailUri(cursor.getString(index++)) + .setSearchable(cursor.getInt(index++) == 1) + .setDataUri(cursor.getString(index++)) + .setDataBytes(cursor.getLong(index++)) + .setDurationMillis(cursor.getLong(index++)) + .setExpireTimeUtcMillis(cursor.getLong(index++)) + .setInternalProviderFlag1(cursor.getInt(index++)) + .setInternalProviderFlag2(cursor.getInt(index++)) + .setInternalProviderFlag3(cursor.getInt(index++)) + .setInternalProviderFlag4(cursor.getInt(index++)) + .setVersionNumber(cursor.getInt(index++)); + if (Utils.isInBundledPackageSet(builder.mPackageName)) { + InternalDataUtils.deserializeInternalProviderData(cursor.getBlob(index), builder); + } + return builder.build(); + } + + public static ContentValues toValues(RecordedProgram recordedProgram) { + ContentValues values = new ContentValues(); + if (recordedProgram.mId != ID_NOT_SET) { + values.put(RecordedPrograms._ID, recordedProgram.mId); + } + values.put(RecordedPrograms.COLUMN_INPUT_ID, recordedProgram.mInputId); + values.put(RecordedPrograms.COLUMN_CHANNEL_ID, recordedProgram.mChannelId); + values.put(RecordedPrograms.COLUMN_TITLE, recordedProgram.mTitle); + values.put(RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, recordedProgram.mSeasonNumber); + values.put(RecordedPrograms.COLUMN_SEASON_TITLE, recordedProgram.mSeasonTitle); + values.put(RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, recordedProgram.mEpisodeNumber); + values.put(RecordedPrograms.COLUMN_EPISODE_TITLE, recordedProgram.mTitle); + values.put(RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, + recordedProgram.mStartTimeUtcMillis); + values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, recordedProgram.mEndTimeUtcMillis); + values.put(RecordedPrograms.COLUMN_BROADCAST_GENRE, + safeEncode(recordedProgram.mBroadcastGenres)); + values.put(RecordedPrograms.COLUMN_CANONICAL_GENRE, + safeEncode(recordedProgram.mCanonicalGenres)); + values.put(RecordedPrograms.COLUMN_SHORT_DESCRIPTION, recordedProgram.mShortDescription); + values.put(RecordedPrograms.COLUMN_LONG_DESCRIPTION, recordedProgram.mLongDescription); + if (recordedProgram.mVideoWidth == 0) { + values.putNull(RecordedPrograms.COLUMN_VIDEO_WIDTH); + } else { + values.put(RecordedPrograms.COLUMN_VIDEO_WIDTH, recordedProgram.mVideoWidth); + } + if (recordedProgram.mVideoHeight == 0) { + values.putNull(RecordedPrograms.COLUMN_VIDEO_HEIGHT); + } else { + values.put(RecordedPrograms.COLUMN_VIDEO_HEIGHT, recordedProgram.mVideoHeight); + } + values.put(RecordedPrograms.COLUMN_AUDIO_LANGUAGE, recordedProgram.mAudioLanguage); + values.put(RecordedPrograms.COLUMN_CONTENT_RATING, + TvContentRatingCache.contentRatingsToString(recordedProgram.mContentRatings)); + values.put(RecordedPrograms.COLUMN_POSTER_ART_URI, recordedProgram.mPosterArtUri); + values.put(RecordedPrograms.COLUMN_THUMBNAIL_URI, recordedProgram.mThumbnailUri); + values.put(RecordedPrograms.COLUMN_SEARCHABLE, recordedProgram.mSearchable ? 1 : 0); + values.put(RecordedPrograms.COLUMN_RECORDING_DATA_URI, + safeToString(recordedProgram.mDataUri)); + values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, recordedProgram.mDataBytes); + values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, + recordedProgram.mDurationMillis); + values.put(RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, + recordedProgram.mExpireTimeUtcMillis); + values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, + InternalDataUtils.serializeInternalProviderData(recordedProgram)); + values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, + recordedProgram.mInternalProviderFlag1); + values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, + recordedProgram.mInternalProviderFlag2); + values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, + recordedProgram.mInternalProviderFlag3); + values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, + recordedProgram.mInternalProviderFlag4); + values.put(RecordedPrograms.COLUMN_VERSION_NUMBER, recordedProgram.mVersionNumber); + return values; + } + + public static class Builder{ + private long mId = ID_NOT_SET; + private String mPackageName; + private String mInputId; + private long mChannelId; + private String mTitle; + private String mSeriesId; + private String mSeasonNumber; + private String mSeasonTitle; + private String mEpisodeNumber; + private String mEpisodeTitle; + private long mStartTimeUtcMillis; + private long mEndTimeUtcMillis; + private String[] mBroadcastGenres; + private String[] mCanonicalGenres; + private String mShortDescription; + private String mLongDescription; + private int mVideoWidth; + private int mVideoHeight; + private String mAudioLanguage; + private TvContentRating[] mContentRatings; + private String mPosterArtUri; + private String mThumbnailUri; + private boolean mSearchable = true; + private Uri mDataUri; + private long mDataBytes; + private long mDurationMillis; + private long mExpireTimeUtcMillis; + private int mInternalProviderFlag1; + private int mInternalProviderFlag2; + private int mInternalProviderFlag3; + private int mInternalProviderFlag4; + private int mVersionNumber; + + public Builder setId(long id) { + mId = id; + return this; + } + + public Builder setPackageName(String packageName) { + mPackageName = packageName; + return this; + } + + public Builder setInputId(String inputId) { + mInputId = inputId; + return this; + } + + public Builder setChannelId(long channelId) { + mChannelId = channelId; + return this; + } + + public Builder setTitle(String title) { + mTitle = title; + return this; + } + + public Builder setSeriesId(String seriesId) { + mSeriesId = seriesId; + return this; + } + + public Builder setSeasonNumber(String seasonNumber) { + mSeasonNumber = seasonNumber; + return this; + } + + public Builder setSeasonTitle(String seasonTitle) { + mSeasonTitle = seasonTitle; + return this; + } + + public Builder setEpisodeNumber(String episodeNumber) { + mEpisodeNumber = episodeNumber; + return this; + } + + public Builder setEpisodeTitle(String episodeTitle) { + mEpisodeTitle = episodeTitle; + return this; + } + + public Builder setStartTimeUtcMillis(long startTimeUtcMillis) { + mStartTimeUtcMillis = startTimeUtcMillis; + return this; + } + + public Builder setEndTimeUtcMillis(long endTimeUtcMillis) { + mEndTimeUtcMillis = endTimeUtcMillis; + return this; + } + + public Builder setBroadcastGenres(String broadcastGenres) { + if (TextUtils.isEmpty(broadcastGenres)) { + mBroadcastGenres = null; + return this; + } + return setBroadcastGenres(TvContract.Programs.Genres.decode(broadcastGenres)); + } + + private Builder setBroadcastGenres(String[] broadcastGenres) { + mBroadcastGenres = broadcastGenres; + return this; + } + + public Builder setCanonicalGenres(String canonicalGenres) { + if (TextUtils.isEmpty(canonicalGenres)) { + mCanonicalGenres = null; + return this; + } + return setCanonicalGenres(TvContract.Programs.Genres.decode(canonicalGenres)); + } + + private Builder setCanonicalGenres(String[] canonicalGenres) { + mCanonicalGenres = canonicalGenres; + return this; + } + + public Builder setShortDescription(String shortDescription) { + mShortDescription = shortDescription; + return this; + } + + public Builder setLongDescription(String longDescription) { + mLongDescription = longDescription; + return this; + } + + public Builder setVideoWidth(int videoWidth) { + mVideoWidth = videoWidth; + return this; + } + + public Builder setVideoHeight(int videoHeight) { + mVideoHeight = videoHeight; + return this; + } + + public Builder setAudioLanguage(String audioLanguage) { + mAudioLanguage = audioLanguage; + return this; + } + + public Builder setContentRatings(TvContentRating[] contentRatings) { + mContentRatings = contentRatings; + return this; + } + + private Uri toUri(String uriString) { + try { + return uriString == null ? null : Uri.parse(uriString); + } catch (Exception e) { + return null; + } + } + + public Builder setPosterArtUri(String posterArtUri) { + mPosterArtUri = posterArtUri; + return this; + } + + public Builder setThumbnailUri(String thumbnailUri) { + mThumbnailUri = thumbnailUri; + return this; + } + + public Builder setSearchable(boolean searchable) { + mSearchable = searchable; + return this; + } + + public Builder setDataUri(String dataUri) { + return setDataUri(toUri(dataUri)); + } + + public Builder setDataUri(Uri dataUri) { + mDataUri = dataUri; + return this; + } + + public Builder setDataBytes(long dataBytes) { + mDataBytes = dataBytes; + return this; + } + + public Builder setDurationMillis(long durationMillis) { + mDurationMillis = durationMillis; + return this; + } + + public Builder setExpireTimeUtcMillis(long expireTimeUtcMillis) { + mExpireTimeUtcMillis = expireTimeUtcMillis; + return this; + } + + public Builder setInternalProviderFlag1(int internalProviderFlag1) { + mInternalProviderFlag1 = internalProviderFlag1; + return this; + } + + public Builder setInternalProviderFlag2(int internalProviderFlag2) { + mInternalProviderFlag2 = internalProviderFlag2; + return this; + } + + public Builder setInternalProviderFlag3(int internalProviderFlag3) { + mInternalProviderFlag3 = internalProviderFlag3; + return this; + } + + public Builder setInternalProviderFlag4(int internalProviderFlag4) { + mInternalProviderFlag4 = internalProviderFlag4; + return this; + } + + public Builder setVersionNumber(int versionNumber) { + mVersionNumber = versionNumber; + return this; + } + + public RecordedProgram build() { + if (TextUtils.isEmpty(mTitle)) { + // If title is null, series cannot be generated for this program. + setSeriesId(null); + } else if (TextUtils.isEmpty(mSeriesId) && !TextUtils.isEmpty(mEpisodeNumber)) { + // If series ID is not set, generate it for the episodic program of other TV input. + setSeriesId(BaseProgram.generateSeriesId(mPackageName, mTitle)); + } + return new RecordedProgram(mId, mPackageName, mInputId, mChannelId, mTitle, mSeriesId, + mSeasonNumber, mSeasonTitle, mEpisodeNumber, mEpisodeTitle, mStartTimeUtcMillis, + mEndTimeUtcMillis, mBroadcastGenres, mCanonicalGenres, mShortDescription, + mLongDescription, mVideoWidth, mVideoHeight, mAudioLanguage, mContentRatings, + mPosterArtUri, mThumbnailUri, mSearchable, mDataUri, mDataBytes, + mDurationMillis, mExpireTimeUtcMillis, mInternalProviderFlag1, + mInternalProviderFlag2, mInternalProviderFlag3, mInternalProviderFlag4, + mVersionNumber); + } + } + + public static Builder builder() { return new Builder(); } + + public static Builder buildFrom(RecordedProgram orig) { + return builder() + .setId(orig.getId()) + .setPackageName(orig.getPackageName()) + .setInputId(orig.getInputId()) + .setChannelId(orig.getChannelId()) + .setTitle(orig.getTitle()) + .setSeriesId(orig.getSeriesId()) + .setSeasonNumber(orig.getSeasonNumber()) + .setSeasonTitle(orig.getSeasonTitle()) + .setEpisodeNumber(orig.getEpisodeNumber()) + .setEpisodeTitle(orig.getEpisodeTitle()) + .setStartTimeUtcMillis(orig.getStartTimeUtcMillis()) + .setEndTimeUtcMillis(orig.getEndTimeUtcMillis()) + .setBroadcastGenres(orig.getBroadcastGenres()) + .setCanonicalGenres(orig.getCanonicalGenres()) + .setShortDescription(orig.getDescription()) + .setLongDescription(orig.getLongDescription()) + .setVideoWidth(orig.getVideoWidth()) + .setVideoHeight(orig.getVideoHeight()) + .setAudioLanguage(orig.getAudioLanguage()) + .setContentRatings(orig.getContentRatings()) + .setPosterArtUri(orig.getPosterArtUri()) + .setThumbnailUri(orig.getThumbnailUri()) + .setSearchable(orig.isSearchable()) + .setInternalProviderFlag1(orig.getInternalProviderFlag1()) + .setInternalProviderFlag2(orig.getInternalProviderFlag2()) + .setInternalProviderFlag3(orig.getInternalProviderFlag3()) + .setInternalProviderFlag4(orig.getInternalProviderFlag4()) + .setVersionNumber(orig.getVersionNumber()); + } + + public static final Comparator<RecordedProgram> START_TIME_THEN_ID_COMPARATOR = + new Comparator<RecordedProgram>() { + @Override + public int compare(RecordedProgram lhs, RecordedProgram rhs) { + int res = + Long.compare(lhs.getStartTimeUtcMillis(), rhs.getStartTimeUtcMillis()); + if (res != 0) { + return res; + } + return Long.compare(lhs.mId, rhs.mId); + } + }; + + private static final long CLIPPED_THRESHOLD_MS = TimeUnit.MINUTES.toMillis(5); + + private final long mId; + private final String mPackageName; + private final String mInputId; + private final long mChannelId; + private final String mTitle; + private final String mSeriesId; + private final String mSeasonNumber; + private final String mSeasonTitle; + private final String mEpisodeNumber; + private final String mEpisodeTitle; + private final long mStartTimeUtcMillis; + private final long mEndTimeUtcMillis; + private final String[] mBroadcastGenres; + private final String[] mCanonicalGenres; + private final String mShortDescription; + private final String mLongDescription; + private final int mVideoWidth; + private final int mVideoHeight; + private final String mAudioLanguage; + private final TvContentRating[] mContentRatings; + private final String mPosterArtUri; + private final String mThumbnailUri; + private final boolean mSearchable; + private final Uri mDataUri; + private final long mDataBytes; + private final long mDurationMillis; + private final long mExpireTimeUtcMillis; + private final int mInternalProviderFlag1; + private final int mInternalProviderFlag2; + private final int mInternalProviderFlag3; + private final int mInternalProviderFlag4; + private final int mVersionNumber; + + private RecordedProgram(long id, String packageName, String inputId, long channelId, + String title, String seriesId, 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, TvContentRating[] contentRatings, String posterArtUri, + String thumbnailUri, boolean searchable, Uri dataUri, long dataBytes, + long durationMillis, long expireTimeUtcMillis, int internalProviderFlag1, + int internalProviderFlag2, int internalProviderFlag3, int internalProviderFlag4, + int versionNumber) { + mId = id; + mPackageName = packageName; + mInputId = inputId; + mChannelId = channelId; + mTitle = title; + mSeriesId = seriesId; + mSeasonNumber = seasonNumber; + mSeasonTitle = seasonTitle; + mEpisodeNumber = episodeNumber; + mEpisodeTitle = episodeTitle; + mStartTimeUtcMillis = startTimeUtcMillis; + mEndTimeUtcMillis = endTimeUtcMillis; + mBroadcastGenres = broadcastGenres; + mCanonicalGenres = canonicalGenres; + mShortDescription = shortDescription; + mLongDescription = longDescription; + mVideoWidth = videoWidth; + mVideoHeight = videoHeight; + + mAudioLanguage = audioLanguage; + mContentRatings = contentRatings; + mPosterArtUri = posterArtUri; + mThumbnailUri = thumbnailUri; + mSearchable = searchable; + mDataUri = dataUri; + mDataBytes = dataBytes; + mDurationMillis = durationMillis; + mExpireTimeUtcMillis = expireTimeUtcMillis; + mInternalProviderFlag1 = internalProviderFlag1; + mInternalProviderFlag2 = internalProviderFlag2; + mInternalProviderFlag3 = internalProviderFlag3; + mInternalProviderFlag4 = internalProviderFlag4; + mVersionNumber = versionNumber; + } + + public String getAudioLanguage() { + return mAudioLanguage; + } + + public String[] getBroadcastGenres() { + return mBroadcastGenres; + } + + public String[] getCanonicalGenres() { + return mCanonicalGenres; + } + + /** + * Returns array of canonical genre ID's for this recorded program. + */ + @Override + public int[] getCanonicalGenreIds() { + if (mCanonicalGenres == null) { + return null; + } + int[] genreIds = new int[mCanonicalGenres.length]; + for (int i = 0; i < mCanonicalGenres.length; i++) { + genreIds[i] = GenreItems.getId(mCanonicalGenres[i]); + } + return genreIds; + } + + @Override + public long getChannelId() { + return mChannelId; + } + + @Nullable + @Override + public TvContentRating[] getContentRatings() { + return mContentRatings; + } + + public Uri getDataUri() { + return mDataUri; + } + + public long getDataBytes() { + return mDataBytes; + } + + @Override + public long getDurationMillis() { + return mDurationMillis; + } + + @Override + public long getEndTimeUtcMillis() { + return mEndTimeUtcMillis; + } + + @Override + public String getEpisodeNumber() { + return mEpisodeNumber; + } + + @Override + public String getEpisodeTitle() { + return mEpisodeTitle; + } + + @Nullable + public String getEpisodeDisplayNumber(Context context) { + if (!TextUtils.isEmpty(mEpisodeNumber)) { + if (TextUtils.equals(mSeasonNumber, "0")) { + // Do not show "S0: ". + return String.format(context.getResources().getString( + R.string.display_episode_number_format_no_season_number), mEpisodeNumber); + } else { + return String.format(context.getResources().getString( + R.string.display_episode_number_format), mSeasonNumber, mEpisodeNumber); + } + } + return null; + } + + public long getExpireTimeUtcMillis() { + return mExpireTimeUtcMillis; + } + + public long getId() { + return mId; + } + + public String getPackageName() { + return mPackageName; + } + + public String getInputId() { + return mInputId; + } + + public int getInternalProviderFlag1() { + return mInternalProviderFlag1; + } + + public int getInternalProviderFlag2() { + return mInternalProviderFlag2; + } + + public int getInternalProviderFlag3() { + return mInternalProviderFlag3; + } + + public int getInternalProviderFlag4() { + return mInternalProviderFlag4; + } + + @Override + public String getDescription() { + return mShortDescription; + } + + @Override + public String getLongDescription() { + return mLongDescription; + } + + @Override + public String getPosterArtUri() { + return mPosterArtUri; + } + + @Override + public boolean isValid() { + return true; + } + + public boolean isSearchable() { + return mSearchable; + } + + @Override + public String getSeriesId() { + return mSeriesId; + } + + @Override + public String getSeasonNumber() { + return mSeasonNumber; + } + + public String getSeasonTitle() { + return mSeasonTitle; + } + + @Override + public long getStartTimeUtcMillis() { + return mStartTimeUtcMillis; + } + + @Override + public String getThumbnailUri() { + return mThumbnailUri; + } + + @Override + public String getTitle() { + return mTitle; + } + + public Uri getUri() { + return ContentUris.withAppendedId(RecordedPrograms.CONTENT_URI, mId); + } + + public int getVersionNumber() { + return mVersionNumber; + } + + public int getVideoHeight() { + return mVideoHeight; + } + + public int getVideoWidth() { + return mVideoWidth; + } + + /** + * Checks whether the recording has been clipped or not. + */ + public boolean isClipped() { + return mEndTimeUtcMillis - mStartTimeUtcMillis - mDurationMillis > CLIPPED_THRESHOLD_MS; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RecordedProgram that = (RecordedProgram) o; + return Objects.equals(mId, that.mId) && + Objects.equals(mChannelId, that.mChannelId) && + Objects.equals(mSeriesId, that.mSeriesId) && + Objects.equals(mSeasonNumber, that.mSeasonNumber) && + Objects.equals(mSeasonTitle, that.mSeasonTitle) && + Objects.equals(mEpisodeNumber, that.mEpisodeNumber) && + Objects.equals(mStartTimeUtcMillis, that.mStartTimeUtcMillis) && + Objects.equals(mEndTimeUtcMillis, that.mEndTimeUtcMillis) && + Objects.equals(mVideoWidth, that.mVideoWidth) && + Objects.equals(mVideoHeight, that.mVideoHeight) && + Objects.equals(mSearchable, that.mSearchable) && + Objects.equals(mDataBytes, that.mDataBytes) && + Objects.equals(mDurationMillis, that.mDurationMillis) && + Objects.equals(mExpireTimeUtcMillis, that.mExpireTimeUtcMillis) && + Objects.equals(mInternalProviderFlag1, that.mInternalProviderFlag1) && + Objects.equals(mInternalProviderFlag2, that.mInternalProviderFlag2) && + Objects.equals(mInternalProviderFlag3, that.mInternalProviderFlag3) && + Objects.equals(mInternalProviderFlag4, that.mInternalProviderFlag4) && + Objects.equals(mVersionNumber, that.mVersionNumber) && + Objects.equals(mTitle, that.mTitle) && + Objects.equals(mEpisodeTitle, that.mEpisodeTitle) && + Arrays.equals(mBroadcastGenres, that.mBroadcastGenres) && + Arrays.equals(mCanonicalGenres, that.mCanonicalGenres) && + Objects.equals(mShortDescription, that.mShortDescription) && + Objects.equals(mLongDescription, that.mLongDescription) && + Objects.equals(mAudioLanguage, that.mAudioLanguage) && + Arrays.equals(mContentRatings, that.mContentRatings) && + Objects.equals(mPosterArtUri, that.mPosterArtUri) && + Objects.equals(mThumbnailUri, that.mThumbnailUri); + } + + /** + * Hashes based on the ID. + */ + @Override + public int hashCode() { + return Objects.hash(mId); + } + + @Override + public String toString() { + return "RecordedProgram" + + "[" + mId + + "]{ mPackageName=" + mPackageName + + ", mInputId='" + mInputId + '\'' + + ", mChannelId='" + mChannelId + '\'' + + ", mTitle='" + mTitle + '\'' + + ", mSeriesId='" + mSeriesId + '\'' + + ", mEpisodeNumber=" + mEpisodeNumber + + ", mEpisodeTitle='" + mEpisodeTitle + '\'' + + ", mStartTimeUtcMillis=" + mStartTimeUtcMillis + + ", mEndTimeUtcMillis=" + mEndTimeUtcMillis + + ", mBroadcastGenres=" + + (mBroadcastGenres != null ? Arrays.toString(mBroadcastGenres) : "null") + + ", mCanonicalGenres=" + + (mCanonicalGenres != null ? Arrays.toString(mCanonicalGenres) : "null") + + ", mShortDescription='" + mShortDescription + '\'' + + ", mLongDescription='" + mLongDescription + '\'' + + ", mVideoHeight=" + mVideoHeight + + ", mVideoWidth=" + mVideoWidth + + ", mAudioLanguage='" + mAudioLanguage + '\'' + + ", mContentRatings='" + + TvContentRatingCache.contentRatingsToString(mContentRatings) + '\'' + + ", mPosterArtUri=" + mPosterArtUri + + ", mThumbnailUri=" + mThumbnailUri + + ", mSearchable=" + mSearchable + + ", mDataUri=" + mDataUri + + ", mDataBytes=" + mDataBytes + + ", mDurationMillis=" + mDurationMillis + + ", mExpireTimeUtcMillis=" + mExpireTimeUtcMillis + + ", mInternalProviderFlag1=" + mInternalProviderFlag1 + + ", mInternalProviderFlag2=" + mInternalProviderFlag2 + + ", mInternalProviderFlag3=" + mInternalProviderFlag3 + + ", mInternalProviderFlag4=" + mInternalProviderFlag4 + + ", mSeasonNumber=" + mSeasonNumber + + ", mSeasonTitle=" + mSeasonTitle + + ", mVersionNumber=" + mVersionNumber + + '}'; + } + + @Nullable + private static String safeToString(@Nullable Object o) { + return o == null ? null : o.toString(); + } + + @Nullable + private static String safeEncode(@Nullable String[] genres) { + return genres == null ? null : TvContract.Programs.Genres.encode(genres); + } + + /** + * Returns an array containing all of the elements in the list. + */ + public static RecordedProgram[] toArray(Collection<RecordedProgram> recordedPrograms) { + return recordedPrograms.toArray(new RecordedProgram[recordedPrograms.size()]); + } +} |