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