• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.media.tv.TvInputManager;
22 import android.support.annotation.IntDef;
23 import com.android.tv.common.util.SharedPreferencesUtils;
24 import com.android.tv.dvr.data.RecordedProgram;
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.concurrent.CopyOnWriteArraySet;
32 
33 /**
34  * A class to manage DVR watched state. It will remember and provides previous watched position of
35  * DVR playback.
36  */
37 public class DvrWatchedPositionManager {
38     private SharedPreferences mWatchedPositions;
39     private final Map<Long, Set> mListeners = new HashMap<>();
40 
41     /**
42      * The minimum percentage of recorded program being watched that will be considered as being
43      * completely watched.
44      */
45     public static final float DVR_WATCHED_THRESHOLD_RATE = 0.98f;
46 
47     @Retention(RetentionPolicy.SOURCE)
48     @IntDef({DVR_WATCHED_STATUS_NEW, DVR_WATCHED_STATUS_WATCHING, DVR_WATCHED_STATUS_WATCHED})
49     public @interface DvrWatchedStatus {}
50     /** The status indicates the recorded program has not been watched at all. */
51     public static final int DVR_WATCHED_STATUS_NEW = 0;
52     /** The status indicates the recorded program is being watched. */
53     public static final int DVR_WATCHED_STATUS_WATCHING = 1;
54     /** The status indicates the recorded program was completely watched. */
55     public static final int DVR_WATCHED_STATUS_WATCHED = 2;
56 
DvrWatchedPositionManager(Context context)57     public DvrWatchedPositionManager(Context context) {
58         mWatchedPositions =
59                 context.getSharedPreferences(
60                         SharedPreferencesUtils.SHARED_PREF_DVR_WATCHED_POSITION,
61                         Context.MODE_PRIVATE);
62     }
63 
64     /** Sets the watched position of the give program. */
setWatchedPosition(long recordedProgramId, long positionMs)65     public void setWatchedPosition(long recordedProgramId, long positionMs) {
66         mWatchedPositions.edit().putLong(Long.toString(recordedProgramId), positionMs).apply();
67         notifyWatchedPositionChanged(recordedProgramId, positionMs);
68     }
69 
70     /** Gets the watched position of the give program. */
getWatchedPosition(long recordedProgramId)71     public long getWatchedPosition(long recordedProgramId) {
72         return mWatchedPositions.getLong(
73                 Long.toString(recordedProgramId), TvInputManager.TIME_SHIFT_INVALID_TIME);
74     }
75 
76     @DvrWatchedStatus
getWatchedStatus(RecordedProgram recordedProgram)77     public int getWatchedStatus(RecordedProgram recordedProgram) {
78         long watchedPosition = getWatchedPosition(recordedProgram.getId());
79         if (watchedPosition == TvInputManager.TIME_SHIFT_INVALID_TIME) {
80             return DVR_WATCHED_STATUS_NEW;
81         } else if (watchedPosition
82                 > recordedProgram.getDurationMillis() * DVR_WATCHED_THRESHOLD_RATE) {
83             return DVR_WATCHED_STATUS_WATCHED;
84         } else {
85             return DVR_WATCHED_STATUS_WATCHING;
86         }
87     }
88 
89     /** Adds {@link WatchedPositionChangedListener}. */
addListener(WatchedPositionChangedListener listener, long recordedProgramId)90     public void addListener(WatchedPositionChangedListener listener, long recordedProgramId) {
91         if (recordedProgramId == RecordedProgram.ID_NOT_SET) {
92             return;
93         }
94         Set<WatchedPositionChangedListener> listenerSet = mListeners.get(recordedProgramId);
95         if (listenerSet == null) {
96             listenerSet = new CopyOnWriteArraySet<>();
97             mListeners.put(recordedProgramId, listenerSet);
98         }
99         listenerSet.add(listener);
100     }
101 
102     /** Removes {@link WatchedPositionChangedListener}. */
removeListener(WatchedPositionChangedListener listener)103     public void removeListener(WatchedPositionChangedListener listener) {
104         for (long recordedProgramId : new ArrayList<>(mListeners.keySet())) {
105             removeListener(listener, recordedProgramId);
106         }
107     }
108 
109     /** Removes {@link WatchedPositionChangedListener}. */
removeListener(WatchedPositionChangedListener listener, long recordedProgramId)110     public void removeListener(WatchedPositionChangedListener listener, long recordedProgramId) {
111         Set<WatchedPositionChangedListener> listenerSet = mListeners.get(recordedProgramId);
112         if (listenerSet == null) {
113             return;
114         }
115         listenerSet.remove(listener);
116         if (listenerSet.isEmpty()) {
117             mListeners.remove(recordedProgramId);
118         }
119     }
120 
notifyWatchedPositionChanged(long recordedProgramId, long positionMs)121     private void notifyWatchedPositionChanged(long recordedProgramId, long positionMs) {
122         Set<WatchedPositionChangedListener> listenerSet = mListeners.get(recordedProgramId);
123         if (listenerSet == null) {
124             return;
125         }
126         for (WatchedPositionChangedListener listener : listenerSet) {
127             listener.onWatchedPositionChanged(recordedProgramId, positionMs);
128         }
129     }
130 
131     public interface WatchedPositionChangedListener {
132         /** Called when the watched position of some program is changed. */
onWatchedPositionChanged(long recordedProgramId, long positionMs)133         void onWatchedPositionChanged(long recordedProgramId, long positionMs);
134     }
135 }
136