diff options
9 files changed, 188 insertions, 1 deletions
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl index 77391841c6fe..e3dba03d6093 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl @@ -48,6 +48,7 @@ oneway interface ITvInteractiveAppClient { void onRequestCurrentChannelLcn(int seq); void onRequestStreamVolume(int seq); void onRequestTrackInfoList(int seq); + void onRequestSelectedTrackInfo(int seq); void onRequestCurrentTvInputId(int seq); void onRequestTimeShiftMode(int seq); void onRequestAvailableSpeeds(int seq); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl index 41cbe4ae02d0..4316d053a275 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl @@ -102,6 +102,8 @@ interface ITvInteractiveAppManager { int UserId); void notifyAdResponse(in IBinder sessionToken, in AdResponse response, int UserId); void notifyAdBufferConsumed(in IBinder sessionToken, in AdBuffer buffer, int userId); + void sendSelectedTrackInfo(in IBinder sessionToken, in List<TvTrackInfo> tracks, + int userId); void createMediaView(in IBinder sessionToken, in IBinder windowToken, in Rect frame, int userId); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl index 052bc3d5adce..ba7cf13a7a1d 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSession.aidl @@ -78,6 +78,7 @@ oneway interface ITvInteractiveAppSession { void notifyBroadcastInfoResponse(in BroadcastInfoResponse response); void notifyAdResponse(in AdResponse response); void notifyAdBufferConsumed(in AdBuffer buffer); + void sendSelectedTrackInfo(in List<TvTrackInfo> tracks); void createMediaView(in IBinder windowToken, in Rect frame); void relayoutMediaView(in Rect frame); diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl index 9e43e79144fd..416b8f12d5ea 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl @@ -50,6 +50,7 @@ oneway interface ITvInteractiveAppSessionCallback { void onRequestCurrentTvInputId(); void onRequestTimeShiftMode(); void onRequestAvailableSpeeds(); + void onRequestSelectedTrackInfo(); void onRequestStartRecording(in String requestId, in Uri programUri); void onRequestStopRecording(in String recordingId); void onRequestScheduleRecording(in String requestId, in String inputId, in Uri channelUri, diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java index 253ade809ece..518b08a93f95 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java @@ -102,6 +102,7 @@ public class ITvInteractiveAppSessionWrapper private static final int DO_NOTIFY_RECORDING_SCHEDULED = 45; private static final int DO_SEND_TIME_SHIFT_MODE = 46; private static final int DO_SEND_AVAILABLE_SPEEDS = 47; + private static final int DO_SEND_SELECTED_TRACK_INFO = 48; private final HandlerCaller mCaller; private Session mSessionImpl; @@ -247,6 +248,10 @@ public class ITvInteractiveAppSessionWrapper args.recycle(); break; } + case DO_SEND_SELECTED_TRACK_INFO: { + mSessionImpl.sendSelectedTrackInfo((List<TvTrackInfo>) msg.obj); + break; + } case DO_NOTIFY_VIDEO_AVAILABLE: { mSessionImpl.notifyVideoAvailable(); break; @@ -526,6 +531,12 @@ public class ITvInteractiveAppSessionWrapper } @Override + public void sendSelectedTrackInfo(List<TvTrackInfo> tracks) { + mCaller.executeOrSendMessage( + mCaller.obtainMessageO(DO_SEND_SELECTED_TRACK_INFO, tracks)); + } + + @Override public void notifyTracksChanged(List<TvTrackInfo> tracks) { mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_NOTIFY_TRACKS_CHANGED, tracks)); } diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java index 7cce84a1ee16..bf4379f470d8 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java @@ -33,7 +33,6 @@ import android.media.tv.TvContentRating; import android.media.tv.TvInputManager; import android.media.tv.TvRecordingInfo; import android.media.tv.TvTrackInfo; -import android.media.tv.interactive.TvInteractiveAppService.Session; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -506,6 +505,18 @@ public final class TvInteractiveAppManager { } @Override + public void onRequestSelectedTrackInfo(int seq) { + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); + if (record == null) { + Log.e(TAG, "Callback not found for seq " + seq); + return; + } + record.postRequestSelectedTrackInfo(); + } + } + + @Override public void onRequestCurrentTvInputId(int seq) { synchronized (mSessionCallbackRecordMap) { SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); @@ -1209,6 +1220,18 @@ public final class TvInteractiveAppManager { } } + void sendSelectedTrackInfo(@NonNull List<TvTrackInfo> tracks) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.sendSelectedTrackInfo(mToken, tracks, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + void sendCurrentTvInputId(@Nullable String inputId) { if (mToken == null) { Log.w(TAG, "The session has been already released"); @@ -2108,6 +2131,15 @@ public final class TvInteractiveAppManager { }); } + void postRequestSelectedTrackInfo() { + mHandler.post(new Runnable() { + @Override + public void run() { + mSessionCallback.onRequestSelectedTrackInfo(mSession); + } + }); + } + void postRequestCurrentTvInputId() { mHandler.post(new Runnable() { @Override @@ -2378,6 +2410,15 @@ public final class TvInteractiveAppManager { } /** + * This is called when {@link TvInteractiveAppService.Session#requestSelectedTrackInfo()} is + * called. + * + * @param session A {@link TvInteractiveAppManager.Session} associated with this callback. + */ + public void onRequestSelectedTrackInfo(Session session) { + } + + /** * This is called when {@link TvInteractiveAppService.Session#requestCurrentTvInputId} is * called. * diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java index 241940486a14..5cc86bacf54f 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java @@ -932,6 +932,16 @@ public abstract class TvInteractiveAppService extends Service { @NonNull Bundle data) { } + /** + * Called when the TV App sends the selected track info as a response to + * requestSelectedTrackInfo. + * + * @param tracks + * @hide + */ + public void onSelectedTrackInfo(List<TvTrackInfo> tracks) { + } + @Override public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { return false; @@ -1338,6 +1348,30 @@ public abstract class TvInteractiveAppService extends Service { } /** + * Requests the currently selected {@link TvTrackInfo} from the TV App. + * + * <p> Normally, track info cannot be synchronized until the channel has + * been changed. This is used when the session of the TIAS is newly + * created and the normal synchronization has not happened yet. + * @hide + */ + @CallSuper + public void requestSelectedTrackInfo() { + executeOrPostRunnableOnMainThread(() -> { + try { + if (DEBUG) { + Log.d(TAG, "requestSelectedTrackInfo"); + } + if (mSessionCallback != null) { + mSessionCallback.onRequestSelectedTrackInfo(); + } + } catch (RemoteException e) { + Log.w(TAG, "error in requestSelectedTrackInfo", e); + } + }); + } + + /** * Requests starting of recording * * <p> This is used to request the active {@link android.media.tv.TvRecordingClient} to @@ -1781,6 +1815,13 @@ public abstract class TvInteractiveAppService extends Service { onTvMessage(type, data); } + void sendSelectedTrackInfo(List<TvTrackInfo> tracks) { + if (DEBUG) { + Log.d(TAG, "notifySelectedTrackInfo (tracks= " + tracks + ")"); + } + onSelectedTrackInfo(tracks); + } + /** * Calls {@link #onAdBufferConsumed}. */ diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java index cbaf5e482faa..40a12e4db4cc 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java @@ -582,6 +582,20 @@ public class TvInteractiveAppView extends ViewGroup { } /** + * Sends the currently selected track info to the TV Interactive App. + * + * @hide + */ + public void sendSelectedTrackInfo(@Nullable List<TvTrackInfo> tracks) { + if (DEBUG) { + Log.d(TAG, "sendSelectedTrackInfo"); + } + if (mSession != null) { + mSession.sendSelectedTrackInfo(tracks); + } + } + + /** * Sends current TV input ID to related TV interactive app. * * @param inputId The current TV input ID whose channel is tuned. {@code null} if no channel is @@ -1197,6 +1211,16 @@ public class TvInteractiveAppView extends ViewGroup { } /** + * This is called when {@link TvInteractiveAppService.Session#requestSelectedTrackInfo()} is + * called. + * + * @param iAppServiceId The ID of the TV interactive app service bound to this view. + * @hide + */ + public void onRequestSelectedTrackInfo(@NonNull String iAppServiceId) { + } + + /** * This is called when {@link TvInteractiveAppService.Session#requestCurrentTvInputId()} is * called. * @@ -1714,6 +1738,28 @@ public class TvInteractiveAppView extends ViewGroup { } @Override + public void onRequestSelectedTrackInfo(Session session) { + if (DEBUG) { + Log.d(TAG, "onRequestSelectedTrackInfo"); + } + if (this != mSessionCallback) { + Log.w(TAG, "onRequestSelectedTrackInfo - session not created"); + return; + } + synchronized (mCallbackLock) { + if (mCallbackExecutor != null) { + mCallbackExecutor.execute(() -> { + synchronized (mCallbackLock) { + if (mCallback != null) { + mCallback.onRequestSelectedTrackInfo(mIAppServiceId); + } + } + }); + } + } + } + + @Override public void onRequestCurrentTvInputId(Session session) { if (DEBUG) { Log.d(TAG, "onRequestCurrentTvInputId"); 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 51a0553964fb..7ab075e2f3a7 100644 --- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java +++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java @@ -1882,6 +1882,32 @@ public class TvInteractiveAppManagerService extends SystemService { } @Override + public void sendSelectedTrackInfo(IBinder sessionToken, List<TvTrackInfo> tracks, + int userId) { + if (DEBUG) { + Slogf.d(TAG, "sendSelectedTrackInfo(tracks=%s)", tracks.toString()); + } + final int callingUid = Binder.getCallingUid(); + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid, + userId, "sendSelectedTrackInfo"); + SessionState sessionState = null; + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + sessionState = getSessionStateLocked(sessionToken, callingUid, + resolvedUserId); + getSessionLocked(sessionState).sendSelectedTrackInfo(tracks); + } catch (RemoteException | SessionNotFoundException e) { + Slogf.e(TAG, "error in sendSelectedTrackInfo", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public void sendCurrentTvInputId(IBinder sessionToken, String inputId, int userId) { if (DEBUG) { Slogf.d(TAG, "sendCurrentTvInputId(inputId=%s)", inputId); @@ -3558,6 +3584,23 @@ public class TvInteractiveAppManagerService extends SystemService { } @Override + public void onRequestSelectedTrackInfo() { + synchronized (mLock) { + if (DEBUG) { + Slogf.d(TAG, "onRequestSelectedTrackInfo"); + } + if (mSessionState.mSession == null || mSessionState.mClient == null) { + return; + } + try { + mSessionState.mClient.onRequestSelectedTrackInfo(mSessionState.mSeq); + } catch (RemoteException e) { + Slogf.e(TAG, "error in onRequestSelectedTrackInfo", e); + } + } + } + + @Override public void onRequestCurrentTvInputId() { synchronized (mLock) { if (DEBUG) { |