diff --git a/media/java/android/media/tv/interactive/ITvIAppManager.aidl b/media/java/android/media/tv/interactive/ITvIAppManager.aidl new file mode 100644 index 0000000000000..ef7b1cd7c2637 --- /dev/null +++ b/media/java/android/media/tv/interactive/ITvIAppManager.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.tv.interactive; + +/** + * Interface to the TV interactive app service. + * @hide + */ +interface ITvIAppManager { + void startIApp(in IBinder sessionToken, int userId); +} \ No newline at end of file diff --git a/media/java/android/media/tv/interactive/ITvIAppSession.aidl b/media/java/android/media/tv/interactive/ITvIAppSession.aidl new file mode 100644 index 0000000000000..970afc6a455fb --- /dev/null +++ b/media/java/android/media/tv/interactive/ITvIAppSession.aidl @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.tv.interactive; + +/** + * Sub-interface of ITvIAppService which is created per session and has its own context. + * @hide + */ +oneway interface ITvIAppSession { + void startIApp(); +} \ No newline at end of file diff --git a/media/java/android/media/tv/interactive/TvIAppManager.java b/media/java/android/media/tv/interactive/TvIAppManager.java new file mode 100644 index 0000000000000..8f01f79794ea7 --- /dev/null +++ b/media/java/android/media/tv/interactive/TvIAppManager.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.tv.interactive; + +import android.annotation.SystemService; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +/** + * Central system API to the overall TV interactive application framework (TIAF) architecture, which + * arbitrates interaction between applications and interactive apps. + * @hide + */ +@SystemService("tv_interactive_app") +public final class TvIAppManager { + private static final String TAG = "TvIAppManager"; + + private final ITvIAppManager mService; + private final int mUserId; + + public TvIAppManager(ITvIAppManager service, int userId) { + mService = service; + mUserId = userId; + } + + /** + * The Session provides the per-session functionality of interactive app. + */ + public static final class Session { + private final IBinder mToken; + private final ITvIAppManager mService; + private final int mUserId; + + private Session(IBinder token, ITvIAppManager service, int userId) { + mToken = token; + mService = service; + mUserId = userId; + } + + void startIApp() { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.startIApp(mToken, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } +} diff --git a/media/java/android/media/tv/interactive/TvIAppService.java b/media/java/android/media/tv/interactive/TvIAppService.java new file mode 100644 index 0000000000000..2a851f3964d0d --- /dev/null +++ b/media/java/android/media/tv/interactive/TvIAppService.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.tv.interactive; + +import android.app.Service; +import android.view.KeyEvent; + +/** + * The TvIAppService class represents a TV interactive applications RTE. + * @hide + */ +public abstract class TvIAppService extends Service { + private static final boolean DEBUG = false; + private static final String TAG = "TvIAppService"; + + /** + * Base class for derived classes to implement to provide a TV interactive app session. + */ + public abstract static class Session implements KeyEvent.Callback { + /** + * Starts TvIAppService session. + */ + public void onStartIApp() { + } + + void startIApp() { + onStartIApp(); + } + } + + /** + * Implements the internal ITvIAppSession interface. + */ + public static class ITvIAppSessionWrapper extends ITvIAppSession.Stub { + private final Session mSessionImpl; + + public ITvIAppSessionWrapper(Session mSessionImpl) { + this.mSessionImpl = mSessionImpl; + } + + @Override + public void startIApp() { + mSessionImpl.startIApp(); + } + } +} diff --git a/media/java/android/media/tv/interactive/TvIAppView.java b/media/java/android/media/tv/interactive/TvIAppView.java new file mode 100644 index 0000000000000..9af9daeb6af46 --- /dev/null +++ b/media/java/android/media/tv/interactive/TvIAppView.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.tv.interactive; + +import android.content.Context; +import android.util.Log; +import android.view.ViewGroup; + +/** + * Displays contents of interactive TV applications. + * @hide + */ +public class TvIAppView extends ViewGroup { + private static final String TAG = "TvIAppView"; + private static final boolean DEBUG = false; + + // TODO: create session + private TvIAppManager.Session mSession; + + public TvIAppView(Context context) { + super(context, /* attrs = */null, /* defStyleAttr = */0); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + if (DEBUG) { + Log.d(TAG, + "onLayout (left=" + l + ", top=" + t + ", right=" + r + ", bottom=" + b + ",)"); + } + } + + /** + * Starts the interactive application. + */ + public void startIApp() { + if (DEBUG) { + Log.d(TAG, "start"); + } + if (mSession != null) { + mSession.startIApp(); + } + } +} diff --git a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java new file mode 100644 index 0000000000000..620be3a903416 --- /dev/null +++ b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.tv.interactive; + +import android.content.Context; +import android.media.tv.interactive.ITvIAppManager; +import android.media.tv.interactive.ITvIAppSession; +import android.os.IBinder; +import android.os.RemoteException; + +import com.android.server.SystemService; +import com.android.server.utils.Slogf; + +/** + * This class provides a system service that manages interactive TV applications. + */ +public class TvIAppManagerService extends SystemService { + private static final boolean DEBUG = false; + private static final String TAG = "TvIAppManagerService"; + + /** + * Initializes the system service. + *
+ * Subclasses must define a single argument constructor that accepts the context + * and passes it to super. + *
+ * + * @param context The system server context. + */ + public TvIAppManagerService(Context context) { + super(context); + } + + @Override + public void onStart() { + if (DEBUG) { + Slogf.d(TAG, "onStart"); + } + // TODO: make service name a constant in Context + publishBinderService("tv_interactive_app", new BinderService()); + } + + private SessionState getSessionState(IBinder sessionToken) { + // TODO: implement user state and get session from it. + return null; + } + + private final class BinderService extends ITvIAppManager.Stub { + @Override + public void startIApp(IBinder sessionToken, int userId) { + if (DEBUG) { + Slogf.d(TAG, "BinderService#start(userId=%d)", userId); + } + try { + SessionState sessionState = getSessionState(sessionToken); + if (sessionState != null && sessionState.mSession != null) { + sessionState.mSession.startIApp(); + } + } catch (RemoteException e) { + Slogf.e(TAG, "error in start", e); + } + } + } + + private final class SessionState implements IBinder.DeathRecipient { + private final IBinder mSessionToken; + private ITvIAppSession mSession; + + private SessionState(IBinder sessionToken) { + mSessionToken = sessionToken; + } + + @Override + public void binderDied() { + } + } +}