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 
     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 
     55     public ParentalControlSettings(Context context) {
     56         mContext = context;
     57         mTvInputManager = (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE);
     58     }
     59 
     60     public boolean isParentalControlsEnabled() {
     61         return mTvInputManager.isParentalControlsEnabled();
     62     }
     63 
     64     public void setParentalControlsEnabled(boolean enabled) {
     65         mTvInputManager.setParentalControlsEnabled(enabled);
     66     }
     67 
     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 
     87     public boolean isContentRatingSystemEnabled(ContentRatingSystem contentRatingSystem) {
     88         return TvSettings.hasContentRatingSystem(mContext, contentRatingSystem.getId());
     89     }
     90 
     91     public void loadRatings() {
     92         mRatings = new HashSet<>(mTvInputManager.getBlockedRatings());
     93     }
     94 
     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 
    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 
    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
    147     public int getContentRatingLevel() {
    148         return TvSettings.getContentRatingLevel(mContext);
    149     }
    150 
    151     /** Sets the blocked status of a unrated contents. */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    252     public boolean isSubRatingEnabled(ContentRatingSystem contentRatingSystem, Rating rating,
    253             SubRating subRating) {
    254         return mRatings.contains(toTvContentRating(contentRatingSystem, rating, subRating));
    255     }
    256 
    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 
    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      */
    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 
    298     private TvContentRating toTvContentRating(ContentRatingSystem contentRatingSystem,
    299             Rating rating) {
    300         return TvContentRating.createRating(contentRatingSystem.getDomain(),
    301                 contentRatingSystem.getName(), rating.getName());
    302     }
    303 
    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