/* * 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 mRatings; private Set 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 removed = new HashSet<>(mTvInputManager.getBlockedRatings()); removed.removeAll(mRatings); for (TvContentRating tvContentRating : removed) { mTvInputManager.removeBlockedRating(tvContentRating); } Set 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 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. * *

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 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. * *

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()); } }