| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.tv.parental; |
| |
| import android.content.Context; |
| import android.media.tv.TvContentRating; |
| import android.media.tv.TvInputManager; |
| import com.android.tv.parental.ContentRatingSystem.Rating; |
| import com.android.tv.parental.ContentRatingSystem.SubRating; |
| import com.android.tv.util.TvSettings; |
| import com.android.tv.util.TvSettings.ContentRatingLevel; |
| import com.google.common.collect.ImmutableList; |
| import com.android.tv.common.flags.LegacyFlags; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| public class ParentalControlSettings { |
| /** The rating and all of its sub-ratings are blocked. */ |
| public static final int RATING_BLOCKED = 0; |
| |
| /** The rating is blocked but not all of its sub-ratings are blocked. */ |
| public static final int RATING_BLOCKED_PARTIAL = 1; |
| |
| /** The rating is not blocked. */ |
| public static final int RATING_NOT_BLOCKED = 2; |
| |
| private final Context mContext; |
| private final TvInputManager mTvInputManager; |
| private final LegacyFlags mLegacyFlags; |
| |
| // mRatings is expected to be synchronized with mTvInputManager.getBlockedRatings(). |
| private Set<TvContentRating> mRatings; |
| private Set<TvContentRating> mCustomRatings; |
| |
| public ParentalControlSettings(Context context, LegacyFlags legacyFlags) { |
| mContext = context; |
| mTvInputManager = (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE); |
| mLegacyFlags = legacyFlags; |
| } |
| |
| public boolean isParentalControlsEnabled() { |
| return mTvInputManager.isParentalControlsEnabled(); |
| } |
| |
| public void setParentalControlsEnabled(boolean enabled) { |
| mTvInputManager.setParentalControlsEnabled(enabled); |
| } |
| |
| public void setContentRatingSystemEnabled( |
| ContentRatingsManager manager, |
| ContentRatingSystem contentRatingSystem, |
| boolean enabled) { |
| if (enabled) { |
| TvSettings.addContentRatingSystem(mContext, contentRatingSystem.getId()); |
| |
| // Ensure newly added system has ratings for current level set |
| updateRatingsForCurrentLevel(manager); |
| } else { |
| // Ensure no ratings are blocked for the selected rating system |
| for (TvContentRating tvContentRating : mTvInputManager.getBlockedRatings()) { |
| if (contentRatingSystem.ownsRating(tvContentRating)) { |
| mTvInputManager.removeBlockedRating(tvContentRating); |
| } |
| } |
| |
| TvSettings.removeContentRatingSystem(mContext, contentRatingSystem.getId()); |
| } |
| } |
| |
| public boolean isContentRatingSystemEnabled(ContentRatingSystem contentRatingSystem) { |
| return TvSettings.hasContentRatingSystem(mContext, contentRatingSystem.getId()); |
| } |
| |
| public void loadRatings() { |
| mRatings = new HashSet<>(mTvInputManager.getBlockedRatings()); |
| } |
| |
| private void storeRatings() { |
| Set<TvContentRating> removed = new HashSet<>(mTvInputManager.getBlockedRatings()); |
| removed.removeAll(mRatings); |
| for (TvContentRating tvContentRating : removed) { |
| mTvInputManager.removeBlockedRating(tvContentRating); |
| } |
| |
| Set<TvContentRating> added = new HashSet<>(mRatings); |
| added.removeAll(mTvInputManager.getBlockedRatings()); |
| for (TvContentRating tvContentRating : added) { |
| mTvInputManager.addBlockedRating(tvContentRating); |
| } |
| } |
| |
| private void updateRatingsForCurrentLevel(ContentRatingsManager manager) { |
| @ContentRatingLevel int currentLevel = getContentRatingLevel(); |
| if (currentLevel != TvSettings.CONTENT_RATING_LEVEL_CUSTOM) { |
| mRatings = ContentRatingLevelPolicy.getRatingsForLevel(this, manager, currentLevel); |
| if (currentLevel != TvSettings.CONTENT_RATING_LEVEL_NONE) { |
| // UNRATED contents should be blocked unless the rating level is none or custom |
| mRatings.add(TvContentRating.UNRATED); |
| } |
| storeRatings(); |
| } |
| } |
| |
| public void setContentRatingLevel( |
| ContentRatingsManager manager, @ContentRatingLevel int level) { |
| @ContentRatingLevel int currentLevel = getContentRatingLevel(); |
| if (level == currentLevel) { |
| return; |
| } |
| if (currentLevel == TvSettings.CONTENT_RATING_LEVEL_CUSTOM) { |
| mCustomRatings = mRatings; |
| } |
| TvSettings.setContentRatingLevel(mContext, level); |
| if (level == TvSettings.CONTENT_RATING_LEVEL_CUSTOM) { |
| if (mCustomRatings != null) { |
| mRatings = new HashSet<>(mCustomRatings); |
| } |
| } else { |
| mRatings = ContentRatingLevelPolicy.getRatingsForLevel(this, manager, level); |
| if (level != TvSettings.CONTENT_RATING_LEVEL_NONE |
| && mLegacyFlags.enableUnratedContentSettings()) { |
| // UNRATED contents should be blocked unless the rating level is none or custom |
| mRatings.add(TvContentRating.UNRATED); |
| } |
| } |
| storeRatings(); |
| } |
| |
| @ContentRatingLevel |
| public int getContentRatingLevel() { |
| return TvSettings.getContentRatingLevel(mContext); |
| } |
| |
| /** Sets the blocked status of a unrated contents. */ |
| public boolean setUnratedBlocked(boolean blocked) { |
| boolean changed; |
| if (blocked) { |
| changed = mRatings.add(TvContentRating.UNRATED); |
| mTvInputManager.addBlockedRating(TvContentRating.UNRATED); |
| } else { |
| changed = mRatings.remove(TvContentRating.UNRATED); |
| mTvInputManager.removeBlockedRating(TvContentRating.UNRATED); |
| } |
| if (changed) { |
| // change to custom level if the blocked status is changed |
| changeToCustomLevel(); |
| } |
| return changed; |
| } |
| |
| /** |
| * Checks whether any of given ratings is blocked and returns the first blocked rating. |
| * |
| * @param ratings The array of ratings to check |
| * @return The {@link TvContentRating} that is blocked. |
| */ |
| public TvContentRating getBlockedRating(ImmutableList<TvContentRating> ratings) { |
| if (ratings == null || ratings.isEmpty()) { |
| return mTvInputManager.isRatingBlocked(TvContentRating.UNRATED) |
| ? TvContentRating.UNRATED |
| : null; |
| } |
| for (TvContentRating rating : ratings) { |
| if (mTvInputManager.isRatingBlocked(rating)) { |
| return rating; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the blocked status of a given content rating. |
| * |
| * <p>Note that a call to this method automatically changes the current rating level to {@code |
| * TvSettings.CONTENT_RATING_LEVEL_CUSTOM} if needed. |
| * |
| * @param contentRatingSystem The content rating system where the given rating belongs. |
| * @param rating The content rating to set. |
| * @return {@code true} if changed, {@code false} otherwise. |
| * @see #setSubRatingBlocked |
| */ |
| public boolean setRatingBlocked( |
| ContentRatingSystem contentRatingSystem, Rating rating, boolean blocked) { |
| return setRatingBlockedInternal(contentRatingSystem, rating, null, blocked); |
| } |
| |
| /** |
| * Checks whether any of given ratings is blocked. |
| * |
| * @param ratings The list of ratings to check |
| * @return {@code true} if a rating is blocked, {@code false} otherwise. |
| */ |
| public boolean isRatingBlocked(ImmutableList<TvContentRating> ratings) { |
| return getBlockedRating(ratings) != null; |
| } |
| |
| /** |
| * Checks whether a given rating is blocked by the user or not. |
| * |
| * @param contentRatingSystem The content rating system where the given rating belongs. |
| * @param rating The content rating to check. |
| * @return {@code true} if blocked, {@code false} otherwise. |
| */ |
| public boolean isRatingBlocked(ContentRatingSystem contentRatingSystem, Rating rating) { |
| return mRatings.contains(toTvContentRating(contentRatingSystem, rating)); |
| } |
| |
| /** |
| * Sets the blocked status of a given content sub-rating. |
| * |
| * <p>Note that a call to this method automatically changes the current rating level to {@code |
| * TvSettings.CONTENT_RATING_LEVEL_CUSTOM} if needed. |
| * |
| * @param contentRatingSystem The content rating system where the given rating belongs. |
| * @param rating The content rating associated with the given sub-rating. |
| * @param subRating The content sub-rating to set. |
| * @return {@code true} if changed, {@code false} otherwise. |
| * @see #setRatingBlocked |
| */ |
| public boolean setSubRatingBlocked( |
| ContentRatingSystem contentRatingSystem, |
| Rating rating, |
| SubRating subRating, |
| boolean blocked) { |
| return setRatingBlockedInternal(contentRatingSystem, rating, subRating, blocked); |
| } |
| |
| /** |
| * Checks whether a given content sub-rating is blocked by the user or not. |
| * |
| * @param contentRatingSystem The content rating system where the given rating belongs. |
| * @param rating The content rating associated with the given sub-rating. |
| * @param subRating The content sub-rating to check. |
| * @return {@code true} if blocked, {@code false} otherwise. |
| */ |
| public boolean isSubRatingEnabled( |
| ContentRatingSystem contentRatingSystem, Rating rating, SubRating subRating) { |
| return mRatings.contains(toTvContentRating(contentRatingSystem, rating, subRating)); |
| } |
| |
| private boolean setRatingBlockedInternal( |
| ContentRatingSystem contentRatingSystem, |
| Rating rating, |
| SubRating subRating, |
| boolean blocked) { |
| TvContentRating tvContentRating = |
| (subRating == null) |
| ? toTvContentRating(contentRatingSystem, rating) |
| : toTvContentRating(contentRatingSystem, rating, subRating); |
| boolean changed; |
| if (blocked) { |
| changed = mRatings.add(tvContentRating); |
| mTvInputManager.addBlockedRating(tvContentRating); |
| } else { |
| changed = mRatings.remove(tvContentRating); |
| mTvInputManager.removeBlockedRating(tvContentRating); |
| } |
| if (changed) { |
| changeToCustomLevel(); |
| } |
| return changed; |
| } |
| |
| private void changeToCustomLevel() { |
| if (getContentRatingLevel() != TvSettings.CONTENT_RATING_LEVEL_CUSTOM) { |
| TvSettings.setContentRatingLevel(mContext, TvSettings.CONTENT_RATING_LEVEL_CUSTOM); |
| } |
| } |
| |
| /** |
| * Returns the blocked status of a given rating. The status can be one of the followings: {@link |
| * #RATING_BLOCKED}, {@link #RATING_BLOCKED_PARTIAL} and {@link #RATING_NOT_BLOCKED} |
| */ |
| public int getBlockedStatus(ContentRatingSystem contentRatingSystem, Rating rating) { |
| if (isRatingBlocked(contentRatingSystem, rating)) { |
| return RATING_BLOCKED; |
| } |
| for (SubRating subRating : rating.getSubRatings()) { |
| if (isSubRatingEnabled(contentRatingSystem, rating, subRating)) { |
| return RATING_BLOCKED_PARTIAL; |
| } |
| } |
| return RATING_NOT_BLOCKED; |
| } |
| |
| private TvContentRating toTvContentRating( |
| ContentRatingSystem contentRatingSystem, Rating rating) { |
| return TvContentRating.createRating( |
| contentRatingSystem.getDomain(), contentRatingSystem.getName(), rating.getName()); |
| } |
| |
| private TvContentRating toTvContentRating( |
| ContentRatingSystem contentRatingSystem, Rating rating, SubRating subRating) { |
| return TvContentRating.createRating( |
| contentRatingSystem.getDomain(), |
| contentRatingSystem.getName(), |
| rating.getName(), |
| subRating.getName()); |
| } |
| } |