aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/dvr/recorder/RecordingTask.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/dvr/recorder/RecordingTask.java')
-rw-r--r--src/com/android/tv/dvr/recorder/RecordingTask.java362
1 files changed, 201 insertions, 161 deletions
diff --git a/src/com/android/tv/dvr/recorder/RecordingTask.java b/src/com/android/tv/dvr/recorder/RecordingTask.java
index 14888056..07a29e51 100644
--- a/src/com/android/tv/dvr/recorder/RecordingTask.java
+++ b/src/com/android/tv/dvr/recorder/RecordingTask.java
@@ -26,24 +26,24 @@ 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;
import android.widget.Toast;
-
import com.android.tv.InputSessionManager;
import com.android.tv.InputSessionManager.RecordingSession;
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.Clock;
+import com.android.tv.common.util.CommonUtils;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.WritableDvrDataManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.recorder.InputTaskScheduler.HandlerWrapper;
-import com.android.tv.util.Clock;
import com.android.tv.util.Utils;
-
import java.util.Comparator;
import java.util.concurrent.TimeUnit;
@@ -55,58 +55,45 @@ import java.util.concurrent.TimeUnit;
*/
@WorkerThread
@TargetApi(Build.VERSION_CODES.N)
-public class RecordingTask extends RecordingCallback implements Handler.Callback,
- DvrManager.Listener {
+public class RecordingTask extends RecordingCallback
+ implements Handler.Callback, DvrManager.Listener {
private static final String TAG = "RecordingTask";
private static final boolean DEBUG = false;
- /**
- * Compares the end time in ascending order.
- */
- public static final Comparator<RecordingTask> END_TIME_COMPARATOR
- = new Comparator<RecordingTask>() {
- @Override
- public int compare(RecordingTask lhs, RecordingTask rhs) {
- return Long.compare(lhs.getEndTimeMs(), rhs.getEndTimeMs());
- }
- };
-
- /**
- * Compares ID in ascending order.
- */
- public static final Comparator<RecordingTask> ID_COMPARATOR
- = new Comparator<RecordingTask>() {
- @Override
- public int compare(RecordingTask lhs, RecordingTask rhs) {
- return Long.compare(lhs.getScheduleId(), rhs.getScheduleId());
- }
- };
-
- /**
- * Compares the priority in ascending order.
- */
- public static final Comparator<RecordingTask> PRIORITY_COMPARATOR
- = new Comparator<RecordingTask>() {
- @Override
- public int compare(RecordingTask lhs, RecordingTask rhs) {
- return Long.compare(lhs.getPriority(), rhs.getPriority());
- }
- };
+ /** Compares the end time in ascending order. */
+ public static final Comparator<RecordingTask> END_TIME_COMPARATOR =
+ new Comparator<RecordingTask>() {
+ @Override
+ public int compare(RecordingTask lhs, RecordingTask rhs) {
+ return Long.compare(lhs.getEndTimeMs(), rhs.getEndTimeMs());
+ }
+ };
+
+ /** Compares ID in ascending order. */
+ public static final Comparator<RecordingTask> ID_COMPARATOR =
+ new Comparator<RecordingTask>() {
+ @Override
+ public int compare(RecordingTask lhs, RecordingTask rhs) {
+ return Long.compare(lhs.getScheduleId(), rhs.getScheduleId());
+ }
+ };
+
+ /** Compares the priority in ascending order. */
+ public static final Comparator<RecordingTask> PRIORITY_COMPARATOR =
+ new Comparator<RecordingTask>() {
+ @Override
+ public int compare(RecordingTask lhs, RecordingTask rhs) {
+ return Long.compare(lhs.getPriority(), rhs.getPriority());
+ }
+ };
- @VisibleForTesting
- static final int MSG_INITIALIZE = 1;
- @VisibleForTesting
- static final int MSG_START_RECORDING = 2;
- @VisibleForTesting
- static final int MSG_STOP_RECORDING = 3;
- /**
- * Message to update schedule.
- */
+ @VisibleForTesting static final int MSG_INITIALIZE = 1;
+ @VisibleForTesting static final int MSG_START_RECORDING = 2;
+ @VisibleForTesting static final int MSG_STOP_RECORDING = 3;
+ /** Message to update schedule. */
public static final int MSG_UDPATE_SCHEDULE = 4;
- /**
- * The time when the start command will be sent before the recording starts.
- */
+ /** The time when the start command will be sent before the recording starts. */
public static final long RECORDING_EARLY_START_OFFSET_MS = TimeUnit.SECONDS.toMillis(3);
/**
* If the recording starts later than the scheduled start time or ends before the scheduled end
@@ -126,6 +113,7 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
ERROR,
RELEASED,
}
+
private final InputSessionManager mSessionManager;
private final DvrManager mDvrManager;
private final Context mContext;
@@ -142,9 +130,14 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
private Uri mRecordedProgramUri;
private boolean mCanceled;
- RecordingTask(Context context, ScheduledRecording scheduledRecording, Channel channel,
- DvrManager dvrManager, InputSessionManager sessionManager,
- WritableDvrDataManager dataManager, Clock clock) {
+ RecordingTask(
+ Context context,
+ ScheduledRecording scheduledRecording,
+ Channel channel,
+ DvrManager dvrManager,
+ InputSessionManager sessionManager,
+ WritableDvrDataManager dataManager,
+ Clock clock) {
mContext = context;
mScheduledRecording = scheduledRecording;
mChannel = channel;
@@ -163,8 +156,10 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
@Override
public boolean handleMessage(Message msg) {
if (DEBUG) Log.d(TAG, "handleMessage " + msg);
- SoftPreconditions.checkState(msg.what == HandlerWrapper.MESSAGE_REMOVE || mHandler != null,
- TAG, "Null handler trying to handle " + msg);
+ SoftPreconditions.checkState(
+ msg.what == HandlerWrapper.MESSAGE_REMOVE || mHandler != null,
+ TAG,
+ "Null handler trying to handle " + msg);
try {
switch (msg.what) {
case MSG_INITIALIZE:
@@ -185,7 +180,7 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
release();
return false;
default:
- SoftPreconditions.checkArgument(false, TAG, "unexpected message type " + msg);
+ SoftPreconditions.checkArgument(false, TAG, "unexpected message type %s", msg);
break;
}
return true;
@@ -200,7 +195,7 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
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);
}
}
@@ -208,7 +203,7 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
public void onConnectionFailed(String inputId) {
if (DEBUG) Log.d(TAG, "onConnectionFailed(" + inputId + ")");
if (mRecordingSession != null) {
- failAndQuit();
+ failAndQuit(ScheduledRecording.FAILED_REASON_CONNECTION_FAILED);
}
}
@@ -219,23 +214,27 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
return;
}
mState = State.CONNECTED;
- if (mHandler == null || !sendEmptyMessageAtAbsoluteTime(MSG_START_RECORDING,
- mScheduledRecording.getStartTimeMs() - RECORDING_EARLY_START_OFFSET_MS)) {
- failAndQuit();
+ if (mHandler == null
+ || !sendEmptyMessageAtAbsoluteTime(
+ MSG_START_RECORDING,
+ mScheduledRecording.getStartTimeMs() - RECORDING_EARLY_START_OFFSET_MS)) {
+ failAndQuit(ScheduledRecording.FAILED_REASON_MESSAGE_NOT_SENT);
}
}
@Override
public void onRecordingStopped(Uri recordedProgramUri) {
- if (DEBUG) Log.d(TAG, "onRecordingStopped");
+ Log.i(TAG, "Recording Stopped: " + mScheduledRecording);
+ Log.i(TAG, "Recording Stopped: stored as " + recordedProgramUri);
if (mRecordingSession == null) {
return;
}
mRecordedProgramUri = recordedProgramUri;
mState = State.FINISHED;
int state = ScheduledRecording.STATE_RECORDING_FINISHED;
- if (mStartedWithClipping || mScheduledRecording.getEndTimeMs() - CLIPPED_THRESHOLD_MS
- > mClock.currentTimeMillis()) {
+ if (mStartedWithClipping
+ || mScheduledRecording.getEndTimeMs() - CLIPPED_THRESHOLD_MS
+ > mClock.currentTimeMillis()) {
state = ScheduledRecording.STATE_RECORDING_CLIPPED;
}
updateRecordingState(state);
@@ -247,65 +246,89 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
@Override
public void onError(int reason) {
- if (DEBUG) Log.d(TAG, "onError reason " + reason);
+ Log.i(TAG, "Recording failed with code=" + reason + " for " + mScheduledRecording);
if (mRecordingSession == null) {
return;
}
+ int error;
switch (reason) {
case TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE:
- mMainThreadHandler.post(new Runnable() {
- @Override
- public void run() {
- if (TvApplication.getSingletons(mContext).getMainActivityWrapper()
- .isResumed()) {
- ScheduledRecording scheduledRecording = mDataManager
- .getScheduledRecording(mScheduledRecording.getId());
- if (scheduledRecording != null) {
- Toast.makeText(mContext.getApplicationContext(),
- mContext.getString(R.string
- .dvr_error_insufficient_space_description_one_recording,
- scheduledRecording.getProgramDisplayTitle(mContext)),
- Toast.LENGTH_LONG)
- .show();
+ Log.i(TAG, "Insufficient space to record " + mScheduledRecording);
+ mMainThreadHandler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (TvSingletons.getSingletons(mContext)
+ .getMainActivityWrapper()
+ .isResumed()) {
+ ScheduledRecording scheduledRecording =
+ mDataManager.getScheduledRecording(
+ mScheduledRecording.getId());
+ if (scheduledRecording != null) {
+ Toast.makeText(
+ mContext.getApplicationContext(),
+ mContext.getString(
+ R.string
+ .dvr_error_insufficient_space_description_one_recording,
+ scheduledRecording
+ .getProgramDisplayTitle(
+ mContext)),
+ Toast.LENGTH_LONG)
+ .show();
+ }
+ } else {
+ Utils.setRecordingFailedReason(
+ mContext.getApplicationContext(),
+ TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
+ Utils.addFailedScheduledRecordingInfo(
+ mContext.getApplicationContext(),
+ mScheduledRecording.getProgramDisplayTitle(mContext));
+ }
}
- } else {
- Utils.setRecordingFailedReason(mContext.getApplicationContext(),
- TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
- Utils.addFailedScheduledRecordingInfo(mContext.getApplicationContext(),
- mScheduledRecording.getProgramDisplayTitle(mContext));
- }
- }
- });
- // Pass 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()) {
- Log.w(TAG, "Channel" + mChannel + " does not match scheduled recording "
- + mScheduledRecording);
- failAndQuit();
+ Log.w(
+ TAG,
+ "Channel"
+ + mChannel
+ + " does not match scheduled recording "
+ + mScheduledRecording);
+ failAndQuit(ScheduledRecording.FAILED_REASON_INVALID_CHANNEL);
return;
}
String inputId = mChannel.getInputId();
- mRecordingSession = mSessionManager.createRecordingSession(inputId,
- "recordingTask-" + mScheduledRecording.getId(), this,
- mHandler, mScheduledRecording.getEndTimeMs());
+ mRecordingSession =
+ mSessionManager.createRecordingSession(
+ inputId,
+ "recordingTask-" + mScheduledRecording.getId(),
+ this,
+ mHandler,
+ mScheduledRecording.getEndTimeMs());
mState = State.SESSION_ACQUIRED;
mDvrManager.addListener(this, mHandler);
mRecordingSession.tune(inputId, mChannel.getUri());
@@ -313,8 +336,14 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
}
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();
}
@@ -322,16 +351,18 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
private void sendRemove() {
if (DEBUG) Log.d(TAG, "sendRemove");
if (mHandler != null) {
- mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(
- HandlerWrapper.MESSAGE_REMOVE));
+ mHandler.sendMessageAtFrontOfQueue(
+ mHandler.obtainMessage(HandlerWrapper.MESSAGE_REMOVE));
}
}
private void handleStartRecording() {
- if (DEBUG) Log.d(TAG, "handleStartRecording " + mScheduledRecording);
+ Log.i(TAG, "Start Recording: " + mScheduledRecording);
long programId = mScheduledRecording.getProgramId();
- mRecordingSession.startRecording(programId == ScheduledRecording.ID_NOT_SET ? null
- : TvContract.buildProgramUri(programId));
+ mRecordingSession.startRecording(
+ programId == ScheduledRecording.ID_NOT_SET
+ ? null
+ : TvContract.buildProgramUri(programId));
updateRecordingState(ScheduledRecording.STATE_RECORDING_IN_PROGRESS);
// If it starts late, it's clipped.
if (mScheduledRecording.getStartTimeMs() + CLIPPED_THRESHOLD_MS
@@ -340,14 +371,14 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
}
mState = State.RECORDING_STARTED;
- if (!sendEmptyMessageAtAbsoluteTime(MSG_STOP_RECORDING,
- mScheduledRecording.getEndTimeMs())) {
- failAndQuit();
+ if (!sendEmptyMessageAtAbsoluteTime(
+ MSG_STOP_RECORDING, mScheduledRecording.getEndTimeMs())) {
+ failAndQuit(ScheduledRecording.FAILED_REASON_MESSAGE_NOT_SENT);
}
}
private void handleStopRecording() {
- if (DEBUG) Log.d(TAG, "handleStopRecording " + mScheduledRecording);
+ Log.i(TAG, "Stop Recording: " + mScheduledRecording);
mRecordingSession.stopRecording();
mState = State.RECORDING_STOP_REQUESTED;
}
@@ -362,7 +393,7 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
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);
}
}
}
@@ -377,23 +408,17 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
return mScheduledRecording.getId();
}
- /**
- * Returns the priority.
- */
+ /** Returns the priority. */
public long getPriority() {
return mScheduledRecording.getPriority();
}
- /**
- * Returns the start time of the recording.
- */
+ /** Returns the start time of the recording. */
public long getStartTimeMs() {
return mScheduledRecording.getStartTimeMs();
}
- /**
- * Returns the end time of the recording.
- */
+ /** Returns the end time of the recording. */
public long getEndTimeMs() {
return mScheduledRecording.getEndTimeMs();
}
@@ -410,33 +435,53 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
long now = mClock.currentTimeMillis();
long delay = Math.max(0L, when - now);
if (DEBUG) {
- Log.d(TAG, "Sending message " + what + " with a delay of " + delay / 1000
- + " seconds to arrive at " + Utils.toIsoDateTimeString(when));
+ Log.d(
+ TAG,
+ "Sending message "
+ + what
+ + " with a delay of "
+ + delay / 1000
+ + " seconds to arrive at "
+ + CommonUtils.toIsoDateTimeString(when));
}
return mHandler.sendEmptyMessageDelayed(what, delay);
}
private void updateRecordingState(@ScheduledRecording.RecordingState int state) {
- if (DEBUG) Log.d(TAG, "Updating the state of " + mScheduledRecording + " to " + state);
- mScheduledRecording = ScheduledRecording.buildFrom(mScheduledRecording).setState(state)
- .build();
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- ScheduledRecording schedule = mDataManager.getScheduledRecording(
- mScheduledRecording.getId());
- if (schedule == null) {
- // Schedule has been deleted. Delete the recorded program.
- removeRecordedProgram();
- } else {
- // Update the state based on the object in DataManager in case when it has been
- // updated. mScheduledRecording will be updated from
- // onScheduledRecordingStateChanged.
- mDataManager.updateScheduledRecording(ScheduledRecording.buildFrom(schedule)
- .setState(state).build());
- }
- }
- });
+ 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(
+ new Runnable() {
+ @Override
+ public void run() {
+ ScheduledRecording schedule =
+ mDataManager.getScheduledRecording(mScheduledRecording.getId());
+ if (schedule == null) {
+ // Schedule has been deleted. Delete the recorded program.
+ removeRecordedProgram();
+ } else {
+ // Update the state based on the object in DataManager in case when it
+ // has been updated. mScheduledRecording will be updated from
+ // onScheduledRecordingStateChanged.
+ ScheduledRecording.Builder builder =
+ ScheduledRecording
+ .buildFrom(schedule)
+ .setState(state);
+ if (state == ScheduledRecording.STATE_RECORDING_FAILED
+ && reason != null) {
+ builder.setFailedReason(reason);
+ }
+ mDataManager.updateScheduledRecording(builder.build());
+ }
+ }
+ });
}
@Override
@@ -447,16 +492,12 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
stop();
}
- /**
- * Starts the task.
- */
+ /** Starts the task. */
public void start() {
mHandler.sendEmptyMessage(MSG_INITIALIZE);
}
- /**
- * Stops the task.
- */
+ /** Stops the task. */
public void stop() {
if (DEBUG) Log.d(TAG, "stop");
switch (mState) {
@@ -480,9 +521,7 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
}
}
- /**
- * Cancels the task
- */
+ /** Cancels the task */
public void cancel() {
if (DEBUG) Log.d(TAG, "cancel");
mCanceled = true;
@@ -490,12 +529,12 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
removeRecordedProgram();
}
- /**
- * Clean up the task.
- */
+ /** 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) {
@@ -509,14 +548,15 @@ public class RecordingTask extends RecordingCallback implements Handler.Callback
}
private void removeRecordedProgram() {
- runOnMainThread(new Runnable() {
- @Override
- public void run() {
- if (mRecordedProgramUri != null) {
- mDvrManager.removeRecordedProgram(mRecordedProgramUri);
- }
- }
- });
+ runOnMainThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (mRecordedProgramUri != null) {
+ mDvrManager.removeRecordedProgram(mRecordedProgramUri);
+ }
+ }
+ });
}
private void runOnMainThread(Runnable runnable) {