aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshubang <shubang@google.com>2018-02-21 15:51:43 -0800
committerNick Chalko <nchalko@google.com>2018-02-26 15:39:54 -0800
commit6a2a9219b9ea3a2a9b56acd7038c9819f8959c35 (patch)
treebd497e58adaaddee7a66391af3e6e0e85ae42dfc
parent7737f2ff103e5f8fecad10d1755cb78760f9135b (diff)
downloadTV-6a2a9219b9ea3a2a9b56acd7038c9819f8959c35.tar.gz
Handle click and row updated/added/removed in DVR history
PiperOrigin-RevId: 186532869 Change-Id: Ida96e009a631ce737b02cf4bf52fe2c8065a2d65
-rw-r--r--res/values/strings.xml5
-rw-r--r--src/com/android/tv/dvr/data/ScheduledRecording.java24
-rw-r--r--src/com/android/tv/dvr/ui/DvrUiHelper.java4
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java100
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java237
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRow.java6
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java12
-rw-r--r--tests/common/src/com/android/tv/testing/dvr/DvrDataManagerInMemoryImpl.java57
-rw-r--r--version.mk6
9 files changed, 404 insertions, 47 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 255d9663..0aec0b30 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -892,7 +892,10 @@
<string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info">Won\'t be recorded due to tuner conflicts.</string>
<!-- Description of no schedule recording for now, and ask user to schedule recordings from
the program guide. -->
- <string name="dvr_schedules_empty_state">There are no recordings on schedule yet.\nYou can schedule recording from the program guide.</string>
+ <string name="dvr_schedules_empty_state">There are no recordings scheduled yet.\nYou can schedule recordings from the program guide.</string>
+ <!-- Description of no recording history for now, and ask user to schedule recordings from
+ the program guide. -->
+ <string name="dvr_history_empty_state">There is no recording history.\nYou can schedule recordings from the program guide.</string>
<!-- Description of schedule list header about how many recordings conflict. -->
<plurals name="dvr_series_schedules_header_description">
<item quantity="one">%1$d recording conflict</item>
diff --git a/src/com/android/tv/dvr/data/ScheduledRecording.java b/src/com/android/tv/dvr/data/ScheduledRecording.java
index bc569d96..01005fd9 100644
--- a/src/com/android/tv/dvr/data/ScheduledRecording.java
+++ b/src/com/android/tv/dvr/data/ScheduledRecording.java
@@ -24,6 +24,7 @@ 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;
@@ -144,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 {
@@ -166,6 +168,7 @@ public final class ScheduledRecording implements Parcelable {
private String mProgramThumbnailUri;
private @RecordingState int mState;
private long mSeriesRecordingId = ID_NOT_SET;
+ private Long mRecodedProgramId;
private Builder() {}
@@ -259,6 +262,11 @@ public final class ScheduledRecording implements Parcelable {
return this;
}
+ public Builder setRecordedProgramId(Long recordedProgramId) {
+ mRecodedProgramId = recordedProgramId;
+ return this;
+ }
+
public ScheduledRecording build() {
return new ScheduledRecording(
mId,
@@ -278,7 +286,8 @@ public final class ScheduledRecording implements Parcelable {
mProgramPosterArtUri,
mProgramThumbnailUri,
mState,
- mSeriesRecordingId);
+ mSeriesRecordingId,
+ mRecodedProgramId);
}
}
@@ -480,6 +489,7 @@ public final class ScheduledRecording implements Parcelable {
private final String mProgramThumbnailUri;
@RecordingState private final int mState;
private final long mSeriesRecordingId;
+ private final Long mRecordedProgramId;
private ScheduledRecording(
long id,
@@ -499,7 +509,8 @@ public final class ScheduledRecording implements Parcelable {
String programPosterArtUri,
String programThumbnailUri,
@RecordingState int state,
- long seriesRecordingId) {
+ long seriesRecordingId,
+ Long recordedProgramId) {
mId = id;
mPriority = priority;
mInputId = inputId;
@@ -518,6 +529,7 @@ public final class ScheduledRecording implements Parcelable {
mProgramThumbnailUri = programThumbnailUri;
mState = state;
mSeriesRecordingId = seriesRecordingId;
+ mRecordedProgramId = recordedProgramId;
}
/**
@@ -615,6 +627,12 @@ public final class ScheduledRecording implements Parcelable {
return mSeriesRecordingId;
}
+ /** Returns the ID of the corresponding {@link RecordedProgram}. */
+ @Nullable
+ public Long getRecordedProgramId() {
+ return mRecordedProgramId;
+ }
+
public long getId() {
return mId;
}
diff --git a/src/com/android/tv/dvr/ui/DvrUiHelper.java b/src/com/android/tv/dvr/ui/DvrUiHelper.java
index e5786895..bb23793f 100644
--- a/src/com/android/tv/dvr/ui/DvrUiHelper.java
+++ b/src/com/android/tv/dvr/ui/DvrUiHelper.java
@@ -587,6 +587,10 @@ public class DvrUiHelper {
viewType = DvrDetailsActivity.SCHEDULED_RECORDING_VIEW;
} else if (schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
viewType = DvrDetailsActivity.CURRENT_RECORDING_VIEW;
+ } else if (schedule.getState() == ScheduledRecording.STATE_RECORDING_FINISHED
+ && schedule.getRecordedProgramId() != null) {
+ recordingId = schedule.getRecordedProgramId();
+ viewType = DvrDetailsActivity.RECORDED_PROGRAM_VIEW;
} else {
return;
}
diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java
index 08dc43c1..0ca05fac 100644
--- a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java
+++ b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java
@@ -25,13 +25,19 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.android.tv.R;
import com.android.tv.TvSingletons;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.data.RecordedProgram;
+import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.ui.list.SchedulesHeaderRowPresenter.DateHeaderRowPresenter;
/** A fragment to show the DVR history. */
-public class DvrHistoryFragment extends DetailsFragment {
+public class DvrHistoryFragment extends DetailsFragment
+ implements DvrDataManager.ScheduledRecordingListener,
+ DvrDataManager.RecordedProgramListener {
private DvrHistoryRowAdapter mRowsAdapter;
private TextView mEmptyInfoScreenView;
+ private DvrDataManager mDvrDataManager;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -46,13 +52,22 @@ public class DvrHistoryFragment extends DetailsFragment {
getContext(), presenterSelector, singletons.getClock());
setAdapter(mRowsAdapter);
mRowsAdapter.start();
+ mDvrDataManager = singletons.getDvrDataManager();
+ mDvrDataManager.addScheduledRecordingListener(this);
+ mDvrDataManager.addRecordedProgramListener(this);
mEmptyInfoScreenView = (TextView) getActivity().findViewById(R.id.empty_info_screen);
- // TODO: handle show/hide message
+ }
+
+ @Override
+ public void onDestroy() {
+ mDvrDataManager.removeScheduledRecordingListener(this);
+ mDvrDataManager.removeRecordedProgramListener(this);
+ super.onDestroy();
}
/** Shows the empty message. */
- void showEmptyMessage(int messageId) {
- mEmptyInfoScreenView.setText(messageId);
+ void showEmptyMessage() {
+ mEmptyInfoScreenView.setText(R.string.dvr_history_empty_state);
if (mEmptyInfoScreenView.getVisibility() != View.VISIBLE) {
mEmptyInfoScreenView.setVisibility(View.VISIBLE);
}
@@ -71,4 +86,81 @@ public class DvrHistoryFragment extends DetailsFragment {
// Workaround of b/31046014
return null;
}
+
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ if (mRowsAdapter != null) {
+ for (ScheduledRecording recording : scheduledRecordings) {
+ mRowsAdapter.onScheduledRecordingAdded(recording);
+ }
+ if (mRowsAdapter.size() > 0) {
+ hideEmptyMessage();
+ }
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ if (mRowsAdapter != null) {
+ for (ScheduledRecording recording : scheduledRecordings) {
+ mRowsAdapter.onScheduledRecordingRemoved(recording);
+ }
+ if (mRowsAdapter.size() == 0) {
+ showEmptyMessage();
+ }
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
+ if (mRowsAdapter != null) {
+ for (ScheduledRecording recording : scheduledRecordings) {
+ mRowsAdapter.onScheduledRecordingUpdated(recording);
+ }
+ if (mRowsAdapter.size() == 0) {
+ showEmptyMessage();
+ } else {
+ hideEmptyMessage();
+ }
+ }
+ }
+
+ @Override
+ public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
+ if (mRowsAdapter != null) {
+ for (RecordedProgram p : recordedPrograms) {
+ mRowsAdapter.onScheduledRecordingAdded(p);
+ }
+ if (mRowsAdapter.size() > 0) {
+ hideEmptyMessage();
+ }
+ }
+
+ }
+
+ @Override
+ public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) {
+ if (mRowsAdapter != null) {
+ for (RecordedProgram program : recordedPrograms) {
+ mRowsAdapter.onScheduledRecordingUpdated(program);
+ }
+ if (mRowsAdapter.size() == 0) {
+ showEmptyMessage();
+ } else {
+ hideEmptyMessage();
+ }
+ }
+ }
+
+ @Override
+ public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
+ if (mRowsAdapter != null) {
+ for (RecordedProgram p : recordedPrograms) {
+ mRowsAdapter.onScheduledRecordingRemoved(p);
+ }
+ if (mRowsAdapter.size() == 0) {
+ showEmptyMessage();
+ }
+ }
+ }
}
diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java
index ac828eb8..156d1a7e 100644
--- a/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java
+++ b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java
@@ -19,11 +19,14 @@ package com.android.tv.dvr.ui.list;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build.VERSION_CODES;
+import android.support.annotation.Nullable;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.ClassPresenterSelector;
import android.text.format.DateUtils;
+import android.util.Log;
import com.android.tv.R;
import com.android.tv.TvSingletons;
+import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.util.Clock;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.data.RecordedProgram;
@@ -32,14 +35,17 @@ import com.android.tv.dvr.recorder.ScheduledProgramReaper;
import com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow;
import com.android.tv.util.Utils;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
/** An adapter for DVR history. */
@TargetApi(VERSION_CODES.N)
@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
class DvrHistoryRowAdapter extends ArrayObjectAdapter {
- // TODO: handle row added/removed/updated
+ private static final String TAG = "DvrHistoryRowAdapter";
+ private static final boolean DEBUG = false;
private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);
private static final int MAX_HISTORY_DAYS = ScheduledProgramReaper.DAYS;
@@ -48,6 +54,7 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter {
private final Clock mClock;
private final DvrDataManager mDvrDataManager;
private final List<String> mTitles = new ArrayList<>();
+ private final Map<Long, ScheduledRecording> mRecordedProgramScheduleMap = new HashMap<>();
public DvrHistoryRowAdapter(
Context context, ClassPresenterSelector classPresenterSelector, Clock clock) {
@@ -121,18 +128,226 @@ class DvrHistoryRowAdapter extends ArrayObjectAdapter {
}
private List<ScheduledRecording> recordedProgramsToScheduledRecordings(
- List<RecordedProgram> recordedPrograms, int maxDays) {
- List<ScheduledRecording> result = new ArrayList<>(recordedPrograms.size());
- long firstMillisecondToday = Utils.getFirstMillisecondOfDay(mClock.currentTimeMillis());
- for (RecordedProgram recordedProgram : recordedPrograms) {
- if (maxDays
- < Utils.computeDateDifference(
- recordedProgram.getStartTimeUtcMillis(),
- firstMillisecondToday)) {
- continue;
+ List<RecordedProgram> programs, int maxDays) {
+ List<ScheduledRecording> result = new ArrayList<>();
+ for (RecordedProgram recordedProgram : programs) {
+ ScheduledRecording scheduledRecording =
+ recordedProgramsToScheduledRecordings(recordedProgram, maxDays);
+ if (scheduledRecording != null) {
+ result.add(scheduledRecording);
}
- result.add(ScheduledRecording.builder(recordedProgram).build());
}
return result;
}
+
+ @Nullable
+ private ScheduledRecording recordedProgramsToScheduledRecordings(
+ RecordedProgram program, int maxDays) {
+ long firstMillisecondToday = Utils.getFirstMillisecondOfDay(mClock.currentTimeMillis());
+ if (maxDays
+ < Utils.computeDateDifference(
+ program.getStartTimeUtcMillis(),
+ firstMillisecondToday)) {
+ return null;
+ }
+ ScheduledRecording scheduledRecording = ScheduledRecording.builder(program).build();
+ mRecordedProgramScheduleMap.put(program.getId(), scheduledRecording);
+ return scheduledRecording;
+ }
+
+ public void onScheduledRecordingAdded(ScheduledRecording schedule) {
+ if (DEBUG) {
+ Log.d(TAG, "onScheduledRecordingAdded: " + schedule);
+ }
+ if (findRowByScheduledRecording(schedule) == null
+ && (schedule.getState() == ScheduledRecording.STATE_RECORDING_FINISHED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_CLIPPED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_FAILED)) {
+ addScheduleRow(schedule);
+ }
+ }
+
+ public void onScheduledRecordingAdded(RecordedProgram program) {
+ if (DEBUG) {
+ Log.d(TAG, "onScheduledRecordingAdded: " + program);
+ }
+ if (mRecordedProgramScheduleMap.get(program.getId()) != null) {
+ return;
+ }
+ ScheduledRecording schedule =
+ recordedProgramsToScheduledRecordings(program, MAX_HISTORY_DAYS);
+ if (schedule == null) {
+ return;
+ }
+ addScheduleRow(schedule);
+ }
+
+ public void onScheduledRecordingRemoved(ScheduledRecording schedule) {
+ if (DEBUG) {
+ Log.d(TAG, "onScheduledRecordingRemoved: " + schedule);
+ }
+ ScheduleRow row = findRowByScheduledRecording(schedule);
+ if (row != null) {
+ removeScheduleRow(row);
+ notifyArrayItemRangeChanged(indexOf(row), 1);
+ }
+ }
+
+ public void onScheduledRecordingRemoved(RecordedProgram program) {
+ if (DEBUG) {
+ Log.d(TAG, "onScheduledRecordingRemoved: " + program);
+ }
+ ScheduledRecording scheduledRecording = mRecordedProgramScheduleMap.get(program.getId());
+ if (scheduledRecording != null) {
+ mRecordedProgramScheduleMap.remove(program.getId());
+ ScheduleRow row = findRowByRecordedProgram(program);
+ if (row != null) {
+ removeScheduleRow(row);
+ notifyArrayItemRangeChanged(indexOf(row), 1);
+ }
+ }
+ }
+
+ public void onScheduledRecordingUpdated(ScheduledRecording schedule) {
+ if (DEBUG) {
+ Log.d(TAG, "onScheduledRecordingUpdated: " + schedule);
+ }
+ ScheduleRow row = findRowByScheduledRecording(schedule);
+ if (row != null) {
+ row.setSchedule(schedule);
+ if (schedule.getState() != ScheduledRecording.STATE_RECORDING_FAILED) {
+ // Only handle failed schedules. Finished schedules are handled as recorded programs
+ removeScheduleRow(row);
+ }
+ notifyArrayItemRangeChanged(indexOf(row), 1);
+ }
+ }
+
+ public void onScheduledRecordingUpdated(RecordedProgram program) {
+ if (DEBUG) {
+ Log.d(TAG, "onScheduledRecordingUpdated: " + program);
+ }
+ ScheduleRow row = findRowByRecordedProgram(program);
+ if (row != null) {
+ removeScheduleRow(row);
+ notifyArrayItemRangeChanged(indexOf(row), 1);
+ ScheduledRecording schedule = mRecordedProgramScheduleMap.get(program.getId());
+ if (schedule != null) {
+ mRecordedProgramScheduleMap.remove(program.getId());
+ }
+ }
+ onScheduledRecordingAdded(program);
+ }
+
+ private void addScheduleRow(ScheduledRecording recording) {
+ // This method must not be called from inherited class.
+ SoftPreconditions.checkState(getClass().equals(DvrHistoryRowAdapter.class));
+ if (recording != null) {
+ int pre = -1;
+ int index = 0;
+ for (; index < size(); index++) {
+ if (get(index) instanceof ScheduleRow) {
+ ScheduleRow scheduleRow = (ScheduleRow) get(index);
+ if (ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed()
+ .compare(scheduleRow.getSchedule(), recording) > 0) {
+ break;
+ }
+ pre = index;
+ }
+ }
+ long deadLine = Utils.getFirstMillisecondOfDay(recording.getStartTimeMs());
+ if (pre >= 0 && getHeaderRow(pre).getDeadLineMs() == deadLine) {
+ SchedulesHeaderRow headerRow = ((ScheduleRow) get(pre)).getHeaderRow();
+ headerRow.setItemCount(headerRow.getItemCount() + 1);
+ ScheduleRow addedRow = new ScheduleRow(recording, headerRow);
+ add(++pre, addedRow);
+ updateHeaderDescription(headerRow);
+ } else if (index < size() && getHeaderRow(index).getDeadLineMs() == deadLine) {
+ SchedulesHeaderRow headerRow = ((ScheduleRow) get(index)).getHeaderRow();
+ headerRow.setItemCount(headerRow.getItemCount() + 1);
+ ScheduleRow addedRow = new ScheduleRow(recording, headerRow);
+ add(index, addedRow);
+ updateHeaderDescription(headerRow);
+ } else {
+ SchedulesHeaderRow headerRow =
+ new DateHeaderRow(
+ calculateHeaderDate(deadLine),
+ mContext.getResources()
+ .getQuantityString(
+ R.plurals.dvr_schedules_section_subtitle, 1, 1),
+ 1,
+ deadLine);
+ add(++pre, headerRow);
+ ScheduleRow addedRow = new ScheduleRow(recording, headerRow);
+ add(pre, addedRow);
+ }
+ }
+ }
+
+ private DateHeaderRow getHeaderRow(int index) {
+ return ((DateHeaderRow) ((ScheduleRow) get(index)).getHeaderRow());
+ }
+
+ /** Gets which {@link ScheduleRow} the {@link ScheduledRecording} belongs to. */
+ private ScheduleRow findRowByScheduledRecording(ScheduledRecording recording) {
+ if (recording == null) {
+ return null;
+ }
+ for (int i = 0; i < size(); i++) {
+ Object item = get(i);
+ if (item instanceof ScheduleRow && ((ScheduleRow) item).getSchedule() != null) {
+ if (((ScheduleRow) item).getSchedule().getId() == recording.getId()) {
+ return (ScheduleRow) item;
+ }
+ }
+ }
+ return null;
+ }
+
+ private ScheduleRow findRowByRecordedProgram(RecordedProgram program) {
+ if (program == null) {
+ return null;
+ }
+ for (int i = 0; i < size(); i++) {
+ Object item = get(i);
+ if (item instanceof ScheduleRow) {
+ ScheduleRow row = (ScheduleRow) item;
+ if (row.hasRecordedProgram()
+ && row.getSchedule().getRecordedProgramId() == program.getId()) {
+ return (ScheduleRow) item;
+ }
+ }
+ }
+ return null;
+ }
+
+ private void removeScheduleRow(ScheduleRow scheduleRow) {
+ // This method must not be called from inherited class.
+ SoftPreconditions.checkState(getClass().equals(DvrHistoryRowAdapter.class));
+ if (scheduleRow != null) {
+ scheduleRow.setSchedule(null);
+ SchedulesHeaderRow headerRow = scheduleRow.getHeaderRow();
+ remove(scheduleRow);
+ // Changes the count information of header which the removed row belongs to.
+ if (headerRow != null) {
+ int currentCount = headerRow.getItemCount();
+ headerRow.setItemCount(--currentCount);
+ if (headerRow.getItemCount() == 0) {
+ remove(headerRow);
+ } else {
+ replace(indexOf(headerRow), headerRow);
+ updateHeaderDescription(headerRow);
+ }
+ }
+ }
+ }
+
+ private void updateHeaderDescription(SchedulesHeaderRow headerRow) {
+ headerRow.setDescription(
+ mContext.getResources()
+ .getQuantityString(
+ R.plurals.dvr_schedules_section_subtitle,
+ headerRow.getItemCount(),
+ headerRow.getItemCount()));
+ }
}
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRow.java b/src/com/android/tv/dvr/ui/list/ScheduleRow.java
index ce5f9516..b739c18f 100644
--- a/src/com/android/tv/dvr/ui/list/ScheduleRow.java
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRow.java
@@ -129,6 +129,12 @@ class ScheduleRow {
|| mSchedule.getState() == ScheduledRecording.STATE_RECORDING_FINISHED);
}
+ public boolean hasRecordedProgram() {
+ return mSchedule != null
+ && mSchedule.getRecordedProgramId() != null
+ && mSchedule.getState() == ScheduledRecording.STATE_RECORDING_FINISHED;
+ }
+
/** Creates and returns the new schedule with the existing information. */
public ScheduledRecording.Builder createNewScheduleBuilder() {
return mSchedule != null ? ScheduledRecording.buildFrom(mSchedule) : null;
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
index 48430956..19fd913c 100644
--- a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
@@ -511,9 +511,10 @@ class ScheduleRowPresenter extends RowPresenter {
private boolean isInfoClickable(ScheduleRow row) {
ScheduledRecording schedule = row.getSchedule();
- // TODO: handle onClicked for finished schedules
return schedule != null
- && (schedule.isNotStarted() || schedule.isInProgress() || schedule.isFinished());
+ && (schedule.isNotStarted()
+ || schedule.isInProgress()
+ || schedule.isFinished());
}
/** Called when the button in a row is clicked. */
@@ -810,7 +811,7 @@ class ScheduleRowPresenter extends RowPresenter {
if (row.getSchedule() != null) {
if (row.isRecordingInProgress()) {
return new int[] {ACTION_STOP_RECORDING};
- } else if (row.isOnAir()) {
+ } else if (row.isOnAir() && !row.hasRecordedProgram()) {
if (row.isRecordingNotStarted()) {
if (canResolveConflict()) {
// The "START" action can change the conflict states.
@@ -865,8 +866,9 @@ class ScheduleRowPresenter extends RowPresenter {
/** Checks if the row should be grayed out. */
protected boolean shouldBeGrayedOut(ScheduleRow row) {
return row.getSchedule() == null
- || (row.isOnAir() && !row.isRecordingInProgress())
+ || (row.isOnAir() && !row.isRecordingInProgress() && !row.hasRecordedProgram())
|| mDvrManager.isConflicting(row.getSchedule())
- || row.isScheduleCanceled();
+ || row.isScheduleCanceled()
+ || row.isRecordingFailed();
}
}
diff --git a/tests/common/src/com/android/tv/testing/dvr/DvrDataManagerInMemoryImpl.java b/tests/common/src/com/android/tv/testing/dvr/DvrDataManagerInMemoryImpl.java
index 70e8bfb6..b8a055c7 100644
--- a/tests/common/src/com/android/tv/testing/dvr/DvrDataManagerInMemoryImpl.java
+++ b/tests/common/src/com/android/tv/testing/dvr/DvrDataManagerInMemoryImpl.java
@@ -145,13 +145,17 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
/** Add a new scheduled recording. */
@Override
public void addScheduledRecording(ScheduledRecording... scheduledRecordings) {
+ addScheduledRecording(false, scheduledRecordings);
+ }
+
+ public void addScheduledRecording(boolean keepIds, ScheduledRecording... scheduledRecordings) {
for (ScheduledRecording r : scheduledRecordings) {
- addScheduledRecordingInternal(r);
+ addScheduledRecordingInternal(r, keepIds);
}
}
public void addRecordedProgram(RecordedProgram recordedProgram) {
- addRecordedProgramInternal(recordedProgram);
+ addRecordedProgramInternal(recordedProgram, false);
}
public void updateRecordedProgram(RecordedProgram r) {
@@ -170,29 +174,42 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
}
public ScheduledRecording addScheduledRecordingInternal(ScheduledRecording scheduledRecording) {
- SoftPreconditions.checkState(
- scheduledRecording.getId() == ScheduledRecording.ID_NOT_SET,
- TAG,
- "expected id of "
- + ScheduledRecording.ID_NOT_SET
- + " but was "
- + scheduledRecording);
- scheduledRecording =
- ScheduledRecording.buildFrom(scheduledRecording)
- .setId(mNextId.incrementAndGet())
- .build();
+ return addScheduledRecordingInternal(scheduledRecording, false);
+ }
+
+ public ScheduledRecording addScheduledRecordingInternal(
+ ScheduledRecording scheduledRecording, boolean keepId) {
+ if (!keepId) {
+ SoftPreconditions.checkState(
+ scheduledRecording.getId() == ScheduledRecording.ID_NOT_SET,
+ TAG,
+ "expected id of "
+ + ScheduledRecording.ID_NOT_SET
+ + " but was "
+ + scheduledRecording);
+ scheduledRecording =
+ ScheduledRecording.buildFrom(scheduledRecording)
+ .setId(mNextId.incrementAndGet())
+ .build();
+ }
mScheduledRecordings.put(scheduledRecording.getId(), scheduledRecording);
notifyScheduledRecordingAdded(scheduledRecording);
return scheduledRecording;
}
- public RecordedProgram addRecordedProgramInternal(RecordedProgram recordedProgram) {
- SoftPreconditions.checkState(
- recordedProgram.getId() == RecordedProgram.ID_NOT_SET,
- TAG,
- "expected id of " + RecordedProgram.ID_NOT_SET + " but was " + recordedProgram);
- recordedProgram =
- RecordedProgram.buildFrom(recordedProgram).setId(mNextId.incrementAndGet()).build();
+ public RecordedProgram addRecordedProgramInternal(
+ RecordedProgram recordedProgram, boolean keepId) {
+ if (!keepId) {
+ SoftPreconditions.checkState(
+ recordedProgram.getId() == RecordedProgram.ID_NOT_SET,
+ TAG,
+ "expected id of " + RecordedProgram.ID_NOT_SET + " but was " + recordedProgram);
+ recordedProgram =
+ RecordedProgram
+ .buildFrom(recordedProgram)
+ .setId(mNextId.incrementAndGet())
+ .build();
+ }
mRecordedPrograms.put(recordedProgram.getId(), recordedProgram);
notifyRecordedProgramsAdded(recordedProgram);
return recordedProgram;
diff --git a/version.mk b/version.mk
index 375249e9..57f3a43b 100644
--- a/version.mk
+++ b/version.mk
@@ -58,7 +58,7 @@ code_version_build := 001
#####################################################
#####################################################
# Collect automatic version code parameters
-ifeq ($(strip $(HAS_BUILD_NUMBER)),false)
+ifneq "" "$(filter eng.%,$(BUILD_NUMBER))"
# This is an eng build
base_version_buildtype := 0
else
@@ -94,12 +94,12 @@ version_code_package := $(code_version_major)$(base_version_minor)$(code_version
# and hh is the git hash
# On eng builds, the BUILD_NUMBER has the user and timestamp inline
ifdef TARGET_BUILD_APPS
-ifeq ($(strip $(HAS_BUILD_NUMBER)),false)
+ifneq "" "$(filter eng.%,$(BUILD_NUMBER))"
git_hash := $(shell git --git-dir $(LOCAL_PATH)/.git log -n 1 --pretty=format:%h)
date_string := $(shell date +%Y-%m-%d)
version_name_package := $(base_version_major).$(base_version_minor).$(code_version_build) (eng.$(USER).$(git_hash).$(date_string)-$(base_version_arch)$(base_version_density))
else
- version_name_package := $(base_version_major).$(base_version_minor).$(code_version_build) ($(BUILD_NUMBER_FROM_FILE)-$(base_version_arch)$(base_version_density))
+ version_name_package := $(base_version_major).$(base_version_minor).$(code_version_build) ($(BUILD_NUMBER)-$(base_version_arch)$(base_version_density))
endif
else # !TARGET_BUILD_APPS
version_name_package := $(base_version_major).$(base_version_minor).$(code_version_build)