diff options
author | shubang <shubang@google.com> | 2018-02-21 19:30:58 -0800 |
---|---|---|
committer | Nick Chalko <nchalko@google.com> | 2018-02-26 15:40:17 -0800 |
commit | 4fa6d98a418cba109cd550f5808bd86d01b131cf (patch) | |
tree | 925402e83be618c379f00c56c95ea612a45c3fa1 | |
parent | 6a2a9219b9ea3a2a9b56acd7038c9819f8959c35 (diff) | |
download | TV-4fa6d98a418cba109cd550f5808bd86d01b131cf.tar.gz |
Show failed recordings in DVR recent row
PiperOrigin-RevId: 186556969
Change-Id: I3410d9ea1db451d2e4711631ccd530f9179b428d
10 files changed, 160 insertions, 50 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml index 0aec0b30..cea4ee6c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -576,6 +576,8 @@ <string name="dvr_history_card_view_title">Recording History</string> <!-- Description of a card view to show full list of scheduled recordings. [CHAR LIMIT=25] --> <string name="dvr_full_schedule_card_view_title">Full schedule</string> + <!-- Description of failed recordings. [CHAR LIMIT=25] --> + <string name="dvr_recording_failed">Recording Failed</string> <!-- Description of how many following days the schedule list will show. [CHAR LIMIT=25] --> <plurals name="dvr_full_schedule_card_view_content"> <item quantity="one">Next %1$d day</item> diff --git a/src/com/android/tv/dvr/ui/DvrUiHelper.java b/src/com/android/tv/dvr/ui/DvrUiHelper.java index bb23793f..34ab62b6 100644 --- a/src/com/android/tv/dvr/ui/DvrUiHelper.java +++ b/src/com/android/tv/dvr/ui/DvrUiHelper.java @@ -591,6 +591,13 @@ public class DvrUiHelper { && schedule.getRecordedProgramId() != null) { recordingId = schedule.getRecordedProgramId(); viewType = DvrDetailsActivity.RECORDED_PROGRAM_VIEW; + } else if (schedule.getState() == ScheduledRecording.STATE_RECORDING_FAILED) { + viewType = DvrDetailsActivity.SCHEDULED_RECORDING_VIEW; + hideViewSchedule = true; + // TODO(b/72638385): pass detailed error message + intent.putExtra( + DvrDetailsActivity.EXTRA_FAILED_MESSAGE, + activity.getString(R.string.dvr_recording_failed)); } else { return; } @@ -685,13 +692,10 @@ public class DvrUiHelper { builder = TextUtils.isEmpty(episodeNumber) ? new SpannableStringBuilder(title) - : new SpannableStringBuilder( - Html.fromHtml( - context.getString( - R.string - .program_title_with_episode_number_no_season, - title, - episodeNumber))); + : new SpannableStringBuilder(Html.fromHtml(context.getString( + R.string.program_title_with_episode_number_no_season, + title, + episodeNumber))); } else { builder = new SpannableStringBuilder( diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContent.java b/src/com/android/tv/dvr/ui/browse/DetailsContent.java index 56bbdb46..35713666 100644 --- a/src/com/android/tv/dvr/ui/browse/DetailsContent.java +++ b/src/com/android/tv/dvr/ui/browse/DetailsContent.java @@ -99,6 +99,38 @@ class DetailsContent { .build(context); } + static DetailsContent createFromFailedScheduledRecording( + Context context, ScheduledRecording scheduledRecording, String errMsg) { + Channel channel = + TvSingletons.getSingletons(context) + .getChannelDataManager() + .getChannel(scheduledRecording.getChannelId()); + String description; + if (scheduledRecording.getState() == ScheduledRecording.STATE_RECORDING_FAILED + && errMsg != null) { + description = errMsg; + } else { + description = + !TextUtils.isEmpty(scheduledRecording.getProgramDescription()) + ? scheduledRecording.getProgramDescription() + : scheduledRecording.getProgramLongDescription(); + } + if (TextUtils.isEmpty(description)) { + description = channel != null ? channel.getDescription() : null; + } + return new DetailsContent.Builder() + .setChannelId(scheduledRecording.getChannelId()) + .setProgramTitle(scheduledRecording.getProgramTitle()) + .setSeasonNumber(scheduledRecording.getSeasonNumber()) + .setEpisodeNumber(scheduledRecording.getEpisodeNumber()) + .setStartTimeUtcMillis(scheduledRecording.getStartTimeMs()) + .setEndTimeUtcMillis(scheduledRecording.getEndTimeMs()) + .setDescription(description) + .setPosterArtUri(scheduledRecording.getProgramPosterArtUri()) + .setThumbnailUri(scheduledRecording.getProgramThumbnailUri()) + .build(context); + } + private DetailsContent() {} /** Returns title. */ diff --git a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java index 6d66eea1..51019c08 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java +++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java @@ -31,6 +31,7 @@ import android.support.v17.leanback.widget.TitleViewAdapter; import android.util.Log; import android.view.View; import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; + import com.android.tv.R; import com.android.tv.TvFeatures; import com.android.tv.TvSingletons; @@ -46,6 +47,7 @@ import com.android.tv.dvr.data.RecordedProgram; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.data.SeriesRecording; import com.android.tv.dvr.ui.SortedArrayAdapter; + import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -70,7 +72,7 @@ public class DvrBrowseFragment extends BrowseFragment private boolean mShouldShowScheduleRow; private boolean mEntranceTransitionEnded; - private RecordedProgramAdapter mRecentAdapter; + private RecentRowAdapter mRecentAdapter; private ScheduleAdapter mScheduleAdapter; private SeriesAdapter mSeriesAdapter; private RecordedProgramAdapter[] mGenreAdapters = @@ -146,6 +148,52 @@ public class DvrBrowseFragment extends BrowseFragment } }; + private static final Comparator<Object> RECENT_ROW_COMPARATOR = + new Comparator<Object>() { + @Override + public int compare(Object lhs, Object rhs) { + if (lhs instanceof ScheduledRecording) { + if (rhs instanceof ScheduledRecording) { + return ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR + .reversed() + .compare((ScheduledRecording) lhs, (ScheduledRecording) rhs); + } else if (rhs instanceof RecordedProgram) { + ScheduledRecording scheduled = (ScheduledRecording) lhs; + RecordedProgram recorded = (RecordedProgram) rhs; + int compare = + Long.compare( + recorded.getStartTimeUtcMillis(), + scheduled.getStartTimeMs()); + // recorded program first when the start times are the same + return compare == 0 ? 1 : compare; + } else { + return -1; + } + } else if (lhs instanceof RecordedProgram) { + if (rhs instanceof RecordedProgram) { + return RecordedProgram.START_TIME_THEN_ID_COMPARATOR + .reversed() + .compare((RecordedProgram) lhs, (RecordedProgram) rhs); + } else if (rhs instanceof ScheduledRecording) { + RecordedProgram recorded = (RecordedProgram) lhs; + ScheduledRecording scheduled = (ScheduledRecording) rhs; + int compare = + Long.compare( + scheduled.getStartTimeMs(), + recorded.getStartTimeUtcMillis()); + // recorded program first when the start times are the same + return compare == 0 ? -1 : compare; + } else { + return -1; + } + } else { + return !(rhs instanceof RecordedProgram) + && !(rhs instanceof ScheduledRecording) + ? 0 : 1; + } + } + }; + private final DvrScheduleManager.OnConflictStateChangeListener mOnConflictStateChangeListener = new DvrScheduleManager.OnConflictStateChangeListener() { @Override @@ -282,6 +330,8 @@ public class DvrBrowseFragment extends BrowseFragment for (ScheduledRecording scheduleRecording : scheduledRecordings) { if (needToShowScheduledRecording(scheduleRecording)) { mScheduleAdapter.add(scheduleRecording); + } else if (scheduleRecording.getState() == ScheduledRecording.STATE_RECORDING_FAILED) { + mRecentAdapter.add(scheduleRecording); } } } @@ -380,14 +430,15 @@ public class DvrBrowseFragment extends BrowseFragment private boolean startBrowseIfDvrInitialized() { if (mDvrDataManager.isInitialized()) { // Setup rows - mRecentAdapter = new RecordedProgramAdapter(MAX_RECENT_ITEM_COUNT); + mRecentAdapter = new RecentRowAdapter(MAX_RECENT_ITEM_COUNT); mScheduleAdapter = new ScheduleAdapter(MAX_SCHEDULED_ITEM_COUNT); mSeriesAdapter = new SeriesAdapter(); for (int i = 0; i < mGenreAdapters.length; i++) { mGenreAdapters[i] = new RecordedProgramAdapter(); } // Schedule Recordings. - List<ScheduledRecording> schedules = mDvrDataManager.getAllScheduledRecordings(); + // only get not started or in progress recordings + List<ScheduledRecording> schedules = mDvrDataManager.getAvailableScheduledRecordings(); onScheduledRecordingAdded(ScheduledRecording.toArray(schedules)); mScheduleAdapter.addExtraItem(FullScheduleCardHolder.FULL_SCHEDULE_CARD_HOLDER); // Recorded Programs. @@ -395,6 +446,11 @@ public class DvrBrowseFragment extends BrowseFragment handleRecordedProgramAdded(recordedProgram, false); } if (TvFeatures.DVR_FAILED_LIST.isEnabled(getContext())) { + // only get failed recordings + for (ScheduledRecording scheduledRecording + : mDvrDataManager.getFailedScheduledRecordings()) { + onScheduledRecordingAdded(scheduledRecording); + } mRecentAdapter.addExtraItem(DvrHistoryCardHolder.DVR_HISTORY_CARD_HOLDER); } // Series Recordings. Series recordings should be added after recorded programs, because @@ -697,4 +753,22 @@ public class DvrBrowseFragment extends BrowseFragment } } } + + private class RecentRowAdapter extends SortedArrayAdapter<Object> { + RecentRowAdapter(int maxItemCount) { + super(mPresenterSelector, RECENT_ROW_COMPARATOR, maxItemCount); + } + + @Override + public long getId(Object item) { + // We takes the inverse number for the ID of scheduled recordings to make the ID stable. + if (item instanceof ScheduledRecording) { + return -((ScheduledRecording) item).getId() - 1; + } else if (item instanceof RecordedProgram) { + return ((RecordedProgram) item).getId(); + } else { + return -1; + } + } + } } diff --git a/src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java b/src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java index 2659c3f3..0336b319 100644 --- a/src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java +++ b/src/com/android/tv/dvr/ui/browse/DvrDetailsActivity.java @@ -43,6 +43,9 @@ public class DvrDetailsActivity extends Activity implements PinDialogFragment.On /** Name of shared element between activities. */ public static final String SHARED_ELEMENT_NAME = "shared_element"; + /** Name of error message of a failed recording */ + public static final String EXTRA_FAILED_MESSAGE = "failed_message"; + /** CURRENT_RECORDING_VIEW refers to Current Recordings in DVR. */ public static final int CURRENT_RECORDING_VIEW = 1; @@ -65,6 +68,7 @@ public class DvrDetailsActivity extends Activity implements PinDialogFragment.On long recordId = getIntent().getLongExtra(RECORDING_ID, -1); int detailsViewType = getIntent().getIntExtra(DETAILS_VIEW_TYPE, -1); boolean hideViewSchedule = getIntent().getBooleanExtra(HIDE_VIEW_SCHEDULE, false); + String failedMsg = getIntent().getStringExtra(EXTRA_FAILED_MESSAGE); if (recordId != -1 && detailsViewType != -1 && savedInstanceState == null) { Bundle args = new Bundle(); args.putLong(RECORDING_ID, recordId); @@ -73,6 +77,7 @@ public class DvrDetailsActivity extends Activity implements PinDialogFragment.On detailsFragment = new CurrentRecordingDetailsFragment(); } else if (detailsViewType == SCHEDULED_RECORDING_VIEW) { args.putBoolean(HIDE_VIEW_SCHEDULE, hideViewSchedule); + args.putString(EXTRA_FAILED_MESSAGE, failedMsg); detailsFragment = new ScheduledRecordingDetailsFragment(); } else if (detailsViewType == RECORDED_PROGRAM_VIEW) { detailsFragment = new RecordedProgramDetailsFragment(); diff --git a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java index e4d95630..aa2ccf75 100644 --- a/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/RecordingDetailsFragment.java @@ -41,6 +41,10 @@ abstract class RecordingDetailsFragment extends DvrDetailsFragment { return mRecording != null; } + protected ScheduledRecording getScheduledRecording() { + return mRecording; + } + /** Returns {@link ScheduledRecording} for the current fragment. */ public ScheduledRecording getRecording() { return mRecording; diff --git a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java index 0765117d..302b8318 100644 --- a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java +++ b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingDetailsFragment.java @@ -34,11 +34,14 @@ public class ScheduledRecordingDetailsFragment extends RecordingDetailsFragment private DvrManager mDvrManager; private Action mScheduleAction; private boolean mHideViewSchedule; + private String mFailedMessage; @Override public void onCreate(Bundle savedInstance) { + Bundle args = getArguments(); mDvrManager = TvSingletons.getSingletons(getContext()).getDvrManager(); - mHideViewSchedule = getArguments().getBoolean(DvrDetailsActivity.HIDE_VIEW_SCHEDULE); + mHideViewSchedule = args.getBoolean(DvrDetailsActivity.HIDE_VIEW_SCHEDULE); + mFailedMessage = args.getString(DvrDetailsActivity.EXTRA_FAILED_MESSAGE); super.onCreate(savedInstance); } @@ -51,6 +54,17 @@ public class ScheduledRecordingDetailsFragment extends RecordingDetailsFragment } @Override + protected void onCreateInternal() { + if (mFailedMessage == null) { + super.onCreateInternal(); + return; + } + setDetailsOverviewRow( + DetailsContent.createFromFailedScheduledRecording( + getContext(), getScheduledRecording(), mFailedMessage)); + } + + @Override protected SparseArrayObjectAdapter onCreateActionsAdapter() { SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(new ActionPresenterSelector()); diff --git a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java index f1ed52c8..8e028689 100644 --- a/src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java +++ b/src/com/android/tv/dvr/ui/browse/ScheduledRecordingPresenter.java @@ -119,13 +119,21 @@ class ScheduledRecordingPresenter extends DvrItemPresenter<ScheduledRecording> { DetailsContent details = DetailsContent.createFromScheduledRecording(mContext, recording); cardView.setTitle(details.getTitle()); cardView.setImageUri(details.getLogoImageUri(), details.isUsingChannelLogo()); - cardView.setAffiliatedIcon( - mDvrManager.isConflicting(recording) ? R.drawable.ic_warning_white_32dp : 0); + if (mDvrManager.isConflicting(recording)) { + cardView.setAffiliatedIcon(R.drawable.ic_warning_white_32dp); + } else if (recording.getState() == ScheduledRecording.STATE_RECORDING_FAILED) { + cardView.setAffiliatedIcon(R.drawable.ic_error_white_48dp); + } else { + cardView.setAffiliatedIcon(0); + } cardView.setContent(generateMajorContent(recording), null); cardView.setDetailBackgroundImageUri(details.getBackgroundImageUri()); } private String generateMajorContent(ScheduledRecording recording) { + if (recording.getState() == ScheduledRecording.STATE_RECORDING_FAILED) { + return mContext.getString(R.string.dvr_recording_failed); + } int dateDifference = Utils.computeDateDifference(System.currentTimeMillis(), recording.getStartTimeMs()); if (dateDifference <= 0) { diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java index bbccdb15..ef4a4337 100644 --- a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java +++ b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java @@ -27,14 +27,15 @@ import android.support.v17.leanback.widget.ClassPresenterSelector; import android.text.format.DateUtils; import android.util.ArraySet; import android.util.Log; + import com.android.tv.R; -import com.android.tv.TvFeatures; import com.android.tv.TvSingletons; import com.android.tv.common.SoftPreconditions; import com.android.tv.dvr.DvrManager; import com.android.tv.dvr.data.ScheduledRecording; import com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow; import com.android.tv.util.Utils; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -115,33 +116,6 @@ class ScheduleRowAdapter extends ArrayObjectAdapter { } deadLine += ONE_DAY_MS; } - if (TvFeatures.DVR_FAILED_LIST.isEnabled(getContext())) { - List<ScheduledRecording> failedRecordingList = - TvSingletons.getSingletons(mContext) - .getDvrDataManager() - .getFailedScheduledRecordings(); - Collections.sort( - failedRecordingList, - ScheduledRecording.START_TIME_COMPARATOR.reversed()); - if (!failedRecordingList.isEmpty()) { - SchedulesHeaderRow headerRow = - // TODO(b/72638385): use R.string - // TODO(b/72638385): define another HeaderRow class - new DateHeaderRow( - "Failed recordings", - mContext.getResources() - .getQuantityString( - R.plurals.dvr_schedules_section_subtitle, - failedRecordingList.size(), - failedRecordingList.size()), - failedRecordingList.size(), - Long.MAX_VALUE); - add(headerRow); - for (ScheduledRecording recording : failedRecordingList) { - add(new ScheduleRow(recording, headerRow)); - } - } - } sendNextUpdateMessage(System.currentTimeMillis()); } @@ -414,9 +388,7 @@ class ScheduleRowAdapter extends ArrayObjectAdapter { Object item = get(i); if (item instanceof ScheduleRow) { ScheduleRow row = (ScheduleRow) item; - ScheduledRecording recording = row.getSchedule(); - if (row.getEndTimeMs() <= currentTimeMs && (recording == null - || recording.getState() != ScheduledRecording.STATE_RECORDING_FAILED)) { + if (row.getEndTimeMs() <= currentTimeMs) { removeScheduleRow(row); } } diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java index 19fd913c..65c58ce8 100644 --- a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java +++ b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java @@ -478,13 +478,8 @@ class ScheduleRowPresenter extends RowPresenter { /** Returns time text for time view from scheduled recording. */ protected String onGetRecordingTimeText(ScheduleRow row) { - boolean showDate = - TvFeatures.DVR_FAILED_LIST.isEnabled(getContext()) - && row.getSchedule() != null - && row.getSchedule().getState() - == ScheduledRecording.STATE_RECORDING_FAILED; return Utils.getDurationString( - mContext, row.getStartTimeMs(), row.getEndTimeMs(), true, showDate, true, 0); + mContext, row.getStartTimeMs(), row.getEndTimeMs(), true, false, true, 0); } /** Returns program info text for program title view. */ |