diff --git a/core/api/current.txt b/core/api/current.txt index 52cb4923de185..64557decd96bd 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -27437,6 +27437,7 @@ package android.media.tv { method public boolean onTrackballEvent(android.view.MotionEvent); method public abstract boolean onTune(android.net.Uri); method public boolean onTune(android.net.Uri, android.os.Bundle); + method public void onTvMessage(@NonNull String, @NonNull android.os.Bundle); method public void onUnblockContent(android.media.tv.TvContentRating); method public void setOverlayViewEnabled(boolean); } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 43fa6e262a145..83fdd47ff050a 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1921,6 +1921,10 @@ package android.media.tv { method public void removeHardwareDevice(int); } + public class TvView extends android.view.ViewGroup { + method public void notifyTvMessage(@NonNull String, @NonNull android.os.Bundle); + } + } package android.media.tv.tuner { diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index e9aa321018f3e..113c85802fa28 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -118,6 +118,9 @@ interface ITvInputManager { void requestAd(in IBinder sessionToken, in AdRequest request, int userId); void notifyAdBuffer(in IBinder sessionToken, in AdBuffer buffer, int userId); + // For TV Message + void notifyTvMessage(in IBinder sessionToken, in String type, in Bundle data, int userId); + // For TV input hardware binding List getHardwareList(); ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback, diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl index 82875e5d72f15..165a9ddc26e9c 100644 --- a/media/java/android/media/tv/ITvInputSession.aidl +++ b/media/java/android/media/tv/ITvInputSession.aidl @@ -76,4 +76,7 @@ oneway interface ITvInputSession { // For ad request void requestAd(in AdRequest request); void notifyAdBuffer(in AdBuffer buffer); + + // For TV messages + void notifyTvMessage(in String type, in Bundle data); } diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java index 465b617db1f4b..8389706b501c4 100644 --- a/media/java/android/media/tv/ITvInputSessionWrapper.java +++ b/media/java/android/media/tv/ITvInputSessionWrapper.java @@ -78,6 +78,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand private static final int DO_SELECT_AUDIO_PRESENTATION = 29; private static final int DO_TIME_SHIFT_SET_MODE = 30; private static final int DO_SET_TV_MESSAGE_ENABLED = 31; + private static final int DO_NOTIFY_TV_MESSAGE = 32; private final boolean mIsRecordingSession; private final HandlerCaller mCaller; @@ -277,6 +278,11 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand mTvInputSessionImpl.notifyAdBuffer((AdBuffer) msg.obj); break; } + case DO_NOTIFY_TV_MESSAGE: { + SomeArgs args = (SomeArgs) msg.obj; + mTvInputSessionImpl.onTvMessageReceived((String) args.arg1, (Bundle) args.arg2); + break; + } default: { Log.w(TAG, "Unhandled message code: " + msg.what); break; @@ -463,6 +469,11 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_NOTIFY_AD_BUFFER, buffer)); } + @Override + public void notifyTvMessage(String type, Bundle data) { + mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_NOTIFY_TV_MESSAGE, type, data)); + } + private final class TvInputEventReceiver extends InputEventReceiver { TvInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 8459538f102da..828c88eefb870 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -3220,6 +3220,17 @@ public final class TvInputManager { } } + /** + * Sends TV messages to the service for testing purposes + */ + public void notifyTvMessage(@NonNull @TvMessageType String type, @NonNull Bundle data) { + try { + mService.notifyTvMessage(mToken, type, data, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Starts TV program recording in the current recording session. * diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 4bc137da6f00a..9f40d704f7ac7 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -1491,7 +1491,18 @@ public abstract class TvInputService extends Service { * {@code false} otherwise. */ public void onSetTvMessageEnabled(@NonNull @TvInputManager.TvMessageType String type, - boolean enabled){ + boolean enabled) { + } + + /** + * Called when a TV message is received + * + * @param type The type of message received, such as + * {@link TvInputManager#TV_MESSAGE_TYPE_WATERMARK} + * @param data The raw data of the message + */ + public void onTvMessage(@NonNull @TvInputManager.TvMessageType String type, + @NonNull Bundle data) { } /** @@ -2043,6 +2054,10 @@ public abstract class TvInputService extends Service { onAdBuffer(buffer); } + void onTvMessageReceived(String type, Bundle data) { + onTvMessage(type, data); + } + /** * Takes care of dispatching incoming input events and tells whether the event was handled. */ diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java index 3ef61f289e237..5aeed1fbbaf5f 100644 --- a/media/java/android/media/tv/TvView.java +++ b/media/java/android/media/tv/TvView.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.content.AttributionSource; import android.content.Context; import android.content.pm.PackageManager; @@ -640,6 +641,20 @@ public class TvView extends ViewGroup { } } + + /** + * Sends TV messages to the session for testing purposes + * + * @hide + */ + @TestApi + public void notifyTvMessage(@TvInputManager.TvMessageType @NonNull String type, + @NonNull Bundle data) { + if (mSession != null) { + mSession.notifyTvMessage(type, data); + } + } + /** * Sets the callback to be invoked when the time shift position is changed. * diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 404ca017929d3..c6684dfdb6e0a 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -2124,6 +2124,26 @@ public final class TvInputManagerService extends SystemService { } } + @Override + public void notifyTvMessage(IBinder sessionToken, String type, Bundle data, int userId) { + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "timeShiftEnablePositionTracking"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + getSessionLocked(sessionToken, callingUid, resolvedUserId) + .notifyTvMessage(type, data); + } catch (RemoteException | SessionNotFoundException e) { + Slog.e(TAG, "error in timeShiftEnablePositionTracking", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public void startRecording(IBinder sessionToken, @Nullable Uri programUri, @Nullable Bundle params, int userId) {