Home | History | Annotate | Download | only in parental
      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 import com.android.tv.common.experiments.Experiments;
     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 import java.util.HashSet;
     28 import java.util.Set;
     29 
     30 public 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