blob: 84e42fbed7cd3b47f09e45a0b1b6243b7b16ca14 [file] [log] [blame]
/*
* Copyright (C) 2015 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.data;
import android.annotation.SuppressLint;
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.Programs;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import com.android.tv.common.TvContentRatingCache;
import com.android.tv.common.util.CollectionUtils;
import com.android.tv.common.util.CommonUtils;
import com.android.tv.data.api.BaseProgram;
import com.android.tv.data.api.Channel;
import com.android.tv.data.api.Program;
import com.android.tv.util.TvProviderUtils;
import com.android.tv.util.Utils;
import com.android.tv.util.images.ImageLoader;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/** A convenience class to create and insert program information entries into the database. */
public final class ProgramImpl extends BaseProgramImpl implements Parcelable, Program {
private static final boolean DEBUG = false;
private static final boolean DEBUG_DUMP_DESCRIPTION = false;
private static final String TAG = "Program";
private static final String[] PROJECTION_BASE = {
// Columns must match what is read in Program.fromCursor()
TvContract.Programs._ID,
TvContract.Programs.COLUMN_PACKAGE_NAME,
TvContract.Programs.COLUMN_CHANNEL_ID,
TvContract.Programs.COLUMN_TITLE,
TvContract.Programs.COLUMN_EPISODE_TITLE,
TvContract.Programs.COLUMN_SHORT_DESCRIPTION,
TvContract.Programs.COLUMN_LONG_DESCRIPTION,
TvContract.Programs.COLUMN_POSTER_ART_URI,
TvContract.Programs.COLUMN_THUMBNAIL_URI,
TvContract.Programs.COLUMN_CANONICAL_GENRE,
TvContract.Programs.COLUMN_CONTENT_RATING,
TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
TvContract.Programs.COLUMN_VIDEO_WIDTH,
TvContract.Programs.COLUMN_VIDEO_HEIGHT,
TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA
};
// Columns which is deprecated in NYC
@SuppressWarnings("deprecation")
private static final String[] PROJECTION_DEPRECATED_IN_NYC = {
TvContract.Programs.COLUMN_SEASON_NUMBER, TvContract.Programs.COLUMN_EPISODE_NUMBER
};
private static final String[] PROJECTION_ADDED_IN_NYC = {
TvContract.Programs.COLUMN_SEASON_DISPLAY_NUMBER,
TvContract.Programs.COLUMN_SEASON_TITLE,
TvContract.Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
TvContract.Programs.COLUMN_RECORDING_PROHIBITED
};
public static final String[] PROJECTION = createProjection();
public static final String[] PARTIAL_PROJECTION = {
TvContract.Programs._ID,
TvContract.Programs.COLUMN_CHANNEL_ID,
TvContract.Programs.COLUMN_TITLE,
TvContract.Programs.COLUMN_EPISODE_TITLE,
TvContract.Programs.COLUMN_CANONICAL_GENRE,
TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
};
private static String[] createProjection() {
return CollectionUtils.concatAll(
PROJECTION_BASE,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
? PROJECTION_ADDED_IN_NYC
: PROJECTION_DEPRECATED_IN_NYC);
}
/**
* Returns the column index for {@code column},-1 if the column doesn't exist in {@link
* #PROJECTION}.
*/
public static int getColumnIndex(String column) {
for (int i = 0; i < PROJECTION.length; ++i) {
if (PROJECTION[i].equals(column)) {
return i;
}
}
return -1;
}
/** Creates {@code Program} object from cursor. */
public static Program fromCursor(Cursor cursor) {
// Columns read must match the order of match {@link #PROJECTION}
Builder builder = new Builder();
int index = 0;
builder.setId(cursor.getLong(index++));
String packageName = cursor.getString(index++);
builder.setPackageName(packageName);
builder.setChannelId(cursor.getLong(index++));
builder.setTitle(cursor.getString(index++));
builder.setEpisodeTitle(cursor.getString(index++));
builder.setDescription(cursor.getString(index++));
builder.setLongDescription(cursor.getString(index++));
builder.setPosterArtUri(cursor.getString(index++));
builder.setThumbnailUri(cursor.getString(index++));
builder.setCanonicalGenres(cursor.getString(index++));
builder.setContentRatings(
TvContentRatingCache.getInstance().getRatings(cursor.getString(index++)));
builder.setStartTimeUtcMillis(cursor.getLong(index++));
builder.setEndTimeUtcMillis(cursor.getLong(index++));
builder.setVideoWidth((int) cursor.getLong(index++));
builder.setVideoHeight((int) cursor.getLong(index++));
if (CommonUtils.isInBundledPackageSet(packageName)) {
InternalDataUtils.deserializeInternalProviderData(cursor.getBlob(index), builder);
}
index++;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setSeasonNumber(cursor.getString(index++));
builder.setSeasonTitle(cursor.getString(index++));
builder.setEpisodeNumber(cursor.getString(index++));
builder.setRecordingProhibited(cursor.getInt(index++) == 1);
} else {
builder.setSeasonNumber(cursor.getString(index++));
builder.setEpisodeNumber(cursor.getString(index++));
}
if (TvProviderUtils.getProgramHasSeriesIdColumn()) {
String seriesId = cursor.getString(index);
if (!TextUtils.isEmpty(seriesId)) {
builder.setSeriesId(seriesId);
}
}
return builder.build();
}
/** Creates {@code Program} object from cursor. */
public static Program fromCursorPartialProjection(Cursor cursor) {
// Columns read must match the order of match {@link #PARTIAL_PROJECTION}
Builder builder = new Builder();
int index = 0;
builder.setId(cursor.getLong(index++));
builder.setChannelId(cursor.getLong(index++));
builder.setTitle(cursor.getString(index++));
builder.setEpisodeTitle(cursor.getString(index++));
builder.setCanonicalGenres(cursor.getString(index++));
builder.setStartTimeUtcMillis(cursor.getLong(index++));
builder.setEndTimeUtcMillis(cursor.getLong(index++));
return builder.build();
}
public static ProgramImpl fromParcel(Parcel in) {
ProgramImpl program = new ProgramImpl();
program.mId = in.readLong();
program.mPackageName = in.readString();
program.mChannelId = in.readLong();
program.mTitle = in.readString();
program.mSeriesId = in.readString();
program.mEpisodeTitle = in.readString();
program.mSeasonNumber = in.readString();
program.mSeasonTitle = in.readString();
program.mEpisodeNumber = in.readString();
program.mStartTimeUtcMillis = in.readLong();
program.mEndTimeUtcMillis = in.readLong();
program.mDescription = in.readString();
program.mLongDescription = in.readString();
program.mVideoWidth = in.readInt();
program.mVideoHeight = in.readInt();
program.mCriticScores = in.readArrayList(Thread.currentThread().getContextClassLoader());
program.mPosterArtUri = in.readString();
program.mThumbnailUri = in.readString();
program.mCanonicalGenreIds = in.createIntArray();
int length = in.readInt();
if (length > 0) {
ImmutableList.Builder<TvContentRating> ratingsBuilder =
ImmutableList.builderWithExpectedSize(length);
for (int i = 0; i < length; ++i) {
ratingsBuilder.add(TvContentRating.unflattenFromString(in.readString()));
}
program.mContentRatings = ratingsBuilder.build();
} else {
program.mContentRatings = ImmutableList.of();
}
program.mRecordingProhibited = in.readByte() != (byte) 0;
return program;
}
public static final Parcelable.Creator<Program> CREATOR =
new Parcelable.Creator<Program>() {
@Override
public Program createFromParcel(Parcel in) {
return ProgramImpl.fromParcel(in);
}
@Override
public Program[] newArray(int size) {
return new Program[size];
}
};
private long mId;
private String mPackageName;
private long mChannelId;
private String mTitle;
private String mSeriesId;
private String mEpisodeTitle;
private String mSeasonNumber;
private String mSeasonTitle;
private String mEpisodeNumber;
private long mStartTimeUtcMillis;
private long mEndTimeUtcMillis;
private String mDurationString;
private String mDescription;
private String mLongDescription;
private int mVideoWidth;
private int mVideoHeight;
private List<CriticScore> mCriticScores;
private String mPosterArtUri;
private String mThumbnailUri;
private int[] mCanonicalGenreIds;
private ImmutableList<TvContentRating> mContentRatings;
private boolean mRecordingProhibited;
private ProgramImpl() {
// Do nothing.
}
@Override
public long getId() {
return mId;
}
@Override
public String getPackageName() {
return mPackageName;
}
@Override
public long getChannelId() {
return mChannelId;
}
/** Returns {@code true} if this program is valid or {@code false} otherwise. */
@Override
public boolean isValid() {
return mChannelId >= 0;
}
@Override
public String getTitle() {
return mTitle;
}
/** Returns the series ID. */
@Override
public String getSeriesId() {
return mSeriesId;
}
/** Returns the episode title. */
@Override
public String getEpisodeTitle() {
return mEpisodeTitle;
}
@Override
public String getSeasonNumber() {
return mSeasonNumber;
}
@Override
public String getSeasonTitle() {
return mSeasonTitle;
}
@Override
public String getEpisodeNumber() {
return mEpisodeNumber;
}
@Override
public long getStartTimeUtcMillis() {
return mStartTimeUtcMillis;
}
@Override
public long getEndTimeUtcMillis() {
return mEndTimeUtcMillis;
}
@Override
public String getDurationString(Context context) {
// TODO(b/71717446): expire the calculated string
if (mDurationString == null) {
mDurationString =
Utils.getDurationString(context, mStartTimeUtcMillis, mEndTimeUtcMillis, true);
}
return mDurationString;
}
/** Returns the program duration. */
@Override
public long getDurationMillis() {
return mEndTimeUtcMillis - mStartTimeUtcMillis;
}
@Override
public String getDescription() {
return mDescription;
}
@Override
public String getLongDescription() {
return mLongDescription;
}
@Override
public int getVideoWidth() {
return mVideoWidth;
}
@Override
public int getVideoHeight() {
return mVideoHeight;
}
@Override
@Nullable
public List<CriticScore> getCriticScores() {
return mCriticScores;
}
@Nullable
@Override
public ImmutableList<TvContentRating> getContentRatings() {
return mContentRatings;
}
@Override
public String getPosterArtUri() {
return mPosterArtUri;
}
@Override
public String getThumbnailUri() {
return mThumbnailUri;
}
@Override
public boolean isRecordingProhibited() {
return mRecordingProhibited;
}
@Override
@Nullable
public String[] getCanonicalGenres() {
if (mCanonicalGenreIds == null) {
return null;
}
String[] genres = new String[mCanonicalGenreIds.length];
for (int i = 0; i < mCanonicalGenreIds.length; i++) {
genres[i] = GenreItems.getCanonicalGenre(mCanonicalGenreIds[i]);
}
return genres;
}
/** Returns array of canonical genre ID's for this program. */
@Override
public int[] getCanonicalGenreIds() {
return mCanonicalGenreIds;
}
@Override
public boolean hasGenre(int genreId) {
if (genreId == GenreItems.ID_ALL_CHANNELS) {
return true;
}
if (mCanonicalGenreIds != null) {
for (int id : mCanonicalGenreIds) {
if (id == genreId) {
return true;
}
}
}
return false;
}
@Override
public int hashCode() {
// Hash with all the properties because program ID can be invalid for the stub programs.
return Objects.hash(
mChannelId,
mStartTimeUtcMillis,
mEndTimeUtcMillis,
mTitle,
mSeriesId,
mEpisodeTitle,
mDescription,
mLongDescription,
mVideoWidth,
mVideoHeight,
mPosterArtUri,
mThumbnailUri,
mContentRatings,
Arrays.hashCode(mCanonicalGenreIds),
mSeasonNumber,
mSeasonTitle,
mEpisodeNumber,
mRecordingProhibited);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ProgramImpl)) {
return false;
}
// Compare all the properties because program ID can be invalid for the stub programs.
ProgramImpl program = (ProgramImpl) other;
return Objects.equals(mPackageName, program.mPackageName)
&& mChannelId == program.mChannelId
&& mStartTimeUtcMillis == program.mStartTimeUtcMillis
&& mEndTimeUtcMillis == program.mEndTimeUtcMillis
&& Objects.equals(mTitle, program.mTitle)
&& Objects.equals(mSeriesId, program.mSeriesId)
&& Objects.equals(mEpisodeTitle, program.mEpisodeTitle)
&& Objects.equals(mDescription, program.mDescription)
&& Objects.equals(mLongDescription, program.mLongDescription)
&& mVideoWidth == program.mVideoWidth
&& mVideoHeight == program.mVideoHeight
&& Objects.equals(mPosterArtUri, program.mPosterArtUri)
&& Objects.equals(mThumbnailUri, program.mThumbnailUri)
&& Objects.equals(mContentRatings, program.mContentRatings)
&& Arrays.equals(mCanonicalGenreIds, program.mCanonicalGenreIds)
&& Objects.equals(mSeasonNumber, program.mSeasonNumber)
&& Objects.equals(mSeasonTitle, program.mSeasonTitle)
&& Objects.equals(mEpisodeNumber, program.mEpisodeNumber)
&& mRecordingProhibited == program.mRecordingProhibited;
}
@Override
public int compareTo(@NonNull Program other) {
return Long.compare(mStartTimeUtcMillis, other.getStartTimeUtcMillis());
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Program[")
.append(mId)
.append("]{channelId=")
.append(mChannelId)
.append(", packageName=")
.append(mPackageName)
.append(", title=")
.append(mTitle)
.append(", seriesId=")
.append(mSeriesId)
.append(", episodeTitle=")
.append(mEpisodeTitle)
.append(", seasonNumber=")
.append(mSeasonNumber)
.append(", seasonTitle=")
.append(mSeasonTitle)
.append(", episodeNumber=")
.append(mEpisodeNumber)
.append(", startTimeUtcSec=")
.append(Utils.toTimeString(mStartTimeUtcMillis))
.append(", endTimeUtcSec=")
.append(Utils.toTimeString(mEndTimeUtcMillis))
.append(", videoWidth=")
.append(mVideoWidth)
.append(", videoHeight=")
.append(mVideoHeight)
.append(", contentRatings=")
.append(TvContentRatingCache.contentRatingsToString(mContentRatings))
.append(", posterArtUri=")
.append(mPosterArtUri)
.append(", thumbnailUri=")
.append(mThumbnailUri)
.append(", canonicalGenres=")
.append(Arrays.toString(mCanonicalGenreIds))
.append(", recordingProhibited=")
.append(mRecordingProhibited);
if (DEBUG_DUMP_DESCRIPTION) {
builder.append(", description=")
.append(mDescription)
.append(", longDescription=")
.append(mLongDescription);
}
return builder.append("}").toString();
}
/**
* Translates a {@link ProgramImpl} to {@link ContentValues} that are ready to be written into
* Database.
*/
@SuppressLint("InlinedApi")
@SuppressWarnings("deprecation")
@WorkerThread
public static ContentValues toContentValues(Program program, Context context) {
ContentValues values = new ContentValues();
values.put(TvContract.Programs.COLUMN_CHANNEL_ID, program.getChannelId());
if (!TextUtils.isEmpty(program.getPackageName())) {
values.put(Programs.COLUMN_PACKAGE_NAME, program.getPackageName());
}
putValue(values, TvContract.Programs.COLUMN_TITLE, program.getTitle());
putValue(values, TvContract.Programs.COLUMN_EPISODE_TITLE, program.getEpisodeTitle());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
putValue(
values,
TvContract.Programs.COLUMN_SEASON_DISPLAY_NUMBER,
program.getSeasonNumber());
putValue(
values,
TvContract.Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
program.getEpisodeNumber());
} else {
putValue(values, TvContract.Programs.COLUMN_SEASON_NUMBER, program.getSeasonNumber());
putValue(values, TvContract.Programs.COLUMN_EPISODE_NUMBER, program.getEpisodeNumber());
}
if (TvProviderUtils.checkSeriesIdColumn(context, Programs.CONTENT_URI)) {
putValue(values, COLUMN_SERIES_ID, program.getSeriesId());
}
putValue(values, TvContract.Programs.COLUMN_SHORT_DESCRIPTION, program.getDescription());
putValue(values, TvContract.Programs.COLUMN_LONG_DESCRIPTION, program.getLongDescription());
putValue(values, TvContract.Programs.COLUMN_POSTER_ART_URI, program.getPosterArtUri());
putValue(values, TvContract.Programs.COLUMN_THUMBNAIL_URI, program.getThumbnailUri());
String[] canonicalGenres = program.getCanonicalGenres();
if (canonicalGenres != null && canonicalGenres.length > 0) {
putValue(
values,
TvContract.Programs.COLUMN_CANONICAL_GENRE,
TvContract.Programs.Genres.encode(canonicalGenres));
} else {
putValue(values, TvContract.Programs.COLUMN_CANONICAL_GENRE, "");
}
putValue(
values,
Programs.COLUMN_CONTENT_RATING,
TvContentRatingCache.contentRatingsToString(program.getContentRatings()));
values.put(
TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, program.getStartTimeUtcMillis());
values.put(TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, program.getEndTimeUtcMillis());
putValue(
values,
TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA,
InternalDataUtils.serializeInternalProviderData(program));
return values;
}
private static void putValue(ContentValues contentValues, String key, String value) {
if (TextUtils.isEmpty(value)) {
contentValues.putNull(key);
} else {
contentValues.put(key, value);
}
}
private static void putValue(ContentValues contentValues, String key, byte[] value) {
if (value == null || value.length == 0) {
contentValues.putNull(key);
} else {
contentValues.put(key, value);
}
}
public void copyFrom(Program other) {
if (this == other) {
return;
}
mId = other.getId();
mPackageName = other.getPackageName();
mChannelId = other.getChannelId();
mTitle = other.getTitle();
mSeriesId = other.getSeriesId();
mEpisodeTitle = other.getEpisodeTitle();
mSeasonNumber = other.getSeasonNumber();
mSeasonTitle = other.getSeasonTitle();
mEpisodeNumber = other.getEpisodeNumber();
mStartTimeUtcMillis = other.getStartTimeUtcMillis();
mEndTimeUtcMillis = other.getEndTimeUtcMillis();
mDurationString = null; // Recreate Duration when needed.
mDescription = other.getDescription();
mLongDescription = other.getLongDescription();
mVideoWidth = other.getVideoWidth();
mVideoHeight = other.getVideoHeight();
mCriticScores = other.getCriticScores();
mPosterArtUri = other.getPosterArtUri();
mThumbnailUri = other.getThumbnailUri();
mCanonicalGenreIds = other.getCanonicalGenreIds();
mContentRatings = other.getContentRatings();
mRecordingProhibited = other.isRecordingProhibited();
}
/** A Builder for the Program class */
public static final class Builder {
private final ProgramImpl mProgram;
/** Creates a Builder for this Program class */
public Builder() {
mProgram = new ProgramImpl();
// Fill initial data.
mProgram.mPackageName = null;
mProgram.mChannelId = Channel.INVALID_ID;
mProgram.mTitle = null;
mProgram.mSeasonNumber = null;
mProgram.mSeasonTitle = null;
mProgram.mEpisodeNumber = null;
mProgram.mStartTimeUtcMillis = -1;
mProgram.mEndTimeUtcMillis = -1;
mProgram.mDurationString = null;
mProgram.mDescription = null;
mProgram.mLongDescription = null;
mProgram.mRecordingProhibited = false;
mProgram.mCriticScores = null;
}
/**
* Creates a builder for this Program class by setting default values equivalent to another
* Program
*
* @param other the program to be copied
*/
@VisibleForTesting
public Builder(Program other) {
mProgram = new ProgramImpl();
mProgram.copyFrom(other);
}
/**
* Sets the ID of this program
*
* @param id the ID
* @return a reference to this object
*/
public Builder setId(long id) {
mProgram.mId = id;
return this;
}
/**
* Sets the package name for this program
*
* @param packageName the package name
* @return a reference to this object
*/
public Builder setPackageName(String packageName) {
mProgram.mPackageName = packageName;
return this;
}
/**
* Sets the channel ID for this program
*
* @param channelId the channel ID
* @return a reference to this object
*/
public Builder setChannelId(long channelId) {
mProgram.mChannelId = channelId;
return this;
}
/**
* Sets the program title
*
* @param title the title
* @return a reference to this object
*/
public Builder setTitle(String title) {
mProgram.mTitle = title;
return this;
}
/**
* Sets the series ID.
*
* @param seriesId the series ID
* @return a reference to this object
*/
public Builder setSeriesId(String seriesId) {
mProgram.mSeriesId = seriesId;
return this;
}
/**
* Sets the episode title if this is a series program
*
* @param episodeTitle the episode title
* @return a reference to this object
*/
public Builder setEpisodeTitle(String episodeTitle) {
mProgram.mEpisodeTitle = episodeTitle;
return this;
}
/**
* Sets the season number if this is a series program
*
* @param seasonNumber the season number
* @return a reference to this object
*/
public Builder setSeasonNumber(String seasonNumber) {
mProgram.mSeasonNumber = seasonNumber;
return this;
}
/**
* Sets the season title if this is a series program
*
* @param seasonTitle the season title
* @return a reference to this object
*/
public Builder setSeasonTitle(String seasonTitle) {
mProgram.mSeasonTitle = seasonTitle;
return this;
}
/**
* Sets the episode number if this is a series program
*
* @param episodeNumber the episode number
* @return a reference to this object
*/
public Builder setEpisodeNumber(String episodeNumber) {
mProgram.mEpisodeNumber = episodeNumber;
return this;
}
/**
* Sets the start time of this program
*
* @param startTimeUtcMillis the start time in UTC milliseconds
* @return a reference to this object
*/
public Builder setStartTimeUtcMillis(long startTimeUtcMillis) {
mProgram.mStartTimeUtcMillis = startTimeUtcMillis;
return this;
}
/**
* Sets the end time of this program
*
* @param endTimeUtcMillis the end time in UTC milliseconds
* @return a reference to this object
*/
public Builder setEndTimeUtcMillis(long endTimeUtcMillis) {
mProgram.mEndTimeUtcMillis = endTimeUtcMillis;
return this;
}
/**
* Sets a description
*
* @param description the description
* @return a reference to this object
*/
public Builder setDescription(String description) {
mProgram.mDescription = description;
return this;
}
/**
* Sets a long description
*
* @param longDescription the long description
* @return a reference to this object
*/
public Builder setLongDescription(String longDescription) {
mProgram.mLongDescription = longDescription;
return this;
}
/**
* Defines the video width of this program
*
* @param width
* @return a reference to this object
*/
public Builder setVideoWidth(int width) {
mProgram.mVideoWidth = width;
return this;
}
/**
* Defines the video height of this program
*
* @param height
* @return a reference to this object
*/
public Builder setVideoHeight(int height) {
mProgram.mVideoHeight = height;
return this;
}
/**
* Sets the content ratings for this program
*
* @param contentRatings the content ratings
* @return a reference to this object
*/
public Builder setContentRatings(ImmutableList<TvContentRating> contentRatings) {
mProgram.mContentRatings = contentRatings;
return this;
}
/**
* Sets the poster art URI
*
* @param posterArtUri the poster art URI
* @return a reference to this object
*/
public Builder setPosterArtUri(String posterArtUri) {
mProgram.mPosterArtUri = posterArtUri;
return this;
}
/**
* Sets the thumbnail URI
*
* @param thumbnailUri the thumbnail URI
* @return a reference to this object
*/
public Builder setThumbnailUri(String thumbnailUri) {
mProgram.mThumbnailUri = thumbnailUri;
return this;
}
/**
* Sets the canonical genres by id
*
* @param genres the genres
* @return a reference to this object
*/
public Builder setCanonicalGenres(String genres) {
mProgram.mCanonicalGenreIds = Utils.getCanonicalGenreIds(genres);
return this;
}
/**
* Sets the recording prohibited flag
*
* @param recordingProhibited recording prohibited flag
* @return a reference to this object
*/
public Builder setRecordingProhibited(boolean recordingProhibited) {
mProgram.mRecordingProhibited = recordingProhibited;
return this;
}
/**
* Adds a critic score
*
* @param criticScore the critic score
* @return a reference to this object
*/
public Builder addCriticScore(CriticScore criticScore) {
if (criticScore.score != null) {
if (mProgram.mCriticScores == null) {
mProgram.mCriticScores = new ArrayList<>();
}
mProgram.mCriticScores.add(criticScore);
}
return this;
}
/**
* Sets the critic scores
*
* @param criticScores the critic scores
* @return a reference to this objects
*/
public Builder setCriticScores(List<CriticScore> criticScores) {
mProgram.mCriticScores = criticScores;
return this;
}
/**
* Returns a reference to the Program object being constructed
*
* @return the Program object constructed
*/
public ProgramImpl build() {
// Generate the series ID for the episodic program of other TV input.
if (TextUtils.isEmpty(mProgram.mTitle)) {
// If title is null, series cannot be generated for this program.
setSeriesId(null);
} else if (TextUtils.isEmpty(mProgram.mSeriesId)
&& !TextUtils.isEmpty(mProgram.mEpisodeNumber)) {
// If series ID is not set, generate it for the episodic program of other TV input.
setSeriesId(BaseProgram.generateSeriesId(mProgram.mPackageName, mProgram.mTitle));
}
ProgramImpl program = new ProgramImpl();
program.copyFrom(mProgram);
return program;
}
}
@Override
public void prefetchPosterArt(Context context, int posterArtWidth, int posterArtHeight) {
if (mPosterArtUri == null) {
return;
}
ImageLoader.prefetchBitmap(context, mPosterArtUri, posterArtWidth, posterArtHeight);
}
@Override
@UiThread
public boolean loadPosterArt(
Context context,
int posterArtWidth,
int posterArtHeight,
ImageLoader.ImageLoaderCallback<?> callback) {
if (mPosterArtUri == null) {
return false;
}
return ImageLoader.loadBitmap(
context, mPosterArtUri, posterArtWidth, posterArtHeight, callback);
}
@Override
public Parcelable toParcelable() {
return this;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int paramInt) {
out.writeLong(mId);
out.writeString(mPackageName);
out.writeLong(mChannelId);
out.writeString(mTitle);
out.writeString(mSeriesId);
out.writeString(mEpisodeTitle);
out.writeString(mSeasonNumber);
out.writeString(mSeasonTitle);
out.writeString(mEpisodeNumber);
out.writeLong(mStartTimeUtcMillis);
out.writeLong(mEndTimeUtcMillis);
out.writeString(mDescription);
out.writeString(mLongDescription);
out.writeInt(mVideoWidth);
out.writeInt(mVideoHeight);
out.writeList(mCriticScores);
out.writeString(mPosterArtUri);
out.writeString(mThumbnailUri);
out.writeIntArray(mCanonicalGenreIds);
out.writeInt(mContentRatings == null ? 0 : mContentRatings.size());
if (mContentRatings != null) {
for (TvContentRating rating : mContentRatings) {
out.writeString(rating.flattenToString());
}
}
out.writeByte((byte) (mRecordingProhibited ? 1 : 0));
}
}