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