Merge "TIAF: add state change methods"

This commit is contained in:
Shubang Lu
2021-12-03 23:37:18 +00:00
committed by Android (Google) Code Review
7 changed files with 241 additions and 5 deletions

View File

@@ -30,4 +30,5 @@ oneway interface ITvIAppClient {
void onSessionReleased(int seq);
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);
}

View File

@@ -27,4 +27,5 @@ interface ITvIAppManagerCallback {
void onIAppServiceRemoved(in String iAppServiceId);
void onIAppServiceUpdated(in String iAppServiceId);
void onTvIAppInfoUpdated(in TvIAppInfo tvIAppInfo);
void onStateChanged(in String iAppServiceId, int type, int state);
}

View File

@@ -22,4 +22,5 @@ package android.media.tv.interactive;
* @hide
*/
oneway interface ITvIAppServiceCallback {
void onStateChanged(int type, int state);
}

View File

@@ -29,4 +29,5 @@ oneway interface ITvIAppSessionCallback {
void onSessionCreated(in ITvIAppSession session);
void onLayoutSurface(int left, int top, int right, int bottom);
void onBroadcastInfoRequest(in BroadcastInfoRequest request);
void onSessionStateChanged(int state);
}

View File

@@ -16,6 +16,7 @@
package android.media.tv.interactive;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
@@ -41,6 +42,8 @@ import android.view.View;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -54,6 +57,36 @@ public final class TvIAppManager {
// TODO: cleanup and unhide public APIs
private static final String TAG = "TvIAppManager";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = false, prefix = "TV_IAPP_RTE_STATE_", value = {
TV_IAPP_RTE_STATE_UNREALIZED,
TV_IAPP_RTE_STATE_PREPARING,
TV_IAPP_RTE_STATE_READY,
TV_IAPP_RTE_STATE_ERROR})
public @interface TvIAppRteState {}
/**
* Unrealized state of interactive app RTE.
* @hide
*/
public static final int TV_IAPP_RTE_STATE_UNREALIZED = 1;
/**
* Preparing state of interactive app RTE.
* @hide
*/
public static final int TV_IAPP_RTE_STATE_PREPARING = 2;
/**
* Ready state of interactive app RTE.
* @hide
*/
public static final int TV_IAPP_RTE_STATE_READY = 3;
/**
* Error state of interactive app RTE.
* @hide
*/
public static final int TV_IAPP_RTE_STATE_ERROR = 4;
private final ITvIAppManager mService;
private final int mUserId;
@@ -134,9 +167,20 @@ public final class TvIAppManager {
record.postBroadcastInfoRequest(request);
}
}
@Override
public void onSessionStateChanged(int state, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
record.postSessionStateChanged(state);
}
}
};
ITvIAppManagerCallback managerCallback = new ITvIAppManagerCallback.Stub() {
// TODO: handle IApp service state changes
@Override
public void onIAppServiceAdded(String iAppServiceId) {
synchronized (mLock) {
@@ -173,6 +217,15 @@ public final class TvIAppManager {
}
}
}
@Override
public void onStateChanged(String iAppServiceId, int type, int state) {
synchronized (mLock) {
for (TvIAppCallbackRecord record : mCallbackRecords) {
record.postStateChanged(iAppServiceId, type, state);
}
}
}
};
try {
if (mService != null) {
@@ -233,6 +286,15 @@ public final class TvIAppManager {
*/
public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
}
/**
* This is called when the state of the interactive app service is changed.
* @hide
*/
public void onTvIAppServiceStateChanged(
String iAppServiceId, int type, @TvIAppRteState int state) {
}
}
private static final class TvIAppCallbackRecord {
@@ -283,6 +345,15 @@ public final class TvIAppManager {
}
});
}
public void postStateChanged(String iAppServiceId, int type, int state) {
mHandler.post(new Runnable() {
@Override
public void run() {
mCallback.onTvIAppServiceStateChanged(iAppServiceId, type, state);
}
});
}
}
/**
@@ -875,6 +946,15 @@ public final class TvIAppManager {
}
});
}
void postSessionStateChanged(int state) {
mHandler.post(new Runnable() {
@Override
public void run() {
mSessionCallback.onSessionStateChanged(mSession, state);
}
});
}
}
/**
@@ -912,5 +992,14 @@ public final class TvIAppManager {
*/
public void onLayoutSurface(Session session, int left, int top, int right, int bottom) {
}
/**
* This is called when {@link TvIAppService.Session#notifySessionStateChanged} is called.
*
* @param session A {@link TvIAppManager.Session} associated with this callback.
* @param state the current state.
*/
public void onSessionStateChanged(Session session, int state) {
}
}
}

