TIF: add TvInputManager methods to notify apps
Adds TvInputManager methods to notify apps with protected broadcasts
for:
1. Disabling browsable state of preview and watch next programs.
2. Adding preview programs to watch next programs.
Test: build and verify manually to check if notifications are
broadcasted.
Bug: 35881266
Change-Id: I20fd5b63f42b2c74277315bbbd251b71c649e5c1
diff --git a/api/system-current.txt b/api/system-current.txt
index fa2a69e..fc567b9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -163,6 +163,7 @@
field public static final java.lang.String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
field public static final java.lang.String NFC = "android.permission.NFC";
field public static final java.lang.String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
+ field public static final java.lang.String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
field public static final java.lang.String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
@@ -27006,6 +27007,9 @@
method public boolean isParentalControlsEnabled();
method public boolean isRatingBlocked(android.media.tv.TvContentRating);
method public boolean isSingleSessionActive();
+ method public void notifyPreviewProgramAddedToWatchNext(java.lang.String, long, long);
+ method public void notifyPreviewProgramBrowsableDisabled(java.lang.String, long);
+ method public void notifyWatchNextProgramBrowsableDisabled(java.lang.String, long);
method public void registerCallback(android.media.tv.TvInputManager.TvInputCallback, android.os.Handler);
method public void releaseTvInputHardware(int, android.media.tv.TvInputManager.Hardware);
method public void removeBlockedRating(android.media.tv.TvContentRating);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0a50048..866c47e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -531,6 +531,9 @@
<protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
<protected-broadcast android:name="android.os.action.USER_RESTRICTIONS_CHANGED" />
+ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT" />
+ <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED" />
+ <protected-broadcast android:name="android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
@@ -2511,6 +2514,13 @@
<permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an application to notify TV inputs by sending broadcasts.
+ <p>Protection level: signature|privileged
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.NOTIFY_TV_INPUTS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Must be required by a {@link android.media.routing.MediaRouteService}
to ensure that only the system can interact with it.
@hide -->
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 0d51b5b..af4a5be 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -17,6 +17,7 @@
package android.media.tv;
import android.content.ComponentName;
+import android.content.Intent;
import android.graphics.Rect;
import android.media.PlaybackParams;
import android.media.tv.DvbDeviceInfo;
@@ -105,4 +106,7 @@
// For DVB device binding
List<DvbDeviceInfo> getDvbDeviceList();
ParcelFileDescriptor openDvbDevice(in DvbDeviceInfo info, int device);
+
+ // For preview programs
+ void sendTvInputNotifyIntent(in Intent intent, int userId);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 09b2050..276a0dc 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.content.Intent;
import android.graphics.Rect;
import android.media.PlaybackParams;
import android.net.Uri;
@@ -1394,6 +1395,64 @@
}
/**
+ * Notifies the TV input of the given preview program that the program's browsable state is
+ * disabled.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS)
+ public void notifyPreviewProgramBrowsableDisabled(String packageName, long programId) {
+ Intent intent = new Intent();
+ intent.setAction(TvContract.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED);
+ intent.putExtra(TvContract.EXTRA_PREVIEW_PROGRAM_ID, programId);
+ intent.setPackage(packageName);
+ try {
+ mService.sendTvInputNotifyIntent(intent, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notifies the TV input of the given watch next program that the program's browsable state is
+ * disabled.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS)
+ public void notifyWatchNextProgramBrowsableDisabled(String packageName, long programId) {
+ Intent intent = new Intent();
+ intent.setAction(TvContract.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED);
+ intent.putExtra(TvContract.EXTRA_WATCH_NEXT_PROGRAM_ID, programId);
+ intent.setPackage(packageName);
+ try {
+ mService.sendTvInputNotifyIntent(intent, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notifies the TV input of the given preview program that the program is added to watch next.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS)
+ public void notifyPreviewProgramAddedToWatchNext(String packageName, long previewProgramId,
+ long watchNextProgramId) {
+ Intent intent = new Intent();
+ intent.setAction(TvContract.ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT);
+ intent.putExtra(TvContract.EXTRA_PREVIEW_PROGRAM_ID, previewProgramId);
+ intent.putExtra(TvContract.EXTRA_WATCH_NEXT_PROGRAM_ID, watchNextProgramId);
+ intent.setPackage(packageName);
+ try {
+ mService.sendTvInputNotifyIntent(intent, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Creates a {@link Session} for a given TV input.
*
* <p>The number of sessions that can be created at the same time is limited by the capability
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index be91f48..a519acc 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -942,6 +942,50 @@
}
@Override
+ public void sendTvInputNotifyIntent(Intent intent, int userId) {
+ if (mContext.checkCallingPermission(android.Manifest.permission.NOTIFY_TV_INPUTS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("The caller: " + getCallingPackageName()
+ + " doesn't have permission: "
+ + android.Manifest.permission.NOTIFY_TV_INPUTS);
+ }
+ if (TextUtils.isEmpty(intent.getPackage())) {
+ throw new IllegalArgumentException("Must specify package name to notify.");
+ }
+ switch (intent.getAction()) {
+ case TvContract.ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED:
+ if (intent.getLongExtra(TvContract.EXTRA_PREVIEW_PROGRAM_ID, -1) < 0) {
+ throw new IllegalArgumentException("Invalid preview program ID.");
+ }
+ break;
+ case TvContract.ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED:
+ if (intent.getLongExtra(TvContract.EXTRA_WATCH_NEXT_PROGRAM_ID, -1) < 0) {
+ throw new IllegalArgumentException("Invalid watch next program ID.");
+ }
+ break;
+ case TvContract.ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT:
+ if (intent.getLongExtra(TvContract.EXTRA_PREVIEW_PROGRAM_ID, -1) < 0) {
+ throw new IllegalArgumentException("Invalid preview program ID.");
+ }
+ if (intent.getLongExtra(TvContract.EXTRA_WATCH_NEXT_PROGRAM_ID, -1) < 0) {
+ throw new IllegalArgumentException("Invalid watch next program ID.");
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid TV input notifying action: "
+ + intent.getAction());
+ }
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "sendTvInputNotifyIntent");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ getContext().sendBroadcastAsUser(intent, new UserHandle(resolvedUserId));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void registerCallback(final ITvInputManagerCallback callback, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "registerCallback");
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a5eac46..e4be27b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1423,7 +1423,8 @@
traceEnd();
}
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LIVE_TV)) {
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LIVE_TV)
+ || mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
traceBeginAndSlog("StartTvInputManager");
mSystemServiceManager.startService(TvInputManagerService.class);
traceEnd();