| /* |
| * Copyright (C) 2016 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.graphics.drawable.Drawable; |
| import android.media.tv.TvInputInfo; |
| import android.os.Bundle; |
| import android.support.annotation.NonNull; |
| import android.support.annotation.Nullable; |
| import android.support.v17.leanback.widget.GuidanceStylist.Guidance; |
| import android.support.v17.leanback.widget.GuidedAction; |
| import android.util.Log; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import com.android.tv.MainActivity; |
| import com.android.tv.R; |
| import com.android.tv.TvSingletons; |
| import com.android.tv.common.SoftPreconditions; |
| import com.android.tv.data.Program; |
| import com.android.tv.data.api.Channel; |
| import com.android.tv.dvr.data.ScheduledRecording; |
| import com.android.tv.dvr.recorder.ConflictChecker; |
| import com.android.tv.dvr.recorder.ConflictChecker.OnUpcomingConflictChangeListener; |
| import com.android.tv.util.Utils; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| |
| public abstract class DvrConflictFragment extends DvrGuidedStepFragment { |
| private static final String TAG = "DvrConflictFragment"; |
| private static final boolean DEBUG = false; |
| |
| private static final int ACTION_DELETE_CONFLICT = 1; |
| private static final int ACTION_CANCEL = 2; |
| private static final int ACTION_VIEW_SCHEDULES = 3; |
| |
| // The program count which will be listed in the description. This is the number of the |
| // program strings in R.plurals.dvr_program_conflict_dialog_description_many. |
| private static final int LISTED_PROGRAM_COUNT = 2; |
| |
| protected List<ScheduledRecording> mConflicts; |
| |
| void setConflicts(List<ScheduledRecording> conflicts) { |
| mConflicts = conflicts; |
| } |
| |
| List<ScheduledRecording> getConflicts() { |
| return mConflicts; |
| } |
| |
| @Override |
| public int onProvideTheme() { |
| return R.style.Theme_TV_Dvr_Conflict_GuidedStep; |
| } |
| |
| @Override |
| public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) { |
| actions.add( |
| new GuidedAction.Builder(getContext()) |
| .clickAction(GuidedAction.ACTION_ID_OK) |
| .build()); |
| actions.add( |
| new GuidedAction.Builder(getContext()) |
| .id(ACTION_VIEW_SCHEDULES) |
| .title(R.string.dvr_action_view_schedules) |
| .build()); |
| } |
| |
| @Override |
| public void onTrackedGuidedActionClicked(GuidedAction action) { |
| if (action.getId() == ACTION_VIEW_SCHEDULES) { |
| DvrUiHelper.startSchedulesActivityForOneTimeRecordingConflict( |
| getContext(), getConflicts()); |
| } |
| dismissDialog(); |
| } |
| |
| @Override |
| public String getTrackerLabelForGuidedAction(GuidedAction action) { |
| long actionId = getId(); |
| if (actionId == ACTION_VIEW_SCHEDULES) { |
| return "view-schedules"; |
| } else { |
| return super.getTrackerLabelForGuidedAction(action); |
| } |
| } |
| |
| String getConflictDescription() { |
| List<String> titles = new ArrayList<>(); |
| HashSet<String> titleSet = new HashSet<>(); |
| for (ScheduledRecording schedule : getConflicts()) { |
| String scheduleTitle = getScheduleTitle(schedule); |
| if (scheduleTitle != null && !titleSet.contains(scheduleTitle)) { |
| titles.add(scheduleTitle); |
| titleSet.add(scheduleTitle); |
| } |
| } |
| switch (titles.size()) { |
| case 0: |
| Log.i( |
| TAG, |
| "Conflict has been resolved by any reason. Maybe input might have" |
| + " been deleted."); |
| return null; |
| case 1: |
| return getResources() |
| .getString( |
| R.string.dvr_program_conflict_dialog_description_1, titles.get(0)); |
| case 2: |
| return getResources() |
| .getString( |
| R.string.dvr_program_conflict_dialog_description_2, |
| titles.get(0), |
| titles.get(1)); |
| case 3: |
| return getResources() |
| .getString( |
| R.string.dvr_program_conflict_dialog_description_3, |
| titles.get(0), |
| titles.get(1)); |
| default: |
| return getResources() |
| .getQuantityString( |
| R.plurals.dvr_program_conflict_dialog_description_many, |
| titles.size() - LISTED_PROGRAM_COUNT, |
| titles.get(0), |
| titles.get(1), |
| titles.size() - LISTED_PROGRAM_COUNT); |
| } |
| } |
| |
| @Nullable |
| private String getScheduleTitle(ScheduledRecording schedule) { |
| if (schedule.getType() == ScheduledRecording.TYPE_TIMED) { |
| Channel channel = |
| TvSingletons.getSingletons(getContext()) |
| .getChannelDataManager() |
| .getChannel(schedule.getChannelId()); |
| if (channel != null) { |
| return channel.getDisplayName(); |
| } else { |
| return null; |
| } |
| } else { |
| return schedule.getProgramTitle(); |
| } |
| } |
| |
| /** A fragment to show the program conflict. */ |
| public static class DvrProgramConflictFragment extends DvrConflictFragment { |
| private Program mProgram; |
| |
| @Override |
| public View onCreateView( |
| LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
| Bundle args = getArguments(); |
| if (args != null) { |
| mProgram = args.getParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM); |
| } |
| SoftPreconditions.checkArgument(mProgram != null); |
| TvInputInfo input = Utils.getTvInputInfoForProgram(getContext(), mProgram); |
| SoftPreconditions.checkNotNull(input); |
| List<ScheduledRecording> conflicts = null; |
| if (input != null) { |
| conflicts = |
| TvSingletons.getSingletons(getContext()) |
| .getDvrManager() |
| .getConflictingSchedules(mProgram); |
| } |
| if (conflicts == null) { |
| conflicts = Collections.emptyList(); |
| } |
| if (conflicts.isEmpty()) { |
| dismissDialog(); |
| } |
| setConflicts(conflicts); |
| return super.onCreateView(inflater, container, savedInstanceState); |
| } |
| |
| @NonNull |
| @Override |
| public Guidance onCreateGuidance(Bundle savedInstanceState) { |
| String title = getResources().getString(R.string.dvr_program_conflict_dialog_title); |
| String descriptionPrefix = |
| getString( |
| R.string.dvr_program_conflict_dialog_description_prefix, |
| mProgram.getTitle()); |
| String description = getConflictDescription(); |
| if (description == null) { |
| dismissDialog(); |
| } |
| Drawable icon = getResources().getDrawable(R.drawable.quantum_ic_error_white_48, null); |
| return new Guidance(title, descriptionPrefix + " " + description, null, icon); |
| } |
| |
| @Override |
| public String getTrackerPrefix() { |
| return "DvrProgramConflictFragment"; |
| } |
| } |
| |
| /** A fragment to show the channel recording conflict. */ |
| public static class DvrChannelRecordConflictFragment extends DvrConflictFragment { |
| private Channel mChannel; |
| private long mStartTimeMs; |
| private long mEndTimeMs; |
| |
| @Override |
| public View onCreateView( |
| LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
| Bundle args = getArguments(); |
| long channelId = args.getLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID); |
| mChannel = |
| TvSingletons.getSingletons(getContext()) |
| .getChannelDataManager() |
| .getChannel(channelId); |
| SoftPreconditions.checkArgument(mChannel != null); |
| TvInputInfo input = Utils.getTvInputInfoForChannelId(getContext(), mChannel.getId()); |
| SoftPreconditions.checkNotNull(input); |
| List<ScheduledRecording> conflicts = null; |
| if (input != null) { |
| mStartTimeMs = args.getLong(DvrHalfSizedDialogFragment.KEY_START_TIME_MS); |
| mEndTimeMs = args.getLong(DvrHalfSizedDialogFragment.KEY_END_TIME_MS); |
| conflicts = |
| TvSingletons.getSingletons(getContext()) |
| .getDvrManager() |
| .getConflictingSchedules( |
| mChannel.getId(), mStartTimeMs, mEndTimeMs); |
| } |
| if (conflicts == null) { |
| conflicts = Collections.emptyList(); |
| } |
| if (conflicts.isEmpty()) { |
| dismissDialog(); |
| } |
| setConflicts(conflicts); |
| return super.onCreateView(inflater, container, savedInstanceState); |
| } |
| |
| @NonNull |
| @Override |
| public Guidance onCreateGuidance(Bundle savedInstanceState) { |
| String title = getResources().getString(R.string.dvr_channel_conflict_dialog_title); |
| String descriptionPrefix = |
| getString( |
| R.string.dvr_channel_conflict_dialog_description_prefix, |
| mChannel.getDisplayName()); |
| String description = getConflictDescription(); |
| if (description == null) { |
| dismissDialog(); |
| } |
| Drawable icon = getResources().getDrawable(R.drawable.quantum_ic_error_white_48, null); |
| return new Guidance(title, descriptionPrefix + " " + description, null, icon); |
| } |
| |
| @Override |
| public String getTrackerPrefix() { |
| return "DvrChannelRecordConflictFragment"; |
| } |
| } |
| |
| /** |
| * A fragment to show the channel watching conflict. |
| * |
| * <p>This fragment is automatically closed when there are no upcoming conflicts. |
| */ |
| public static class DvrChannelWatchConflictFragment extends DvrConflictFragment |
| implements OnUpcomingConflictChangeListener { |
| private long mChannelId; |
| |
| @Override |
| public View onCreateView( |
| LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
| Bundle args = getArguments(); |
| if (args != null) { |
| mChannelId = args.getLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID); |
| } |
| SoftPreconditions.checkArgument(mChannelId != Channel.INVALID_ID); |
| ConflictChecker checker = ((MainActivity) getContext()).getDvrConflictChecker(); |
| List<ScheduledRecording> conflicts = null; |
| if (checker != null) { |
| checker.addOnUpcomingConflictChangeListener(this); |
| conflicts = checker.getUpcomingConflicts(); |
| if (DEBUG) Log.d(TAG, "onCreateView: upcoming conflicts: " + conflicts); |
| if (conflicts.isEmpty()) { |
| dismissDialog(); |
| } |
| } |
| if (conflicts == null) { |
| if (DEBUG) Log.d(TAG, "onCreateView: There's no conflict."); |
| conflicts = Collections.emptyList(); |
| } |
| if (conflicts.isEmpty()) { |
| dismissDialog(); |
| } |
| setConflicts(conflicts); |
| return super.onCreateView(inflater, container, savedInstanceState); |
| } |
| |
| @NonNull |
| @Override |
| public Guidance onCreateGuidance(Bundle savedInstanceState) { |
| String title = |
| getResources().getString(R.string.dvr_epg_channel_watch_conflict_dialog_title); |
| String description = |
| getResources() |
| .getString(R.string.dvr_epg_channel_watch_conflict_dialog_description); |
| return new Guidance(title, description, null, null); |
| } |
| |
| @Override |
| public void onCreateActions( |
| @NonNull List<GuidedAction> actions, Bundle savedInstanceState) { |
| actions.add( |
| new GuidedAction.Builder(getContext()) |
| .id(ACTION_DELETE_CONFLICT) |
| .title(R.string.dvr_action_delete_schedule) |
| .build()); |
| actions.add( |
| new GuidedAction.Builder(getContext()) |
| .id(ACTION_CANCEL) |
| .title(R.string.dvr_action_record_program) |
| .build()); |
| } |
| |
| @Override |
| public void onTrackedGuidedActionClicked(GuidedAction action) { |
| if (action.getId() == ACTION_CANCEL) { |
| ConflictChecker checker = ((MainActivity) getContext()).getDvrConflictChecker(); |
| if (checker != null) { |
| checker.setCheckedConflictsForChannel(mChannelId, getConflicts()); |
| } |
| } else if (action.getId() == ACTION_DELETE_CONFLICT) { |
| for (ScheduledRecording schedule : mConflicts) { |
| if (schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) { |
| getDvrManager().stopRecording(schedule); |
| } else { |
| getDvrManager().removeScheduledRecording(schedule); |
| } |
| } |
| } |
| super.onGuidedActionClicked(action); |
| } |
| |
| @Override |
| public String getTrackerPrefix() { |
| return "DvrChannelWatchConflictFragment"; |
| } |
| |
| @Override |
| public String getTrackerLabelForGuidedAction(GuidedAction action) { |
| long actionId = action.getId(); |
| if (actionId == ACTION_CANCEL) { |
| return "cancel"; |
| } else if (actionId == ACTION_DELETE_CONFLICT) { |
| return "delete"; |
| } else { |
| return super.getTrackerLabelForGuidedAction(action); |
| } |
| } |
| |
| @Override |
| public void onDetach() { |
| ConflictChecker checker = ((MainActivity) getContext()).getDvrConflictChecker(); |
| if (checker != null) { |
| checker.removeOnUpcomingConflictChangeListener(this); |
| } |
| super.onDetach(); |
| } |
| |
| @Override |
| public void onUpcomingConflictChange() { |
| ConflictChecker checker = ((MainActivity) getContext()).getDvrConflictChecker(); |
| if (checker == null || checker.getUpcomingConflicts().isEmpty()) { |
| if (DEBUG) Log.d(TAG, "onUpcomingConflictChange: There's no conflict."); |
| dismissDialog(); |
| } |
| } |
| } |
| } |