diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl index 537e71122cefa..494571fc37cf2 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl @@ -41,6 +41,7 @@ oneway interface ITvInteractiveAppClient { void onTeletextAppStateChanged(int state, int seq); void onAdBuffer(in AdBuffer buffer, int seq); void onCommandRequest(in String cmdType, in Bundle parameters, int seq); + void onTimeShiftCommandRequest(in String cmdType, in Bundle parameters, int seq); void onSetVideoBounds(in Rect rect, int seq); void onRequestCurrentChannelUri(int seq); void onRequestCurrentChannelLcn(int seq); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl index 5a0ac84e5c5e7..1cfb6efbd1721 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl @@ -26,6 +26,7 @@ import android.media.tv.interactive.AppLinkInfo; import android.media.tv.interactive.ITvInteractiveAppClient; import android.media.tv.interactive.ITvInteractiveAppManagerCallback; import android.media.tv.interactive.TvInteractiveAppServiceInfo; +import android.media.PlaybackParams; import android.net.Uri; import android.os.Bundle; import android.view.Surface; @@ -57,6 +58,14 @@ interface ITvInteractiveAppManager { void sendTvRecordingInfoList(in IBinder sessionToken, in List recordingInfoList, int userId); void notifyError(in IBinder sessionToken, in String errMsg, in Bundle params, int userId); + void notifyTimeShiftPlaybackParams( + in IBinder sessionToken, in PlaybackParams params, int userId); + void notifyTimeShiftStatusChanged( + in IBinder sessionToken, in String inputId, int status, int userId); + void notifyTimeShiftStartPositionChanged( + in IBinder sessionToken, in String inputId, long timeMs, int userId); + void notifyTimeShiftCurrentPositionChanged( + in IBinder sessionToken, in String inputId, long timeMs, int userId); void createSession(in ITvInteractiveAppClient client, in String iAppServiceId, int type, int seq, int userId); void releaseSession(in IBinder sessionToken, int userId); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl index 20ba57b11b11e..17a70d1d8a7d4 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl @@ -20,6 +20,7 @@ import android.graphics.Rect; import android.media.tv.BroadcastInfoResponse; import android.net.Uri; import android.media.tv.AdBuffer; +import android.media.PlaybackParams; import android.media.tv.AdResponse; import android.media.tv.BroadcastInfoResponse; import android.media.tv.TvTrackInfo; @@ -48,6 +49,10 @@ oneway interface ITvInteractiveAppSession { void sendTvRecordingInfo(in TvRecordingInfo recordingInfo); void sendTvRecordingInfoList(in List recordingInfoList); void notifyError(in String errMsg, in Bundle params); + void notifyTimeShiftPlaybackParams(in PlaybackParams params); + void notifyTimeShiftStatusChanged(in String inputId, int status); + void notifyTimeShiftStartPositionChanged(in String inputId, long timeMs); + void notifyTimeShiftCurrentPositionChanged(in String inputId, long timeMs); void release(); void notifyTuned(in Uri channelUri); void notifyTrackSelected(int type, in String trackId); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl index c5dbd1941c90c..056574295cd8a 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl @@ -40,6 +40,7 @@ oneway interface ITvInteractiveAppSessionCallback { void onTeletextAppStateChanged(int state); void onAdBuffer(in AdBuffer buffer); void onCommandRequest(in String cmdType, in Bundle parameters); + void onTimeShiftCommandRequest(in String cmdType, in Bundle parameters); void onSetVideoBounds(in Rect rect); void onRequestCurrentChannelUri(); void onRequestCurrentChannelLcn(); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java index a55e1acf78379..b8158cd1d949b 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.graphics.Rect; +import android.media.PlaybackParams; import android.media.tv.AdBuffer; import android.media.tv.AdResponse; import android.media.tv.BroadcastInfoResponse; @@ -89,6 +90,10 @@ public class ITvInteractiveAppSessionWrapper private static final int DO_NOTIFY_TV_MESSAGE = 33; private static final int DO_SEND_RECORDING_INFO = 34; private static final int DO_SEND_RECORDING_INFO_LIST = 35; + private static final int DO_NOTIFY_TIME_SHIFT_PLAYBACK_PARAMS = 36; + private static final int DO_NOTIFY_TIME_SHIFT_STATUS_CHANGED = 37; + private static final int DO_NOTIFY_TIME_SHIFT_START_POSITION_CHANGED = 38; + private static final int DO_NOTIFY_TIME_SHIFT_CURRENT_POSITION_CHANGED = 39; private final HandlerCaller mCaller; private Session mSessionImpl; @@ -277,6 +282,30 @@ public class ITvInteractiveAppSessionWrapper mSessionImpl.notifyAdBufferConsumed((AdBuffer) msg.obj); break; } + case DO_NOTIFY_TIME_SHIFT_PLAYBACK_PARAMS: { + mSessionImpl.notifyTimeShiftPlaybackParams((PlaybackParams) msg.obj); + break; + } + case DO_NOTIFY_TIME_SHIFT_STATUS_CHANGED: { + SomeArgs args = (SomeArgs) msg.obj; + mSessionImpl.notifyTimeShiftStatusChanged((String) args.arg1, (Integer) args.arg2); + args.recycle(); + break; + } + case DO_NOTIFY_TIME_SHIFT_START_POSITION_CHANGED: { + SomeArgs args = (SomeArgs) msg.obj; + mSessionImpl.notifyTimeShiftStartPositionChanged( + (String) args.arg1, (Long) args.arg2); + args.recycle(); + break; + } + case DO_NOTIFY_TIME_SHIFT_CURRENT_POSITION_CHANGED: { + SomeArgs args = (SomeArgs) msg.obj; + mSessionImpl.notifyTimeShiftCurrentPositionChanged( + (String) args.arg1, (Long) args.arg2); + args.recycle(); + break; + } default: { Log.w(TAG, "Unhandled message code: " + msg.what); break; @@ -379,6 +408,30 @@ public class ITvInteractiveAppSessionWrapper mCaller.obtainMessageOO(DO_NOTIFY_ERROR, errMsg, params)); } + @Override + public void notifyTimeShiftPlaybackParams(@NonNull PlaybackParams params) { + mCaller.executeOrSendMessage( + mCaller.obtainMessageO(DO_NOTIFY_TIME_SHIFT_PLAYBACK_PARAMS, params)); + } + + @Override + public void notifyTimeShiftStatusChanged(@NonNull String inputId, int status) { + mCaller.executeOrSendMessage( + mCaller.obtainMessageOO(DO_NOTIFY_TIME_SHIFT_STATUS_CHANGED, inputId, status)); + } + + @Override + public void notifyTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) { + mCaller.executeOrSendMessage(mCaller.obtainMessageOO( + DO_NOTIFY_TIME_SHIFT_START_POSITION_CHANGED, inputId, timeMs)); + } + + @Override + public void notifyTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) { + mCaller.executeOrSendMessage(mCaller.obtainMessageOO( + DO_NOTIFY_TIME_SHIFT_CURRENT_POSITION_CHANGED, inputId, timeMs)); + } + @Override public void release() { mSessionImpl.scheduleMediaViewCleanup(); diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java index f4847f70fcee3..3647a9ccd5ccd 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.annotation.SystemService; import android.content.Context; import android.graphics.Rect; +import android.media.PlaybackParams; import android.media.tv.AdBuffer; import android.media.tv.AdRequest; import android.media.tv.AdResponse; @@ -404,6 +405,21 @@ public final class TvInteractiveAppManager { } } + @Override + public void onTimeShiftCommandRequest( + @TvInteractiveAppService.TimeShiftCommandType String cmdType, + Bundle parameters, + int seq) { + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); + if (record == null) { + Log.e(TAG, "Callback not found for seq " + seq); + return; + } + record.postTimeShiftCommandRequest(cmdType, parameters); + } + } + @Override public void onSetVideoBounds(Rect rect, int seq) { synchronized (mSessionCallbackRecordMap) { @@ -1182,6 +1198,55 @@ public final class TvInteractiveAppManager { } } + void notifyTimeShiftPlaybackParams(@NonNull PlaybackParams params) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.notifyTimeShiftPlaybackParams(mToken, params, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + void notifyTimeShiftStatusChanged( + @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.notifyTimeShiftStatusChanged(mToken, inputId, status, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + void notifyTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.notifyTimeShiftStartPositionChanged(mToken, inputId, timeMs, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + void notifyTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.notifyTimeShiftCurrentPositionChanged(mToken, inputId, timeMs, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Sets the {@link android.view.Surface} for this session. * @@ -1795,6 +1860,17 @@ public final class TvInteractiveAppManager { }); } + void postTimeShiftCommandRequest( + final @TvInteractiveAppService.TimeShiftCommandType String cmdType, + final Bundle parameters) { + mHandler.post(new Runnable() { + @Override + public void run() { + mSessionCallback.onTimeShiftCommandRequest(mSession, cmdType, parameters); + } + }); + } + void postSetVideoBounds(Rect rect) { mHandler.post(new Runnable() { @Override @@ -2002,6 +2078,20 @@ public final class TvInteractiveAppManager { Bundle parameters) { } + /** + * This is called when {@link TvInteractiveAppService.Session#requestTimeShiftCommand} is + * called. + * + * @param session A {@link TvInteractiveAppManager.Session} associated with this callback. + * @param cmdType type of the time shift command. + * @param parameters parameters of the command. + */ + public void onTimeShiftCommandRequest( + Session session, + @TvInteractiveAppService.TimeShiftCommandType String cmdType, + Bundle parameters) { + } + /** * This is called when {@link TvInteractiveAppService.Session#SetVideoBounds} is called. * diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java index 3ca9f2fa2986c..949e01775aeb6 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java @@ -30,6 +30,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.media.PlaybackParams; import android.media.tv.AdBuffer; import android.media.tv.AdRequest; import android.media.tv.AdResponse; @@ -182,6 +183,78 @@ public abstract class TvInteractiveAppService extends Service { public static final String COMMAND_PARAMETER_KEY_CHANGE_CHANNEL_QUIETLY = "command_change_channel_quietly"; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @StringDef(prefix = "TIME_SHIFT_COMMAND_TYPE_", value = { + TIME_SHIFT_COMMAND_TYPE_PLAY, + TIME_SHIFT_COMMAND_TYPE_PAUSE, + TIME_SHIFT_COMMAND_TYPE_RESUME, + TIME_SHIFT_COMMAND_TYPE_SEEK_TO, + TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS, + }) + public @interface TimeShiftCommandType {} + + /** + * Time shift command type: play. + * + * @see TvView#timeShiftPlay(String, Uri) + * @hide + */ + public static final String TIME_SHIFT_COMMAND_TYPE_PLAY = "play"; + /** + * Time shift command type: pause. + * + * @see TvView#timeShiftPause() + * @hide + */ + public static final String TIME_SHIFT_COMMAND_TYPE_PAUSE = "pause"; + /** + * Time shift command type: resume. + * + * @see TvView#timeShiftResume() + * @hide + */ + public static final String TIME_SHIFT_COMMAND_TYPE_RESUME = "resume"; + /** + * Time shift command type: seek to. + * + * @see TvView#timeShiftSeekTo(long) + * @hide + */ + public static final String TIME_SHIFT_COMMAND_TYPE_SEEK_TO = "seek_to"; + /** + * Time shift command type: set playback params. + * + * @see TvView#timeShiftSetPlaybackParams(PlaybackParams) + * @hide + */ + public static final String TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS = "set_playback_params"; + + /** + * Time shift command parameter: program URI. + *

Type: android.net.Uri + * + * @see #TIME_SHIFT_COMMAND_TYPE_PLAY + * @hide + */ + public static final String COMMAND_PARAMETER_KEY_PROGRAM_URI = "command_program_uri"; + /** + * Time shift command parameter: time position for time shifting, in milliseconds. + *

Type: long + * + * @see #TIME_SHIFT_COMMAND_TYPE_SEEK_TO + * @hide + */ + public static final String COMMAND_PARAMETER_KEY_TIME_POSITION = "command_time_position"; + /** + * Time shift command parameter: playback params. + *

Type: android.media.PlaybackParams + * + * @see #TIME_SHIFT_COMMAND_TYPE_SET_PLAYBACK_PARAMS + * @hide + */ + public static final String COMMAND_PARAMETER_KEY_PLAYBACK_PARAMS = "command_playback_params"; + private final Handler mServiceHandler = new ServiceHandler(); private final RemoteCallbackList mCallbacks = new RemoteCallbackList<>(); @@ -519,6 +592,44 @@ public abstract class TvInteractiveAppService extends Service { public void onError(@NonNull String errMsg, @NonNull Bundle params) { } + /** + * Called when the time shift {@link android.media.PlaybackParams} is set or changed. + * + * @see TvView#timeShiftSetPlaybackParams(PlaybackParams) + * @hide + */ + public void onTimeShiftPlaybackParams(@NonNull PlaybackParams params) { + } + + /** + * Called when time shift status is changed. + * + * @see TvView.TvInputCallback#onTimeShiftStatusChanged(String, int) + * @see android.media.tv.TvInputService.Session#notifyTimeShiftStatusChanged(int) + * @hide + */ + public void onTimeShiftStatusChanged( + @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) { + } + + /** + * Called when time shift start position is changed. + * + * @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged(String, long) + * @hide + */ + public void onTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) { + } + + /** + * Called when time shift current position is changed. + * + * @see TvView.TimeShiftPositionCallback#onTimeShiftCurrentPositionChanged(String, long) + * @hide + */ + public void onTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) { + } + /** * Called when the application sets the surface. * @@ -819,6 +930,35 @@ public abstract class TvInteractiveAppService extends Service { }); } + /** + * Sends a specific time shift command to be processed by the related TV input. + * + * @param cmdType type of the specific command + * @param parameters parameters of the specific command + * @hide + */ + @CallSuper + public void sendTimeShiftCommandRequest( + @TimeShiftCommandType @NonNull String cmdType, @Nullable Bundle parameters) { + executeOrPostRunnableOnMainThread(new Runnable() { + @MainThread + @Override + public void run() { + try { + if (DEBUG) { + Log.d(TAG, "requestTimeShiftCommand (cmdType=" + cmdType + + ", parameters=" + parameters.toString() + ")"); + } + if (mSessionCallback != null) { + mSessionCallback.onTimeShiftCommandRequest(cmdType, parameters); + } + } catch (RemoteException e) { + Log.w(TAG, "error in requestTimeShiftCommand", e); + } + } + }); + } + /** * Sets broadcast video bounds. */ @@ -1329,6 +1469,34 @@ public abstract class TvInteractiveAppService extends Service { onRecordingStopped(recordingId); } + /** + * Calls {@link #onTimeShiftPlaybackParams(PlaybackParams)}. + */ + void notifyTimeShiftPlaybackParams(PlaybackParams params) { + onTimeShiftPlaybackParams(params); + } + + /** + * Calls {@link #onTimeShiftStatusChanged(String, int)}. + */ + void notifyTimeShiftStatusChanged(String inputId, int status) { + onTimeShiftStatusChanged(inputId, status); + } + + /** + * Calls {@link #onTimeShiftStartPositionChanged(String, long)}. + */ + void notifyTimeShiftStartPositionChanged(String inputId, long timeMs) { + onTimeShiftStartPositionChanged(inputId, timeMs); + } + + /** + * Calls {@link #onTimeShiftCurrentPositionChanged(String, long)}. + */ + void notifyTimeShiftCurrentPositionChanged(String inputId, long timeMs) { + onTimeShiftCurrentPositionChanged(inputId, timeMs); + } + /** * Notifies when the session state is changed. * diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java index 6777d1a3c1eb1..9211a12de0d0d 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java @@ -25,6 +25,7 @@ import android.content.res.XmlResourceParser; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; +import android.media.PlaybackParams; import android.media.tv.TvInputManager; import android.media.tv.TvRecordingInfo; import android.media.tv.TvTrackInfo; @@ -684,6 +685,75 @@ public class TvInteractiveAppView extends ViewGroup { } } + /** + * Notifies the corresponding {@link TvInteractiveAppService} when a time shift + * {@link android.media.PlaybackParams} is set or changed. + * + * @see TvView#timeShiftSetPlaybackParams(PlaybackParams) + * @hide + */ + public void notifyTimeShiftPlaybackParams(@NonNull PlaybackParams params) { + if (DEBUG) { + Log.d(TAG, "notifyTimeShiftPlaybackParams params=" + params); + } + if (mSession != null) { + mSession.notifyTimeShiftPlaybackParams(params); + } + } + + /** + * Notifies the corresponding {@link TvInteractiveAppService} when time shift + * status is changed. + * + * @see TvView.TvInputCallback#onTimeShiftStatusChanged(String, int) + * @see android.media.tv.TvInputService.Session#notifyTimeShiftStatusChanged(int) + * @hide + */ + public void notifyTimeShiftStatusChanged( + @NonNull String inputId, @TvInputManager.TimeShiftStatus int status) { + if (DEBUG) { + Log.d(TAG, + "notifyTimeShiftStatusChanged inputId=" + inputId + "; status=" + status); + } + if (mSession != null) { + mSession.notifyTimeShiftStatusChanged(inputId, status); + } + } + + /** + * Notifies the corresponding {@link TvInteractiveAppService} when time shift + * start position is changed. + * + * @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged(String, long) + * @hide + */ + public void notifyTimeShiftStartPositionChanged(@NonNull String inputId, long timeMs) { + if (DEBUG) { + Log.d(TAG, "notifyTimeShiftStartPositionChanged inputId=" + inputId + + "; timeMs=" + timeMs); + } + if (mSession != null) { + mSession.notifyTimeShiftStartPositionChanged(inputId, timeMs); + } + } + + /** + * Notifies the corresponding {@link TvInteractiveAppService} when time shift + * current position is changed. + * + * @see TvView.TimeShiftPositionCallback#onTimeShiftCurrentPositionChanged(String, long) + * @hide + */ + public void notifyTimeShiftCurrentPositionChanged(@NonNull String inputId, long timeMs) { + if (DEBUG) { + Log.d(TAG, "notifyTimeShiftCurrentPositionChanged inputId=" + inputId + + "; timeMs=" + timeMs); + } + if (mSession != null) { + mSession.notifyTimeShiftCurrentPositionChanged(inputId, timeMs); + } + } + private void resetInternal() { mSessionCallback = null; if (mSession != null) { @@ -807,6 +877,21 @@ public class TvInteractiveAppView extends ViewGroup { @NonNull Bundle parameters) { } + /** + * This is called when a time shift command is requested to be processed by the related TV + * input. + * + * @param iAppServiceId The ID of the TV interactive app service bound to this view. + * @param cmdType type of the command + * @param parameters parameters of the command + * @hide + */ + public void onTimeShiftCommandRequest( + @NonNull String iAppServiceId, + @NonNull @TvInteractiveAppService.TimeShiftCommandType String cmdType, + @NonNull Bundle parameters) { + } + /** * This is called when the state of corresponding interactive app is changed. * @@ -1067,6 +1152,33 @@ public class TvInteractiveAppView extends ViewGroup { } } + @Override + public void onTimeShiftCommandRequest( + Session session, + @TvInteractiveAppService.TimeShiftCommandType String cmdType, + Bundle parameters) { + if (DEBUG) { + Log.d(TAG, "onTimeShiftCommandRequest (cmdType=" + cmdType + ", parameters=" + + parameters.toString() + ")"); + } + if (this != mSessionCallback) { + Log.w(TAG, "onTimeShiftCommandRequest - session not created"); + return; + } + synchronized (mCallbackLock) { + if (mCallbackExecutor != null) { + mCallbackExecutor.execute(() -> { + synchronized (mCallbackLock) { + if (mCallback != null) { + mCallback.onTimeShiftCommandRequest( + mIAppServiceId, cmdType, parameters); + } + } + }); + } + } + } + @Override public void onSessionStateChanged( Session session, diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java index ebee995533092..6dc4b731ac777 100644 --- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java +++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java @@ -29,6 +29,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.graphics.Rect; +import android.media.PlaybackParams; import android.media.tv.AdBuffer; import android.media.tv.AdRequest; import android.media.tv.AdResponse; @@ -1495,6 +1496,118 @@ public class TvInteractiveAppManagerService extends SystemService { } } + @Override + public void notifyTimeShiftPlaybackParams( + IBinder sessionToken, PlaybackParams params, int userId) { + if (DEBUG) { + Slogf.d(TAG, "notifyTimeShiftPlaybackParams(params=%s)", params); + } + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId( + Binder.getCallingPid(), callingUid, userId, "notifyTimeShiftPlaybackParams"); + SessionState sessionState = null; + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + sessionState = + getSessionStateLocked(sessionToken, callingUid, resolvedUserId); + getSessionLocked(sessionState).notifyTimeShiftPlaybackParams(params); + } catch (RemoteException | SessionNotFoundException e) { + Slogf.e(TAG, "error in notifyTimeShiftPlaybackParams", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void notifyTimeShiftStatusChanged( + IBinder sessionToken, String inputId, int status, int userId) { + if (DEBUG) { + Slogf.d(TAG, "notifyTimeShiftStatusChanged(inputId=%s, status=%d)", + inputId, status); + } + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId( + Binder.getCallingPid(), callingUid, userId, "notifyTimeShiftStatusChanged"); + SessionState sessionState = null; + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + sessionState = + getSessionStateLocked(sessionToken, callingUid, resolvedUserId); + getSessionLocked(sessionState).notifyTimeShiftStatusChanged( + inputId, status); + } catch (RemoteException | SessionNotFoundException e) { + Slogf.e(TAG, "error in notifyTimeShiftStatusChanged", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void notifyTimeShiftStartPositionChanged( + IBinder sessionToken, String inputId, long timeMs, int userId) { + if (DEBUG) { + Slogf.d(TAG, "notifyTimeShiftStartPositionChanged(inputId=%s, timeMs=%d)", + inputId, timeMs); + } + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId( + Binder.getCallingPid(), callingUid, userId, + "notifyTimeShiftStartPositionChanged"); + SessionState sessionState = null; + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + sessionState = + getSessionStateLocked(sessionToken, callingUid, resolvedUserId); + getSessionLocked(sessionState).notifyTimeShiftStartPositionChanged( + inputId, timeMs); + } catch (RemoteException | SessionNotFoundException e) { + Slogf.e(TAG, "error in notifyTimeShiftStartPositionChanged", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void notifyTimeShiftCurrentPositionChanged( + IBinder sessionToken, String inputId, long timeMs, int userId) { + if (DEBUG) { + Slogf.d(TAG, "notifyTimeShiftCurrentPositionChanged(inputId=%s, timeMs=%d)", + inputId, timeMs); + } + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId( + Binder.getCallingPid(), callingUid, userId, + "notifyTimeShiftCurrentPositionChanged"); + SessionState sessionState = null; + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + sessionState = + getSessionStateLocked(sessionToken, callingUid, resolvedUserId); + getSessionLocked(sessionState).notifyTimeShiftCurrentPositionChanged( + inputId, timeMs); + } catch (RemoteException | SessionNotFoundException e) { + Slogf.e(TAG, "error in notifyTimeShiftCurrentPositionChanged", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public void setSurface(IBinder sessionToken, Surface surface, int userId) { final int callingUid = Binder.getCallingUid(); @@ -2254,6 +2367,27 @@ public class TvInteractiveAppManagerService extends SystemService { } } + @Override + public void onTimeShiftCommandRequest( + @TvInteractiveAppService.TimeShiftCommandType String cmdType, + Bundle parameters) { + synchronized (mLock) { + if (DEBUG) { + Slogf.d(TAG, "onTimeShiftCommandRequest (cmdType=" + cmdType + + ", parameters=" + parameters.toString() + ")"); + } + if (mSessionState.mSession == null || mSessionState.mClient == null) { + return; + } + try { + mSessionState.mClient.onTimeShiftCommandRequest( + cmdType, parameters, mSessionState.mSeq); + } catch (RemoteException e) { + Slogf.e(TAG, "error in onTimeShiftCommandRequest", e); + } + } + } + @Override public void onSetVideoBounds(Rect rect) { synchronized (mLock) {