diff options
Diffstat (limited to 'src/com/android/tv/dvr/data/ScheduledRecording.java')
-rw-r--r-- | src/com/android/tv/dvr/data/ScheduledRecording.java | 659 |
1 files changed, 409 insertions, 250 deletions
diff --git a/src/com/android/tv/dvr/data/ScheduledRecording.java b/src/com/android/tv/dvr/data/ScheduledRecording.java index 5d11c0f3..7c2d12d9 100644 --- a/src/com/android/tv/dvr/data/ScheduledRecording.java +++ b/src/com/android/tv/dvr/data/ScheduledRecording.java @@ -16,107 +16,97 @@ package com.android.tv.dvr.data; +import android.annotation.TargetApi; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.IntDef; +import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Range; - import com.android.tv.R; -import com.android.tv.TvApplication; +import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; -import com.android.tv.data.Channel; +import com.android.tv.common.util.CommonUtils; import com.android.tv.data.Program; +import com.android.tv.data.api.Channel; import com.android.tv.dvr.DvrScheduleManager; import com.android.tv.dvr.provider.DvrContract.Schedules; import com.android.tv.util.CompositeComparator; -import com.android.tv.util.Utils; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collection; import java.util.Comparator; import java.util.Objects; -/** - * A data class for one recording contents. - */ +/** A data class for one recording contents. */ +@TargetApi(Build.VERSION_CODES.N) +@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated public final class ScheduledRecording implements Parcelable { private static final String TAG = "ScheduledRecording"; - /** - * Indicates that the ID is not assigned yet. - */ + /** Indicates that the ID is not assigned yet. */ public static final long ID_NOT_SET = 0; - /** - * The default priority of the recording. - */ + /** The default priority of the recording. */ public static final long DEFAULT_PRIORITY = Long.MAX_VALUE >> 1; - /** - * Compares the start time in ascending order. - */ - public static final Comparator<ScheduledRecording> START_TIME_COMPARATOR - = new Comparator<ScheduledRecording>() { - @Override - public int compare(ScheduledRecording lhs, ScheduledRecording rhs) { - return Long.compare(lhs.mStartTimeMs, rhs.mStartTimeMs); - } - }; - - /** - * Compares the end time in ascending order. - */ - public static final Comparator<ScheduledRecording> END_TIME_COMPARATOR - = new Comparator<ScheduledRecording>() { - @Override - public int compare(ScheduledRecording lhs, ScheduledRecording rhs) { - return Long.compare(lhs.mEndTimeMs, rhs.mEndTimeMs); - } - }; - - /** - * Compares ID in ascending order. The schedule with the larger ID was created later. - */ - public static final Comparator<ScheduledRecording> ID_COMPARATOR - = new Comparator<ScheduledRecording>() { - @Override - public int compare(ScheduledRecording lhs, ScheduledRecording rhs) { - return Long.compare(lhs.mId, rhs.mId); - } - }; - - /** - * Compares the priority in ascending order. - */ - public static final Comparator<ScheduledRecording> PRIORITY_COMPARATOR - = new Comparator<ScheduledRecording>() { - @Override - public int compare(ScheduledRecording lhs, ScheduledRecording rhs) { - return Long.compare(lhs.mPriority, rhs.mPriority); - } - }; + /** Compares the start time in ascending order. */ + public static final Comparator<ScheduledRecording> START_TIME_COMPARATOR = + new Comparator<ScheduledRecording>() { + @Override + public int compare(ScheduledRecording lhs, ScheduledRecording rhs) { + return Long.compare(lhs.mStartTimeMs, rhs.mStartTimeMs); + } + }; + + /** Compares the end time in ascending order. */ + public static final Comparator<ScheduledRecording> END_TIME_COMPARATOR = + new Comparator<ScheduledRecording>() { + @Override + public int compare(ScheduledRecording lhs, ScheduledRecording rhs) { + return Long.compare(lhs.mEndTimeMs, rhs.mEndTimeMs); + } + }; + + /** Compares ID in ascending order. The schedule with the larger ID was created later. */ + public static final Comparator<ScheduledRecording> ID_COMPARATOR = + new Comparator<ScheduledRecording>() { + @Override + public int compare(ScheduledRecording lhs, ScheduledRecording rhs) { + return Long.compare(lhs.mId, rhs.mId); + } + }; + + /** Compares the priority in ascending order. */ + public static final Comparator<ScheduledRecording> PRIORITY_COMPARATOR = + new Comparator<ScheduledRecording>() { + @Override + public int compare(ScheduledRecording lhs, ScheduledRecording rhs) { + return Long.compare(lhs.mPriority, rhs.mPriority); + } + }; /** * Compares start time in ascending order and then priority in descending order and then ID in * descending order. */ - public static final Comparator<ScheduledRecording> START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR - = new CompositeComparator<>(START_TIME_COMPARATOR, PRIORITY_COMPARATOR.reversed(), - ID_COMPARATOR.reversed()); + public static final Comparator<ScheduledRecording> START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR = + new CompositeComparator<>( + START_TIME_COMPARATOR, + PRIORITY_COMPARATOR.reversed(), + ID_COMPARATOR.reversed()); - /** - * Builds scheduled recordings from programs. - */ + /** Builds scheduled recordings from programs. */ public static Builder builder(String inputId, Program p) { return new Builder() .setInputId(inputId) .setChannelId(p.getChannelId()) - .setStartTimeMs(p.getStartTimeUtcMillis()).setEndTimeMs(p.getEndTimeUtcMillis()) + .setStartTimeMs(p.getStartTimeUtcMillis()) + .setEndTimeMs(p.getEndTimeUtcMillis()) .setProgramId(p.getId()) .setProgramTitle(p.getTitle()) .setSeasonNumber(p.getSeasonNumber()) @@ -138,9 +128,7 @@ public final class ScheduledRecording implements Parcelable { .setType(TYPE_TIMED); } - /** - * Creates a new Builder with the values set from the {@link RecordedProgram}. - */ + /** Creates a new Builder with the values set from the {@link RecordedProgram}. */ public static Builder builder(RecordedProgram p) { boolean isProgramRecording = !TextUtils.isEmpty(p.getTitle()); return new Builder() @@ -157,7 +145,8 @@ public final class ScheduledRecording implements Parcelable { .setProgramLongDescription(p.getLongDescription()) .setProgramPosterArtUri(p.getPosterArtUri()) .setProgramThumbnailUri(p.getThumbnailUri()) - .setState(STATE_RECORDING_FINISHED); + .setState(STATE_RECORDING_FINISHED) + .setRecordedProgramId(p.getId()); } public static final class Builder { @@ -179,8 +168,10 @@ public final class ScheduledRecording implements Parcelable { private String mProgramThumbnailUri; private @RecordingState int mState; private long mSeriesRecordingId = ID_NOT_SET; + private Long mRecodedProgramId; + private Integer mFailedReason; - private Builder() { } + private Builder() {} public Builder setId(long id) { mId = id; @@ -272,17 +263,42 @@ public final class ScheduledRecording implements Parcelable { return this; } + public Builder setRecordedProgramId(Long recordedProgramId) { + mRecodedProgramId = recordedProgramId; + return this; + } + + public Builder setFailedReason(Integer reason) { + mFailedReason = reason; + return this; + } + public ScheduledRecording build() { - return new ScheduledRecording(mId, mPriority, mInputId, mChannelId, mProgramId, - mProgramTitle, mType, mStartTimeMs, mEndTimeMs, mSeasonNumber, mEpisodeNumber, - mEpisodeTitle, mProgramDescription, mProgramLongDescription, - mProgramPosterArtUri, mProgramThumbnailUri, mState, mSeriesRecordingId); + return new ScheduledRecording( + mId, + mPriority, + mInputId, + mChannelId, + mProgramId, + mProgramTitle, + mType, + mStartTimeMs, + mEndTimeMs, + mSeasonNumber, + mEpisodeNumber, + mEpisodeTitle, + mProgramDescription, + mProgramLongDescription, + mProgramPosterArtUri, + mProgramThumbnailUri, + mState, + mSeriesRecordingId, + mRecodedProgramId, + mFailedReason); } } - /** - * Creates {@link Builder} object from the given original {@code Recording}. - */ + /** Creates {@link Builder} object from the given original {@code Recording}. */ public static Builder buildFrom(ScheduledRecording orig) { return new Builder() .setId(orig.mId) @@ -301,14 +317,23 @@ public final class ScheduledRecording implements Parcelable { .setProgramLongDescription(orig.getProgramLongDescription()) .setProgramPosterArtUri(orig.getProgramPosterArtUri()) .setProgramThumbnailUri(orig.getProgramThumbnailUri()) - .setState(orig.mState).setType(orig.mType); + .setState(orig.mState) + .setFailedReason(orig.getFailedReason()) + .setType(orig.mType); } @Retention(RetentionPolicy.SOURCE) - @IntDef({STATE_RECORDING_NOT_STARTED, STATE_RECORDING_IN_PROGRESS, STATE_RECORDING_FINISHED, - STATE_RECORDING_FAILED, STATE_RECORDING_CLIPPED, STATE_RECORDING_DELETED, - STATE_RECORDING_CANCELED}) + @IntDef({ + STATE_RECORDING_NOT_STARTED, + STATE_RECORDING_IN_PROGRESS, + STATE_RECORDING_FINISHED, + STATE_RECORDING_FAILED, + STATE_RECORDING_CLIPPED, + STATE_RECORDING_DELETED, + STATE_RECORDING_CANCELED + }) public @interface RecordingState {} + public static final int STATE_RECORDING_NOT_STARTED = 0; public static final int STATE_RECORDING_IN_PROGRESS = 1; public static final int STATE_RECORDING_FINISHED = 2; @@ -317,48 +342,74 @@ public final class ScheduledRecording implements Parcelable { public static final int STATE_RECORDING_DELETED = 5; public static final int STATE_RECORDING_CANCELED = 6; + /** The reasons of failed recordings */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + FAILED_REASON_OTHER, + FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED, + FAILED_REASON_NOT_FINISHED, + FAILED_REASON_SCHEDULER_STOPPED, + FAILED_REASON_INVALID_CHANNEL, + FAILED_REASON_MESSAGE_NOT_SENT, + FAILED_REASON_CONNECTION_FAILED, + FAILED_REASON_RESOURCE_BUSY, + FAILED_REASON_INPUT_UNAVAILABLE, + FAILED_REASON_INPUT_DVR_UNSUPPORTED, + FAILED_REASON_INSUFFICIENT_SPACE + }) + public @interface RecordingFailedReason {} + + public static final int FAILED_REASON_OTHER = 0; + public static final int FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED = 1; + public static final int FAILED_REASON_NOT_FINISHED = 2; + public static final int FAILED_REASON_SCHEDULER_STOPPED = 3; + public static final int FAILED_REASON_INVALID_CHANNEL = 4; + public static final int FAILED_REASON_MESSAGE_NOT_SENT = 5; + public static final int FAILED_REASON_CONNECTION_FAILED = 6; + public static final int FAILED_REASON_RESOURCE_BUSY = 7; + // For the following reasons, show advice to users + public static final int FAILED_REASON_INPUT_UNAVAILABLE = 8; + public static final int FAILED_REASON_INPUT_DVR_UNSUPPORTED = 9; + public static final int FAILED_REASON_INSUFFICIENT_SPACE = 10; + @Retention(RetentionPolicy.SOURCE) @IntDef({TYPE_TIMED, TYPE_PROGRAM}) public @interface RecordingType {} - /** - * Record with given time range. - */ + /** Record with given time range. */ public static final int TYPE_TIMED = 1; - /** - * Record with a given program. - */ + /** Record with a given program. */ public static final int TYPE_PROGRAM = 2; @RecordingType private final int mType; /** - * Use this projection if you want to create {@link ScheduledRecording} object using - * {@link #fromCursor}. + * Use this projection if you want to create {@link ScheduledRecording} object using {@link + * #fromCursor}. */ public static final String[] PROJECTION = { - // Columns must match what is read in #fromCursor - Schedules._ID, - Schedules.COLUMN_PRIORITY, - Schedules.COLUMN_TYPE, - Schedules.COLUMN_INPUT_ID, - Schedules.COLUMN_CHANNEL_ID, - Schedules.COLUMN_PROGRAM_ID, - Schedules.COLUMN_PROGRAM_TITLE, - Schedules.COLUMN_START_TIME_UTC_MILLIS, - Schedules.COLUMN_END_TIME_UTC_MILLIS, - Schedules.COLUMN_SEASON_NUMBER, - Schedules.COLUMN_EPISODE_NUMBER, - Schedules.COLUMN_EPISODE_TITLE, - Schedules.COLUMN_PROGRAM_DESCRIPTION, - Schedules.COLUMN_PROGRAM_LONG_DESCRIPTION, - Schedules.COLUMN_PROGRAM_POST_ART_URI, - Schedules.COLUMN_PROGRAM_THUMBNAIL_URI, - Schedules.COLUMN_STATE, - Schedules.COLUMN_SERIES_RECORDING_ID}; + // Columns must match what is read in #fromCursor + Schedules._ID, + Schedules.COLUMN_PRIORITY, + Schedules.COLUMN_TYPE, + Schedules.COLUMN_INPUT_ID, + Schedules.COLUMN_CHANNEL_ID, + Schedules.COLUMN_PROGRAM_ID, + Schedules.COLUMN_PROGRAM_TITLE, + Schedules.COLUMN_START_TIME_UTC_MILLIS, + Schedules.COLUMN_END_TIME_UTC_MILLIS, + Schedules.COLUMN_SEASON_NUMBER, + Schedules.COLUMN_EPISODE_NUMBER, + Schedules.COLUMN_EPISODE_TITLE, + Schedules.COLUMN_PROGRAM_DESCRIPTION, + Schedules.COLUMN_PROGRAM_LONG_DESCRIPTION, + Schedules.COLUMN_PROGRAM_POST_ART_URI, + Schedules.COLUMN_PROGRAM_THUMBNAIL_URI, + Schedules.COLUMN_STATE, + Schedules.COLUMN_FAILED_REASON, + Schedules.COLUMN_SERIES_RECORDING_ID + }; - /** - * Creates {@link ScheduledRecording} object from the given {@link Cursor}. - */ + /** Creates {@link ScheduledRecording} object from the given {@link Cursor}. */ public static ScheduledRecording fromCursor(Cursor c) { int index = -1; return new Builder() @@ -379,6 +430,7 @@ public final class ScheduledRecording implements Parcelable { .setProgramPosterArtUri(c.getString(++index)) .setProgramThumbnailUri(c.getString(++index)) .setState(recordingState(c.getString(++index))) + .setFailedReason(recordingFailedReason(c.getString(++index))) .setSeriesRecordingId(c.getLong(++index)) .build(); } @@ -403,6 +455,7 @@ public final class ScheduledRecording implements Parcelable { values.put(Schedules.COLUMN_PROGRAM_POST_ART_URI, r.getProgramPosterArtUri()); values.put(Schedules.COLUMN_PROGRAM_THUMBNAIL_URI, r.getProgramThumbnailUri()); values.put(Schedules.COLUMN_STATE, recordingState(r.getState())); + values.put(Schedules.COLUMN_FAILED_REASON, recordingFailedReason(r.getFailedReason())); values.put(Schedules.COLUMN_TYPE, recordingType(r.getType())); if (r.getSeriesRecordingId() != ID_NOT_SET) { values.put(Schedules.COLUMN_SERIES_RECORDING_ID, r.getSeriesRecordingId()); @@ -431,42 +484,40 @@ public final class ScheduledRecording implements Parcelable { .setProgramPosterArtUri(in.readString()) .setProgramThumbnailUri(in.readString()) .setState(in.readInt()) + .setFailedReason(recordingFailedReason(in.readString())) .setSeriesRecordingId(in.readLong()) .build(); } public static final Parcelable.Creator<ScheduledRecording> CREATOR = new Parcelable.Creator<ScheduledRecording>() { - @Override - public ScheduledRecording createFromParcel(Parcel in) { - return ScheduledRecording.fromParcel(in); - } - - @Override - public ScheduledRecording[] newArray(int size) { - return new ScheduledRecording[size]; - } - }; - - /** - * The ID internal to Live TV - */ + @Override + public ScheduledRecording createFromParcel(Parcel in) { + return ScheduledRecording.fromParcel(in); + } + + @Override + public ScheduledRecording[] newArray(int size) { + return new ScheduledRecording[size]; + } + }; + + /** The ID internal to Live TV */ private long mId; /** * The priority of this recording. * - * <p> The highest number is recorded first. If there is a tie in priority then the higher id + * <p>The highest number is recorded first. If there is a tie in priority then the higher id * wins. */ private final long mPriority; private final String mInputId; private final long mChannelId; - /** - * Optional id of the associated program. - */ + /** Optional id of the associated program. */ private final long mProgramId; + private final String mProgramTitle; private final long mStartTimeMs; @@ -480,12 +531,30 @@ public final class ScheduledRecording implements Parcelable { private final String mProgramThumbnailUri; @RecordingState private final int mState; private final long mSeriesRecordingId; - - private ScheduledRecording(long id, long priority, String inputId, long channelId, long programId, - String programTitle, @RecordingType int type, long startTime, long endTime, - String seasonNumber, String episodeNumber, String episodeTitle, - String programDescription, String programLongDescription, String programPosterArtUri, - String programThumbnailUri, @RecordingState int state, long seriesRecordingId) { + private final Long mRecordedProgramId; + private final Integer mFailedReason; + + private ScheduledRecording( + long id, + long priority, + String inputId, + long channelId, + long programId, + String programTitle, + @RecordingType int type, + long startTime, + long endTime, + String seasonNumber, + String episodeNumber, + String episodeTitle, + String programDescription, + String programLongDescription, + String programPosterArtUri, + String programThumbnailUri, + @RecordingState int state, + long seriesRecordingId, + Long recordedProgramId, + Integer failedReason) { mId = id; mPriority = priority; mInputId = inputId; @@ -504,139 +573,122 @@ public final class ScheduledRecording implements Parcelable { mProgramThumbnailUri = programThumbnailUri; mState = state; mSeriesRecordingId = seriesRecordingId; + mRecordedProgramId = recordedProgramId; + mFailedReason = failedReason; } /** - * Returns recording schedule type. The possible types are {@link #TYPE_PROGRAM} and - * {@link #TYPE_TIMED}. + * Returns recording schedule type. The possible types are {@link #TYPE_PROGRAM} and {@link + * #TYPE_TIMED}. */ @RecordingType public int getType() { return mType; } - /** - * Returns schedules' input id. - */ + /** Returns schedules' input id. */ public String getInputId() { return mInputId; } - /** - * Returns recorded {@link Channel}. - */ + /** Returns recorded {@link Channel}. */ public long getChannelId() { return mChannelId; } - /** - * Return the optional program id - */ + /** Return the optional program id */ public long getProgramId() { return mProgramId; } - /** - * Return the optional program Title - */ + /** Return the optional program Title */ public String getProgramTitle() { return mProgramTitle; } - /** - * Returns started time. - */ + /** Returns started time. */ public long getStartTimeMs() { return mStartTimeMs; } - /** - * Returns ended time. - */ + /** Returns ended time. */ public long getEndTimeMs() { return mEndTimeMs; } - /** - * Returns the season number. - */ + /** Returns the season number. */ public String getSeasonNumber() { return mSeasonNumber; } - /** - * Returns the episode number. - */ + /** Returns the episode number. */ public String getEpisodeNumber() { return mEpisodeNumber; } - /** - * Returns the episode title. - */ + /** Returns the episode title. */ public String getEpisodeTitle() { return mEpisodeTitle; } - /** - * Returns the description of program. - */ + /** Returns the description of program. */ public String getProgramDescription() { return mProgramDescription; } - /** - * Returns the long description of program. - */ + /** Returns the long description of program. */ public String getProgramLongDescription() { return mProgramLongDescription; } - /** - * Returns the poster uri of program. - */ + /** Returns the poster uri of program. */ public String getProgramPosterArtUri() { return mProgramPosterArtUri; } - /** - * Returns the thumb nail uri of program. - */ + /** Returns the thumb nail uri of program. */ public String getProgramThumbnailUri() { return mProgramThumbnailUri; } - /** - * Returns duration. - */ + /** Returns duration. */ public long getDuration() { return mEndTimeMs - mStartTimeMs; } /** - * Returns the state. The possible states are {@link #STATE_RECORDING_NOT_STARTED}, - * {@link #STATE_RECORDING_IN_PROGRESS}, {@link #STATE_RECORDING_FINISHED}, - * {@link #STATE_RECORDING_FAILED}, {@link #STATE_RECORDING_CLIPPED} and - * {@link #STATE_RECORDING_DELETED}. + * Returns the state. The possible states are {@link #STATE_RECORDING_NOT_STARTED}, {@link + * #STATE_RECORDING_IN_PROGRESS}, {@link #STATE_RECORDING_FINISHED}, {@link + * #STATE_RECORDING_FAILED}, {@link #STATE_RECORDING_CLIPPED} and {@link + * #STATE_RECORDING_DELETED}. */ - @RecordingState public int getState() { + @RecordingState + public int getState() { return mState; } - /** - * Returns the ID of the {@link SeriesRecording} including this schedule. - */ + /** Returns the ID of the {@link SeriesRecording} including this schedule. */ public long getSeriesRecordingId() { return mSeriesRecordingId; } + /** Returns the ID of the corresponding {@link RecordedProgram}. */ + @Nullable + public Long getRecordedProgramId() { + return mRecordedProgramId; + } + + /** Returns the failed reason of the {@link ScheduledRecording}. */ + @Nullable @RecordingFailedReason + public Integer getFailedReason() { + return mFailedReason; + } + public long getId() { return mId; } - /** - * Sets the ID; - */ + /** Sets the ID; */ public void setId(long id) { mId = id; } @@ -645,21 +697,23 @@ public final class ScheduledRecording implements Parcelable { return mPriority; } - /** - * Returns season number, episode number and episode title for display. - */ + /** Returns season number, episode number and episode title for display. */ public String getEpisodeDisplayTitle(Context context) { if (!TextUtils.isEmpty(mEpisodeNumber)) { String episodeTitle = mEpisodeTitle == null ? "" : mEpisodeTitle; if (TextUtils.equals(mSeasonNumber, "0")) { // Do not show "S0: ". - return String.format(context.getResources().getString( - R.string.display_episode_title_format_no_season_number), - mEpisodeNumber, episodeTitle); + return String.format( + context.getResources() + .getString(R.string.display_episode_title_format_no_season_number), + mEpisodeNumber, + episodeTitle); } else { - return String.format(context.getResources().getString( - R.string.display_episode_title_format), - mSeasonNumber, mEpisodeNumber, episodeTitle); + return String.format( + context.getResources().getString(R.string.display_episode_title_format), + mSeasonNumber, + mEpisodeNumber, + episodeTitle); } } return mEpisodeTitle; @@ -673,15 +727,14 @@ public final class ScheduledRecording implements Parcelable { if (!TextUtils.isEmpty(mProgramTitle)) { return mProgramTitle; } - Channel channel = TvApplication.getSingletons(context).getChannelDataManager() - .getChannel(mChannelId); - return channel != null ? channel.getDisplayName() + Channel channel = + TvSingletons.getSingletons(context).getChannelDataManager().getChannel(mChannelId); + return channel != null + ? channel.getDisplayName() : context.getString(R.string.no_program_information); } - /** - * Converts a string to a @RecordingType int, defaulting to {@link #TYPE_TIMED}. - */ + /** Converts a string to a @RecordingType int, defaulting to {@link #TYPE_TIMED}. */ private static @RecordingType int recordingType(String type) { switch (type) { case Schedules.TYPE_TIMED: @@ -689,14 +742,12 @@ public final class ScheduledRecording implements Parcelable { case Schedules.TYPE_PROGRAM: return TYPE_PROGRAM; default: - SoftPreconditions.checkArgument(false, TAG, "Unknown recording type " + type); + SoftPreconditions.checkArgument(false, TAG, "Unknown recording type %s", type); return TYPE_TIMED; } } - /** - * Converts a @RecordingType int to a string, defaulting to {@link Schedules#TYPE_TIMED}. - */ + /** Converts a @RecordingType int to a string, defaulting to {@link Schedules#TYPE_TIMED}. */ private static String recordingType(@RecordingType int type) { switch (type) { case TYPE_TIMED: @@ -704,14 +755,14 @@ public final class ScheduledRecording implements Parcelable { case TYPE_PROGRAM: return Schedules.TYPE_PROGRAM; default: - SoftPreconditions.checkArgument(false, TAG, "Unknown recording type " + type); + SoftPreconditions.checkArgument(false, TAG, "Unknown recording type %s", type); return Schedules.TYPE_TIMED; } } /** - * Converts a string to a @RecordingState int, defaulting to - * {@link #STATE_RECORDING_NOT_STARTED}. + * Converts a string to a @RecordingState int, defaulting to {@link + * #STATE_RECORDING_NOT_STARTED}. */ private static @RecordingState int recordingState(String state) { switch (state) { @@ -730,14 +781,14 @@ public final class ScheduledRecording implements Parcelable { case Schedules.STATE_RECORDING_CANCELED: return STATE_RECORDING_CANCELED; default: - SoftPreconditions.checkArgument(false, TAG, "Unknown recording state" + state); + SoftPreconditions.checkArgument(false, TAG, "Unknown recording state %s", state); return STATE_RECORDING_NOT_STARTED; } } /** - * Converts a @RecordingState int to string, defaulting to - * {@link Schedules#STATE_RECORDING_NOT_STARTED}. + * Converts a @RecordingState int to string, defaulting to {@link + * Schedules#STATE_RECORDING_NOT_STARTED}. */ private static String recordingState(@RecordingState int state) { switch (state) { @@ -756,46 +807,138 @@ public final class ScheduledRecording implements Parcelable { case STATE_RECORDING_CANCELED: return Schedules.STATE_RECORDING_CANCELED; default: - SoftPreconditions.checkArgument(false, TAG, "Unknown recording state" + state); + SoftPreconditions.checkArgument(false, TAG, "Unknown recording state %s", state); return Schedules.STATE_RECORDING_NOT_STARTED; } } /** - * Checks if the {@code period} overlaps with the recording time. + * Converts a string to a failed reason integer, defaulting to {@link + * #FAILED_REASON_OTHER}. */ - public boolean isOverLapping(Range<Long> period) { - return mStartTimeMs < period.getUpper() && mEndTimeMs > period.getLower(); + private static Integer recordingFailedReason(String reason) { + if (TextUtils.isEmpty(reason)) { + return null; + } + switch (reason) { + case Schedules.FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED: + return FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED; + case Schedules.FAILED_REASON_NOT_FINISHED: + return FAILED_REASON_NOT_FINISHED; + case Schedules.FAILED_REASON_SCHEDULER_STOPPED: + return FAILED_REASON_SCHEDULER_STOPPED; + case Schedules.FAILED_REASON_INVALID_CHANNEL: + return FAILED_REASON_INVALID_CHANNEL; + case Schedules.FAILED_REASON_MESSAGE_NOT_SENT: + return FAILED_REASON_MESSAGE_NOT_SENT; + case Schedules.FAILED_REASON_CONNECTION_FAILED: + return FAILED_REASON_CONNECTION_FAILED; + case Schedules.FAILED_REASON_RESOURCE_BUSY: + return FAILED_REASON_RESOURCE_BUSY; + case Schedules.FAILED_REASON_INPUT_UNAVAILABLE: + return FAILED_REASON_INPUT_UNAVAILABLE; + case Schedules.FAILED_REASON_INPUT_DVR_UNSUPPORTED: + return FAILED_REASON_INPUT_DVR_UNSUPPORTED; + case Schedules.FAILED_REASON_INSUFFICIENT_SPACE: + return FAILED_REASON_INSUFFICIENT_SPACE; + case Schedules.FAILED_REASON_OTHER: + default: + return FAILED_REASON_OTHER; + } } /** - * Checks if the {@code schedule} overlaps with this schedule. + * Converts a failed reason integer to string, defaulting to {@link + * Schedules#FAILED_REASON_OTHER}. */ + private static String recordingFailedReason(Integer reason) { + if (reason == null) { + return null; + } + switch (reason) { + case FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED: + return Schedules.FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED; + case FAILED_REASON_NOT_FINISHED: + return Schedules.FAILED_REASON_NOT_FINISHED; + case FAILED_REASON_SCHEDULER_STOPPED: + return Schedules.FAILED_REASON_SCHEDULER_STOPPED; + case FAILED_REASON_INVALID_CHANNEL: + return Schedules.FAILED_REASON_INVALID_CHANNEL; + case FAILED_REASON_MESSAGE_NOT_SENT: + return Schedules.FAILED_REASON_MESSAGE_NOT_SENT; + case FAILED_REASON_CONNECTION_FAILED: + return Schedules.FAILED_REASON_CONNECTION_FAILED; + case FAILED_REASON_RESOURCE_BUSY: + return Schedules.FAILED_REASON_RESOURCE_BUSY; + case FAILED_REASON_INPUT_UNAVAILABLE: + return Schedules.FAILED_REASON_INPUT_UNAVAILABLE; + case FAILED_REASON_INPUT_DVR_UNSUPPORTED: + return Schedules.FAILED_REASON_INPUT_DVR_UNSUPPORTED; + case FAILED_REASON_INSUFFICIENT_SPACE: + return Schedules.FAILED_REASON_INSUFFICIENT_SPACE; + case FAILED_REASON_OTHER: // fall through + default: + return Schedules.FAILED_REASON_OTHER; + } + } + + /** Checks if the {@code period} overlaps with the recording time. */ + public boolean isOverLapping(Range<Long> period) { + return mStartTimeMs < period.getUpper() && mEndTimeMs > period.getLower(); + } + + /** Checks if the {@code schedule} overlaps with this schedule. */ public boolean isOverLapping(ScheduledRecording schedule) { return mStartTimeMs < schedule.getEndTimeMs() && mEndTimeMs > schedule.getStartTimeMs(); } @Override public String toString() { - return "ScheduledRecording[" + mId + return "ScheduledRecording[" + + mId + "]" - + "(inputId=" + mInputId - + ",channelId=" + mChannelId - + ",programId=" + mProgramId - + ",programTitle=" + mProgramTitle - + ",type=" + mType - + ",startTime=" + Utils.toIsoDateTimeString(mStartTimeMs) + "(" + mStartTimeMs + ")" - + ",endTime=" + Utils.toIsoDateTimeString(mEndTimeMs) + "(" + mEndTimeMs + ")" - + ",seasonNumber=" + mSeasonNumber - + ",episodeNumber=" + mEpisodeNumber - + ",episodeTitle=" + mEpisodeTitle - + ",programDescription=" + mProgramDescription - + ",programLongDescription=" + mProgramLongDescription - + ",programPosterArtUri=" + mProgramPosterArtUri - + ",programThumbnailUri=" + mProgramThumbnailUri - + ",state=" + mState - + ",priority=" + mPriority - + ",seriesRecordingId=" + mSeriesRecordingId + + "(inputId=" + + mInputId + + ",channelId=" + + mChannelId + + ",programId=" + + mProgramId + + ",programTitle=" + + mProgramTitle + + ",type=" + + mType + + ",startTime=" + + CommonUtils.toIsoDateTimeString(mStartTimeMs) + + "(" + + mStartTimeMs + + ")" + + ",endTime=" + + CommonUtils.toIsoDateTimeString(mEndTimeMs) + + "(" + + mEndTimeMs + + ")" + + ",seasonNumber=" + + mSeasonNumber + + ",episodeNumber=" + + mEpisodeNumber + + ",episodeTitle=" + + mEpisodeTitle + + ",programDescription=" + + mProgramDescription + + ",programLongDescription=" + + mProgramLongDescription + + ",programPosterArtUri=" + + mProgramPosterArtUri + + ",programThumbnailUri=" + + mProgramThumbnailUri + + ",state=" + + mState + + ",failedReason=" + + mFailedReason + + ",priority=" + + mPriority + + ",seriesRecordingId=" + + mSeriesRecordingId + ")"; } @@ -823,23 +966,25 @@ public final class ScheduledRecording implements Parcelable { out.writeString(mProgramPosterArtUri); out.writeString(mProgramThumbnailUri); out.writeInt(mState); + out.writeString(recordingFailedReason(mFailedReason)); out.writeLong(mSeriesRecordingId); } - /** - * Returns {@code true} if the recording is not started yet, otherwise @{code false}. - */ + /** Returns {@code true} if the recording is not started yet, otherwise @{code false}. */ public boolean isNotStarted() { return mState == STATE_RECORDING_NOT_STARTED; } - /** - * Returns {@code true} if the recording is in progress, otherwise @{code false}. - */ + /** Returns {@code true} if the recording is in progress, otherwise @{code false}. */ public boolean isInProgress() { return mState == STATE_RECORDING_IN_PROGRESS; } + /** Returns {@code true} if the recording is finished, otherwise @{code false}. */ + public boolean isFinished() { + return mState == STATE_RECORDING_FINISHED; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof ScheduledRecording)) { @@ -862,20 +1007,34 @@ public final class ScheduledRecording implements Parcelable { && Objects.equals(mProgramPosterArtUri, r.getProgramPosterArtUri()) && Objects.equals(mProgramThumbnailUri, r.getProgramThumbnailUri()) && mState == r.mState + && Objects.equals(mFailedReason, r.mFailedReason) && mSeriesRecordingId == r.mSeriesRecordingId; } @Override public int hashCode() { - return Objects.hash(mId, mPriority, mChannelId, mProgramId, mProgramTitle, mType, - mStartTimeMs, mEndTimeMs, mSeasonNumber, mEpisodeNumber, mEpisodeTitle, - mProgramDescription, mProgramLongDescription, mProgramPosterArtUri, - mProgramThumbnailUri, mState, mSeriesRecordingId); + return Objects.hash( + mId, + mPriority, + mChannelId, + mProgramId, + mProgramTitle, + mType, + mStartTimeMs, + mEndTimeMs, + mSeasonNumber, + mEpisodeNumber, + mEpisodeTitle, + mProgramDescription, + mProgramLongDescription, + mProgramPosterArtUri, + mProgramThumbnailUri, + mState, + mFailedReason, + mSeriesRecordingId); } - /** - * Returns an array containing all of the elements in the list. - */ + /** Returns an array containing all of the elements in the list. */ public static ScheduledRecording[] toArray(Collection<ScheduledRecording> schedules) { return schedules.toArray(new ScheduledRecording[schedules.size()]); } |