1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.tv.dvr.ui.list; 18 19 import android.annotation.TargetApi; 20 import android.content.Context; 21 import android.database.ContentObserver; 22 import android.media.tv.TvContract.Programs; 23 import android.net.Uri; 24 import android.os.Build; 25 import android.os.Bundle; 26 import android.os.Handler; 27 import android.os.Looper; 28 import android.transition.Fade; 29 import android.view.LayoutInflater; 30 import android.view.View; 31 import android.view.ViewGroup; 32 33 import androidx.leanback.widget.ClassPresenterSelector; 34 35 import com.android.tv.R; 36 import com.android.tv.TvSingletons; 37 import com.android.tv.data.ChannelDataManager; 38 import com.android.tv.data.ProgramImpl; 39 import com.android.tv.data.api.Program; 40 import com.android.tv.dvr.DvrDataManager; 41 import com.android.tv.dvr.DvrDataManager.SeriesRecordingListener; 42 import com.android.tv.dvr.data.SeriesRecording; 43 import com.android.tv.dvr.provider.EpisodicProgramLoadTask; 44 import com.android.tv.dvr.ui.BigArguments; 45 46 import java.util.Collections; 47 import java.util.List; 48 49 /** A fragment to show the list of series schedule recordings. */ 50 @TargetApi(Build.VERSION_CODES.N) 51 public class DvrSeriesSchedulesFragment extends BaseDvrSchedulesFragment { 52 /** 53 * The key for series recording whose scheduled recording list will be displayed. Type: {@link 54 * SeriesRecording} 55 */ 56 public static final String SERIES_SCHEDULES_KEY_SERIES_RECORDING = 57 "series_schedules_key_series_recording"; 58 /** 59 * The key for programs which belong to the series recording whose scheduled recording list will 60 * be displayed. Type: List<{@link ProgramImpl}> 61 */ 62 public static final String SERIES_SCHEDULES_KEY_SERIES_PROGRAMS = 63 "series_schedules_key_series_programs"; 64 65 private ChannelDataManager mChannelDataManager; 66 private DvrDataManager mDvrDataManager; 67 private SeriesRecording mSeriesRecording; 68 private List<Program> mPrograms; 69 private EpisodicProgramLoadTask mProgramLoadTask; 70 71 private final SeriesRecordingListener mSeriesRecordingListener = 72 new SeriesRecordingListener() { 73 @Override 74 public void onSeriesRecordingAdded(SeriesRecording... seriesRecordings) {} 75 76 @Override 77 public void onSeriesRecordingRemoved(SeriesRecording... seriesRecordings) { 78 for (SeriesRecording r : seriesRecordings) { 79 if (r.getId() == mSeriesRecording.getId()) { 80 getActivity().finish(); 81 return; 82 } 83 } 84 } 85 86 @Override 87 public void onSeriesRecordingChanged(SeriesRecording... seriesRecordings) { 88 for (SeriesRecording r : seriesRecordings) { 89 if (r.getId() == mSeriesRecording.getId() 90 && getRowsAdapter() instanceof SeriesScheduleRowAdapter) { 91 ((SeriesScheduleRowAdapter) getRowsAdapter()) 92 .onSeriesRecordingUpdated(r); 93 mSeriesRecording = r; 94 updateEmptyMessage(); 95 return; 96 } 97 } 98 } 99 }; 100 101 private final Handler mHandler = new Handler(Looper.getMainLooper()); 102 private final ContentObserver mContentObserver = 103 new ContentObserver(mHandler) { 104 @Override 105 public void onChange(boolean selfChange, Uri uri) { 106 super.onChange(selfChange, uri); 107 executeProgramLoadingTask(); 108 } 109 }; 110 111 private final ChannelDataManager.Listener mChannelListener = 112 new ChannelDataManager.Listener() { 113 @Override 114 public void onLoadFinished() {} 115 116 @Override 117 public void onChannelListUpdated() { 118 executeProgramLoadingTask(); 119 } 120 121 @Override 122 public void onChannelBrowsableChanged() {} 123 }; 124 DvrSeriesSchedulesFragment()125 public DvrSeriesSchedulesFragment() { 126 setEnterTransition(new Fade(Fade.IN)); 127 } 128 129 @Override onAttach(Context context)130 public void onAttach(Context context) { 131 super.onAttach(context); 132 Bundle args = getArguments(); 133 if (args != null) { 134 mSeriesRecording = args.getParcelable(SERIES_SCHEDULES_KEY_SERIES_RECORDING); 135 mPrograms = 136 (List<Program>) BigArguments.getArgument(SERIES_SCHEDULES_KEY_SERIES_PROGRAMS); 137 BigArguments.reset(); 138 } 139 if (args == null || mPrograms == null) { 140 getActivity().finish(); 141 } 142 } 143 144 @Override onCreate(Bundle savedInstanceState)145 public void onCreate(Bundle savedInstanceState) { 146 super.onCreate(savedInstanceState); 147 TvSingletons singletons = TvSingletons.getSingletons(getContext()); 148 mChannelDataManager = singletons.getChannelDataManager(); 149 mChannelDataManager.addListener(mChannelListener); 150 mDvrDataManager = singletons.getDvrDataManager(); 151 mDvrDataManager.addSeriesRecordingListener(mSeriesRecordingListener); 152 getContext() 153 .getContentResolver() 154 .registerContentObserver(Programs.CONTENT_URI, true, mContentObserver); 155 } 156 157 @Override onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)158 public View onCreateView( 159 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 160 onProgramsUpdated(); 161 return super.onCreateView(inflater, container, savedInstanceState); 162 } 163 onProgramsUpdated()164 private void onProgramsUpdated() { 165 ((SeriesScheduleRowAdapter) getRowsAdapter()).setPrograms(mPrograms); 166 updateEmptyMessage(); 167 } 168 updateEmptyMessage()169 private void updateEmptyMessage() { 170 if (mPrograms == null || mPrograms.isEmpty()) { 171 if (mSeriesRecording.getState() == SeriesRecording.STATE_SERIES_STOPPED) { 172 showEmptyMessage(R.string.dvr_series_schedules_stopped_empty_state); 173 } else { 174 showEmptyMessage(R.string.dvr_series_schedules_empty_state); 175 } 176 } else { 177 hideEmptyMessage(); 178 } 179 } 180 181 @Override onDestroy()182 public void onDestroy() { 183 if (mProgramLoadTask != null) { 184 mProgramLoadTask.cancel(true); 185 mProgramLoadTask = null; 186 } 187 getContext().getContentResolver().unregisterContentObserver(mContentObserver); 188 mHandler.removeCallbacksAndMessages(null); 189 mChannelDataManager.removeListener(mChannelListener); 190 mDvrDataManager.removeSeriesRecordingListener(mSeriesRecordingListener); 191 super.onDestroy(); 192 } 193 194 @Override onCreateHeaderRowPresenter()195 public SchedulesHeaderRowPresenter onCreateHeaderRowPresenter() { 196 return new SchedulesHeaderRowPresenter.SeriesRecordingHeaderRowPresenter(getContext()); 197 } 198 199 @Override onCreateRowPresenter()200 public ScheduleRowPresenter onCreateRowPresenter() { 201 return new SeriesScheduleRowPresenter(getContext()); 202 } 203 204 @Override onCreateRowsAdapter(ClassPresenterSelector presenterSelector)205 public ScheduleRowAdapter onCreateRowsAdapter(ClassPresenterSelector presenterSelector) { 206 return new SeriesScheduleRowAdapter(getContext(), presenterSelector, mSeriesRecording); 207 } 208 209 @Override getFirstItemPosition()210 protected int getFirstItemPosition() { 211 if (mSeriesRecording != null 212 && mSeriesRecording.getState() == SeriesRecording.STATE_SERIES_STOPPED) { 213 return 0; 214 } 215 return super.getFirstItemPosition(); 216 } 217 executeProgramLoadingTask()218 private void executeProgramLoadingTask() { 219 if (mProgramLoadTask != null) { 220 mProgramLoadTask.cancel(true); 221 } 222 mProgramLoadTask = 223 new EpisodicProgramLoadTask(getContext(), mSeriesRecording) { 224 @Override 225 protected void onPostExecute(List<Program> programs) { 226 mPrograms = programs == null ? Collections.EMPTY_LIST : programs; 227 onProgramsUpdated(); 228 } 229 }; 230 mProgramLoadTask 231 .setLoadCurrentProgram(true) 232 .setLoadDisallowedProgram(true) 233 .setLoadScheduledEpisode(true) 234 .setIgnoreChannelOption(true) 235 .execute(); 236 } 237 } 238