• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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;
18 
19 import android.annotation.TargetApi;
20 import android.content.Context;
21 import android.os.Build;
22 import android.support.annotation.MainThread;
23 import android.support.annotation.NonNull;
24 import android.util.ArraySet;
25 import android.util.Log;
26 
27 import com.android.tv.common.SoftPreconditions;
28 import com.android.tv.common.feature.CommonFeatures;
29 import com.android.tv.dvr.ScheduledRecording.RecordingState;
30 import com.android.tv.util.Clock;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Set;
40 import java.util.concurrent.CopyOnWriteArraySet;
41 
42 /**
43  * Base implementation of @{link DataManagerInternal}.
44  */
45 @MainThread
46 @TargetApi(Build.VERSION_CODES.N)
47 public abstract class BaseDvrDataManager implements WritableDvrDataManager {
48     private final static String TAG = "BaseDvrDataManager";
49     private final static boolean DEBUG = false;
50     protected final Clock mClock;
51 
52     private final Set<OnDvrScheduleLoadFinishedListener> mOnDvrScheduleLoadFinishedListeners =
53             new CopyOnWriteArraySet<>();
54     private final Set<OnRecordedProgramLoadFinishedListener>
55             mOnRecordedProgramLoadFinishedListeners = new CopyOnWriteArraySet<>();
56     private final Set<ScheduledRecordingListener> mScheduledRecordingListeners = new ArraySet<>();
57     private final Set<SeriesRecordingListener> mSeriesRecordingListeners = new ArraySet<>();
58     private final Set<RecordedProgramListener> mRecordedProgramListeners = new ArraySet<>();
59     private final HashMap<Long, ScheduledRecording> mDeletedScheduleMap = new HashMap<>();
60 
BaseDvrDataManager(Context context, Clock clock)61     BaseDvrDataManager(Context context, Clock clock) {
62         SoftPreconditions.checkFeatureEnabled(context, CommonFeatures.DVR, TAG);
63         mClock = clock;
64     }
65 
66     @Override
addDvrScheduleLoadFinishedListener(OnDvrScheduleLoadFinishedListener listener)67     public void addDvrScheduleLoadFinishedListener(OnDvrScheduleLoadFinishedListener listener) {
68         mOnDvrScheduleLoadFinishedListeners.add(listener);
69     }
70 
71     @Override
removeDvrScheduleLoadFinishedListener(OnDvrScheduleLoadFinishedListener listener)72     public void removeDvrScheduleLoadFinishedListener(OnDvrScheduleLoadFinishedListener listener) {
73         mOnDvrScheduleLoadFinishedListeners.remove(listener);
74     }
75 
76     @Override
addRecordedProgramLoadFinishedListener( OnRecordedProgramLoadFinishedListener listener)77     public void addRecordedProgramLoadFinishedListener(
78             OnRecordedProgramLoadFinishedListener listener) {
79         mOnRecordedProgramLoadFinishedListeners.add(listener);
80     }
81 
82     @Override
removeRecordedProgramLoadFinishedListener( OnRecordedProgramLoadFinishedListener listener)83     public void removeRecordedProgramLoadFinishedListener(
84             OnRecordedProgramLoadFinishedListener listener) {
85         mOnRecordedProgramLoadFinishedListeners.remove(listener);
86     }
87 
88     @Override
addScheduledRecordingListener(ScheduledRecordingListener listener)89     public final void addScheduledRecordingListener(ScheduledRecordingListener listener) {
90         mScheduledRecordingListeners.add(listener);
91     }
92 
93     @Override
removeScheduledRecordingListener(ScheduledRecordingListener listener)94     public final void removeScheduledRecordingListener(ScheduledRecordingListener listener) {
95         mScheduledRecordingListeners.remove(listener);
96     }
97 
98     @Override
addSeriesRecordingListener(SeriesRecordingListener listener)99     public final void addSeriesRecordingListener(SeriesRecordingListener listener) {
100         mSeriesRecordingListeners.add(listener);
101     }
102 
103     @Override
removeSeriesRecordingListener(SeriesRecordingListener listener)104     public final void removeSeriesRecordingListener(SeriesRecordingListener listener) {
105         mSeriesRecordingListeners.remove(listener);
106     }
107 
108     @Override
addRecordedProgramListener(RecordedProgramListener listener)109     public final void addRecordedProgramListener(RecordedProgramListener listener) {
110         mRecordedProgramListeners.add(listener);
111     }
112 
113     @Override
removeRecordedProgramListener(RecordedProgramListener listener)114     public final void removeRecordedProgramListener(RecordedProgramListener listener) {
115         mRecordedProgramListeners.remove(listener);
116     }
117 
118     /**
119      * Calls {@link OnDvrScheduleLoadFinishedListener#onDvrScheduleLoadFinished} for each listener.
120      */
notifyDvrScheduleLoadFinished()121     protected final void notifyDvrScheduleLoadFinished() {
122         for (OnDvrScheduleLoadFinishedListener l : mOnDvrScheduleLoadFinishedListeners) {
123             if (DEBUG) Log.d(TAG, "notify DVR schedule load finished");
124             l.onDvrScheduleLoadFinished();
125         }
126     }
127 
128     /**
129      * Calls {@link OnRecordedProgramLoadFinishedListener#onRecordedProgramLoadFinished()}
130      * for each listener.
131      */
notifyRecordedProgramLoadFinished()132     protected final void notifyRecordedProgramLoadFinished() {
133         for (OnRecordedProgramLoadFinishedListener l : mOnRecordedProgramLoadFinishedListeners) {
134             if (DEBUG) Log.d(TAG, "notify recorded programs load finished");
135             l.onRecordedProgramLoadFinished();
136         }
137     }
138 
139     /**
140      * Calls {@link RecordedProgramListener#onRecordedProgramsAdded}
141      * for each listener.
142      */
notifyRecordedProgramsAdded(RecordedProgram... recordedPrograms)143     protected final void notifyRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
144         for (RecordedProgramListener l : mRecordedProgramListeners) {
145             if (DEBUG) Log.d(TAG, "notify " + l + " added " + Arrays.asList(recordedPrograms));
146             l.onRecordedProgramsAdded(recordedPrograms);
147         }
148     }
149 
150     /**
151      * Calls {@link RecordedProgramListener#onRecordedProgramsChanged}
152      * for each listener.
153      */
notifyRecordedProgramsChanged(RecordedProgram... recordedPrograms)154     protected final void notifyRecordedProgramsChanged(RecordedProgram... recordedPrograms) {
155         for (RecordedProgramListener l : mRecordedProgramListeners) {
156             if (DEBUG) Log.d(TAG, "notify " + l + " changed " + Arrays.asList(recordedPrograms));
157             l.onRecordedProgramsChanged(recordedPrograms);
158         }
159     }
160 
161     /**
162      * Calls {@link RecordedProgramListener#onRecordedProgramsRemoved}
163      * for each  listener.
164      */
notifyRecordedProgramsRemoved(RecordedProgram... recordedPrograms)165     protected final void notifyRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
166         for (RecordedProgramListener l : mRecordedProgramListeners) {
167             if (DEBUG) Log.d(TAG, "notify " + l + " removed " + Arrays.asList(recordedPrograms));
168             l.onRecordedProgramsRemoved(recordedPrograms);
169         }
170     }
171 
172     /**
173      * Calls {@link SeriesRecordingListener#onSeriesRecordingAdded}
174      * for each listener.
175      */
notifySeriesRecordingAdded(SeriesRecording... seriesRecordings)176     protected final void notifySeriesRecordingAdded(SeriesRecording... seriesRecordings) {
177         for (SeriesRecordingListener l : mSeriesRecordingListeners) {
178             if (DEBUG) Log.d(TAG, "notify " + l + " added  " + Arrays.asList(seriesRecordings));
179             l.onSeriesRecordingAdded(seriesRecordings);
180         }
181     }
182 
183     /**
184      * Calls {@link SeriesRecordingListener#onSeriesRecordingRemoved}
185      * for each listener.
186      */
notifySeriesRecordingRemoved(SeriesRecording... seriesRecordings)187     protected final void notifySeriesRecordingRemoved(SeriesRecording... seriesRecordings) {
188         for (SeriesRecordingListener l : mSeriesRecordingListeners) {
189             if (DEBUG) Log.d(TAG, "notify " + l + " removed " + Arrays.asList(seriesRecordings));
190             l.onSeriesRecordingRemoved(seriesRecordings);
191         }
192     }
193 
194     /**
195      * Calls
196      * {@link SeriesRecordingListener#onSeriesRecordingChanged}
197      * for each listener.
198      */
notifySeriesRecordingChanged(SeriesRecording... seriesRecordings)199     protected final void notifySeriesRecordingChanged(SeriesRecording... seriesRecordings) {
200         for (SeriesRecordingListener l : mSeriesRecordingListeners) {
201             if (DEBUG) Log.d(TAG, "notify " + l + " changed " + Arrays.asList(seriesRecordings));
202             l.onSeriesRecordingChanged(seriesRecordings);
203         }
204     }
205 
206     /**
207      * Calls {@link ScheduledRecordingListener#onScheduledRecordingAdded}
208      * for each listener.
209      */
notifyScheduledRecordingAdded(ScheduledRecording... scheduledRecording)210     protected final void notifyScheduledRecordingAdded(ScheduledRecording... scheduledRecording) {
211         for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
212             if (DEBUG) Log.d(TAG, "notify " + l + " added  " + Arrays.asList(scheduledRecording));
213             l.onScheduledRecordingAdded(scheduledRecording);
214         }
215     }
216 
217     /**
218      * Calls {@link ScheduledRecordingListener#onScheduledRecordingRemoved}
219      * for each listener.
220      */
notifyScheduledRecordingRemoved(ScheduledRecording... scheduledRecording)221     protected final void notifyScheduledRecordingRemoved(ScheduledRecording... scheduledRecording) {
222         for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
223             if (DEBUG) Log.d(TAG, "notify " + l + " removed " + Arrays.asList(scheduledRecording));
224             l.onScheduledRecordingRemoved(scheduledRecording);
225         }
226     }
227 
228     /**
229      * Calls
230      * {@link ScheduledRecordingListener#onScheduledRecordingStatusChanged}
231      * for each listener.
232      */
notifyScheduledRecordingStatusChanged( ScheduledRecording... scheduledRecording)233     protected final void notifyScheduledRecordingStatusChanged(
234             ScheduledRecording... scheduledRecording) {
235         for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
236             if (DEBUG) Log.d(TAG, "notify " + l + " changed " + Arrays.asList(scheduledRecording));
237             l.onScheduledRecordingStatusChanged(scheduledRecording);
238         }
239     }
240 
241     /**
242      * Returns a new list with only {@link ScheduledRecording} with a {@link
243      * ScheduledRecording#getEndTimeMs() endTime} after now.
244      */
filterEndTimeIsPast(List<ScheduledRecording> originals)245     private List<ScheduledRecording> filterEndTimeIsPast(List<ScheduledRecording> originals) {
246         List<ScheduledRecording> results = new ArrayList<>(originals.size());
247         for (ScheduledRecording r : originals) {
248             if (r.getEndTimeMs() > mClock.currentTimeMillis()) {
249                 results.add(r);
250             }
251         }
252         return results;
253     }
254 
255     @Override
getAvailableScheduledRecordings()256     public List<ScheduledRecording> getAvailableScheduledRecordings() {
257         return filterEndTimeIsPast(getRecordingsWithState(
258                 ScheduledRecording.STATE_RECORDING_IN_PROGRESS,
259                 ScheduledRecording.STATE_RECORDING_NOT_STARTED));
260     }
261 
262     @Override
getStartedRecordings()263     public List<ScheduledRecording> getStartedRecordings() {
264         return filterEndTimeIsPast(getRecordingsWithState(
265                 ScheduledRecording.STATE_RECORDING_IN_PROGRESS));
266     }
267 
268     @Override
getNonStartedScheduledRecordings()269     public List<ScheduledRecording> getNonStartedScheduledRecordings() {
270         return filterEndTimeIsPast(getRecordingsWithState(
271                 ScheduledRecording.STATE_RECORDING_NOT_STARTED));
272     }
273 
274     @Override
changeState(ScheduledRecording scheduledRecording, @RecordingState int newState)275     public void changeState(ScheduledRecording scheduledRecording, @RecordingState int newState) {
276         if (scheduledRecording.getState() != newState) {
277             updateScheduledRecording(ScheduledRecording.buildFrom(scheduledRecording)
278                     .setState(newState).build());
279         }
280     }
281 
282     @Override
getDeletedSchedules()283     public Collection<ScheduledRecording> getDeletedSchedules() {
284         return mDeletedScheduleMap.values();
285     }
286 
287     @NonNull
288     @Override
getDisallowedProgramIds()289     public Collection<Long> getDisallowedProgramIds() {
290         return mDeletedScheduleMap.keySet();
291     }
292 
293     /**
294      * Returns the map which contains the deleted schedules which are mapped from the program ID.
295      */
getDeletedScheduleMap()296     protected Map<Long, ScheduledRecording> getDeletedScheduleMap() {
297         return mDeletedScheduleMap;
298     }
299 
300     /**
301      * Returns the schedules whose state is contained by states.
302      */
getRecordingsWithState(int... states)303     protected abstract List<ScheduledRecording> getRecordingsWithState(int... states);
304 
305     @Override
getRecordedPrograms(long seriesRecordingId)306     public List<RecordedProgram> getRecordedPrograms(long seriesRecordingId) {
307         SeriesRecording seriesRecording = getSeriesRecording(seriesRecordingId);
308         if (seriesRecording == null) {
309             return Collections.emptyList();
310         }
311         List<RecordedProgram> result = new ArrayList<>();
312         for (RecordedProgram r : getRecordedPrograms()) {
313             if (seriesRecording.getSeriesId().equals(r.getSeriesId())) {
314                 result.add(r);
315             }
316         }
317         return result;
318     }
319 
320     @Override
forgetStorage(String inputId)321     public void forgetStorage(String inputId) { }
322 }
323