TIAF: create & destroy BI IApp

Bug: 211886434
Test: mmm
Change-Id: Ie2b4d1d34b57487318f18a6fcdda116a05f9547f
This commit is contained in:
shubang
2021-12-15 04:53:39 -08:00
parent 17facee4f3
commit 19a1dd02e5
8 changed files with 298 additions and 5 deletions

View File

@@ -17,6 +17,7 @@
package android.media.tv.interactive;
import android.media.tv.BroadcastInfoRequest;
import android.net.Uri;
import android.os.Bundle;
import android.view.InputChannel;
@@ -31,5 +32,6 @@ oneway interface ITvIAppClient {
void onLayoutSurface(int left, int top, int right, int bottom, int seq);
void onBroadcastInfoRequest(in BroadcastInfoRequest request, int seq);
void onSessionStateChanged(int state, int seq);
void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId, int seq);
void onCommandRequest(in String cmdType, in Bundle parameters, int seq);
}

View File

@@ -35,6 +35,9 @@ interface ITvIAppManager {
void notifyAppLinkInfo(String tiasId, in Bundle info, int userId);
void sendAppLinkCommand(String tiasId, in Bundle command, int userId);
void startIApp(in IBinder sessionToken, int userId);
void createBiInteractiveApp(
in IBinder sessionToken, in Uri biIAppUri, in Bundle params, int userId);
void destroyBiInteractiveApp(in IBinder sessionToken, in String biIAppId, int userId);
void createSession(
in ITvIAppClient client, in String iAppServiceId, int type, int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId);

View File

@@ -17,10 +17,10 @@
package android.media.tv.interactive;
import android.graphics.Rect;
import android.media.tv.BroadcastInfoResponse;
import android.net.Uri;
import android.media.tv.BroadcastInfoResponse;
import android.os.Bundle;
import android.view.Surface;
import android.media.tv.BroadcastInfoResponse;
/**
* Sub-interface of ITvIAppService.aidl which is created per session and has its own context.
@@ -28,6 +28,8 @@ import android.media.tv.BroadcastInfoResponse;
*/
oneway interface ITvIAppSession {
void startIApp();
void createBiInteractiveApp(in Uri biIAppUri, in Bundle params);
void destroyBiInteractiveApp(in String biIAppId);
void release();
void notifyTuned(in Uri channelUri);
void setSurface(in Surface surface);

View File

@@ -19,6 +19,7 @@ package android.media.tv.interactive;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.interactive.ITvIAppSession;
import android.media.tv.BroadcastInfoRequest;
import android.net.Uri;
import android.os.Bundle;
/**
@@ -31,5 +32,6 @@ oneway interface ITvIAppSessionCallback {
void onLayoutSurface(int left, int top, int right, int bottom);
void onBroadcastInfoRequest(in BroadcastInfoRequest request);
void onSessionStateChanged(int state);
void onBiInteractiveAppCreated(in Uri biIAppUri, in String biIAppId);
void onCommandRequest(in String cmdType, in Bundle parameters);
}

View File

@@ -267,6 +267,18 @@ public final class TvIAppManager {
record.postSessionStateChanged(state);
}
}
@Override
public void onBiInteractiveAppCreated(Uri biIAppUri, String biIAppId, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
record.postBiInteractiveAppCreated(biIAppUri, biIAppId);
}
}
};
ITvIAppManagerCallback managerCallback = new ITvIAppManagerCallback.Stub() {
@Override
@@ -375,7 +387,6 @@ public final class TvIAppManager {
public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
}
/**
* This is called when the state of the interactive app service is changed.
* @hide
@@ -622,6 +633,30 @@ public final class TvIAppManager {
}
}
void createBiInteractiveApp(Uri biIAppUri, Bundle params) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.createBiInteractiveApp(mToken, biIAppUri, params, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
void destroyBiInteractiveApp(String biIAppId) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.destroyBiInteractiveApp(mToken, biIAppId, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Sets the {@link android.view.Surface} for this session.
*
@@ -1077,6 +1112,15 @@ public final class TvIAppManager {
}
});
}
void postBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
mHandler.post(new Runnable() {
@Override
public void run() {
mSessionCallback.onBiInteractiveAppCreated(mSession, biIAppUri, biIAppId);
}
});
}
}
/**
@@ -1134,5 +1178,18 @@ public final class TvIAppManager {
*/
public void onSessionStateChanged(Session session, int state) {
}
/**
* This is called when {@link TvIAppService.Session#notifyBiInteractiveAppCreated} is
* called.
*
* @param session A {@link TvIAppManager.Session} associated with this callback.
* @param biIAppUri URI associated this BI interactive app. This is the same URI in
* {@link Session#createBiInteractiveApp(Uri, Bundle)}
* @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
* app.
*/
public void onBiInteractiveAppCreated(Session session, Uri biIAppUri, String biIAppId) {
}
}
}

