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