• 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.parental;
18 
19 import android.content.Context;
20 import android.media.tv.TvContentRating;
21 import android.media.tv.TvInputManager;
22 
23 import com.android.tv.experiments.Experiments;
24 import com.android.tv.parental.ContentRatingSystem.Rating;
25 import com.android.tv.parental.ContentRatingSystem.SubRating;
26 import com.android.tv.util.TvSettings;
27 import com.android.tv.util.TvSettings.ContentRatingLevel;
28 
29 import java.util.HashSet;
30 import java.util.Set;
31 
32 public class ParentalControlSettings {
33     /**
34      * The rating and all of its sub-ratings are blocked.
35      */
36     public static final int RATING_BLOCKED = 0;
37 
38     /**
39      * The rating is blocked but not all of its sub-ratings are blocked.
40      */
41     public static final int RATING_BLOCKED_PARTIAL = 1;
42 
43     /**
44      * The rating is not blocked.
45      */
46     public static final int RATING_NOT_BLOCKED = 2;
47 
48     private final Context mContext;
49     private final TvInputManager mTvInputManager;
50 
51     // mRatings is expected to be synchronized with mTvInputManager.getBlockedRatings().
52     private Set<TvContentRating> mRatings;
53     private Set<TvContentRating> mCustomRatings;
54 
ParentalControlSettings(Context context)55     public ParentalControlSettings(Context context) {
56         mContext = context;
57         mTvInputManager = (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE);
58     }
59 
isParentalControlsEnabled()60     public boolean isParentalControlsEnabled() {
61         return mTvInputManager.isParentalControlsEnabled();
62     }
63 
setParentalControlsEnabled(boolean enabled)64     public void setParentalControlsEnabled(boolean enabled) {
65         mTvInputManager.setParentalControlsEnabled(enabled);
66     }
67 
setContentRatingSystemEnabled(ContentRatingsManager manager, ContentRatingSystem contentRatingSystem, boolean enabled)68     public void setContentRatingSystemEnabled(ContentRatingsManager manager,
69             ContentRatingSystem contentRatingSystem, boolean enabled) {
70         if (enabled) {
71             TvSettings.addContentRatingSystem(mContext, contentRatingSystem.getId());
72 
73             // Ensure newly added system has ratings for current level set
74             updateRatingsForCurrentLevel(manager);
75         } else {
76             // Ensure no ratings are blocked for the selected rating system
77             for (TvContentRating tvContentRating : mTvInputManager.getBlockedRatings()) {
78                 if (contentRatingSystem.ownsRating(tvContentRating)) {
79                     mTvInputManager.removeBlockedRating(tvContentRating);
80                 }
81             }
82 
83             TvSettings.removeContentRatingSystem(mContext, contentRatingSystem.getId());
84         }
85     }
86 
isContentRatingSystemEnabled(ContentRatingSystem contentRatingSystem)87     public boolean isContentRatingSystemEnabled(ContentRatingSystem contentRatingSystem) {
88         return TvSettings.hasContentRatingSystem(mContext, contentRatingSystem.getId());
89     }
90 
loadRatings()91     public void loadRatings() {
92         mRatings = new HashSet<>(mTvInputManager.getBlockedRatings());
93     }
94 
storeRatings()95     private void storeRatings() {
96         Set<TvContentRating> removed = new HashSet<>(mTvInputManager.getBlockedRatings());
97         removed.removeAll(mRatings);
98         for (TvContentRating tvContentRating : removed) {
99             mTvInputManager.removeBlockedRating(tvContentRating);
100         }
101 
102         Set<TvContentRating> added = new HashSet<>(mRatings);
103         added.removeAll(mTvInputManager.getBlockedRatings());
104         for (TvContentRating tvContentRating : added) {
105             mTvInputManager.addBlockedRating(tvContentRating);
106         }
107     }
108 
updateRatingsForCurrentLevel(ContentRatingsManager manager)109     private void updateRatingsForCurrentLevel(ContentRatingsManager manager) {
110         @ContentRatingLevel int currentLevel = getContentRatingLevel();
111         if (currentLevel != TvSettings.CONTENT_RATING_LEVEL_CUSTOM) {
112             mRatings = ContentRatingLevelPolicy.getRatingsForLevel(this, manager, currentLevel);
113             if (currentLevel != TvSettings.CONTENT_RATING_LEVEL_NONE) {
114                 // UNRATED contents should be blocked unless the rating level is none or custom
115                 mRatings.add(TvContentRating.UNRATED);
116             }
117             storeRatings();
118         }
119     }
120 
setContentRatingLevel(ContentRatingsManager manager, @ContentRatingLevel int level)121     public void setContentRatingLevel(ContentRatingsManager manager,
122             @ContentRatingLevel int level) {
123         @ContentRatingLevel int currentLevel = getContentRatingLevel();
124         if (level == currentLevel) {
125             return;
126         }
127         if (currentLevel == TvSettings.CONTENT_RATING_LEVEL_CUSTOM) {
128             mCustomRatings = mRatings;
129         }
130         TvSettings.setContentRatingLevel(mContext, level);
131         if (level == TvSettings.CONTENT_RATING_LEVEL_CUSTOM) {
132             if (mCustomRatings != null) {
133                 mRatings = new HashSet<>(mCustomRatings);
134             }
135         } else {
136             mRatings = ContentRatingLevelPolicy.getRatingsForLevel(this, manager, level);
137             if (level != TvSettings.CONTENT_RATING_LEVEL_NONE
138                     && Boolean.TRUE.equals(Experiments.ENABLE_UNRATED_CONTENT_SETTINGS.get())) {
139                 // UNRATED contents should be blocked unless the rating level is none or custom
140                 mRatings.add(TvContentRating.UNRATED);
141             }
142         }
143         storeRatings();
144     }
145 
146     @ContentRatingLevel
getContentRatingLevel()147     public int getContentRatingLevel() {
148         return TvSettings.getContentRatingLevel(mContext);
149     }
150 
151     /** Sets the blocked status of a unrated contents. */
setUnratedBlocked(boolean blocked)152     public boolean setUnratedBlocked(boolean blocked) {
153         boolean changed;
154         if (blocked) {
155             changed = mRatings.add(TvContentRating.UNRATED);
156             mTvInputManager.addBlockedRating(TvContentRating.UNRATED);
157         } else {
158             changed = mRatings.remove(TvContentRating.UNRATED);
159             mTvInputManager.removeBlockedRating(TvContentRating.UNRATED);
160         }
161         if (changed) {
162             // change to custom level if the blocked status is changed
163             changeToCustomLevel();
164         }
165         return changed;
166     }
167 
168     /**
169      * Sets the blocked status of a given content rating.
170      * <p>
171      * Note that a call to this method automatically changes the current rating level to
172      * {@code TvSettings.CONTENT_RATING_LEVEL_CUSTOM} if needed.
173      * </p>
174      *
175      * @param contentRatingSystem The content rating system where the given rating belongs.
176      * @param rating The content rating to set.
177      * @return {@code true} if changed, {@code false} otherwise.
178      * @see #setSubRatingBlocked
179      */
setRatingBlocked(ContentRatingSystem contentRatingSystem, Rating rating, boolean blocked)180     public boolean setRatingBlocked(ContentRatingSystem contentRatingSystem, Rating rating,
181             boolean blocked) {
182         return setRatingBlockedInternal(contentRatingSystem, rating, null, blocked);
183     }
184 
185     /**
186      * Checks whether any of given ratings is blocked.
187      *
188      * @param ratings The array of ratings to check
189      * @return {@code true} if a rating is blocked, {@code false} otherwise.
190      */
isRatingBlocked(TvContentRating[] ratings)191     public boolean isRatingBlocked(TvContentRating[] ratings) {
192         return getBlockedRating(ratings) != null;
193     }
194 
195     /**
196      * Checks whether any of given ratings is blocked and returns the first blocked rating.
197      *
198      * @param ratings The array of ratings to check
199      * @return The {@link TvContentRating} that is blocked.
200      */
getBlockedRating(TvContentRating[] ratings)201     public TvContentRating getBlockedRating(TvContentRating[] ratings) {
202         if (ratings == null || ratings.length <= 0) {
203             return mTvInputManager.isRatingBlocked(TvContentRating.UNRATED)
204                     ? TvContentRating.UNRATED
205                     : null;
206         }
207         for (TvContentRating rating : ratings) {
208             if (mTvInputManager.isRatingBlocked(rating)) {
209                 return rating;
210             }
211         }
212         return null;
213     }
214 
215     /**
216      * Checks whether a given rating is blocked by the user or not.
217      *
218      * @param contentRatingSystem The content rating system where the given rating belongs.
219      * @param rating The content rating to check.
220      * @return {@code true} if blocked, {@code false} otherwise.
221      */
isRatingBlocked(ContentRatingSystem contentRatingSystem, Rating rating)222     public boolean isRatingBlocked(ContentRatingSystem contentRatingSystem, Rating rating) {
223         return mRatings.contains(toTvContentRating(contentRatingSystem, rating));
224     }
225 
226     /**
227      * Sets the blocked status of a given content sub-rating.
228      * <p>
229      * Note that a call to this method automatically changes the current rating level to
230      * {@code TvSettings.CONTENT_RATING_LEVEL_CUSTOM} if needed.
231      * </p>
232      *
233      * @param contentRatingSystem The content rating system where the given rating belongs.
234      * @param rating The content rating associated with the given sub-rating.
235      * @param subRating The content sub-rating to set.
236      * @return {@code true} if changed, {@code false} otherwise.
237      * @see #setRatingBlocked
238      */
setSubRatingBlocked(ContentRatingSystem contentRatingSystem, Rating rating, SubRating subRating, boolean blocked)239     public boolean setSubRatingBlocked(ContentRatingSystem contentRatingSystem, Rating rating,
240             SubRating subRating, boolean blocked) {
241         return setRatingBlockedInternal(contentRatingSystem, rating, subRating, blocked);
242     }
243 
244     /**
245      * Checks whether a given content sub-rating is blocked by the user or not.
246      *
247      * @param contentRatingSystem The content rating system where the given rating belongs.
248      * @param rating The content rating associated with the given sub-rating.
249      * @param subRating The content sub-rating to check.
250      * @return {@code true} if blocked, {@code false} otherwise.
251      */
isSubRatingEnabled(ContentRatingSystem contentRatingSystem, Rating rating, SubRating subRating)252     public boolean isSubRatingEnabled(ContentRatingSystem contentRatingSystem, Rating rating,
253             SubRating subRating) {
254         return mRatings.contains(toTvContentRating(contentRatingSystem, rating, subRating));
255     }
256 
setRatingBlockedInternal(ContentRatingSystem contentRatingSystem, Rating rating, SubRating subRating, boolean blocked)257     private boolean setRatingBlockedInternal(ContentRatingSystem contentRatingSystem, Rating rating,
258             SubRating subRating, boolean blocked) {
259         TvContentRating tvContentRating = (subRating == null)
260                 ? toTvContentRating(contentRatingSystem, rating)
261                 : toTvContentRating(contentRatingSystem, rating, subRating);
262         boolean changed;
263         if (blocked) {
264             changed = mRatings.add(tvContentRating);
265             mTvInputManager.addBlockedRating(tvContentRating);
266         } else {
267             changed = mRatings.remove(tvContentRating);
268             mTvInputManager.removeBlockedRating(tvContentRating);
269         }
270         if (changed) {
271             changeToCustomLevel();
272         }
273         return changed;
274     }
275 
changeToCustomLevel()276     private void changeToCustomLevel() {
277         if (getContentRatingLevel() != TvSettings.CONTENT_RATING_LEVEL_CUSTOM) {
278             TvSettings.setContentRatingLevel(mContext, TvSettings.CONTENT_RATING_LEVEL_CUSTOM);
279         }
280     }
281 
282     /**
283      * Returns the blocked status of a given rating. The status can be one of the followings:
284      * {@link #RATING_BLOCKED}, {@link #RATING_BLOCKED_PARTIAL} and {@link #RATING_NOT_BLOCKED}
285      */
getBlockedStatus(ContentRatingSystem contentRatingSystem, Rating rating)286     public int getBlockedStatus(ContentRatingSystem contentRatingSystem, Rating rating) {
287         if (isRatingBlocked(contentRatingSystem, rating)) {
288             return RATING_BLOCKED;
289         }
290         for (SubRating subRating : rating.getSubRatings()) {
291             if (isSubRatingEnabled(contentRatingSystem, rating, subRating)) {
292                 return RATING_BLOCKED_PARTIAL;
293             }
294         }
295         return RATING_NOT_BLOCKED;
296     }
297 
toTvContentRating(ContentRatingSystem contentRatingSystem, Rating rating)298     private TvContentRating toTvContentRating(ContentRatingSystem contentRatingSystem,
299             Rating rating) {
300         return TvContentRating.createRating(contentRatingSystem.getDomain(),
301                 contentRatingSystem.getName(), rating.getName());
302     }
303 
toTvContentRating(ContentRatingSystem contentRatingSystem, Rating rating, SubRating subRating)304     private TvContentRating toTvContentRating(ContentRatingSystem contentRatingSystem,
305             Rating rating, SubRating subRating) {
306         return TvContentRating.createRating(contentRatingSystem.getDomain(),
307                 contentRatingSystem.getName(), rating.getName(), subRating.getName());
308     }
309 }
310