View File

@@ -287,6 +287,28 @@ public abstract class TvIAppService extends Service {
public void onStartIApp() {
}
/**
* Creates broadcast-independent(BI) interactive application.
*
* @see #onDestroyBiInteractiveApp(String)
* @hide
*/
public void onCreateBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
}
/**
* Destroys broadcast-independent(BI) interactive application.
*
* @param biIAppId the BI interactive app ID from
* {@link #createBiInteractiveApp(Uri, Bundle)}
*
* @see #onCreateBiInteractiveApp(Uri, Bundle)
* @hide
*/
public void onDestroyBiInteractiveApp(@NonNull String biIAppId) {
}
/**
* Called when the application sets the surface.
*
@@ -497,6 +519,14 @@ public abstract class TvIAppService extends Service {
onStartIApp();
}
void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
onCreateBiInteractiveApp(biIAppUri, params);
}
void destroyBiInteractiveApp(@NonNull String biIAppId) {
onDestroyBiInteractiveApp(biIAppId);
}
void release() {
onRelease();
if (mSurface != null) {
@@ -555,6 +585,32 @@ public abstract class TvIAppService extends Service {
});
}
/**
* Notifies the broadcast-independent(BI) interactive application has been created.
* @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
* app.
* @hide
*/
public final void notifyBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
public void run() {
try {
if (DEBUG) {
Log.d(TAG, "notifyBiInteractiveAppCreated (biIAppId="
+ biIAppId + ")");
}
if (mSessionCallback != null) {
mSessionCallback.onBiInteractiveAppCreated(biIAppUri, biIAppId);
}
} catch (RemoteException e) {
Log.w(TAG, "error in notifyBiInteractiveAppCreated", e);
}
}
});
}
/**
* Takes care of dispatching incoming input events and tells whether the event was handled.
*/
@@ -792,6 +848,16 @@ public abstract class TvIAppService extends Service {
mSessionImpl.startIApp();
}
@Override
public void createBiInteractiveApp(Uri biIAppUri, Bundle params) {
mSessionImpl.createBiInteractiveApp(biIAppUri, params);
}
@Override
public void destroyBiInteractiveApp(String biIAppId) {
mSessionImpl.destroyBiInteractiveApp(biIAppId);
}
@Override
public void release() {
mSessionImpl.scheduleMediaViewCleanup();

View File

@@ -16,6 +16,7 @@
package android.media.tv.interactive;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
@@ -26,6 +27,7 @@ import android.media.tv.TvInputManager;
import android.media.tv.TvView;
import android.media.tv.interactive.TvIAppManager.Session;
import android.media.tv.interactive.TvIAppManager.SessionCallback;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
@@ -301,6 +303,38 @@ public class TvIAppView extends ViewGroup {
}
}
/**
* Creates broadcast-independent(BI) interactive application.
*
* @see #destroyBiInteractiveApp(String)
* @hide
*/
public void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
if (DEBUG) {
Log.d(TAG, "createBiInteractiveApp Uri=" + biIAppUri + ", params=" + params);
}
if (mSession != null) {
mSession.createBiInteractiveApp(biIAppUri, params);
}
}
/**
* Destroys broadcast-independent(BI) interactive application.
*
* @param biIAppId the BI interactive app ID from {@link #createBiInteractiveApp(Uri, Bundle)}
*
* @see #createBiInteractiveApp(Uri, Bundle)
* @hide
*/
public void destroyBiInteractiveApp(@NonNull String biIAppId) {
if (DEBUG) {
Log.d(TAG, "destroyBiInteractiveApp biIAppId=" + biIAppId);
}
if (mSession != null) {
mSession.destroyBiInteractiveApp(biIAppId);
}
}
public Session getIAppSession() {
return mSession;
}
@@ -349,6 +383,28 @@ public class TvIAppView extends ViewGroup {
public void onCommandRequest(String iAppServiceId,
@TvIAppService.IAppServiceCommandType String cmdType, Bundle parameters) {
}
/**
* This is called when the session state is changed.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param state current session state.
*/
public void onSessionStateChanged(String iAppServiceId, int state) {
}
/**
* This is called when broadcast-independent (BI) interactive app is created.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param biIAppUri URI associated this BI interactive app. This is the same URI in
* {@link Session#createBiInteractiveApp(Uri, Bundle)}
* @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
* app.
*/
public void onBiInteractiveAppCreated(String iAppServiceId, Uri biIAppUri,
String biIAppId) {
}
}
private class MySessionCallback extends SessionCallback {
@@ -440,5 +496,34 @@ public class TvIAppView extends ViewGroup {
mCallback.onCommandRequest(mIAppServiceId, cmdType, parameters);
}
}
@Override
public void onSessionStateChanged(Session session, int state) {
if (DEBUG) {
Log.d(TAG, "onSessionStateChanged (state=" + state + ")");
}
if (this != mSessionCallback) {
Log.w(TAG, "onSessionStateChanged - session not created");
return;
}
if (mCallback != null) {
mCallback.onSessionStateChanged(mIAppServiceId, state);
}
}
@Override
public void onBiInteractiveAppCreated(Session session, Uri biIAppUri, String biIAppId) {
if (DEBUG) {
Log.d(TAG, "onBiInteractiveAppCreated (biIAppUri=" + biIAppUri + ", biIAppId="
+ biIAppId + ")");
}
if (this != mSessionCallback) {
Log.w(TAG, "onBiInteractiveAppCreated - session not created");
return;
}
if (mCallback != null) {
mCallback.onBiInteractiveAppCreated(mIAppServiceId, biIAppUri, biIAppId);
}
}
}
}

