diff options
| -rw-r--r-- | media/java/android/media/tv/ITvInputManager.aidl | 4 | ||||
| -rw-r--r-- | media/java/android/media/tv/ITvInputSession.aidl | 3 | ||||
| -rw-r--r-- | media/java/android/media/tv/ITvInputSessionWrapper.java | 21 | ||||
| -rw-r--r-- | media/java/android/media/tv/TvInputManager.java | 32 | ||||
| -rw-r--r-- | media/java/android/media/tv/TvInputService.java | 41 | ||||
| -rw-r--r-- | media/java/android/media/tv/TvView.java | 30 | ||||
| -rw-r--r-- | services/core/java/com/android/server/tv/TvInputManagerService.java | 40 |
7 files changed, 170 insertions, 1 deletions
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index 901ea46ba38b..a8ffd2b4dd8f 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -110,6 +110,10 @@ interface ITvInputManager { void pauseRecording(in IBinder sessionToken, in Bundle params, int userId); void resumeRecording(in IBinder sessionToken, in Bundle params, int userId); + // For playback control + void startPlayback(in IBinder sessionToken, int userId); + void stopPlayback(in IBinder sessionToken, int mode, int userId); + // For broadcast info void requestBroadcastInfo(in IBinder sessionToken, in BroadcastInfoRequest request, int userId); void removeBroadcastInfo(in IBinder sessionToken, int id, int userId); diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl index 5246f5c4dc1e..e37ee6e342e5 100644 --- a/media/java/android/media/tv/ITvInputSession.aidl +++ b/media/java/android/media/tv/ITvInputSession.aidl @@ -63,6 +63,9 @@ oneway interface ITvInputSession { void timeShiftSetMode(int mode); void timeShiftEnablePositionTracking(boolean enable); + void startPlayback(); + void stopPlayback(int mode); + // For the recording session void startRecording(in Uri programUri, in Bundle params); void stopRecording(); diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java index d749b91e3889..ae3ee6535c71 100644 --- a/media/java/android/media/tv/ITvInputSessionWrapper.java +++ b/media/java/android/media/tv/ITvInputSessionWrapper.java @@ -79,6 +79,8 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand 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 static final int DO_STOP_PLAYBACK = 33; + private static final int DO_START_PLAYBACK = 34; private final boolean mIsRecordingSession; private final HandlerCaller mCaller; @@ -286,6 +288,14 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand mTvInputSessionImpl.onTvMessageReceived((Integer) args.arg1, (Bundle) args.arg2); break; } + case DO_STOP_PLAYBACK: { + mTvInputSessionImpl.stopPlayback(msg.arg1); + break; + } + case DO_START_PLAYBACK: { + mTvInputSessionImpl.startPlayback(); + break; + } default: { Log.w(TAG, "Unhandled message code: " + msg.what); break; @@ -483,6 +493,17 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand enabled)); } + @Override + public void stopPlayback(int mode) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_STOP_PLAYBACK, mode)); + } + + @Override + public void startPlayback() { + mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_START_PLAYBACK)); + } + + 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 631ab9a2693d..c685a5adb08b 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -339,6 +339,14 @@ public final class TvInputManager { */ public static final int VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN = VIDEO_UNAVAILABLE_REASON_END; + /** + * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and + * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because + * it has been stopped by stopPlayback. + * @hide + */ + public static final int VIDEO_UNAVAILABLE_REASON_STOPPED = 19; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED, @@ -3302,6 +3310,30 @@ public final class TvInputManager { } } + void stopPlayback(int mode) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.stopPlayback(mToken, mode, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + void startPlayback() { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.startPlayback(mToken, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Sends TV messages to the service for testing purposes */ diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 720d9a6291de..55fa51755177 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -34,6 +34,7 @@ import android.graphics.Rect; import android.hardware.hdmi.HdmiDeviceInfo; import android.media.AudioPresentation; import android.media.PlaybackParams; +import android.media.tv.interactive.TvInteractiveAppService; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; @@ -1531,6 +1532,32 @@ public abstract class TvInputService extends Service { } /** + * Called when the application requests playback of the Audio, Video, and CC streams to be + * stopped, but the metadata should continue to be filtered. + * + * <p>The metadata that will continue to be filtered includes the PSI + * (Program specific information) and SI (Service Information), part of ISO/IEC 13818-1. + * + * <p> Note that this is different form {@link #timeShiftPause()} as should release the + * stream, making it impossible to resume from this position again. + * @param mode + * @hide + */ + public void onStopPlayback(@TvInteractiveAppService.PlaybackCommandStopMode int mode) { + } + + /** + * Starts playback of the Audio, Video, and CC streams. + * + * <p> Note that this is different form {@link #timeShiftResume()} as this is intended to be + * used after stopping playback. This is used to restart playback from the current position + * in the live broadcast. + * @hide + */ + public void onStartPlayback() { + } + + /** * Called when the application requests to play a given recorded TV program. * * @param recordedProgramUri The URI of a recorded TV program. @@ -1993,6 +2020,20 @@ public abstract class TvInputService extends Service { } /** + * Calls {@link #onStopPlayback(int)}. + */ + void stopPlayback(int mode) { + onStopPlayback(mode); + } + + /** + * Calls {@link #onStartPlayback()}. + */ + void startPlayback() { + onStartPlayback(); + } + + /** * Calls {@link #onTimeShiftPlay(Uri)}. */ void timeShiftPlay(Uri recordedProgramUri) { diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java index 196b5c3112c0..233f96675543 100644 --- a/media/java/android/media/tv/TvView.java +++ b/media/java/android/media/tv/TvView.java @@ -37,6 +37,7 @@ import android.media.PlaybackParams; import android.media.tv.TvInputManager.Session; import android.media.tv.TvInputManager.Session.FinishedInputEventCallback; import android.media.tv.TvInputManager.SessionCallback; +import android.media.tv.interactive.TvInteractiveAppService; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -643,6 +644,35 @@ public class TvView extends ViewGroup { } } + /** + * Stops playback of the Audio, Video, and CC streams, but continue filtering the metadata. + * + * <p>The metadata that will continue to be filtered includes the PSI + * (Program specific information) and SI (Service Information), part of ISO/IEC 13818-1. + * + * <p> Note that this is different form {@link #timeShiftPause()} as this completely drops + * the stream, making it impossible to resume from this position again. + * @hide + */ + public void stopPlayback(@TvInteractiveAppService.PlaybackCommandStopMode int mode) { + if (mSession != null) { + mSession.stopPlayback(mode); + } + } + + /** + * Starts playback of the Audio, Video, and CC streams. + * + * <p> Note that this is different form {@link #timeShiftResume()} as this is intended to be + * used after stopping playback. This is used to restart playback from the current position + * in the live broadcast. + * @hide + */ + public void startPlayback() { + if (mSession != null) { + mSession.startPlayback(); + } + } /** * Sends TV messages to the session for testing purposes diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 6f2750767094..d903ad4d9f0d 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -41,7 +41,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; -import android.content.res.Resources; import android.graphics.Rect; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; @@ -2081,6 +2080,45 @@ public final class TvInputManagerService extends SystemService { } @Override + public void stopPlayback(IBinder sessionToken, int mode, int userId) { + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "stopPlayback"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + getSessionLocked(sessionToken, callingUid, resolvedUserId).stopPlayback( + mode); + } catch (RemoteException | SessionNotFoundException e) { + Slog.e(TAG, "error in stopPlayback(mode)", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void startPlayback(IBinder sessionToken, int userId) { + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "stopPlayback"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + getSessionLocked(sessionToken, callingUid, resolvedUserId).startPlayback(); + } catch (RemoteException | SessionNotFoundException e) { + Slog.e(TAG, "error in startPlayback()", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public void timeShiftPlay(IBinder sessionToken, final Uri recordedProgramUri, int userId) { final int callingUid = Binder.getCallingUid(); final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, |