aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshubang <shubang@google.com>2018-02-23 17:08:03 -0800
committerNick Chalko <nchalko@google.com>2018-02-26 15:42:56 -0800
commit9850ee71f931f597658b39fba8fd18bead506955 (patch)
treec900aad62a7ab95bbeb25e1b32ae2fae2fa5e8b7
parent9d283c91d496eac51237ced05d649081bb08d3e1 (diff)
downloadTV-9850ee71f931f597658b39fba8fd18bead506955.tar.gz
Write DVR failed reasons to DB
PiperOrigin-RevId: 186845549 Change-Id: I327129322ade4ef3ef0110bb51ec8f172c7a99ec
-rw-r--r--src/com/android/tv/dvr/BaseDvrDataManager.java13
-rw-r--r--src/com/android/tv/dvr/DvrDataManagerImpl.java7
-rw-r--r--src/com/android/tv/dvr/WritableDvrDataManager.java8
-rw-r--r--src/com/android/tv/dvr/data/ScheduledRecording.java72
-rw-r--r--src/com/android/tv/dvr/provider/DvrContract.java43
-rw-r--r--src/com/android/tv/dvr/recorder/InputTaskScheduler.java13
-rw-r--r--src/com/android/tv/dvr/recorder/RecordingScheduler.java10
-rw-r--r--src/com/android/tv/dvr/recorder/RecordingTask.java61
-rw-r--r--src/com/android/tv/dvr/ui/browse/DetailsContent.java3
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java3
10 files changed, 206 insertions, 27 deletions
diff --git a/src/com/android/tv/dvr/BaseDvrDataManager.java b/src/com/android/tv/dvr/BaseDvrDataManager.java
index 4a04de4e..b8bffa18 100644
--- a/src/com/android/tv/dvr/BaseDvrDataManager.java
+++ b/src/com/android/tv/dvr/BaseDvrDataManager.java
@@ -258,6 +258,19 @@ public abstract class BaseDvrDataManager implements WritableDvrDataManager {
}
@Override
+ public void changeState(
+ ScheduledRecording scheduledRecording, @RecordingState int newState, int reason) {
+ if (scheduledRecording.getState() != newState) {
+ ScheduledRecording.Builder builder =
+ ScheduledRecording.buildFrom(scheduledRecording).setState(newState);
+ if (newState == ScheduledRecording.STATE_RECORDING_FAILED) {
+ builder.setFailedReason(reason);
+ }
+ updateScheduledRecording(builder.build());
+ }
+ }
+
+ @Override
public Collection<ScheduledRecording> getDeletedSchedules() {
return mDeletedScheduleMap.values();
}
diff --git a/src/com/android/tv/dvr/DvrDataManagerImpl.java b/src/com/android/tv/dvr/DvrDataManagerImpl.java
index c74aa208..2b4ecbf5 100644
--- a/src/com/android/tv/dvr/DvrDataManagerImpl.java
+++ b/src/com/android/tv/dvr/DvrDataManagerImpl.java
@@ -228,6 +228,9 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
protected void onPostExecute(List<ScheduledRecording> result) {
mPendingTasks.remove(this);
long maxId = 0;
+ int reasonNotStarted =
+ ScheduledRecording
+ .FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED;
List<ScheduledRecording> toUpdate = new ArrayList<>();
List<ScheduledRecording> toDelete = new ArrayList<>();
for (ScheduledRecording r : result) {
@@ -244,11 +247,14 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
switch (r.getState()) {
case ScheduledRecording.STATE_RECORDING_IN_PROGRESS:
if (r.getEndTimeMs() <= mClock.currentTimeMillis()) {
+ int reason =
+ ScheduledRecording.FAILED_REASON_NOT_FINISHED;
toUpdate.add(
ScheduledRecording.buildFrom(r)
.setState(
ScheduledRecording
.STATE_RECORDING_FAILED)
+ .setFailedReason(reason)
.build());
} else {
toUpdate.add(
@@ -266,6 +272,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
.setState(
ScheduledRecording
.STATE_RECORDING_FAILED)
+ .setFailedReason(reasonNotStarted)
.build());
}
break;
diff --git a/src/com/android/tv/dvr/WritableDvrDataManager.java b/src/com/android/tv/dvr/WritableDvrDataManager.java
index 059b0a6d..1b505e80 100644
--- a/src/com/android/tv/dvr/WritableDvrDataManager.java
+++ b/src/com/android/tv/dvr/WritableDvrDataManager.java
@@ -57,6 +57,14 @@ public interface WritableDvrDataManager extends DvrDataManager {
void changeState(ScheduledRecording scheduledRecording, @RecordingState int newState);
/**
+ * Changes the state of the recording.
+ *
+ * @param reason the reason of this change
+ */
+ void changeState(
+ ScheduledRecording scheduledRecording, @RecordingState int newState, int reason);
+
+ /**
* Remove all the records related to the input.
*
* <p>Note that this should be called after the input was removed.
diff --git a/src/com/android/tv/dvr/data/ScheduledRecording.java b/src/com/android/tv/dvr/data/ScheduledRecording.java
index 851aabc3..7c2d12d9 100644
--- a/src/com/android/tv/dvr/data/ScheduledRecording.java
+++ b/src/com/android/tv/dvr/data/ScheduledRecording.java
@@ -342,7 +342,35 @@ 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})
@@ -651,7 +679,7 @@ public final class ScheduledRecording implements Parcelable {
}
/** Returns the failed reason of the {@link ScheduledRecording}. */
- @Nullable
+ @Nullable @RecordingFailedReason
public Integer getFailedReason() {
return mFailedReason;
}
@@ -793,6 +821,26 @@ public final class ScheduledRecording implements Parcelable {
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;
@@ -808,7 +856,27 @@ public final class ScheduledRecording implements Parcelable {
return null;
}
switch (reason) {
- // TODO(b/72638385): add reasons
+ 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;
}
diff --git a/src/com/android/tv/dvr/provider/DvrContract.java b/src/com/android/tv/dvr/provider/DvrContract.java
index e4f505ac..a5f2e2cd 100644
--- a/src/com/android/tv/dvr/provider/DvrContract.java
+++ b/src/com/android/tv/dvr/provider/DvrContract.java
@@ -58,6 +58,49 @@ public final class DvrContract {
/** The recording failed reason for other reasons */
public static final String FAILED_REASON_OTHER = "FAILED_REASON_OTHER";
+ /** The recording failed because the program ended before recording started. */
+ public static final String FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED =
+ "FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED";
+
+ /** The recording failed because it was not finished successfully */
+ public static final String FAILED_REASON_NOT_FINISHED = "FAILED_REASON_NOT_FINISHED";
+
+ /** The recording failed because the channel ID was invalid */
+ public static final String FAILED_REASON_INVALID_CHANNEL = "FAILED_REASON_INVALID_CHANNEL";
+
+ /** The recording failed because the scheduler was stopped */
+ public static final String FAILED_REASON_SCHEDULER_STOPPED
+ = "FAILED_REASON_SCHEDULER_STOPPED";
+
+ /** The recording failed because some messages were not sent to the message queue */
+ public static final String FAILED_REASON_MESSAGE_NOT_SENT =
+ "FAILED_REASON_MESSAGE_NOT_SENT";
+
+ /**
+ * The recording failed because it was failed to establish a connection to the recording
+ * session for the corresponding TV input.
+ */
+ public static final String FAILED_REASON_CONNECTION_FAILED =
+ "FAILED_REASON_CONNECTION_FAILED";
+
+ /**
+ * The recording failed because a required recording resource was not able to be
+ * allocated.
+ */
+ public static final String FAILED_REASON_RESOURCE_BUSY = "FAILED_REASON_RESOURCE_BUSY";
+
+ /** The recording failed because the input was not available */
+ public static final String FAILED_REASON_INPUT_UNAVAILABLE =
+ "FAILED_REASON_INPUT_UNAVAILABLE";
+
+ /** The recording failed because the input doesn't support recording */
+ public static final String FAILED_REASON_INPUT_DVR_UNSUPPORTED =
+ "FAILED_REASON_INPUT_DVR_UNSUPPORTED";
+
+ /** The recording failed because the space was not sufficient */
+ public static final String FAILED_REASON_INSUFFICIENT_SPACE =
+ "FAILED_REASON_INSUFFICIENT_SPACE";
+
/**
* The priority of this recording.
*
diff --git a/src/com/android/tv/dvr/recorder/InputTaskScheduler.java b/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
index 0f1ea3b0..1021b2bc 100644
--- a/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
+++ b/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
@@ -278,7 +278,9 @@ public class InputTaskScheduler {
ScheduledRecording schedule = iter.next();
if (schedule.getEndTimeMs() - currentTimeMs
<= MIN_REMAIN_DURATION_PERCENT * schedule.getDuration()) {
- fail(schedule);
+ Log.e(TAG, "Error! Program ended before recording started:" + schedule);
+ fail(schedule,
+ ScheduledRecording.FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED);
iter.remove();
}
}
@@ -389,7 +391,7 @@ public class InputTaskScheduler {
return candidate;
}
- private void fail(ScheduledRecording schedule) {
+ private void fail(ScheduledRecording schedule, int reason) {
// It's called when the scheduling has been failed without creating RecordingTask.
runOnMainHandler(
new Runnable() {
@@ -399,10 +401,11 @@ public class InputTaskScheduler {
mDataManager.getScheduledRecording(schedule.getId());
if (scheduleInManager != null) {
// The schedule should be updated based on the object from DataManager
- // in case
- // when it has been updated.
+ // in case when it has been updated.
mDataManager.changeState(
- scheduleInManager, ScheduledRecording.STATE_RECORDING_FAILED);
+ scheduleInManager,
+ ScheduledRecording.STATE_RECORDING_FAILED,
+ reason);
}
}
});
diff --git a/src/com/android/tv/dvr/recorder/RecordingScheduler.java b/src/com/android/tv/dvr/recorder/RecordingScheduler.java
index d631d84f..f309537d 100644
--- a/src/com/android/tv/dvr/recorder/RecordingScheduler.java
+++ b/src/com/android/tv/dvr/recorder/RecordingScheduler.java
@@ -280,12 +280,18 @@ public class RecordingScheduler extends TvInputCallback implements ScheduledReco
TvInputInfo input = Utils.getTvInputInfoForInputId(mContext, schedule.getInputId());
if (input == null) {
Log.e(TAG, "Can't find input for " + schedule);
- mDataManager.changeState(schedule, ScheduledRecording.STATE_RECORDING_FAILED);
+ mDataManager.changeState(
+ schedule,
+ ScheduledRecording.STATE_RECORDING_FAILED,
+ ScheduledRecording.FAILED_REASON_INPUT_UNAVAILABLE);
return;
}
if (!input.canRecord() || input.getTunerCount() <= 0) {
Log.e(TAG, "TV input doesn't support recording: " + input);
- mDataManager.changeState(schedule, ScheduledRecording.STATE_RECORDING_FAILED);
+ mDataManager.changeState(
+ schedule,
+ ScheduledRecording.STATE_RECORDING_FAILED,
+ ScheduledRecording.FAILED_REASON_INPUT_DVR_UNSUPPORTED);
return;
}
InputTaskScheduler inputTaskScheduler = mInputSchedulerMap.get(input.getId());
diff --git a/src/com/android/tv/dvr/recorder/RecordingTask.java b/src/com/android/tv/dvr/recorder/RecordingTask.java
index ff37f3f0..07a29e51 100644
--- a/src/com/android/tv/dvr/recorder/RecordingTask.java
+++ b/src/com/android/tv/dvr/recorder/RecordingTask.java
@@ -26,6 +26,7 @@ import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.util.Log;
@@ -194,7 +195,7 @@ public class RecordingTask extends RecordingCallback
public void onDisconnected(String inputId) {
if (DEBUG) Log.d(TAG, "onDisconnected(" + inputId + ")");
if (mRecordingSession != null && mState != State.FINISHED) {
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_NOT_FINISHED);
}
}
@@ -202,7 +203,7 @@ public class RecordingTask extends RecordingCallback
public void onConnectionFailed(String inputId) {
if (DEBUG) Log.d(TAG, "onConnectionFailed(" + inputId + ")");
if (mRecordingSession != null) {
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_CONNECTION_FAILED);
}
}
@@ -217,7 +218,7 @@ public class RecordingTask extends RecordingCallback
|| !sendEmptyMessageAtAbsoluteTime(
MSG_START_RECORDING,
mScheduledRecording.getStartTimeMs() - RECORDING_EARLY_START_OFFSET_MS)) {
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_MESSAGE_NOT_SENT);
}
}
@@ -249,6 +250,7 @@ public class RecordingTask extends RecordingCallback
if (mRecordingSession == null) {
return;
}
+ int error;
switch (reason) {
case TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE:
Log.i(TAG, "Insufficient space to record " + mScheduledRecording);
@@ -284,23 +286,28 @@ public class RecordingTask extends RecordingCallback
}
}
});
- // fall through
+ error = ScheduledRecording.FAILED_REASON_INSUFFICIENT_SPACE;
+ break;
+ case TvInputManager.RECORDING_ERROR_RESOURCE_BUSY:
+ error = ScheduledRecording.FAILED_REASON_RESOURCE_BUSY;
+ break;
default:
- failAndQuit();
+ error = ScheduledRecording.FAILED_REASON_OTHER;
break;
}
+ failAndQuit(error);
}
private void handleInit() {
if (DEBUG) Log.d(TAG, "handleInit " + mScheduledRecording);
if (mScheduledRecording.getEndTimeMs() < mClock.currentTimeMillis()) {
Log.w(TAG, "End time already past, not recording " + mScheduledRecording);
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_PROGRAM_ENDED_BEFORE_RECORDING_STARTED);
return;
}
if (mChannel == null) {
Log.w(TAG, "Null channel for " + mScheduledRecording);
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_INVALID_CHANNEL);
return;
}
if (mChannel.getId() != mScheduledRecording.getChannelId()) {
@@ -310,7 +317,7 @@ public class RecordingTask extends RecordingCallback
+ mChannel
+ " does not match scheduled recording "
+ mScheduledRecording);
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_INVALID_CHANNEL);
return;
}
@@ -329,8 +336,14 @@ public class RecordingTask extends RecordingCallback
}
private void failAndQuit() {
+ failAndQuit(ScheduledRecording.FAILED_REASON_OTHER);
+ }
+
+ private void failAndQuit(Integer reason) {
if (DEBUG) Log.d(TAG, "failAndQuit");
- updateRecordingState(ScheduledRecording.STATE_RECORDING_FAILED);
+ updateRecordingState(
+ ScheduledRecording.STATE_RECORDING_FAILED,
+ reason);
mState = State.ERROR;
sendRemove();
}
@@ -360,7 +373,7 @@ public class RecordingTask extends RecordingCallback
if (!sendEmptyMessageAtAbsoluteTime(
MSG_STOP_RECORDING, mScheduledRecording.getEndTimeMs())) {
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_MESSAGE_NOT_SENT);
}
}
@@ -380,7 +393,7 @@ public class RecordingTask extends RecordingCallback
if (mState == State.RECORDING_STARTED) {
mHandler.removeMessages(MSG_STOP_RECORDING);
if (!sendEmptyMessageAtAbsoluteTime(MSG_STOP_RECORDING, schedule.getEndTimeMs())) {
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_MESSAGE_NOT_SENT);
}
}
}
@@ -435,7 +448,13 @@ public class RecordingTask extends RecordingCallback
}
private void updateRecordingState(@ScheduledRecording.RecordingState int state) {
- if (DEBUG) Log.d(TAG, "Updating the state of " + mScheduledRecording + " to " + state);
+ updateRecordingState(state, null);
+ }
+ private void updateRecordingState(
+ @ScheduledRecording.RecordingState int state, @Nullable Integer reason) {
+ if (DEBUG) {
+ Log.d(TAG, "Updating the state of " + mScheduledRecording + " to " + state);
+ }
mScheduledRecording =
ScheduledRecording.buildFrom(mScheduledRecording).setState(state).build();
runOnMainThread(
@@ -449,11 +468,17 @@ public class RecordingTask extends RecordingCallback
removeRecordedProgram();
} else {
// Update the state based on the object in DataManager in case when it
- // has been
- // updated. mScheduledRecording will be updated from
+ // has been updated. mScheduledRecording will be updated from
// onScheduledRecordingStateChanged.
- mDataManager.updateScheduledRecording(
- ScheduledRecording.buildFrom(schedule).setState(state).build());
+ ScheduledRecording.Builder builder =
+ ScheduledRecording
+ .buildFrom(schedule)
+ .setState(state);
+ if (state == ScheduledRecording.STATE_RECORDING_FAILED
+ && reason != null) {
+ builder.setFailedReason(reason);
+ }
+ mDataManager.updateScheduledRecording(builder.build());
}
}
});
@@ -507,7 +532,9 @@ public class RecordingTask extends RecordingCallback
/** Clean up the task. */
public void cleanUp() {
if (mState == State.RECORDING_STARTED || mState == State.RECORDING_STOP_REQUESTED) {
- updateRecordingState(ScheduledRecording.STATE_RECORDING_FAILED);
+ updateRecordingState(
+ ScheduledRecording.STATE_RECORDING_FAILED,
+ ScheduledRecording.FAILED_REASON_SCHEDULER_STOPPED);
}
release();
if (mHandler != null) {
diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContent.java b/src/com/android/tv/dvr/ui/browse/DetailsContent.java
index 35713666..cba6293b 100644
--- a/src/com/android/tv/dvr/ui/browse/DetailsContent.java
+++ b/src/com/android/tv/dvr/ui/browse/DetailsContent.java
@@ -108,7 +108,8 @@ class DetailsContent {
String description;
if (scheduledRecording.getState() == ScheduledRecording.STATE_RECORDING_FAILED
&& errMsg != null) {
- description = errMsg;
+ description = errMsg
+ + " (Error code: " + scheduledRecording.getFailedReason() + ")";
} else {
description =
!TextUtils.isEmpty(scheduledRecording.getProgramDescription())
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
index 65c58ce8..38d3d582 100644
--- a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
@@ -437,6 +437,9 @@ class ScheduleRowPresenter extends RowPresenter {
// TODO(b/72638385): show real error messages
// TODO(b/72638385): use a better name for ConflictInfoXXX
conflictInfo = "Failed";
+ if (schedule.getFailedReason() != null) {
+ conflictInfo += " (Error code: " + schedule.getFailedReason() + ")";
+ }
} else if (mDvrScheduleManager.isPartiallyConflicting(row.getSchedule())) {
conflictInfo = mTunerConflictWillBePartiallyRecordedInfo;
} else {