View File

@@ -652,11 +652,13 @@ public class TvIAppManagerService extends SystemService {
serviceState = new ServiceState(
componentName, tiasId, resolvedUserId, true, type);
userState.mServiceStateMap.put(componentName, serviceState);
updateServiceConnectionLocked(componentName, resolvedUserId);
} else if (serviceState.mService != null) {
serviceState.mService.prepare(type);
} else {
serviceState.mPendingPrepare = true;
serviceState.mPendingPrepareType = type;
updateServiceConnectionLocked(componentName, resolvedUserId);
}
}
} catch (RemoteException e) {
@@ -687,10 +689,12 @@ public class TvIAppManagerService extends SystemService {
componentName, tiasId, resolvedUserId);
serviceState.addPendingAppLink(appLinkInfo);
userState.mServiceStateMap.put(componentName, serviceState);
updateServiceConnectionLocked(componentName, resolvedUserId);
} else if (serviceState.mService != null) {
serviceState.mService.notifyAppLinkInfo(appLinkInfo);
} else {
serviceState.addPendingAppLink(appLinkInfo);
updateServiceConnectionLocked(componentName, resolvedUserId);
}
}
} catch (RemoteException e) {
@@ -850,7 +854,7 @@ public class TvIAppManagerService extends SystemService {
}
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "notifyTuned");
userId, "startIApp");
SessionState sessionState = null;
final long identity = Binder.clearCallingIdentity();
try {
@@ -868,6 +872,58 @@ public class TvIAppManagerService extends SystemService {
}
}
@Override
public void createBiInteractiveApp(
IBinder sessionToken, Uri biIAppUri, Bundle params, int userId) {
if (DEBUG) {
Slogf.d(TAG, "createBiInteractiveApp(biIAppUri=%s,params=%s)", biIAppUri, params);
}
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "createBiInteractiveApp");
SessionState sessionState = null;
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
getSessionLocked(sessionState).createBiInteractiveApp(
biIAppUri, params);
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in createBiInteractiveApp", e);
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void destroyBiInteractiveApp(IBinder sessionToken, String biIAppId, int userId) {
if (DEBUG) {
Slogf.d(TAG, "destroyBiInteractiveApp(biIAppId=%s)", biIAppId);
}
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "destroyBiInteractiveApp");
SessionState sessionState = null;
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
getSessionLocked(sessionState).destroyBiInteractiveApp(biIAppId);
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in destroyBiInteractiveApp", e);
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void setSurface(IBinder sessionToken, Surface surface, int userId) {
final int callingUid = Binder.getCallingUid();
@@ -1164,7 +1220,8 @@ public class TvIAppManagerService extends SystemService {
serviceState.mReconnecting = false;
}
boolean shouldBind = !serviceState.mSessionTokens.isEmpty();
boolean shouldBind = (!serviceState.mSessionTokens.isEmpty())
|| (serviceState.mPendingPrepare) || (!serviceState.mPendingAppLinkInfo.isEmpty());
if (serviceState.mService == null && shouldBind) {
// This means that the service is not yet connected but its state indicates that we
@@ -1584,6 +1641,25 @@ public class TvIAppManagerService extends SystemService {
}
}
@Override
public void onBiInteractiveAppCreated(Uri biIAppUri, String biIAppId) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onBiInteractiveAppCreated (biIAppUri=" + biIAppUri
+ ", biIAppId=" + biIAppId + ")");
}
if (mSessionState.mSession == null || mSessionState.mClient == null) {
return;
}
try {
mSessionState.mClient.onBiInteractiveAppCreated(
biIAppUri, biIAppId, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onBiInteractiveAppCreated", e);
}
}
}
@GuardedBy("mLock")
private boolean addSessionTokenToClientStateLocked(ITvIAppSession session) {
try {