blob: 16afbdef79a153e9976cdac453957059a299c6c4 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tv.dvr.ui;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.tv.TvInputManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityOptionsCompat;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.TextAppearanceSpan;
import android.widget.ImageView;
import android.widget.Toast;
import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.common.BuildConfig;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.recording.RecordingStorageStatusManager;
import com.android.tv.common.util.CommonUtils;
import com.android.tv.data.BaseProgram;
import com.android.tv.data.Program;
import com.android.tv.data.api.Channel;
import com.android.tv.dialog.HalfSizedDialogFragment;
import com.android.tv.dvr.DvrManager;
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.provider.EpisodicProgramLoadTask;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrAlreadyRecordedDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrAlreadyScheduledDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrChannelRecordDurationOptionDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrChannelWatchConflictDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrFutureProgramInfoDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrInsufficientSpaceErrorDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrMissingStorageErrorDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrNoFreeSpaceErrorDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrProgramConflictDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrScheduleDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrSmallSizedStorageErrorDialogFragment;
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrStopRecordingDialogFragment;
import com.android.tv.dvr.ui.browse.DvrBrowseActivity;
import com.android.tv.dvr.ui.browse.DvrDetailsActivity;
import com.android.tv.dvr.ui.list.DvrHistoryActivity;
import com.android.tv.dvr.ui.list.DvrSchedulesActivity;
import com.android.tv.dvr.ui.list.DvrSchedulesFragment;
import com.android.tv.dvr.ui.list.DvrSeriesSchedulesFragment;
import com.android.tv.dvr.ui.playback.DvrPlaybackActivity;
import com.android.tv.util.ToastUtils;
import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/** A helper class for DVR UI. */
@MainThread
@TargetApi(Build.VERSION_CODES.N)
public class DvrUiHelper {
private static final String TAG = "DvrUiHelper";
private static ProgressDialog sProgressDialog = null;
/**
* Checks if the storage status is good for recording and shows error messages if needed.
*
* @param recordingRequestRunnable if the storage status is OK to record or users choose to
* perform the operation anyway, this Runnable will run.
*/
public static void checkStorageStatusAndShowErrorMessage(
Activity activity, String inputId, Runnable recordingRequestRunnable) {
if (CommonUtils.isBundledInput(inputId)) {
switch (TvSingletons.getSingletons(activity)
.getRecordingStorageStatusManager()
.getDvrStorageStatus()) {
case RecordingStorageStatusManager.STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL:
showDvrSmallSizedStorageErrorDialog(activity);
return;
case RecordingStorageStatusManager.STORAGE_STATUS_MISSING:
showDvrMissingStorageErrorDialog(activity);
return;
case RecordingStorageStatusManager.STORAGE_STATUS_FREE_SPACE_INSUFFICIENT:
showDvrNoFreeSpaceErrorDialog(activity, recordingRequestRunnable);
return;
default: // fall out
}
}
recordingRequestRunnable.run();
}
/** Shows the schedule dialog. */
public static void showScheduleDialog(
Activity activity, Program program, boolean addCurrentProgramToSeries) {
if (SoftPreconditions.checkNotNull(program) == null) {
return;
}
Bundle args = new Bundle();
args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
args.putBoolean(
DvrScheduleFragment.KEY_ADD_CURRENT_PROGRAM_TO_SERIES, addCurrentProgramToSeries);
showDialogFragment(activity, new DvrScheduleDialogFragment(), args, true, true);
}
/** Shows the recording duration options dialog. */
public static void showChannelRecordDurationOptions(Activity activity, Channel channel) {
if (SoftPreconditions.checkNotNull(channel) == null) {
return;
}
Bundle args = new Bundle();
args.putLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID, channel.getId());
showDialogFragment(activity, new DvrChannelRecordDurationOptionDialogFragment(), args);
}
/** Shows the dialog which says that the new schedule conflicts with others. */
public static void showScheduleConflictDialog(Activity activity, Program program) {
if (program == null) {
return;
}
Bundle args = new Bundle();
args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
showDialogFragment(activity, new DvrProgramConflictDialogFragment(), args, false, true);
}
/** Shows the conflict dialog for the channel watching. */
public static void showChannelWatchConflictDialog(MainActivity activity, Channel channel) {
if (channel == null) {
return;
}
Bundle args = new Bundle();
args.putLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID, channel.getId());
showDialogFragment(activity, new DvrChannelWatchConflictDialogFragment(), args);
}
/** Shows DVR insufficient space error dialog. */
public static void showDvrInsufficientSpaceErrorDialog(
MainActivity activity, Set<String> failedScheduledRecordingInfoSet) {
Bundle args = new Bundle();
ArrayList<String> failedScheduledRecordingInfoArray =
new ArrayList<>(failedScheduledRecordingInfoSet);
args.putStringArrayList(
DvrInsufficientSpaceErrorFragment.FAILED_SCHEDULED_RECORDING_INFOS,
failedScheduledRecordingInfoArray);
showDialogFragment(activity, new DvrInsufficientSpaceErrorDialogFragment(), args);
Utils.clearRecordingFailedReason(
activity, TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
Utils.clearFailedScheduledRecordingInfoSet(activity);
}
/**
* Shows DVR no free space error dialog.
*
* @param recordingRequestRunnable the recording request to be executed when users choose {@link
* DvrGuidedStepFragment#ACTION_RECORD_ANYWAY}.
*/
public static void showDvrNoFreeSpaceErrorDialog(
Activity activity, Runnable recordingRequestRunnable) {
DvrHalfSizedDialogFragment fragment = new DvrNoFreeSpaceErrorDialogFragment();
fragment.setOnActionClickListener(
new HalfSizedDialogFragment.OnActionClickListener() {
@Override
public void onActionClick(long actionId) {
if (actionId == DvrGuidedStepFragment.ACTION_RECORD_ANYWAY) {
recordingRequestRunnable.run();
} else if (actionId == DvrGuidedStepFragment.ACTION_DELETE_RECORDINGS) {
Intent intent = new Intent(activity, DvrBrowseActivity.class);
activity.startActivity(intent);
}
}
});
showDialogFragment(activity, fragment, null);
}
/** Shows DVR missing storage error dialog. */
private static void showDvrMissingStorageErrorDialog(Activity activity) {
showDialogFragment(activity, new DvrMissingStorageErrorDialogFragment(), null);
}
/** Shows DVR small sized storage error dialog. */
public static void showDvrSmallSizedStorageErrorDialog(Activity activity) {
showDialogFragment(activity, new DvrSmallSizedStorageErrorDialogFragment(), null);
}
/** Shows stop recording dialog. */
public static void showStopRecordingDialog(
Activity activity,
long channelId,
int reason,
HalfSizedDialogFragment.OnActionClickListener listener) {
Bundle args = new Bundle();
args.putLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID, channelId);
args.putInt(DvrStopRecordingFragment.KEY_REASON, reason);
DvrHalfSizedDialogFragment fragment = new DvrStopRecordingDialogFragment();
fragment.setOnActionClickListener(listener);
showDialogFragment(activity, fragment, args);
}
/** Shows "already scheduled" dialog. */
public static void showAlreadyScheduleDialog(Activity activity, Program program) {
if (program == null) {
return;
}
Bundle args = new Bundle();
args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
showDialogFragment(activity, new DvrAlreadyScheduledDialogFragment(), args, false, true);
}
/** Shows "already recorded" dialog. */
public static void showAlreadyRecordedDialog(Activity activity, Program program) {
if (program == null) {
return;
}
Bundle args = new Bundle();
args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
showDialogFragment(activity, new DvrAlreadyRecordedDialogFragment(), args, false, true);
}
/** Shows program information dialog. */
public static void showProgramInfoDialog(Activity activity, Program program) {
if (program == null || !BuildConfig.ENG) {
return;
}
Bundle args = new Bundle();
args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
showDialogFragment(activity, new DvrFutureProgramInfoDialogFragment(), args, false, true);
}
/**
* Handle the request of recording a current program. It will handle creating schedules and
* shows the proper dialog and toast message respectively for timed-recording and program
* recording cases.
*
* @param addProgramToSeries denotes whether the program to be recorded should be added into the
* series recording when users choose to record the entire series.
*/
public static void requestRecordingCurrentProgram(
Activity activity, Channel channel, Program program, boolean addProgramToSeries) {
if (program == null) {
DvrUiHelper.showChannelRecordDurationOptions(activity, channel);
} else if (DvrUiHelper.handleCreateSchedule(activity, program, addProgramToSeries)) {
String msg =
activity.getString(
R.string.dvr_msg_current_program_scheduled,
program.getTitle(),
Utils.toTimeString(program.getEndTimeUtcMillis(), false));
Toast.makeText(activity, msg, Toast.LENGTH_SHORT).show();
}
}
/**
* Handle the request of recording a future program. It will handle creating schedules and shows
* the proper toast message.
*
* @param addProgramToSeries denotes whether the program to be recorded should be added into the
* series recording when users choose to record the entire series.
*/
public static void requestRecordingFutureProgram(
Activity activity, Program program, boolean addProgramToSeries) {
if (DvrUiHelper.handleCreateSchedule(activity, program, addProgramToSeries)) {
String msg = activity.getString(R.string.dvr_msg_program_scheduled, program.getTitle());
ToastUtils.show(activity, msg, Toast.LENGTH_SHORT);
}
}
/**
* Handles the action to create the new schedule. It returns {@code true} if the schedule is
* added and there's no additional UI, otherwise {@code false}.
*/
private static boolean handleCreateSchedule(
Activity activity, Program program, boolean addProgramToSeries) {
if (program == null) {
return false;
}
DvrManager dvrManager = TvSingletons.getSingletons(activity).getDvrManager();
if (!program.isEpisodic()) {
// One time recording.
dvrManager.addSchedule(program);
if (!dvrManager.getConflictingSchedules(program).isEmpty()) {
DvrUiHelper.showScheduleConflictDialog(activity, program);
return false;
}
} else {
// Show recorded program rather than the schedule.
RecordedProgram recordedProgram =
dvrManager.getRecordedProgram(
program.getTitle(),
program.getSeasonNumber(),
program.getEpisodeNumber());
if (recordedProgram != null) {
DvrUiHelper.showAlreadyRecordedDialog(activity, program);
return false;
}
ScheduledRecording duplicate =
dvrManager.getScheduledRecording(
program.getTitle(),
program.getSeasonNumber(),
program.getEpisodeNumber());
if (duplicate != null
&& (duplicate.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED
|| duplicate.getState()
== ScheduledRecording.STATE_RECORDING_IN_PROGRESS)) {
DvrUiHelper.showAlreadyScheduleDialog(activity, program);
return false;
}
SeriesRecording seriesRecording = dvrManager.getSeriesRecording(program);
if (seriesRecording == null || seriesRecording.isStopped()) {
DvrUiHelper.showScheduleDialog(activity, program, addProgramToSeries);
return false;
} else {
// Just add the schedule.
dvrManager.addSchedule(program);
}
}
return true;
}
private static void showDialogFragment(
Activity activity, DvrHalfSizedDialogFragment dialogFragment, Bundle args) {
showDialogFragment(activity, dialogFragment, args, false, false);
}
private static void showDialogFragment(
Activity activity,
DvrHalfSizedDialogFragment dialogFragment,
Bundle args,
boolean keepSidePanelHistory,
boolean keepProgramGuide) {
dialogFragment.setArguments(args);
if (activity instanceof MainActivity) {
((MainActivity) activity)
.getOverlayManager()
.showDialogFragment(
DvrHalfSizedDialogFragment.DIALOG_TAG,
dialogFragment,
keepSidePanelHistory,
keepProgramGuide);
} else {
dialogFragment.show(
activity.getFragmentManager(), DvrHalfSizedDialogFragment.DIALOG_TAG);
}
}
/** Checks whether channel watch conflict dialog is open or not. */
public static boolean isChannelWatchConflictDialogShown(MainActivity activity) {
return activity.getOverlayManager().getCurrentDialog()
instanceof DvrChannelWatchConflictDialogFragment;
}
private static ScheduledRecording getEarliestScheduledRecording(
List<ScheduledRecording> recordings) {
ScheduledRecording earlistScheduledRecording = null;
if (!recordings.isEmpty()) {
Collections.sort(
recordings, ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR);
earlistScheduledRecording = recordings.get(0);
}
return earlistScheduledRecording;
}
/**
* Launches DVR playback activity for the give recorded program.
*
* @param programId the ID of the recorded program going to be played.
* @param seekTimeMs the seek position to initial playback.
* @param pinChecked {@code true} if the pin code for parental controls has already been
* verified, otherwise {@code false}.
*/
public static void startPlaybackActivity(
Context context, long programId, long seekTimeMs, boolean pinChecked) {
Intent intent = new Intent(context, DvrPlaybackActivity.class);
intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_ID, programId);
if (seekTimeMs != TvInputManager.TIME_SHIFT_INVALID_TIME) {
intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_SEEK_TIME, seekTimeMs);
}
intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_PIN_CHECKED, pinChecked);
context.startActivity(intent);
}
/** Shows the schedules activity to resolve the tune conflict. */
public static void startSchedulesActivityForTuneConflict(Context context, Channel channel) {
if (channel == null) {
return;
}
List<ScheduledRecording> conflicts =
TvSingletons.getSingletons(context)
.getDvrManager()
.getConflictingSchedulesForTune(channel.getId());
startSchedulesActivity(context, getEarliestScheduledRecording(conflicts));
}
/** Shows the schedules activity to resolve the one time recording conflict. */
public static void startSchedulesActivityForOneTimeRecordingConflict(
Context context, List<ScheduledRecording> conflicts) {
startSchedulesActivity(context, getEarliestScheduledRecording(conflicts));
}
/** Shows the schedules activity with full schedule. */
public static void startDvrHistoryActivity(Context context) {
Intent intent = new Intent(context, DvrHistoryActivity.class);
context.startActivity(intent);
}
/** Shows the schedules activity with full schedule. */
public static void startSchedulesActivity(
Context context, ScheduledRecording focusedScheduledRecording) {
Intent intent = new Intent(context, DvrSchedulesActivity.class);
intent.putExtra(
DvrSchedulesActivity.KEY_SCHEDULES_TYPE, DvrSchedulesActivity.TYPE_FULL_SCHEDULE);
if (focusedScheduledRecording != null) {
intent.putExtra(
DvrSchedulesFragment.SCHEDULES_KEY_SCHEDULED_RECORDING,
focusedScheduledRecording);
}
context.startActivity(intent);
}
/** Shows the schedules activity for series recording. */
public static void startSchedulesActivityForSeries(
Context context, SeriesRecording seriesRecording) {
Intent intent = new Intent(context, DvrSchedulesActivity.class);
intent.putExtra(
DvrSchedulesActivity.KEY_SCHEDULES_TYPE, DvrSchedulesActivity.TYPE_SERIES_SCHEDULE);
intent.putExtra(
DvrSeriesSchedulesFragment.SERIES_SCHEDULES_KEY_SERIES_RECORDING, seriesRecording);
context.startActivity(intent);
}
/**
* Shows the series settings activity.
*
* @param programs list of programs which belong to the series.
*/
public static void startSeriesSettingsActivity(
Context context,
long seriesRecordingId,
@Nullable List<Program> programs,
boolean removeEmptySeriesSchedule,
boolean isWindowTranslucent,
boolean showViewScheduleOptionInDialog,
Program currentProgram) {
SeriesRecording series =
TvSingletons.getSingletons(context)
.getDvrDataManager()
.getSeriesRecording(seriesRecordingId);
if (series == null) {
return;
}
if (programs != null) {
startSeriesSettingsActivityInternal(
context,
seriesRecordingId,
programs,
removeEmptySeriesSchedule,
isWindowTranslucent,
showViewScheduleOptionInDialog,
currentProgram);
} else {
EpisodicProgramLoadTask episodicProgramLoadTask =
new EpisodicProgramLoadTask(context, series) {
@Override
protected void onPostExecute(List<Program> loadedPrograms) {
sProgressDialog.dismiss();
sProgressDialog = null;
startSeriesSettingsActivityInternal(
context,
seriesRecordingId,
loadedPrograms == null
? Collections.EMPTY_LIST
: loadedPrograms,
removeEmptySeriesSchedule,
isWindowTranslucent,
showViewScheduleOptionInDialog,
currentProgram);
}
}.setLoadCurrentProgram(true)
.setLoadDisallowedProgram(true)
.setLoadScheduledEpisode(true)
.setIgnoreChannelOption(true);
sProgressDialog =
ProgressDialog.show(
context,
null,
context.getString(
R.string.dvr_series_progress_message_reading_programs),
true,
true,
new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
episodicProgramLoadTask.cancel(true);
sProgressDialog = null;
}
});
episodicProgramLoadTask.execute();
}
}
private static void startSeriesSettingsActivityInternal(
Context context,
long seriesRecordingId,
@NonNull List<Program> programs,
boolean removeEmptySeriesSchedule,
boolean isWindowTranslucent,
boolean showViewScheduleOptionInDialog,
Program currentProgram) {
SoftPreconditions.checkState(
programs != null, TAG, "Start series settings activity but programs is null");
Intent intent = new Intent(context, DvrSeriesSettingsActivity.class);
intent.putExtra(DvrSeriesSettingsActivity.SERIES_RECORDING_ID, seriesRecordingId);
BigArguments.reset();
BigArguments.setArgument(DvrSeriesSettingsActivity.PROGRAM_LIST, programs);
intent.putExtra(
DvrSeriesSettingsActivity.REMOVE_EMPTY_SERIES_RECORDING, removeEmptySeriesSchedule);
intent.putExtra(DvrSeriesSettingsActivity.IS_WINDOW_TRANSLUCENT, isWindowTranslucent);
intent.putExtra(
DvrSeriesSettingsActivity.SHOW_VIEW_SCHEDULE_OPTION_IN_DIALOG,
showViewScheduleOptionInDialog);
intent.putExtra(DvrSeriesSettingsActivity.CURRENT_PROGRAM, currentProgram);
context.startActivity(intent);
}
/** Shows "series recording scheduled" dialog activity. */
public static void startSeriesScheduledDialogActivity(
Context context,
SeriesRecording seriesRecording,
boolean showViewScheduleOptionInDialog,
List<Program> programs) {
if (seriesRecording == null) {
return;
}
Intent intent = new Intent(context, DvrSeriesScheduledDialogActivity.class);
intent.putExtra(
DvrSeriesScheduledDialogActivity.SERIES_RECORDING_ID, seriesRecording.getId());
intent.putExtra(
DvrSeriesScheduledDialogActivity.SHOW_VIEW_SCHEDULE_OPTION,
showViewScheduleOptionInDialog);
BigArguments.reset();
BigArguments.setArgument(
DvrSeriesScheduledFragment.SERIES_SCHEDULED_KEY_PROGRAMS, programs);
context.startActivity(intent);
}
/**
* Shows the details activity for the DVR items. The type of DVR items may be {@link
* ScheduledRecording}, {@link RecordedProgram}, or {@link SeriesRecording}.
*/
public static void startDetailsActivity(
Activity activity,
Object dvrItem,
@Nullable ImageView imageView,
boolean hideViewSchedule) {
if (dvrItem == null) {
return;
}
Intent intent = new Intent(activity, DvrDetailsActivity.class);
long recordingId;
int viewType;
if (dvrItem instanceof ScheduledRecording) {
ScheduledRecording schedule = (ScheduledRecording) dvrItem;
recordingId = schedule.getId();
if (schedule.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED) {
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 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;
}
} else if (dvrItem instanceof RecordedProgram) {
recordingId = ((RecordedProgram) dvrItem).getId();
viewType = DvrDetailsActivity.RECORDED_PROGRAM_VIEW;
} else if (dvrItem instanceof SeriesRecording) {
recordingId = ((SeriesRecording) dvrItem).getId();
viewType = DvrDetailsActivity.SERIES_RECORDING_VIEW;
} else {
return;
}
intent.putExtra(DvrDetailsActivity.RECORDING_ID, recordingId);
intent.putExtra(DvrDetailsActivity.DETAILS_VIEW_TYPE, viewType);
intent.putExtra(DvrDetailsActivity.HIDE_VIEW_SCHEDULE, hideViewSchedule);
Bundle bundle = null;
if (imageView != null) {
bundle =
ActivityOptionsCompat.makeSceneTransitionAnimation(
activity, imageView, DvrDetailsActivity.SHARED_ELEMENT_NAME)
.toBundle();
}
activity.startActivity(intent, bundle);
}
/** Shows the cancel all dialog for series schedules list. */
public static void showCancelAllSeriesRecordingDialog(
DvrSchedulesActivity activity, SeriesRecording seriesRecording) {
DvrStopSeriesRecordingDialogFragment dvrStopSeriesRecordingDialogFragment =
new DvrStopSeriesRecordingDialogFragment();
Bundle arguments = new Bundle();
arguments.putParcelable(
DvrStopSeriesRecordingFragment.KEY_SERIES_RECORDING, seriesRecording);
dvrStopSeriesRecordingDialogFragment.setArguments(arguments);
dvrStopSeriesRecordingDialogFragment.show(
activity.getFragmentManager(), DvrStopSeriesRecordingDialogFragment.DIALOG_TAG);
}
/** Shows the series deletion activity. */
public static void startSeriesDeletionActivity(Context context, long seriesRecordingId) {
Intent intent = new Intent(context, DvrSeriesDeletionActivity.class);
intent.putExtra(DvrSeriesDeletionActivity.SERIES_RECORDING_ID, seriesRecordingId);
context.startActivity(intent);
}
public static void showAddScheduleToast(
Context context, String title, long startTimeMs, long endTimeMs) {
String msg =
(startTimeMs > System.currentTimeMillis())
? context.getString(R.string.dvr_msg_program_scheduled, title)
: context.getString(
R.string.dvr_msg_current_program_scheduled,
title,
Utils.toTimeString(endTimeMs, false));
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
/** Returns the styled schedule's title with its season and episode number. */
public static CharSequence getStyledTitleWithEpisodeNumber(
Context context, ScheduledRecording schedule, int episodeNumberStyleResId) {
return getStyledTitleWithEpisodeNumber(
context,
schedule.getProgramTitle(),
schedule.getSeasonNumber(),
schedule.getEpisodeNumber(),
episodeNumberStyleResId);
}
/** Returns the styled program's title with its season and episode number. */
public static CharSequence getStyledTitleWithEpisodeNumber(
Context context, BaseProgram program, int episodeNumberStyleResId) {
return getStyledTitleWithEpisodeNumber(
context,
program.getTitle(),
program.getSeasonNumber(),
program.getEpisodeNumber(),
episodeNumberStyleResId);
}
@NonNull
public static CharSequence getStyledTitleWithEpisodeNumber(
Context context,
String title,
String seasonNumber,
String episodeNumber,
int episodeNumberStyleResId) {
if (TextUtils.isEmpty(title)) {
return "";
}
SpannableStringBuilder builder;
if (TextUtils.isEmpty(seasonNumber) || seasonNumber.equals("0")) {
builder =
TextUtils.isEmpty(episodeNumber)
? new SpannableStringBuilder(title)
: new SpannableStringBuilder(Html.fromHtml(context.getString(
R.string.program_title_with_episode_number_no_season,
title,
episodeNumber)));
} else {
builder =
new SpannableStringBuilder(
Html.fromHtml(
context.getString(
R.string.program_title_with_episode_number,
title,
seasonNumber,
episodeNumber)));
}
Object[] spans = builder.getSpans(0, builder.length(), Object.class);
if (spans.length > 0) {
if (episodeNumberStyleResId != 0) {
builder.setSpan(
new TextAppearanceSpan(context, episodeNumberStyleResId),
builder.getSpanStart(spans[0]),
builder.getSpanEnd(spans[0]),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
builder.removeSpan(spans[0]);
}
return new SpannableString(builder);
}
}