View File

@@ -152,6 +152,16 @@ public abstract class TvIAppService extends Service {
return null;
}
/**
* Notifies the system when the state of the interactive app has been changed.
* @param state the current state
* @hide
*/
public final void notifyStateChanged(int type, @TvIAppManager.TvIAppRteState int state) {
mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_RTE_STATE_CHANGED,
type, state).sendToTarget();
}
/**
* Base class for derived classes to implement to provide a TV interactive app session.
* @hide
@@ -384,7 +394,7 @@ public abstract class TvIAppService extends Service {
/**
* Requests broadcast related information from the related TV input.
* @param request
* @param request the request for broadcast info
*/
public void requestBroadcastInfo(@NonNull final BroadcastInfoRequest request) {
executeOrPostRunnableOnMainThread(new Runnable() {
@@ -444,6 +454,30 @@ public abstract class TvIAppService extends Service {
onBroadcastInfoResponse(response);
}
/**
* Notifies when the session state is changed.
* @param state the current state.
*/
public void notifySessionStateChanged(@TvIAppManager.TvIAppRteState int state) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
public void run() {
try {
if (DEBUG) {
Log.d(TAG, "notifySessionStateChanged (state="
+ state + ")");
}
if (mSessionCallback != null) {
mSessionCallback.onSessionStateChanged(state);
}
} catch (RemoteException e) {
Log.w(TAG, "error in notifySessionStateChanged", e);
}
}
});
}
/**
* Takes care of dispatching incoming input events and tells whether the event was handled.
*/
@@ -747,6 +781,19 @@ public abstract class TvIAppService extends Service {
private final class ServiceHandler extends Handler {
private static final int DO_CREATE_SESSION = 1;
private static final int DO_NOTIFY_SESSION_CREATED = 2;
private static final int DO_NOTIFY_RTE_STATE_CHANGED = 3;
private void broadcastRteStateChanged(int type, int state) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
mCallbacks.getBroadcastItem(i).onStateChanged(type, state);
} catch (RemoteException e) {
Log.e(TAG, "error in broadcastRteStateChanged", e);
}
}
mCallbacks.finishBroadcast();
}
@Override
public void handleMessage(Message msg) {
@@ -795,6 +842,12 @@ public abstract class TvIAppService extends Service {
args.recycle();
return;
}
case DO_NOTIFY_RTE_STATE_CHANGED: {
int type = msg.arg1;
int state = msg.arg2;
broadcastRteStateChanged(type, state);
return;
}
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
return;

View File

@@ -239,6 +239,24 @@ public class TvIAppManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
@GuardedBy("mLock")
private void notifyStateChangedLocked(
UserState userState, String iAppServiceId, int type, int state) {
if (DEBUG) {
Slog.d(TAG, "notifyRteStateChanged(iAppServiceId="
+ iAppServiceId + ", type=" + type + ", state=" + state + ")");
}
int n = userState.mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
userState.mCallbacks.getBroadcastItem(i).onStateChanged(iAppServiceId, type, state);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report RTE state changed", e);
}
}
userState.mCallbacks.finishBroadcast();
}
private int getIAppUid(TvIAppInfo info) {
try {
return getContext().getPackageManager().getApplicationInfo(
@@ -545,6 +563,17 @@ public class TvIAppManagerService extends SystemService {
return mUserStates.get(userId);
}
@GuardedBy("mLock")
private ServiceState getServiceStateLocked(ComponentName component, int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
ServiceState serviceState = userState.mServiceStateMap.get(component);
if (serviceState == null) {
throw new IllegalStateException("Service state not found for " + component + " (userId="
+ userId + ")");
}
return serviceState;
}
@GuardedBy("mLock")
private SessionState getSessionStateLocked(IBinder sessionToken, int callingUid, int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
@@ -617,7 +646,11 @@ public class TvIAppManagerService extends SystemService {
}
ComponentName componentName = iAppState.mInfo.getComponent();
ServiceState serviceState = userState.mServiceStateMap.get(componentName);
if (serviceState != null) {
if (serviceState == null) {
serviceState = new ServiceState(
componentName, tiasId, resolvedUserId, true, type);
userState.mServiceStateMap.put(componentName, serviceState);
} else if (serviceState.mService != null) {
serviceState.mService.prepare(type);
}
}
@@ -657,7 +690,8 @@ public class TvIAppManagerService extends SystemService {
if (serviceState == null) {
int tiasUid = PackageManager.getApplicationInfoAsUserCached(
iAppState.mComponentName.getPackageName(), 0, resolvedUserId).uid;
serviceState = new ServiceState(iAppState.mComponentName, resolvedUserId);
serviceState = new ServiceState(
iAppState.mComponentName, iAppServiceId, resolvedUserId);
userState.mServiceStateMap.put(iAppState.mComponentName, serviceState);
}
// Send a null token immediately while reconnecting.
@@ -1202,15 +1236,26 @@ public class TvIAppManagerService extends SystemService {
private final List<IBinder> mSessionTokens = new ArrayList<>();
private final ServiceConnection mConnection;
private final ComponentName mComponent;
private final String mIAppSeriviceId;
private boolean mPendingPrepare = false;
private Integer mPendingPrepareType = null;
private ITvIAppService mService;
private ServiceCallback mCallback;
private boolean mBound;
private boolean mReconnecting;
private ServiceState(ComponentName component, int userId) {
private ServiceState(ComponentName component, String tias, int userId) {
this(component, tias, userId, false, null);
}
private ServiceState(ComponentName component, String tias, int userId,
boolean pendingPrepare, Integer prepareType) {
mComponent = component;
mPendingPrepare = pendingPrepare;
mPendingPrepareType = prepareType;
mConnection = new IAppServiceConnection(component, userId);
mIAppSeriviceId = tias;
}
}
@@ -1238,6 +1283,19 @@ public class TvIAppManagerService extends SystemService {
ServiceState serviceState = userState.mServiceStateMap.get(mComponent);
serviceState.mService = ITvIAppService.Stub.asInterface(service);
if (serviceState.mPendingPrepare) {
final long identity = Binder.clearCallingIdentity();
try {
serviceState.mService.prepare(serviceState.mPendingPrepareType);
serviceState.mPendingPrepare = false;
serviceState.mPendingPrepareType = null;
} catch (RemoteException e) {
Slogf.e(TAG, "error in prepare when onServiceConnected", e);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
List<IBinder> tokensToBeRemoved = new ArrayList<>();
// And create sessions, if any.
@@ -1286,6 +1344,21 @@ public class TvIAppManagerService extends SystemService {
mComponent = component;
mUserId = userId;
}
@Override
public void onStateChanged(int type, int state) {
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
String iAppServiceId = serviceState.mIAppSeriviceId;
UserState userState = getUserStateLocked(mUserId);
notifyStateChangedLocked(userState, iAppServiceId, type, state);
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
private final class SessionCallback extends ITvIAppSessionCallback.Stub {
@@ -1358,6 +1431,23 @@ public class TvIAppManagerService extends SystemService {
}
}
@Override
public void onSessionStateChanged(int state) {
synchronized (mLock) {
if (DEBUG) {
Slogf.d(TAG, "onSessionStateChanged (state=" + state + ")");
}
if (mSessionState.mSession == null || mSessionState.mClient == null) {
return;
}
try {
mSessionState.mClient.onSessionStateChanged(state, mSessionState.mSeq);
} catch (RemoteException e) {
Slogf.e(TAG, "error in onSessionStateChanged", e);
}
}
}
@GuardedBy("mLock")
private boolean addSessionTokenToClientStateLocked(ITvIAppSession session) {
try {