field public static final java.lang.String TELEPHONY_SERVICE = "phone";
field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
field public static final java.lang.String TV_INPUT_SERVICE = "tv_input";
+ field public static final java.lang.String TV_PARENTAL_CONTROL_SERVICE = "tv_parental_control";
field public static final java.lang.String UI_MODE_SERVICE = "uimode";
field public static final java.lang.String USB_SERVICE = "usb";
field public static final java.lang.String USER_SERVICE = "user";
package android.media.tv {
- public class TvContentRating {
+ public final class TvContentRating {
ctor public TvContentRating(java.lang.String);
ctor public TvContentRating(java.lang.String, java.lang.String[]);
method public java.lang.String flattenToString();
+ method public java.lang.String getRating();
+ method public java.util.List<java.lang.String> getSubRatings();
method public static android.media.tv.TvContentRating unflattenFromString(java.lang.String);
field public static final java.lang.String RATING_KR_12 = "RATING_KR_12";
field public static final java.lang.String RATING_KR_15 = "RATING_KR_15";
public abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
ctor public TvInputService.Session();
method public void dispatchChannelRetuned(android.net.Uri);
+ method public void dispatchContentBlocked(android.media.tv.TvContentRating);
method public void dispatchTrackInfoChanged(java.util.List<android.media.tv.TvTrackInfo>);
method public void dispatchVideoAvailable();
method public void dispatchVideoUnavailable(int);
method public void setOverlayViewEnabled(boolean);
}
+ public final class TvParentalControlManager {
+ method public void addParentalControlCallback(android.media.tv.TvParentalControlManager.ParentalControlCallback, android.os.Handler);
+ method public final boolean isEnabled();
+ method public final boolean isRatingBlocked(android.media.tv.TvContentRating);
+ method public void removeParentalControlCallback(android.media.tv.TvParentalControlManager.ParentalControlCallback);
+ }
+
+ public static abstract class TvParentalControlManager.ParentalControlCallback {
+ ctor public TvParentalControlManager.ParentalControlCallback();
+ method public void onBlockedRatingsChanged();
+ method public void onEnabledChanged(boolean);
+ }
+
public final class TvTrackInfo implements android.os.Parcelable {
method public boolean containsKey(java.lang.String);
method public int describeContents();
public static abstract class TvView.TvInputListener {
ctor public TvView.TvInputListener();
method public void onChannelRetuned(java.lang.String, android.net.Uri);
+ method public void onContentBlocked(java.lang.String, android.media.tv.TvContentRating);
method public void onError(java.lang.String, int);
method public void onTrackInfoChanged(java.lang.String, java.util.List<android.media.tv.TvTrackInfo>);
method public void onVideoAvailable(java.lang.String);
import android.media.MediaRouter;
import android.media.session.MediaSessionManager;
import android.media.tv.ITvInputManager;
+import android.media.tv.TvParentalControlManager;
import android.media.tv.TvInputManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
return new TvInputManager(service, UserHandle.myUserId());
}});
+ registerService(TV_PARENTAL_CONTROL_SERVICE, new ServiceFetcher() {
+ public Object getService(ContextImpl ctx) {
+ return new TvParentalControlManager(ctx);
+ }});
+
registerService(NETWORK_SCORE_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new NetworkScoreManager(ctx);
public static final String TV_INPUT_SERVICE = "tv_input";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.media.tv.TvParentalControlManager} for obtaining parental
+ * control settings and listening to their changes.
+ *
+ * @see #getSystemService
+ * @see android.media.tv.TvParentalControlManager
+ */
+ public static final String TV_PARENTAL_CONTROL_SERVICE = "tv_parental_control";
+
+ /**
* {@link android.net.NetworkScoreManager} for managing network scoring.
* @see #getSystemService
* @see android.net.NetworkScoreManager
*/
public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
+
+ /**
+ * Whether the TV parental control is enabled.
+ * @hide
+ */
+ public static final String TV_PARENTAL_CONTROL_ENABLED = "tv_parental_control_enabled";
+
+ /**
+ * List of TV content ratings blocked by the user. (comma-delimited)
+ * @hide
+ */
+ public static final String TV_PARENTAL_CONTROL_BLOCKED_RATINGS =
+ "tv_parental_control_blocked_ratings";
+
/**
* Settings classname to launch when Settings is clicked from All
* Applications. Needed because of user testing between the old
void onTrackInfoChanged(in List<TvTrackInfo> tracks, int seq);
void onVideoAvailable(int seq);
void onVideoUnavailable(int reason, int seq);
+ void onContentBlocked(in String rating, int seq);
}
void onTrackInfoChanged(in List<TvTrackInfo> tracks);
void onVideoAvailable();
void onVideoUnavailable(int reason);
+ void onContentBlocked(in String rating);
}
package android.media.tv;
+import android.annotation.SystemApi;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
import java.util.Arrays;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A class representing a TV content rating.
*/
-public class TvContentRating {
+public final class TvContentRating {
private static final String TAG = "TvContentRating";
private static final int RATING_PREFIX_LENGTH = 10;
// A mapping from two-letter country code (ISO 3166-1 alpha-2) to its rating-to-sub-ratings map.
// This is used for validating the builder parameters.
private static final Map<String, Map<String, String[]>> sRatings
- = new HashMap<String, Map<String, String[]>>();
+ = new ArrayMap<String, Map<String, String[]>>();
static {
- Map<String, String[]> usRatings = new HashMap<String, String[]>();
+ Map<String, String[]> usRatings = new ArrayMap<String, String[]>();
usRatings.put(RATING_US_TV_Y, null);
usRatings.put(RATING_US_TV_Y7, new String[] { SUBRATING_US_FV });
usRatings.put(RATING_US_TV_G, null);
SUBRATING_US_L, SUBRATING_US_S, SUBRATING_US_V });
sRatings.put(PREFIX_RATING_US, usRatings);
- Map<String, String[]> krRatings = new HashMap<String, String[]>();
+ Map<String, String[]> krRatings = new ArrayMap<String, String[]>();
krRatings.put(RATING_KR_ALL, null);
krRatings.put(RATING_KR_7, null);
krRatings.put(RATING_KR_12, null);
* @param rating The rating constant defined in this class.
*/
public TvContentRating(String rating) {
- mRating = rating;
- mSubRatings = null;
+ this(rating, null);
}
/**
* @param subRatings The String array of sub-rating constants defined in this class.
*/
public TvContentRating(String rating, String[] subRatings) {
- mRating = rating;
- mSubRatings = subRatings;
- if (TextUtils.isEmpty(mRating)) {
+ if (TextUtils.isEmpty(rating)) {
throw new IllegalArgumentException("rating cannot be null");
}
+ mRating = rating;
+ mSubRatings = subRatings;
String prefix = "";
if (mRating.length() > RATING_PREFIX_LENGTH) {
prefix = mRating.substring(0, RATING_PREFIX_LENGTH);
} else {
List<String> validSubRatingList = Arrays.asList(subRatings);
for (String sr : mSubRatings) {
+ if (TextUtils.isEmpty(sr)) {
+ throw new IllegalArgumentException(
+ "subRatings cannot contain empty elements");
+ }
if (!validSubRatingList.contains(sr)) {
Log.w(TAG, "Invalid subrating: " + sr);
break;
}
/**
+ * Returns the main rating constant.
+ *
+ * @return the rating string that starts with "RATING_" prefix as defined in this class.
+ */
+ public String getMainRating() {
+ return mRating;
+ }
+
+ /**
+ * Returns the list of sub-rating constants.
+ *
+ * @return the unmodifiable {@code List} of sub-rating strings that start with "SUBRATING_"
+ * prefix as defined in this class.
+ */
+ public List<String> getSubRatings() {
+ if (mSubRatings == null) {
+ return null;
+ }
+ return Collections.unmodifiableList(Arrays.asList(mSubRatings));
+ }
+
+
+ /**
+ * Returns a String that unambiguously describes both the rating and sub-rating information
+ * contained in the TvContentRating. You can later recover the TvContentRating from this string
+ * through {@link #unflattenFromString}.
+ *
+ * @return a new String holding rating/sub-rating information, which can later be stored in the
+ * database and settings.
+ * @see #unflattenFromString
+ */
+ public String flattenToString() {
+ // TODO: Consider removing all obvious/redundant sub-strings including "RATING" and
+ // "SUBRATING" and find out a storage-efficient string format such as:
+ // <country>-<primary>/<sub1>/<sub2>/<sub3>
+ StringBuilder builder = new StringBuilder(mRating);
+ if (mSubRatings != null) {
+ for (String subRating : mSubRatings) {
+ builder.append(DELIMITER);
+ builder.append(subRating);
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
* Recovers a TvContentRating from a String that was previously created with
* {@link #flattenToString}.
*
}
/**
- * @return a String that unambiguously describes both the rating and sub-rating information
- * contained in the TvContentRating. You can later recover the TvContentRating from this
- * string through {@link #unflattenFromString}.
- * @see #unflattenFromString
+ * Returns true if this rating has the same main rating as the specified rating and when this
+ * rating's sub-ratings contain the other's.
+ * <p>
+ * For example, a TvContentRating object that represents TV-PG with S(Sexual content) and
+ * V(Violence) contains TV-PG, TV-PG/S, TV-PG/V and itself.
+ * </p>
+ *
+ * @param rating The {@link TvContentRating} to check.
+ * @return {@code true} if this object contains {@code rating}, {@code false} otherwise.
+ * @hide
*/
- public String flattenToString() {
- StringBuffer ratingStr = new StringBuffer();
- ratingStr.append(mRating);
- if (mSubRatings != null) {
- for (String subRating : mSubRatings) {
- ratingStr.append(DELIMITER);
- ratingStr.append(subRating);
- }
+ @SystemApi
+ public final boolean contains(TvContentRating rating) {
+ if (rating == null) {
+ throw new IllegalArgumentException("rating cannot be null");
+ }
+ if (!rating.getMainRating().equals(mRating)) {
+ return false;
+ }
+ List<String> subRatings = getSubRatings();
+ List<String> subRatingsOther = rating.getSubRatings();
+ if (subRatings == null && subRatingsOther == null) {
+ return true;
+ } else if (subRatings == null && subRatingsOther != null) {
+ return false;
+ } else if (subRatings != null && subRatingsOther == null) {
+ return true;
+ } else {
+ return subRatings.containsAll(subRatingsOther);
}
- return ratingStr.toString();
}
}
import android.view.View;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public final class TvInputManager {
private static final String TAG = "TvInputManager";
+ static final int VIDEO_UNAVAILABLE_REASON_START = 0;
+ static final int VIDEO_UNAVAILABLE_REASON_END = 3;
+
/**
* A generic reason. Video is not available due to an unspecified error.
*/
- public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = 0;
+ public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = VIDEO_UNAVAILABLE_REASON_START;
/**
* Video is not available because the TV input is tuning to another channel.
*/
* Video is not available because the TV input stopped the playback temporarily to buffer more
* data.
*/
- public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = 3;
+ public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = VIDEO_UNAVAILABLE_REASON_END;
/**
* The TV input is connected.
}
/**
+ * This is called when the current program content is blocked by parental controls.
+ *
+ * @param session A {@link TvInputManager.Session} associated with this callback
+ * @param rating The content ration of the blocked program.
+ */
+ public void onContentBlocked(Session session, TvContentRating rating) {
+ }
+
+ /**
* This is called when a custom event has been sent from this session.
*
* @param session A {@link TvInputManager.Session} associated with this callback
});
}
+ public void postContentBlocked(final TvContentRating rating) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onContentBlocked(mSession, rating);
+ }
+ });
+ }
+
public void postSessionEvent(final String eventType, final Bundle eventArgs) {
mHandler.post(new Runnable() {
@Override
}
@Override
+ public void onContentBlocked(String rating, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postContentBlocked(TvContentRating.unflattenFromString(rating));
+ }
+ }
+
+ @Override
public void onSessionEvent(String eventType, Bundle eventArgs, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
import android.annotation.SuppressLint;
import android.app.Service;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
}
/**
+ * Informs the application that the current program content is blocked by parent controls.
+ * <p>
+ * Each TV input service is required to query the system whether the user is allowed to
+ * watch the current program before showing it to the user if the parental control is turned
+ * on, which can be checked by calling {@link TvParentalControlManager#isEnabled}. Whether
+ * the TV input service should block the content or not is determined by invoking
+ * {@link TvParentalControlManager#isRatingBlocked} with the content rating for the current
+ * program. Then the TvParentalControlManager makes a judgment based on the user blocked
+ * ratings stored in the secure settings and returns the result. If the rating in question
+ * turns out to be blocked, the TV input service must immediately block the content and call
+ * this method with the content rating of the current program to prompt the PIN verification
+ * screen.
+ * </p><p>
+ * Each TV input service also needs to continuously listen to any changes made to the
+ * parental control settings by registering a
+ * {@link TvParentalControlManager.ParentalControlCallback} to the manager and immediately
+ * reevaluate the current program with the new parental control settings.
+ * </p>
+ *
+ * @param rating The content rating for the current TV program.
+ */
+ public void dispatchContentBlocked(final TvContentRating rating) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) Log.d(TAG, "dispatchContentBlocked");
+ mSessionCallback.onContentBlocked(rating.flattenToString());
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in dispatchContentBlocked");
+ }
+ }
+ });
+ }
+
+ /**
* Informs the application that video is not available, so the TV input cannot continue
* playing the TV stream.
*
* </ul>
*/
public void dispatchVideoUnavailable(final int reason) {
- if (reason != TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN
- && reason != TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNE
- && reason != TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL
- && reason != TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING) {
+ if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START
+ || reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
throw new IllegalArgumentException("Unknown reason: " + reason);
}
mHandler.post(new Runnable() {
--- /dev/null
+/*
+ * Copyright (C) 2014 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 android.media.tv;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Contains methods for accessing and monitoring the user's parental control settings.
+ * <p>
+ * To obtain a handle to the TV parental control manager, do the following:
+ * <p>
+ * <code>
+ * <pre>TvParentalControlManager tvParentalControlManager =
+ * (TvParentalControlManager) context.getSystemService(Context.TV_PARENTAL_CONTROL_SERVICE);
+ * </pre>
+ * </code>
+ */
+public final class TvParentalControlManager {
+ /** Default parental control enabled value. */
+ private static final int DEFAULT_ENABLED = 0;
+
+ private final Handler mHandler = new Handler();
+
+ private final ContentResolver mContentResolver;
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final List<ParentalControlCallbackRecord> mParentalControlCallbackRecordList =
+ new LinkedList<ParentalControlCallbackRecord>();
+
+ @GuardedBy("mLock")
+ private final List<TvContentRating> mBlockedRatings = new ArrayList<TvContentRating>();
+
+ @GuardedBy("mLock")
+ private String mBlockedRatingsString;
+
+ /**
+ * Creates a new parental control manager for the specified context.
+ *
+ * @hide
+ */
+ public TvParentalControlManager(Context context) {
+ mContentResolver = context.getContentResolver();
+ }
+
+ /**
+ * Returns the user's parental control enabled state.
+ *
+ * @return {@code true} if the user enabled the parental control, {@code false} otherwise.
+ */
+ public final boolean isEnabled() {
+ return Settings.Secure.getInt(mContentResolver, Settings.Secure.TV_PARENTAL_CONTROL_ENABLED,
+ DEFAULT_ENABLED) == 1;
+ }
+
+ /**
+ * Checks whether a given TV content rating is blocked by the user.
+ *
+ * @param rating The TV content rating to check.
+ * @return {@code true} if blocked, {@code false} if not blocked or parental control is
+ * disabled.
+ */
+ public final boolean isRatingBlocked(TvContentRating rating) {
+ if (!isEnabled()) {
+ // Parental control is disabled. Enjoy watching good stuff.
+ return false;
+ }
+
+ // Update the blocked ratings only when they change.
+ final String blockedRatingsString = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.TV_PARENTAL_CONTROL_BLOCKED_RATINGS);
+ synchronized (mLock) {
+ if (!TextUtils.equals(blockedRatingsString, mBlockedRatingsString)) {
+ mBlockedRatingsString = blockedRatingsString;
+ updateBlockedRatingsLocked();
+ }
+ for (TvContentRating blockedRating : mBlockedRatings) {
+ if (rating.contains(blockedRating)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void updateBlockedRatingsLocked() {
+ mBlockedRatings.clear();
+ if (TextUtils.isEmpty(mBlockedRatingsString)) {
+ return;
+ }
+ for (String blockedRatingString : mBlockedRatingsString.split("\\s*,\\s*")) {
+ mBlockedRatings.add(TvContentRating.unflattenFromString(blockedRatingString));
+ }
+ }
+
+ /**
+ * Adds a callback for monitoring the changes in the user's parental control settings.
+ *
+ * @param callback The callback to add.
+ * @param handler a {@link Handler} that the settings change will be delivered to.
+ */
+ public void addParentalControlCallback(ParentalControlCallback callback,
+ Handler handler) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback cannot be null");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException("handler cannot be null");
+ }
+ synchronized (mLock) {
+ if (mParentalControlCallbackRecordList.isEmpty()) {
+ registerObserver(Settings.Secure.TV_PARENTAL_CONTROL_ENABLED);
+ registerObserver(Settings.Secure.TV_PARENTAL_CONTROL_BLOCKED_RATINGS);
+ }
+ mParentalControlCallbackRecordList.add(
+ new ParentalControlCallbackRecord(callback, handler));
+ }
+ }
+
+ private void registerObserver(String key) {
+ mContentResolver.registerContentObserver(Settings.Secure.getUriFor(key), false,
+ mContentObserver);
+ }
+
+ /**
+ * Removes a callback previously added using {@link #addParentalControlCallback}.
+ *
+ * @param callback The callback to remove.
+ */
+ public void removeParentalControlCallback(ParentalControlCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback cannot be null");
+ }
+ synchronized (mLock) {
+ for (Iterator<ParentalControlCallbackRecord> it =
+ mParentalControlCallbackRecordList.iterator(); it.hasNext();) {
+ ParentalControlCallbackRecord record = it.next();
+ if (record.getCallback() == callback) {
+ it.remove();
+ break;
+ }
+ }
+ }
+ }
+
+ private void notifyEnabledChanged() {
+ final boolean enabled = isEnabled();
+ synchronized (mLock) {
+ for (ParentalControlCallbackRecord record : mParentalControlCallbackRecordList) {
+ record.postEnabledChanged(enabled);
+ }
+ }
+ }
+
+ private final ContentObserver mContentObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ final String uriPath = uri.getPath();
+ final String name = uriPath.substring(uriPath.lastIndexOf('/') + 1);
+ if (Settings.Secure.TV_PARENTAL_CONTROL_ENABLED.equals(name)) {
+ notifyEnabledChanged();
+ } else if (Settings.Secure.TV_PARENTAL_CONTROL_BLOCKED_RATINGS.equals(name)) {
+ // We only need a single callback when multiple ratings change in rapid
+ // succession.
+ mHandler.removeCallbacks(mBlockedRatingsChangedRunnable);
+ mHandler.post(mBlockedRatingsChangedRunnable);
+ }
+ }
+ };
+
+ /**
+ * Runnable posted when user blocked ratings change. This is used to prevent unnecessary change
+ * notifications when multiple ratings change in rapid succession.
+ */
+ private final Runnable mBlockedRatingsChangedRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ for (ParentalControlCallbackRecord record : mParentalControlCallbackRecordList) {
+ record.postBlockedRatingsChanged();
+ }
+ }
+ }
+ };
+
+ /**
+ * Callback for changes in parental control settings, including enabled state.
+ */
+ public static abstract class ParentalControlCallback {
+ /**
+ * Called when the parental control enabled state changes.
+ *
+ * @param enabled the user's parental control enabled state
+ */
+ public void onEnabledChanged(boolean enabled) {}
+
+ /**
+ * Called when the user blocked ratings change.
+ * <p>
+ * When this is invoked, one should immediately call
+ * {@link TvParentalControlManager#isRatingBlocked} to reevaluate the current content since
+ * the user might have changed her mind and blocked the rating for the content.
+ *
+ * @see TvParentalControlManager#isRatingBlocked
+ */
+ public void onBlockedRatingsChanged() {}
+ }
+
+ private static final class ParentalControlCallbackRecord {
+ private final ParentalControlCallback mCallback;
+ private final Handler mHandler;
+
+ public ParentalControlCallbackRecord(ParentalControlCallback callback, Handler handler) {
+ mCallback = callback;
+ mHandler = handler;
+ }
+
+ public ParentalControlCallback getCallback() {
+ return mCallback;
+ }
+
+ public void postEnabledChanged(final boolean enabled) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onEnabledChanged(enabled);
+ }
+ });
+ }
+
+ public void postBlockedRatingsChanged() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onBlockedRatingsChanged();
+ }
+ });
+ }
+ }
+}
}
/**
+ * This is called when the current program content is blocked by parental controls.
+ *
+ * @param inputId The ID of the TV input bound to this view.
+ * @param rating The content rating of the blocked program.
+ */
+ public void onContentBlocked(String inputId, TvContentRating rating) {
+ }
+
+ /**
* This is invoked when a custom event from the bound TV input is sent to this view.
*
* @param eventType The type of the event.
}
}
+ @Override
public void onVideoAvailable(Session session) {
if (DEBUG) {
Log.d(TAG, "onVideoAvailable()");
}
}
+ @Override
public void onVideoUnavailable(Session session, int reason) {
if (DEBUG) {
Log.d(TAG, "onVideoUnavailable(" + reason + ")");
}
@Override
+ public void onContentBlocked(Session session, TvContentRating rating) {
+ if (DEBUG) {
+ Log.d(TAG, "onContentBlocked()");
+ }
+ if (mListener != null) {
+ mListener.onContentBlocked(mInputId, rating);
+ }
+ }
+
+ @Override
public void onSessionEvent(TvInputManager.Session session, String eventType,
Bundle eventArgs) {
if (this != mSessionCallback) {
}
@Override
+ public void onContentBlocked(String rating) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(TAG, "onContentBlocked()");
+ }
+ if (sessionState.mSession == null || sessionState.mClient == null) {
+ return;
+ }
+ try {
+ sessionState.mClient.onContentBlocked(rating, sessionState.mSeq);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in onContentBlocked");
+ }
+ }
+ }
+
+ @Override
public void onSessionEvent(String eventType, Bundle eventArgs) {
synchronized (mLock) {
if (DEBUG) {