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