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