Merge "TIAF: rename IApp -> InteractiveApp part 1/2"

This commit is contained in:
Shubang Lu
2022-01-15 05:31:30 +00:00
committed by Android (Google) Code Review
21 changed files with 806 additions and 631 deletions

View File

@@ -77,7 +77,7 @@ interface ITvInputManager {
void setCaptionEnabled(in IBinder sessionToken, boolean enabled, int userId);
void selectTrack(in IBinder sessionToken, int type, in String trackId, int userId);
void setIAppNotificationEnabled(in IBinder sessionToken, boolean enabled, int userId);
void setInteractiveAppNotificationEnabled(in IBinder sessionToken, boolean enabled, int userId);
void sendAppPrivateCommand(in IBinder sessionToken, in String action, in Bundle data,
int userId);

View File

@@ -42,7 +42,7 @@ oneway interface ITvInputSession {
void setCaptionEnabled(boolean enabled);
void selectTrack(int type, in String trackId);
void setIAppNotificationEnabled(boolean enable);
void setInteractiveAppNotificationEnabled(boolean enable);
void appPrivateCommand(in String action, in Bundle data);

View File

@@ -247,7 +247,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
break;
}
case DO_SET_IAPP_NOTIFICATION_ENABLED: {
mTvInputSessionImpl.setIAppNotificationEnabled((Boolean) msg.obj);
mTvInputSessionImpl.setInteractiveAppNotificationEnabled((Boolean) msg.obj);
break;
}
case DO_REQUEST_AD: {
@@ -322,7 +322,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
}
@Override
public void setIAppNotificationEnabled(boolean enabled) {
public void setInteractiveAppNotificationEnabled(boolean enabled) {
mCaller.executeOrSendMessage(
mCaller.obtainMessageO(DO_SET_IAPP_NOTIFICATION_ENABLED, enabled));
}

View File

@@ -735,8 +735,9 @@ public final class TvInputManager {
@Override
public void run() {
mSessionCallback.onTracksChanged(mSession, tracks);
if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyTracksChanged(tracks);
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyTracksChanged(tracks);
}
}
});
@@ -747,8 +748,9 @@ public final class TvInputManager {
@Override
public void run() {
mSessionCallback.onTrackSelected(mSession, type, trackId);
if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyTrackSelected(type, trackId);
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyTrackSelected(type, trackId);
}
}
});
@@ -768,8 +770,9 @@ public final class TvInputManager {
@Override
public void run() {
mSessionCallback.onVideoAvailable(mSession);
if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyVideoAvailable();
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyVideoAvailable();
}
}
});
@@ -780,8 +783,9 @@ public final class TvInputManager {
@Override
public void run() {
mSessionCallback.onVideoUnavailable(mSession, reason);
if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyVideoUnavailable(reason);
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyVideoUnavailable(reason);
}
}
});
@@ -792,8 +796,9 @@ public final class TvInputManager {
@Override
public void run() {
mSessionCallback.onContentAllowed(mSession);
if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyContentAllowed();
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyContentAllowed();
}
}
});
@@ -804,8 +809,9 @@ public final class TvInputManager {
@Override
public void run() {
mSessionCallback.onContentBlocked(mSession, rating);
if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyContentBlocked(rating);
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyContentBlocked(rating);
}
}
});
@@ -871,8 +877,9 @@ public final class TvInputManager {
@Override
public void run() {
mSessionCallback.onTuned(mSession, channelUri);
if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyTuned(channelUri);
if (mSession.mIAppNotificationEnabled
&& mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyTuned(channelUri);
}
}
});
@@ -903,8 +910,9 @@ public final class TvInputManager {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyBroadcastInfoResponse(response);
if (mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession()
.notifyBroadcastInfoResponse(response);
}
}
});
@@ -916,8 +924,8 @@ public final class TvInputManager {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyAdResponse(response);
if (mSession.getInteractiveAppSession() != null) {
mSession.getInteractiveAppSession().notifyAdResponse(response);
}
}
});
@@ -2265,12 +2273,12 @@ public final class TvInputManager {
mSessionCallbackRecordMap = sessionCallbackRecordMap;
}
public TvIAppManager.Session getIAppSession() {
public TvIAppManager.Session getInteractiveAppSession() {
return mIAppSession;
}
public void setIAppSession(TvIAppManager.Session IAppSession) {
this.mIAppSession = IAppSession;
public void setInteractiveAppSession(TvIAppManager.Session iAppSession) {
this.mIAppSession = iAppSession;
}
/**
@@ -2531,13 +2539,13 @@ public final class TvInputManager {
* {@code false} otherwise.
* @hide
*/
public void setIAppNotificationEnabled(boolean enabled) {
public void setInteractiveAppNotificationEnabled(boolean enabled) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.setIAppNotificationEnabled(mToken, enabled, mUserId);
mService.setInteractiveAppNotificationEnabled(mToken, enabled, mUserId);
mIAppNotificationEnabled = enabled;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();

View File

@@ -1180,7 +1180,7 @@ public abstract class TvInputService extends Service {
* @param enabled {@code true} to enable, {@code false} to disable.
* @hide
*/
public void onSetIAppNotificationEnabled(boolean enabled) {
public void onSetInteractiveAppNotificationEnabled(boolean enabled) {
}
/**
@@ -1532,10 +1532,10 @@ public abstract class TvInputService extends Service {
}
/**
* Calls {@link #onSetIAppNotificationEnabled}.
* Calls {@link #onSetInteractiveAppNotificationEnabled}.
*/
void setIAppNotificationEnabled(boolean enabled) {
onSetIAppNotificationEnabled(enabled);
void setInteractiveAppNotificationEnabled(boolean enabled) {
onSetInteractiveAppNotificationEnabled(enabled);
}
/**

View File

@@ -486,9 +486,9 @@ public class TvView extends ViewGroup {
* {@code false} otherwise.
* @hide
*/
public void setIAppNotificationEnabled(boolean enabled) {
public void setInteractiveAppNotificationEnabled(boolean enabled) {
if (mSession != null) {
mSession.setIAppNotificationEnabled(enabled);
mSession.setInteractiveAppNotificationEnabled(enabled);
}
}

View File

@@ -20,9 +20,9 @@ import android.graphics.Rect;
import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvTrackInfo;
import android.media.tv.interactive.ITvIAppClient;
import android.media.tv.interactive.ITvIAppManagerCallback;
import android.media.tv.interactive.TvIAppInfo;
import android.media.tv.interactive.ITvInteractiveAppClient;
import android.media.tv.interactive.ITvInteractiveAppManagerCallback;
import android.media.tv.interactive.TvInteractiveAppInfo;
import android.net.Uri;
import android.os.Bundle;
import android.view.Surface;
@@ -32,12 +32,12 @@ import android.view.Surface;
* @hide
*/
interface ITvIAppManager {
List<TvIAppInfo> getTvIAppServiceList(int userId);
List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId);
void prepare(String tiasId, int type, int userId);
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 stopIApp(in IBinder sessionToken, int userId);
void startInteractiveApp(in IBinder sessionToken, int userId);
void stopInteractiveApp(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);
@@ -45,8 +45,8 @@ interface ITvIAppManager {
void sendCurrentChannelLcn(in IBinder sessionToken, int lcn, int userId);
void sendStreamVolume(in IBinder sessionToken, float volume, int userId);
void sendTrackInfoList(in IBinder sessionToken, in List<TvTrackInfo> tracks, int userId);
void createSession(
in ITvIAppClient client, in String iAppServiceId, int type, int seq, int userId);
void createSession(in ITvInteractiveAppClient client, in String iAppServiceId, int type,
int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId);
void notifyTuned(in IBinder sessionToken, in Uri channelUri, int userId);
void notifyTrackSelected(in IBinder sessionToken, int type, in String trackId, int userId);
@@ -67,6 +67,6 @@ interface ITvIAppManager {
void relayoutMediaView(in IBinder sessionToken, in Rect frame, int userId);
void removeMediaView(in IBinder sessionToken, int userId);
void registerCallback(in ITvIAppManagerCallback callback, int userId);
void unregisterCallback(in ITvIAppManagerCallback callback, int userId);
void registerCallback(in ITvInteractiveAppManagerCallback callback, int userId);
void unregisterCallback(in ITvInteractiveAppManagerCallback callback, int userId);
}

View File

@@ -24,11 +24,11 @@ import android.os.Bundle;
import android.view.InputChannel;
/**
* Interface a client of the ITvIAppManager implements, to identify itself and receive information
* about changes to the state of each TV interactive application service.
* Interface a client of the ITvInteractiveAppManager implements, to identify itself and receive
* information about changes to the state of each TV interactive application service.
* @hide
*/
oneway interface ITvIAppClient {
oneway interface ITvInteractiveAppClient {
void onSessionCreated(in String iAppServiceId, IBinder token, in InputChannel channel, int seq);
void onSessionReleased(int seq);
void onLayoutSurface(int left, int top, int right, int bottom, int seq);

View File

@@ -16,16 +16,16 @@
package android.media.tv.interactive;
import android.media.tv.interactive.TvIAppInfo;
import android.media.tv.interactive.TvInteractiveAppInfo;
/**
* Interface to receive callbacks from ITvIAppManager regardless of sessions.
* Interface to receive callbacks from ITvInteractiveAppManager regardless of sessions.
* @hide
*/
interface ITvIAppManagerCallback {
void onIAppServiceAdded(in String iAppServiceId);
void onIAppServiceRemoved(in String iAppServiceId);
void onIAppServiceUpdated(in String iAppServiceId);
void onTvIAppInfoUpdated(in TvIAppInfo tvIAppInfo);
interface ITvInteractiveAppManagerCallback {
void onInteractiveAppServiceAdded(in String iAppServiceId);
void onInteractiveAppServiceRemoved(in String iAppServiceId);
void onInteractiveAppServiceUpdated(in String iAppServiceId);
void onTvInteractiveAppInfoUpdated(in TvInteractiveAppInfo tvIAppInfo);
void onStateChanged(in String iAppServiceId, int type, int state);
}

View File

@@ -16,20 +16,20 @@
package android.media.tv.interactive;
import android.media.tv.interactive.ITvIAppServiceCallback;
import android.media.tv.interactive.ITvIAppSessionCallback;
import android.media.tv.interactive.ITvInteractiveAppServiceCallback;
import android.media.tv.interactive.ITvInteractiveAppSessionCallback;
import android.os.Bundle;
import android.view.InputChannel;
/**
* Top-level interface to a TV IApp component (implemented in a Service). It's used for
* Top-level interface to a TV Interactive App component (implemented in a Service). It's used for
* TvIAppManagerService to communicate with TvIAppService.
* @hide
*/
oneway interface ITvIAppService {
void registerCallback(in ITvIAppServiceCallback callback);
void unregisterCallback(in ITvIAppServiceCallback callback);
void createSession(in InputChannel channel, in ITvIAppSessionCallback callback,
oneway interface ITvInteractiveAppService {
void registerCallback(in ITvInteractiveAppServiceCallback callback);
void unregisterCallback(in ITvInteractiveAppServiceCallback callback);
void createSession(in InputChannel channel, in ITvInteractiveAppSessionCallback callback,
in String iAppServiceId, int type);
void prepare(int type);
void notifyAppLinkInfo(in Bundle info);

View File

@@ -17,10 +17,10 @@
package android.media.tv.interactive;
/**
* Helper interface for ITvIAppService to allow the TvIAppService to notify the
* Helper interface for ITvInteractiveAppService to allow the TvIAppService to notify the
* TvIAppManagerService.
* @hide
*/
oneway interface ITvIAppServiceCallback {
oneway interface ITvInteractiveAppServiceCallback {
void onStateChanged(int type, int state);
}

View File

@@ -26,12 +26,13 @@ import android.os.Bundle;
import android.view.Surface;
/**
* Sub-interface of ITvIAppService.aidl which is created per session and has its own context.
* Sub-interface of ITvInteractiveAppService.aidl which is created per session and has its own
* context.
* @hide
*/
oneway interface ITvIAppSession {
void startIApp();
void stopIApp();
oneway interface ITvInteractiveAppSession {
void startInteractiveApp();
void stopInteractiveApp();
void createBiInteractiveApp(in Uri biIAppUri, in Bundle params);
void destroyBiInteractiveApp(in String biIAppId);
void sendCurrentChannelUri(in Uri channelUri);

View File

@@ -19,17 +19,17 @@ package android.media.tv.interactive;
import android.graphics.Rect;
import android.media.tv.AdRequest;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.interactive.ITvIAppSession;
import android.media.tv.interactive.ITvInteractiveAppSession;
import android.net.Uri;
import android.os.Bundle;
/**
* Helper interface for ITvIAppSession to allow TvIAppService to notify the system service when
* there is a related event.
* Helper interface for ITvInteractiveAppSession to allow TvIAppService to notify the
* system service when there is a related event.
* @hide
*/
oneway interface ITvIAppSessionCallback {
void onSessionCreated(in ITvIAppSession session);
oneway interface ITvInteractiveAppSessionCallback {
void onSessionCreated(in ITvInteractiveAppSession session);
void onLayoutSurface(int left, int top, int right, int bottom);
void onBroadcastInfoRequest(in BroadcastInfoRequest request);
void onRemoveBroadcastInfo(int id);

View File

@@ -1,227 +0,0 @@
/*
* 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.NonNull;
import android.annotation.StringDef;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
/**
* This class is used to specify meta information of a TV interactive app.
* @hide
*/
public final class TvIAppInfo implements Parcelable {
private static final boolean DEBUG = false;
private static final String TAG = "TvIAppInfo";
@Retention(RetentionPolicy.SOURCE)
@StringDef(prefix = { "INTERACTIVE_APP_TYPE_" }, value = {
INTERACTIVE_APP_TYPE_HBBTV,
INTERACTIVE_APP_TYPE_ATSC,
INTERACTIVE_APP_TYPE_GINGA,
})
@interface InteractiveAppType {}
/** HbbTV interactive app type */
public static final String INTERACTIVE_APP_TYPE_HBBTV = "hbbtv";
/** ATSC interactive app type */
public static final String INTERACTIVE_APP_TYPE_ATSC = "atsc";
/** Ginga interactive app type */
public static final String INTERACTIVE_APP_TYPE_GINGA = "ginga";
private final ResolveInfo mService;
private final String mId;
private List<String> mTypes = new ArrayList<>();
private TvIAppInfo(ResolveInfo service, String id, List<String> types) {
mService = service;
mId = id;
mTypes = types;
}
private TvIAppInfo(@NonNull Parcel in) {
mService = ResolveInfo.CREATOR.createFromParcel(in);
mId = in.readString();
in.readStringList(mTypes);
}
public static final @NonNull Creator<TvIAppInfo> CREATOR = new Creator<TvIAppInfo>() {
@Override
public TvIAppInfo createFromParcel(Parcel in) {
return new TvIAppInfo(in);
}
@Override
public TvIAppInfo[] newArray(int size) {
return new TvIAppInfo[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
mService.writeToParcel(dest, flags);
dest.writeString(mId);
dest.writeStringList(mTypes);
}
@NonNull
public String getId() {
return mId;
}
/**
* Returns the component of the TV IApp service.
* @hide
*/
public ComponentName getComponent() {
return new ComponentName(mService.serviceInfo.packageName, mService.serviceInfo.name);
}
/**
* Returns the information of the service that implements this TV IApp service.
*/
public ServiceInfo getServiceInfo() {
return mService.serviceInfo;
}
/**
* Gets supported interactive app types
*/
@NonNull
public List<String> getSupportedTypes() {
return new ArrayList<>(mTypes);
}
/**
* A convenience builder for creating {@link TvIAppInfo} objects.
*/
public static final class Builder {
private static final String XML_START_TAG_NAME = "tv-iapp";
private final Context mContext;
private final ResolveInfo mResolveInfo;
private final List<String> mTypes = new ArrayList<>();
/**
* Constructs a new builder for {@link TvIAppInfo}.
*
* @param context A Context of the application package implementing this class.
* @param component The name of the application component to be used for the
* {@link TvIAppService}.
*/
public Builder(@NonNull Context context, @NonNull ComponentName component) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null.");
}
Intent intent = new Intent(TvIAppService.SERVICE_INTERFACE).setComponent(component);
mResolveInfo = context.getPackageManager().resolveService(intent,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
if (mResolveInfo == null) {
throw new IllegalArgumentException("Invalid component. Can't find the service.");
}
mContext = context;
}
/**
* Creates a {@link TvIAppInfo} instance with the specified fields. Most of the information
* is obtained by parsing the AndroidManifest and {@link TvIAppService#SERVICE_META_DATA}
* for the {@link TvIAppService} this TV IApp implements.
*
* @return TvIAppInfo containing information about this TV IApp service.
*/
@NonNull
public TvIAppInfo build() {
ComponentName componentName = new ComponentName(mResolveInfo.serviceInfo.packageName,
mResolveInfo.serviceInfo.name);
String id;
id = generateIAppServiceId(componentName);
parseServiceMetadata();
return new TvIAppInfo(mResolveInfo, id, mTypes);
}
private static String generateIAppServiceId(ComponentName name) {
return name.flattenToShortString();
}
private void parseServiceMetadata() {
ServiceInfo si = mResolveInfo.serviceInfo;
PackageManager pm = mContext.getPackageManager();
try (XmlResourceParser parser =
si.loadXmlMetaData(pm, TvIAppService.SERVICE_META_DATA)) {
if (parser == null) {
throw new IllegalStateException("No " + TvIAppService.SERVICE_META_DATA
+ " meta-data found for " + si.name);
}
Resources res = pm.getResourcesForApplication(si.applicationInfo);
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
// move to the START_TAG
}
String nodeName = parser.getName();
if (!XML_START_TAG_NAME.equals(nodeName)) {
throw new IllegalStateException("Meta-data does not start with "
+ XML_START_TAG_NAME + " tag for " + si.name);
}
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.TvIAppService);
CharSequence[] types = sa.getTextArray(
com.android.internal.R.styleable.TvIAppService_supportedTypes);
for (CharSequence cs : types) {
mTypes.add(cs.toString().toLowerCase());
}
sa.recycle();
} catch (IOException | XmlPullParserException e) {
throw new IllegalStateException(
"Failed reading meta-data for " + si.packageName, e);
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalStateException("No resources found for " + si.packageName, e);
}
}
}
}

View File

@@ -64,33 +64,33 @@ public final class 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 {}
@IntDef(flag = false, prefix = "TV_INTERACTIVE_APP_RTE_STATE_", value = {
TV_INTERACTIVE_APP_RTE_STATE_UNREALIZED,
TV_INTERACTIVE_APP_RTE_STATE_PREPARING,
TV_INTERACTIVE_APP_RTE_STATE_READY,
TV_INTERACTIVE_APP_RTE_STATE_ERROR})
public @interface TvInteractiveAppRteState {}
/**
* Unrealized state of interactive app RTE.
* @hide
*/
public static final int TV_IAPP_RTE_STATE_UNREALIZED = 1;
public static final int TV_INTERACTIVE_APP_RTE_STATE_UNREALIZED = 1;
/**
* Preparing state of interactive app RTE.
* @hide
*/
public static final int TV_IAPP_RTE_STATE_PREPARING = 2;
public static final int TV_INTERACTIVE_APP_RTE_STATE_PREPARING = 2;
/**
* Ready state of interactive app RTE.
* @hide
*/
public static final int TV_IAPP_RTE_STATE_READY = 3;
public static final int TV_INTERACTIVE_APP_RTE_STATE_READY = 3;
/**
* Error state of interactive app RTE.
* @hide
*/
public static final int TV_IAPP_RTE_STATE_ERROR = 4;
public static final int TV_INTERACTIVE_APP_RTE_STATE_ERROR = 4;
/**
* Key for package name in app link.
@@ -174,7 +174,7 @@ public final class TvIAppManager {
new SparseArray<>();
// @GuardedBy("mLock")
private final List<TvIAppCallbackRecord> mCallbackRecords = new LinkedList<>();
private final List<TvInteractiveAppCallbackRecord> mCallbackRecords = new LinkedList<>();
// A sequence number for the next session to be created. Should be protected by a lock
// {@code mSessionCallbackRecordMap}.
@@ -182,13 +182,13 @@ public final class TvIAppManager {
private final Object mLock = new Object();
private final ITvIAppClient mClient;
private final ITvInteractiveAppClient mClient;
/** @hide */
public TvIAppManager(ITvIAppManager service, int userId) {
mService = service;
mUserId = userId;
mClient = new ITvIAppClient.Stub() {
mClient = new ITvInteractiveAppClient.Stub() {
@Override
public void onSessionCreated(String iAppServiceId, IBinder token, InputChannel channel,
int seq) {
@@ -260,8 +260,10 @@ public final class TvIAppManager {
}
@Override
public void onCommandRequest(@TvIAppService.IAppServiceCommandType String cmdType,
Bundle parameters, int seq) {
public void onCommandRequest(
@TvIAppService.InteractiveAppServiceCommandType String cmdType,
Bundle parameters,
int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
@@ -368,40 +370,41 @@ public final class TvIAppManager {
}
}
};
ITvIAppManagerCallback managerCallback = new ITvIAppManagerCallback.Stub() {
ITvInteractiveAppManagerCallback managerCallback =
new ITvInteractiveAppManagerCallback.Stub() {
@Override
public void onIAppServiceAdded(String iAppServiceId) {
public void onInteractiveAppServiceAdded(String iAppServiceId) {
synchronized (mLock) {
for (TvIAppCallbackRecord record : mCallbackRecords) {
record.postIAppServiceAdded(iAppServiceId);
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
record.postInteractiveAppServiceAdded(iAppServiceId);
}
}
}
@Override
public void onIAppServiceRemoved(String iAppServiceId) {
public void onInteractiveAppServiceRemoved(String iAppServiceId) {
synchronized (mLock) {
for (TvIAppCallbackRecord record : mCallbackRecords) {
record.postIAppServiceRemoved(iAppServiceId);
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
record.postInteractiveAppServiceRemoved(iAppServiceId);
}
}
}
@Override
public void onIAppServiceUpdated(String iAppServiceId) {
public void onInteractiveAppServiceUpdated(String iAppServiceId) {
synchronized (mLock) {
for (TvIAppCallbackRecord record : mCallbackRecords) {
record.postIAppServiceUpdated(iAppServiceId);
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
record.postInteractiveAppServiceUpdated(iAppServiceId);
}
}
}
@Override
public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
// TODO: add public API updateIAppInfo()
public void onTvInteractiveAppInfoUpdated(TvInteractiveAppInfo iAppInfo) {
// TODO: add public API updateInteractiveAppInfo()
synchronized (mLock) {
for (TvIAppCallbackRecord record : mCallbackRecords) {
record.postTvIAppInfoUpdated(iAppInfo);
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
record.postTvInteractiveAppInfoUpdated(iAppInfo);
}
}
}
@@ -409,7 +412,7 @@ public final class TvIAppManager {
@Override
public void onStateChanged(String iAppServiceId, int type, int state) {
synchronized (mLock) {
for (TvIAppCallbackRecord record : mCallbackRecords) {
for (TvInteractiveAppCallbackRecord record : mCallbackRecords) {
record.postStateChanged(iAppServiceId, type, state);
}
}
@@ -425,110 +428,112 @@ public final class TvIAppManager {
}
/**
* Callback used to monitor status of the TV IApp.
* Callback used to monitor status of the TV Interactive App.
* @hide
*/
public abstract static class TvIAppCallback {
public abstract static class TvInteractiveAppCallback {
/**
* This is called when a TV IApp service is added to the system.
* This is called when a TV Interactive App service is added to the system.
*
* <p>Normally it happens when the user installs a new TV IApp service package that
* implements {@link TvIAppService} interface.
* <p>Normally it happens when the user installs a new TV Interactive App service package
* that implements {@link TvIAppService} interface.
*
* @param iAppServiceId The ID of the TV IApp service.
* @param iAppServiceId The ID of the TV Interactive App service.
*/
public void onIAppServiceAdded(@NonNull String iAppServiceId) {
public void onInteractiveAppServiceAdded(@NonNull String iAppServiceId) {
}
/**
* This is called when a TV IApp service is removed from the system.
* This is called when a TV Interactive App service is removed from the system.
*
* <p>Normally it happens when the user uninstalls the previously installed TV IApp service
* package.
* <p>Normally it happens when the user uninstalls the previously installed TV Interactive
* App service package.
*
* @param iAppServiceId The ID of the TV IApp service.
* @param iAppServiceId The ID of the TV Interactive App service.
*/
public void onIAppServiceRemoved(@NonNull String iAppServiceId) {
public void onInteractiveAppServiceRemoved(@NonNull String iAppServiceId) {
}
/**
* This is called when a TV IApp service is updated on the system.
* This is called when a TV Interactive App service is updated on the system.
*
* <p>Normally it happens when a previously installed TV IApp service package is
* <p>Normally it happens when a previously installed TV Interactive App service package is
* re-installed or a newer version of the package exists becomes available/unavailable.
*
* @param iAppServiceId The ID of the TV IApp service.
* @param iAppServiceId The ID of the TV Interactive App service.
*/
public void onIAppServiceUpdated(@NonNull String iAppServiceId) {
public void onInteractiveAppServiceUpdated(@NonNull String iAppServiceId) {
}
/**
* This is called when the information about an existing TV IApp service has been updated.
* This is called when the information about an existing TV Interactive App service has been
* updated.
*
* <p>Because the system automatically creates a <code>TvIAppInfo</code> object for each TV
* IApp service based on the information collected from the
* <p>Because the system automatically creates a <code>TvInteractiveAppInfo</code> object
* for each TV Interactive App service based on the information collected from the
* <code>AndroidManifest.xml</code>, this method is only called back when such information
* has changed dynamically.
*
* @param iAppInfo The <code>TvIAppInfo</code> object that contains new information.
* @param iAppInfo The <code>TvInteractiveAppInfo</code> object that contains new
* information.
*/
public void onTvIAppInfoUpdated(@NonNull TvIAppInfo iAppInfo) {
public void onTvInteractiveAppInfoUpdated(@NonNull TvInteractiveAppInfo iAppInfo) {
}
/**
* This is called when the state of the interactive app service is changed.
* @hide
*/
public void onTvIAppServiceStateChanged(
@NonNull String iAppServiceId, int type, @TvIAppRteState int state) {
public void onTvInteractiveAppServiceStateChanged(
@NonNull String iAppServiceId, int type, @TvInteractiveAppRteState int state) {
}
}
private static final class TvIAppCallbackRecord {
private final TvIAppCallback mCallback;
private static final class TvInteractiveAppCallbackRecord {
private final TvInteractiveAppCallback mCallback;
private final Handler mHandler;
TvIAppCallbackRecord(TvIAppCallback callback, Handler handler) {
TvInteractiveAppCallbackRecord(TvInteractiveAppCallback callback, Handler handler) {
mCallback = callback;
mHandler = handler;
}
public TvIAppCallback getCallback() {
public TvInteractiveAppCallback getCallback() {
return mCallback;
}
public void postIAppServiceAdded(final String iAppServiceId) {
public void postInteractiveAppServiceAdded(final String iAppServiceId) {
mHandler.post(new Runnable() {
@Override
public void run() {
mCallback.onIAppServiceAdded(iAppServiceId);
mCallback.onInteractiveAppServiceAdded(iAppServiceId);
}
});
}
public void postIAppServiceRemoved(final String iAppServiceId) {
public void postInteractiveAppServiceRemoved(final String iAppServiceId) {
mHandler.post(new Runnable() {
@Override
public void run() {
mCallback.onIAppServiceRemoved(iAppServiceId);
mCallback.onInteractiveAppServiceRemoved(iAppServiceId);
}
});
}
public void postIAppServiceUpdated(final String iAppServiceId) {
public void postInteractiveAppServiceUpdated(final String iAppServiceId) {
mHandler.post(new Runnable() {
@Override
public void run() {
mCallback.onIAppServiceUpdated(iAppServiceId);
mCallback.onInteractiveAppServiceUpdated(iAppServiceId);
}
});
}
public void postTvIAppInfoUpdated(final TvIAppInfo iAppInfo) {
public void postTvInteractiveAppInfoUpdated(final TvInteractiveAppInfo iAppInfo) {
mHandler.post(new Runnable() {
@Override
public void run() {
mCallback.onTvIAppInfoUpdated(iAppInfo);
mCallback.onTvInteractiveAppInfoUpdated(iAppInfo);
}
});
}
@@ -537,7 +542,7 @@ public final class TvIAppManager {
mHandler.post(new Runnable() {
@Override
public void run() {
mCallback.onTvIAppServiceStateChanged(iAppServiceId, type, state);
mCallback.onTvInteractiveAppServiceStateChanged(iAppServiceId, type, state);
}
});
}
@@ -578,23 +583,23 @@ public final class TvIAppManager {
}
/**
* Returns the complete list of TV IApp service on the system.
* Returns the complete list of TV Interactive App service on the system.
*
* @return List of {@link TvIAppInfo} for each TV IApp service that describes its meta
* information.
* @return List of {@link TvInteractiveAppInfo} for each TV Interactive App service that
* describes its meta information.
* @hide
*/
@NonNull
public List<TvIAppInfo> getTvIAppServiceList() {
public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList() {
try {
return mService.getTvIAppServiceList(mUserId);
return mService.getTvInteractiveAppServiceList(mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Prepares TV IApp service for the given type.
* Prepares TV Interactive App service for the given type.
* @hide
*/
public void prepare(@NonNull String tvIAppServiceId, int type) {
@@ -630,32 +635,33 @@ public final class TvIAppManager {
}
/**
* Registers a {@link TvIAppManager.TvIAppCallback}.
* Registers a {@link TvInteractiveAppCallback}.
*
* @param callback A callback used to monitor status of the TV IApp services.
* @param callback A callback used to monitor status of the TV Interactive App services.
* @param handler A {@link Handler} that the status change will be delivered to.
* @hide
*/
public void registerCallback(@NonNull TvIAppCallback callback, @NonNull Handler handler) {
public void registerCallback(
@NonNull TvInteractiveAppCallback callback, @NonNull Handler handler) {
Preconditions.checkNotNull(callback);
Preconditions.checkNotNull(handler);
synchronized (mLock) {
mCallbackRecords.add(new TvIAppCallbackRecord(callback, handler));
mCallbackRecords.add(new TvInteractiveAppCallbackRecord(callback, handler));
}
}
/**
* Unregisters the existing {@link TvIAppManager.TvIAppCallback}.
* Unregisters the existing {@link TvInteractiveAppCallback}.
*
* @param callback The existing callback to remove.
* @hide
*/
public void unregisterCallback(@NonNull final TvIAppCallback callback) {
public void unregisterCallback(@NonNull final TvInteractiveAppCallback callback) {
Preconditions.checkNotNull(callback);
synchronized (mLock) {
for (Iterator<TvIAppCallbackRecord> it = mCallbackRecords.iterator();
for (Iterator<TvInteractiveAppCallbackRecord> it = mCallbackRecords.iterator();
it.hasNext(); ) {
TvIAppCallbackRecord record = it.next();
TvInteractiveAppCallbackRecord record = it.next();
if (record.getCallback() == callback) {
it.remove();
break;
@@ -692,8 +698,8 @@ public final class TvIAppManager {
private TvInputEventSender mSender;
private InputChannel mInputChannel;
private Session(IBinder token, InputChannel channel, ITvIAppManager service, int userId,
int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
private Session(IBinder token, InputChannel channel, ITvIAppManager service,
int userId, int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
mToken = token;
mInputChannel = channel;
mService = service;
@@ -710,25 +716,25 @@ public final class TvIAppManager {
mInputSession = inputSession;
}
void startIApp() {
void startInteractiveApp() {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.startIApp(mToken, mUserId);
mService.startInteractiveApp(mToken, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
void stopIApp() {
void stopInteractiveApp() {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.stopIApp(mToken, mUserId);
mService.stopInteractiveApp(mToken, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -994,7 +1000,7 @@ public final class TvIAppManager {
}
/**
* Notifies IAPP session when a channel is tuned.
* Notifies Interactive APP session when a channel is tuned.
*/
public void notifyTuned(Uri channelUri) {
if (mToken == null) {
@@ -1009,7 +1015,7 @@ public final class TvIAppManager {
}
/**
* Notifies IAPP session when a track is selected.
* Notifies Interactive APP session when a track is selected.
*/
public void notifyTrackSelected(int type, String trackId) {
if (mToken == null) {
@@ -1024,7 +1030,7 @@ public final class TvIAppManager {
}
/**
* Notifies IAPP session when tracks are changed.
* Notifies Interactive APP session when tracks are changed.
*/
public void notifyTracksChanged(List<TvTrackInfo> tracks) {
if (mToken == null) {
@@ -1359,7 +1365,8 @@ public final class TvIAppManager {
});
}
void postCommandRequest(final @TvIAppService.IAppServiceCommandType String cmdType,
void postCommandRequest(
final @TvIAppService.InteractiveAppServiceCommandType String cmdType,
final Bundle parameters) {
mHandler.post(new Runnable() {
@Override
@@ -1452,8 +1459,8 @@ public final class TvIAppManager {
/**
* This is called after {@link TvIAppManager#createSession} has been processed.
*
* @param session A {@link TvIAppManager.Session} instance created. This can be {@code null}
* if the creation request failed.
* @param session A {@link TvIAppManager.Session} instance created. This can be
* {@code null} if the creation request failed.
*/
public void onSessionCreated(@Nullable Session session) {
}
@@ -1468,8 +1475,8 @@ public final class TvIAppManager {
}
/**
* This is called when {@link TvIAppService.Session#layoutSurface} is called to change the
* layout of surface.
* This is called when {@link TvIAppService.Session#layoutSurface} is called to
* change the layout of surface.
*
* @param session A {@link TvIAppManager.Session} associated with this callback.
* @param left Left position.
@@ -1487,8 +1494,10 @@ public final class TvIAppManager {
* @param cmdType type of the command.
* @param parameters parameters of the command.
*/
public void onCommandRequest(Session session,
@TvIAppService.IAppServiceCommandType String cmdType, Bundle parameters) {
public void onCommandRequest(
Session session,
@TvIAppService.InteractiveAppServiceCommandType String cmdType,
Bundle parameters) {
}
/**
@@ -1500,7 +1509,8 @@ public final class TvIAppManager {
}
/**
* This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is called.
* This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is
* called.
*
* @param session A {@link TvIAppManager.Session} associated with this callback.
*/
@@ -1508,7 +1518,8 @@ public final class TvIAppManager {
}
/**
* This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is called.
* This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is
* called.
*
* @param session A {@link TvIAppManager.Session} associated with this callback.
*/
@@ -1516,7 +1527,8 @@ public final class TvIAppManager {
}
/**
* This is called when {@link TvIAppService.Session#RequestStreamVolume} is called.
* This is called when {@link TvIAppService.Session#RequestStreamVolume} is
* called.
*
* @param session A {@link TvIAppManager.Session} associated with this callback.
*/
@@ -1524,7 +1536,8 @@ public final class TvIAppManager {
}
/**
* This is called when {@link TvIAppService.Session#RequestTrackInfoList} is called.
* This is called when {@link TvIAppService.Session#RequestTrackInfoList} is
* called.
*
* @param session A {@link TvIAppManager.Session} associated with this callback.
*/
@@ -1532,7 +1545,8 @@ public final class TvIAppManager {
}
/**
* This is called when {@link TvIAppService.Session#notifySessionStateChanged} is called.
* 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.
@@ -1541,8 +1555,8 @@ public final class TvIAppManager {
}
/**
* This is called when {@link TvIAppService.Session#notifyBiInteractiveAppCreated} is
* called.
* 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

View File

@@ -75,45 +75,48 @@ public abstract class TvIAppService extends Service {
// TODO: cleanup and unhide APIs.
/**
* This is the interface name that a service implementing a TV IApp service should say that it
* supports -- that is, this is the action it uses for its intent filter. To be supported, the
* service must also require the android.Manifest.permission#BIND_TV_IAPP permission so
* that other applications cannot abuse it.
* This is the interface name that a service implementing a TV Interactive App service should
* say that it supports -- that is, this is the action it uses for its intent filter. To be
* supported, the service must also require the
* android.Manifest.permission#BIND_TV_INTERACTIVE_APP permission so that other applications
* cannot abuse it.
*/
public static final String SERVICE_INTERFACE = "android.media.tv.interactive.TvIAppService";
public static final String SERVICE_INTERFACE =
"android.media.tv.interactive.TvIAppService";
/**
* Name under which a TvIAppService component publishes information about itself. This meta-data
* must reference an XML resource containing an
* <code>&lt;{@link android.R.styleable#TvIAppService tv-iapp}&gt;</code>
* Name under which a TvIAppService component publishes information about itself. This
* meta-data must reference an XML resource containing an
* <code>&lt;{@link android.R.styleable#TvIAppService tv-interactive-app}&gt;</code>
* tag.
*/
public static final String SERVICE_META_DATA = "android.media.tv.interactive.app";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@StringDef(prefix = "IAPP_SERVICE_COMMAND_TYPE_", value = {
IAPP_SERVICE_COMMAND_TYPE_TUNE,
IAPP_SERVICE_COMMAND_TYPE_TUNE_NEXT,
IAPP_SERVICE_COMMAND_TYPE_TUNE_PREV,
IAPP_SERVICE_COMMAND_TYPE_STOP,
IAPP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME,
IAPP_SERVICE_COMMAND_TYPE_SELECT_TRACK
@StringDef(prefix = "INTERACTIVE_APP_SERVICE_COMMAND_TYPE_", value = {
INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE,
INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE_NEXT,
INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE_PREV,
INTERACTIVE_APP_SERVICE_COMMAND_TYPE_STOP,
INTERACTIVE_APP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME,
INTERACTIVE_APP_SERVICE_COMMAND_TYPE_SELECT_TRACK
})
public @interface IAppServiceCommandType {}
public @interface InteractiveAppServiceCommandType {}
/** @hide */
public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE = "tune";
public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE = "tune";
/** @hide */
public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE_NEXT = "tune_next";
public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE_NEXT = "tune_next";
/** @hide */
public static final String IAPP_SERVICE_COMMAND_TYPE_TUNE_PREV = "tune_previous";
public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_TUNE_PREV = "tune_previous";
/** @hide */
public static final String IAPP_SERVICE_COMMAND_TYPE_STOP = "stop";
public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_STOP = "stop";
/** @hide */
public static final String IAPP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME = "set_stream_volume";
public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_SET_STREAM_VOLUME =
"set_stream_volume";
/** @hide */
public static final String IAPP_SERVICE_COMMAND_TYPE_SELECT_TRACK = "select_track";
public static final String INTERACTIVE_APP_SERVICE_COMMAND_TYPE_SELECT_TRACK = "select_track";
/** @hide */
public static final String COMMAND_PARAMETER_KEY_CHANNEL_URI = "command_channel_uri";
/** @hide */
@@ -129,29 +132,29 @@ public abstract class TvIAppService extends Service {
"command_track_select_mode";
private final Handler mServiceHandler = new ServiceHandler();
private final RemoteCallbackList<ITvIAppServiceCallback> mCallbacks =
private final RemoteCallbackList<ITvInteractiveAppServiceCallback> mCallbacks =
new RemoteCallbackList<>();
/** @hide */
@Override
public final IBinder onBind(Intent intent) {
ITvIAppService.Stub tvIAppServiceBinder = new ITvIAppService.Stub() {
ITvInteractiveAppService.Stub tvIAppServiceBinder = new ITvInteractiveAppService.Stub() {
@Override
public void registerCallback(ITvIAppServiceCallback cb) {
public void registerCallback(ITvInteractiveAppServiceCallback cb) {
if (cb != null) {
mCallbacks.register(cb);
}
}
@Override
public void unregisterCallback(ITvIAppServiceCallback cb) {
public void unregisterCallback(ITvInteractiveAppServiceCallback cb) {
if (cb != null) {
mCallbacks.unregister(cb);
}
}
@Override
public void createSession(InputChannel channel, ITvIAppSessionCallback cb,
public void createSession(InputChannel channel, ITvInteractiveAppSessionCallback cb,
String iAppServiceId, int type) {
if (cb == null) {
return;
@@ -184,7 +187,7 @@ public abstract class TvIAppService extends Service {
}
/**
* Prepares TV IApp service for the given type.
* Prepares TV Interactive App service for the given type.
* @hide
*/
public void onPrepare(int type) {
@@ -211,11 +214,11 @@ public abstract class TvIAppService extends Service {
/**
* Returns a concrete implementation of {@link Session}.
*
* <p>May return {@code null} if this TV IApp service fails to create a session for some
* reason.
* <p>May return {@code null} if this TV Interactive App service fails to create a session for
* some reason.
*
* @param iAppServiceId The ID of the TV IApp associated with the session.
* @param type The type of the TV IApp associated with the session.
* @param iAppServiceId The ID of the TV Interactive App associated with the session.
* @param type The type of the TV Interactive App associated with the session.
* @hide
*/
@Nullable
@@ -229,7 +232,8 @@ public abstract class TvIAppService extends Service {
* @param state the current state
* @hide
*/
public final void notifyStateChanged(int type, @TvIAppManager.TvIAppRteState int state) {
public final void notifyStateChanged(
int type, @TvIAppManager.TvInteractiveAppRteState int state) {
mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_RTE_STATE_CHANGED,
type, state).sendToTarget();
}
@@ -243,7 +247,7 @@ public abstract class TvIAppService extends Service {
private final Object mLock = new Object();
// @GuardedBy("mLock")
private ITvIAppSessionCallback mSessionCallback;
private ITvInteractiveAppSessionCallback mSessionCallback;
// @GuardedBy("mLock")
private final List<Runnable> mPendingActions = new ArrayList<>();
@@ -276,7 +280,7 @@ public abstract class TvIAppService extends Service {
* <p>By default, the media view is disabled. Must be called explicitly after the
* session is created to enable the media view.
*
* <p>The TV IApp service can disable its media view when needed.
* <p>The TV Interactive App service can disable its media view when needed.
*
* @param enable {@code true} if you want to enable the media view. {@code false}
* otherwise.
@@ -304,14 +308,14 @@ public abstract class TvIAppService extends Service {
* Starts TvIAppService session.
* @hide
*/
public void onStartIApp() {
public void onStartInteractiveApp() {
}
/**
* Stops TvIAppService session.
* @hide
*/
public void onStopIApp() {
public void onStopInteractiveApp() {
}
/**
@@ -367,9 +371,9 @@ public abstract class TvIAppService extends Service {
/**
* Called when the application sets the surface.
*
* <p>The TV IApp service should render interactive app UI onto the given surface. When
* called with {@code null}, the IApp service should immediately free any references to the
* currently set surface and stop using it.
* <p>The TV Interactive App service should render interactive app UI onto the given
* surface. When called with {@code null}, the Interactive App service should immediately
* free any references to the currently set surface and stop using it.
*
* @param surface The surface to be used for interactive app UI rendering. Can be
* {@code null}.
@@ -394,8 +398,8 @@ public abstract class TvIAppService extends Service {
*
* <p>This is always called at least once when the session is created regardless of whether
* the media view is enabled or not. The media view container size is the same as the
* containing {@link TvIAppView}. Note that the size of the underlying surface can be
* different if the surface was changed by calling {@link #layoutSurface}.
* containing {@link TvInteractiveAppView}. Note that the size of the underlying surface can
* be different if the surface was changed by calling {@link #layoutSurface}.
*
* @param width The width of the media view.
* @param height The height of the media view.
@@ -624,7 +628,8 @@ public abstract class TvIAppService extends Service {
* @param cmdType type of the specific command
* @param parameters parameters of the specific command
*/
public void requestCommand(@IAppServiceCommandType String cmdType, Bundle parameters) {
public void requestCommand(
@InteractiveAppServiceCommandType String cmdType, Bundle parameters) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
@@ -777,12 +782,12 @@ public abstract class TvIAppService extends Service {
});
}
void startIApp() {
onStartIApp();
void startInteractiveApp() {
onStartInteractiveApp();
}
void stopIApp() {
onStopIApp();
void stopInteractiveApp() {
onStopInteractiveApp();
}
void createBiInteractiveApp(@NonNull Uri biIAppUri, @Nullable Bundle params) {
@@ -898,7 +903,8 @@ public abstract class TvIAppService extends Service {
* Notifies when the session state is changed.
* @param state the current state.
*/
public void notifySessionStateChanged(@TvIAppManager.TvIAppRteState int state) {
public void notifySessionStateChanged(
@TvIAppManager.TvInteractiveAppRteState int state) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
@@ -977,7 +983,7 @@ public abstract class TvIAppService extends Service {
return TvIAppManager.Session.DISPATCH_NOT_HANDLED;
}
private void initialize(ITvIAppSessionCallback callback) {
private void initialize(ITvInteractiveAppSessionCallback callback) {
synchronized (mLock) {
mSessionCallback = callback;
for (Runnable runnable : mPendingActions) {
@@ -1087,8 +1093,8 @@ public abstract class TvIAppService extends Service {
if (DEBUG) Log.d(TAG, "relayoutMediaView(" + frame + ")");
if (mMediaFrame == null || mMediaFrame.width() != frame.width()
|| mMediaFrame.height() != frame.height()) {
// Note: relayoutMediaView is called whenever TvIAppView's layout is changed
// regardless of setMediaViewEnabled.
// Note: relayoutMediaView is called whenever TvInteractiveAppView's layout is
// changed regardless of setMediaViewEnabled.
onMediaViewSizeChanged(frame.right - frame.left, frame.bottom - frame.top);
}
mMediaFrame = frame;
@@ -1159,31 +1165,32 @@ public abstract class TvIAppService extends Service {
}
/**
* Implements the internal ITvIAppSession interface.
* Implements the internal ITvInteractiveAppSession interface.
* @hide
*/
public static class ITvIAppSessionWrapper extends ITvIAppSession.Stub {
// TODO: put ITvIAppSessionWrapper in a separate Java file
public static class ITvInteractiveAppSessionWrapper extends ITvInteractiveAppSession.Stub {
// TODO: put ITvInteractiveAppSessionWrapper in a separate Java file
private final Session mSessionImpl;
private InputChannel mChannel;
private TvIAppEventReceiver mReceiver;
private TvInteractiveAppEventReceiver mReceiver;
public ITvIAppSessionWrapper(Context context, Session mSessionImpl, InputChannel channel) {
public ITvInteractiveAppSessionWrapper(
Context context, Session mSessionImpl, InputChannel channel) {
this.mSessionImpl = mSessionImpl;
mChannel = channel;
if (channel != null) {
mReceiver = new TvIAppEventReceiver(channel, context.getMainLooper());
mReceiver = new TvInteractiveAppEventReceiver(channel, context.getMainLooper());
}
}
@Override
public void startIApp() {
mSessionImpl.startIApp();
public void startInteractiveApp() {
mSessionImpl.startInteractiveApp();
}
@Override
public void stopIApp() {
mSessionImpl.stopIApp();
public void stopInteractiveApp() {
mSessionImpl.stopInteractiveApp();
}
@Override
@@ -1292,8 +1299,8 @@ public abstract class TvIAppService extends Service {
mSessionImpl.removeMediaView(true);
}
private final class TvIAppEventReceiver extends InputEventReceiver {
TvIAppEventReceiver(InputChannel inputChannel, Looper looper) {
private final class TvInteractiveAppEventReceiver extends InputEventReceiver {
TvInteractiveAppEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
@@ -1307,7 +1314,8 @@ public abstract class TvIAppService extends Service {
int handled = mSessionImpl.dispatchInputEvent(event, this);
if (handled != TvIAppManager.Session.DISPATCH_IN_PROGRESS) {
finishInputEvent(event, handled == TvIAppManager.Session.DISPATCH_HANDLED);
finishInputEvent(
event, handled == TvIAppManager.Session.DISPATCH_HANDLED);
}
}
}
@@ -1337,7 +1345,8 @@ public abstract class TvIAppService extends Service {
case DO_CREATE_SESSION: {
SomeArgs args = (SomeArgs) msg.obj;
InputChannel channel = (InputChannel) args.arg1;
ITvIAppSessionCallback cb = (ITvIAppSessionCallback) args.arg2;
ITvInteractiveAppSessionCallback cb =
(ITvInteractiveAppSessionCallback) args.arg2;
String iAppServiceId = (String) args.arg3;
int type = (int) args.arg4;
args.recycle();
@@ -1351,8 +1360,8 @@ public abstract class TvIAppService extends Service {
}
return;
}
ITvIAppSession stub = new ITvIAppSessionWrapper(
TvIAppService.this, sessionImpl, channel);
ITvInteractiveAppSession stub = new ITvInteractiveAppSessionWrapper(
android.media.tv.interactive.TvIAppService.this, sessionImpl, channel);
SomeArgs someArgs = SomeArgs.obtain();
someArgs.arg1 = sessionImpl;
@@ -1365,8 +1374,9 @@ public abstract class TvIAppService extends Service {
case DO_NOTIFY_SESSION_CREATED: {
SomeArgs args = (SomeArgs) msg.obj;
Session sessionImpl = (Session) args.arg1;
ITvIAppSession stub = (ITvIAppSession) args.arg2;
ITvIAppSessionCallback cb = (ITvIAppSessionCallback) args.arg3;
ITvInteractiveAppSession stub = (ITvInteractiveAppSession) args.arg2;
ITvInteractiveAppSessionCallback cb =
(ITvInteractiveAppSessionCallback) args.arg3;
try {
cb.onSessionCreated(stub);
} catch (RemoteException e) {

View File

@@ -16,4 +16,4 @@
package android.media.tv.interactive;
parcelable TvIAppInfo;
parcelable TvInteractiveAppInfo;

View File

@@ -0,0 +1,232 @@
/*
* 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.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
/**
* This class is used to specify meta information of a TV interactive app.
* @hide
*/
public final class TvInteractiveAppInfo implements Parcelable {
private static final boolean DEBUG = false;
private static final String TAG = "TvInteractiveAppInfo";
private static final String XML_START_TAG_NAME = "tv-interactive-app";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "INTERACTIVE_APP_TYPE_" }, value = {
INTERACTIVE_APP_TYPE_HBBTV,
INTERACTIVE_APP_TYPE_ATSC,
INTERACTIVE_APP_TYPE_GINGA,
})
@interface InteractiveAppType {}
/** HbbTV interactive app type */
public static final int INTERACTIVE_APP_TYPE_HBBTV = 0x1;
/** ATSC interactive app type */
public static final int INTERACTIVE_APP_TYPE_ATSC = 0x2;
/** Ginga interactive app type */
public static final int INTERACTIVE_APP_TYPE_GINGA = 0x4;
private final ResolveInfo mService;
private final String mId;
private int mTypes;
public TvInteractiveAppInfo(@NonNull Context context, @NonNull ComponentName component) {
if (context == null) {
throw new IllegalArgumentException("context cannot be null.");
}
Intent intent =
new Intent(TvIAppService.SERVICE_INTERFACE).setComponent(component);
ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
if (resolveInfo == null) {
throw new IllegalArgumentException("Invalid component. Can't find the service.");
}
ComponentName componentName = new ComponentName(resolveInfo.serviceInfo.packageName,
resolveInfo.serviceInfo.name);
String id;
id = generateInteractiveAppServiceId(componentName);
List<String> types = new ArrayList<>();
parseServiceMetadata(resolveInfo, context, types);
mService = resolveInfo;
mId = id;
mTypes = toTypesFlag(types);
}
private TvInteractiveAppInfo(ResolveInfo service, String id, int types) {
mService = service;
mId = id;
mTypes = types;
}
private TvInteractiveAppInfo(@NonNull Parcel in) {
mService = ResolveInfo.CREATOR.createFromParcel(in);
mId = in.readString();
mTypes = in.readInt();
}
public static final @NonNull Creator<TvInteractiveAppInfo> CREATOR =
new Creator<TvInteractiveAppInfo>() {
@Override
public TvInteractiveAppInfo createFromParcel(Parcel in) {
return new TvInteractiveAppInfo(in);
}
@Override
public TvInteractiveAppInfo[] newArray(int size) {
return new TvInteractiveAppInfo[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
mService.writeToParcel(dest, flags);
dest.writeString(mId);
dest.writeInt(mTypes);
}
@NonNull
public String getId() {
return mId;
}
/**
* Returns the component of the TV Interactive App service.
* @hide
*/
public ComponentName getComponent() {
return new ComponentName(mService.serviceInfo.packageName, mService.serviceInfo.name);
}
/**
* Returns the information of the service that implements this TV Interactive App service.
*/
@Nullable
public ServiceInfo getServiceInfo() {
return mService.serviceInfo;
}
/**
* Gets supported interactive app types
*/
@InteractiveAppType
@NonNull
public int getSupportedTypes() {
return mTypes;
}
private static String generateInteractiveAppServiceId(ComponentName name) {
return name.flattenToShortString();
}
private static void parseServiceMetadata(
ResolveInfo resolveInfo, Context context, List<String> types) {
ServiceInfo si = resolveInfo.serviceInfo;
PackageManager pm = context.getPackageManager();
try (XmlResourceParser parser =
si.loadXmlMetaData(pm, TvIAppService.SERVICE_META_DATA)) {
if (parser == null) {
throw new IllegalStateException(
"No " + TvIAppService.SERVICE_META_DATA
+ " meta-data found for " + si.name);
}
Resources res = pm.getResourcesForApplication(si.applicationInfo);
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
// move to the START_TAG
}
String nodeName = parser.getName();
if (!XML_START_TAG_NAME.equals(nodeName)) {
throw new IllegalStateException("Meta-data does not start with "
+ XML_START_TAG_NAME + " tag for " + si.name);
}
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.TvIAppService);
CharSequence[] textArr = sa.getTextArray(
com.android.internal.R.styleable.TvIAppService_supportedTypes);
for (CharSequence cs : textArr) {
types.add(cs.toString().toLowerCase());
}
sa.recycle();
} catch (IOException | XmlPullParserException e) {
throw new IllegalStateException(
"Failed reading meta-data for " + si.packageName, e);
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalStateException("No resources found for " + si.packageName, e);
}
}
private static int toTypesFlag(List<String> types) {
int flag = 0;
for (String type : types) {
switch (type) {
case "hbbtv":
flag |= INTERACTIVE_APP_TYPE_HBBTV;
break;
case "atsc":
flag |= INTERACTIVE_APP_TYPE_ATSC;
break;
case "ginga":
flag |= INTERACTIVE_APP_TYPE_GINGA;
break;
default:
break;
}
}
return flag;
}
}

View File

@@ -16,6 +16,7 @@
package android.media.tv.interactive;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -45,13 +46,14 @@ import android.view.ViewGroup;
import android.view.ViewRootImpl;
import java.util.List;
import java.util.concurrent.Executor;
/**
* Displays contents of interactive TV applications.
* @hide
*/
public class TvIAppView extends ViewGroup {
private static final String TAG = "TvIAppView";
public class TvInteractiveAppView extends ViewGroup {
private static final String TAG = "TvInteractiveAppView";
private static final boolean DEBUG = false;
private static final int SET_TVVIEW_SUCCESS = 1;
@@ -59,11 +61,13 @@ public class TvIAppView extends ViewGroup {
private static final int UNSET_TVVIEW_SUCCESS = 3;
private static final int UNSET_TVVIEW_FAIL = 4;
private final TvIAppManager mTvIAppManager;
private final TvIAppManager mTvInteractiveAppManager;
private final Handler mHandler = new Handler();
private final Object mCallbackLock = new Object();
private Session mSession;
private MySessionCallback mSessionCallback;
private TvIAppCallback mCallback;
private TvInteractiveAppCallback mCallback;
private Executor mCallbackExecutor;
private SurfaceView mSurfaceView;
private Surface mSurface;
@@ -114,15 +118,16 @@ public class TvIAppView extends ViewGroup {
}
};
public TvIAppView(@NonNull Context context) {
public TvInteractiveAppView(@NonNull Context context) {
this(context, null, 0);
}
public TvIAppView(@NonNull Context context, @Nullable AttributeSet attrs) {
public TvInteractiveAppView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public TvIAppView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
public TvInteractiveAppView(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
int sourceResId = Resources.getAttributeSetSourceResId(attrs);
if (sourceResId != Resources.ID_NULL) {
@@ -136,31 +141,50 @@ public class TvIAppView extends ViewGroup {
}
mDefStyleAttr = defStyleAttr;
resetSurfaceView();
mTvIAppManager = (TvIAppManager) getContext().getSystemService(Context.TV_IAPP_SERVICE);
mTvInteractiveAppManager = (TvIAppManager) getContext().getSystemService(
Context.TV_IAPP_SERVICE);
}
/**
* Sets the callback to be invoked when an event is dispatched to this TvIAppView.
* Sets the callback to be invoked when an event is dispatched to this TvInteractiveAppView.
*
* @param callback The callback to receive events. A value of {@code null} removes the existing
* callback.
* callback.
*/
public void setCallback(@Nullable TvIAppCallback callback) {
mCallback = callback;
public void setCallback(
@NonNull TvInteractiveAppCallback callback,
@NonNull @CallbackExecutor Executor executor) {
synchronized (mCallbackLock) {
mCallbackExecutor = executor;
mCallback = callback;
}
}
/**
* Clears the callback.
*/
public void clearCallback() {
synchronized (mCallbackLock) {
mCallback = null;
mCallbackExecutor = null;
}
}
/** @hide */
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
createSessionMediaView();
}
/** @hide */
@Override
protected void onDetachedFromWindow() {
removeSessionMediaView();
super.onDetachedFromWindow();
}
/** @hide */
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (DEBUG) {
@@ -175,6 +199,7 @@ public class TvIAppView extends ViewGroup {
}
}
/** @hide */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mSurfaceView.measure(widthMeasureSpec, heightMeasureSpec);
@@ -186,6 +211,7 @@ public class TvIAppView extends ViewGroup {
childState << MEASURED_HEIGHT_STATE_SHIFT));
}
/** @hide */
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
@@ -216,7 +242,8 @@ public class TvIAppView extends ViewGroup {
}
/**
* Resets this TvIAppView.
* Resets this TvInteractiveAppView.
* @hide
*/
public void reset() {
if (DEBUG) Log.d(TAG, "reset()");
@@ -302,6 +329,7 @@ public class TvIAppView extends ViewGroup {
/**
* Dispatches an unhandled input event to the next receiver.
* @hide
*/
public boolean dispatchUnhandledInputEvent(@NonNull InputEvent event) {
if (mOnUnhandledInputEventListener != null) {
@@ -314,11 +342,13 @@ public class TvIAppView extends ViewGroup {
/**
* Called when an unhandled input event also has not been handled by the user provided
* callback. This is the last chance to handle the unhandled input event in the TvIAppView.
* callback. This is the last chance to handle the unhandled input event in the
* TvInteractiveAppView.
*
* @param event The input event.
* @return If you handled the event, return {@code true}. If you want to allow the event to be
* handled by the next receiver, return {@code false}.
* @hide
*/
public boolean onUnhandledInputEvent(@NonNull InputEvent event) {
return false;
@@ -329,6 +359,7 @@ public class TvIAppView extends ViewGroup {
* by the TV Interactive App.
*
* @param listener The callback to be invoked when the unhandled input event is received.
* @hide
*/
public void setOnUnhandledInputEventListener(@NonNull OnUnhandledInputEventListener listener) {
mOnUnhandledInputEventListener = listener;
@@ -350,44 +381,47 @@ public class TvIAppView extends ViewGroup {
/**
* Prepares the interactive application.
* @hide
*/
public void prepareIApp(@NonNull String iAppServiceId, int type) {
public void prepareInteractiveApp(@NonNull String iAppServiceId, int type) {
// TODO: document and handle the cases that this method is called multiple times.
if (DEBUG) {
Log.d(TAG, "prepareIApp");
Log.d(TAG, "prepareInteractiveApp");
}
mSessionCallback = new MySessionCallback(iAppServiceId, type);
if (mTvIAppManager != null) {
mTvIAppManager.createSession(iAppServiceId, type, mSessionCallback, mHandler);
if (mTvInteractiveAppManager != null) {
mTvInteractiveAppManager.createSession(iAppServiceId, type, mSessionCallback, mHandler);
}
}
/**
* Starts the interactive application.
*/
public void startIApp() {
public void startInteractiveApp() {
if (DEBUG) {
Log.d(TAG, "startIApp");
Log.d(TAG, "startInteractiveApp");
}
if (mSession != null) {
mSession.startIApp();
mSession.startInteractiveApp();
}
}
/**
* Stops the interactive application.
* @hide
*/
public void stopIApp() {
public void stopInteractiveApp() {
if (DEBUG) {
Log.d(TAG, "stopIApp");
Log.d(TAG, "stopInteractiveApp");
}
if (mSession != null) {
mSession.stopIApp();
mSession.stopInteractiveApp();
}
}
/**
* Sends current channel URI to related TV interactive app.
* @hide
*/
public void sendCurrentChannelUri(Uri channelUri) {
if (DEBUG) {
@@ -400,6 +434,7 @@ public class TvIAppView extends ViewGroup {
/**
* Sends current channel logical channel number (LCN) to related TV interactive app.
* @hide
*/
public void sendCurrentChannelLcn(int lcn) {
if (DEBUG) {
@@ -412,6 +447,7 @@ public class TvIAppView extends ViewGroup {
/**
* Sends stream volume to related TV interactive app.
* @hide
*/
public void sendStreamVolume(float volume) {
if (DEBUG) {
@@ -424,6 +460,7 @@ public class TvIAppView extends ViewGroup {
/**
* Sends track info list to related TV interactive app.
* @hide
*/
public void sendTrackInfoList(List<TvTrackInfo> tracks) {
if (DEBUG) {
@@ -478,16 +515,18 @@ public class TvIAppView extends ViewGroup {
}
}
public Session getIAppSession() {
/** @hide */
public Session getInteractiveAppSession() {
return mSession;
}
/**
* Sets the TvIAppView to receive events from TIS. This method links the session of
* Sets the TvInteractiveAppView to receive events from TIS. This method links the session of
* TvIAppManager to TvInputManager session, so the TIAS can get the TIS events.
*
* @param tvView the TvView to be linked to this TvIAppView via linking of Sessions.
* @param tvView the TvView to be linked to this TvInteractiveAppView via linking of Sessions.
* @return to be added
* @hide
*/
public int setTvView(@Nullable TvView tvView) {
if (tvView == null) {
@@ -498,7 +537,7 @@ public class TvIAppView extends ViewGroup {
return SET_TVVIEW_FAIL;
}
mSession.setInputSession(inputSession);
inputSession.setIAppSession(mSession);
inputSession.setInteractiveAppSession(mSession);
return SET_TVVIEW_SUCCESS;
}
@@ -506,15 +545,16 @@ public class TvIAppView extends ViewGroup {
if (mSession == null || mSession.getInputSession() == null) {
return UNSET_TVVIEW_FAIL;
}
mSession.getInputSession().setIAppSession(null);
mSession.getInputSession().setInteractiveAppSession(null);
mSession.setInputSession(null);
return UNSET_TVVIEW_SUCCESS;
}
/**
* Callback used to receive various status updates on the {@link TvIAppView}.
* Callback used to receive various status updates on the {@link TvInteractiveAppView}.
*/
public abstract static class TvIAppCallback {
public abstract static class TvInteractiveAppCallback {
// TODO: unhide the following public APIs
/**
* This is called when a command is requested to be processed by the related TV input.
@@ -522,10 +562,11 @@ public class TvIAppView extends ViewGroup {
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param cmdType type of the command
* @param parameters parameters of the command
* @hide
*/
public void onCommandRequest(
@NonNull String iAppServiceId,
@NonNull @TvIAppService.IAppServiceCommandType String cmdType,
@NonNull @TvIAppService.InteractiveAppServiceCommandType String cmdType,
@Nullable Bundle parameters) {
}
@@ -534,6 +575,7 @@ public class TvIAppView extends ViewGroup {
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @param state current session state.
* @hide
*/
public void onSessionStateChanged(@NonNull String iAppServiceId, int state) {
}
@@ -546,6 +588,7 @@ public class TvIAppView extends ViewGroup {
* {@link Session#createBiInteractiveApp(Uri, Bundle)}
* @param biIAppId BI interactive app ID, which can be used to destroy the BI interactive
* app.
* @hide
*/
public void onBiInteractiveAppCreated(@NonNull String iAppServiceId, @NonNull Uri biIAppUri,
@Nullable String biIAppId) {
@@ -555,38 +598,47 @@ public class TvIAppView extends ViewGroup {
* This is called when {@link TvIAppService.Session#SetVideoBounds} is called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @hide
*/
public void onSetVideoBounds(@NonNull String iAppServiceId, @NonNull Rect rect) {
}
/**
* This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is called.
* This is called when {@link TvIAppService.Session#RequestCurrentChannelUri} is
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @hide
*/
public void onRequestCurrentChannelUri(@NonNull String iAppServiceId) {
}
/**
* This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is called.
* This is called when {@link TvIAppService.Session#RequestCurrentChannelLcn} is
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @hide
*/
public void onRequestCurrentChannelLcn(@NonNull String iAppServiceId) {
}
/**
* This is called when {@link TvIAppService.Session#RequestStreamVolume} is called.
* This is called when {@link TvIAppService.Session#RequestStreamVolume} is
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @hide
*/
public void onRequestStreamVolume(@NonNull String iAppServiceId) {
}
/**
* This is called when {@link TvIAppService.Session#RequestTrackInfoList} is called.
* This is called when {@link TvIAppService.Session#RequestTrackInfoList} is
* called.
*
* @param iAppServiceId The ID of the TV interactive app service bound to this view.
* @hide
*/
public void onRequestTrackInfoList(@NonNull String iAppServiceId) {
}
@@ -595,6 +647,7 @@ public class TvIAppView extends ViewGroup {
/**
* Interface definition for a callback to be invoked when the unhandled input event is received.
* @hide
*/
public interface OnUnhandledInputEventListener {
/**
@@ -685,8 +738,10 @@ public class TvIAppView extends ViewGroup {
}
@Override
public void onCommandRequest(Session session,
@TvIAppService.IAppServiceCommandType String cmdType, Bundle parameters) {
public void onCommandRequest(
Session session,
@TvIAppService.InteractiveAppServiceCommandType String cmdType,
Bundle parameters) {
if (DEBUG) {
Log.d(TAG, "onCommandRequest (cmdType=" + cmdType + ", parameters="
+ parameters.toString() + ")");
@@ -695,8 +750,16 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onCommandRequest - session not created");
return;
}
if (mCallback != null) {
mCallback.onCommandRequest(mIAppServiceId, cmdType, parameters);
synchronized (mCallbackLock) {
if (mCallbackExecutor != null) {
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
mCallback.onCommandRequest(mIAppServiceId, cmdType, parameters);
}
}
});
}
}
}
@@ -709,8 +772,16 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onSessionStateChanged - session not created");
return;
}
if (mCallback != null) {
mCallback.onSessionStateChanged(mIAppServiceId, state);
synchronized (mCallbackLock) {
if (mCallbackExecutor != null) {
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
mCallback.onSessionStateChanged(mIAppServiceId, state);
}
}
});
}
}
}
@@ -724,8 +795,17 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onBiInteractiveAppCreated - session not created");
return;
}
if (mCallback != null) {
mCallback.onBiInteractiveAppCreated(mIAppServiceId, biIAppUri, biIAppId);
synchronized (mCallbackLock) {
if (mCallbackExecutor != null) {
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
mCallback.onBiInteractiveAppCreated(
mIAppServiceId, biIAppUri, biIAppId);
}
}
});
}
}
}
@@ -738,8 +818,16 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onSetVideoBounds - session not created");
return;
}
if (mCallback != null) {
mCallback.onSetVideoBounds(mIAppServiceId, rect);
synchronized (mCallbackLock) {
if (mCallbackExecutor != null) {
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
mCallback.onSetVideoBounds(mIAppServiceId, rect);
}
}
});
}
}
}
@@ -752,8 +840,16 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onRequestCurrentChannelUri - session not created");
return;
}
if (mCallback != null) {
mCallback.onRequestCurrentChannelUri(mIAppServiceId);
synchronized (mCallbackLock) {
if (mCallbackExecutor != null) {
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
mCallback.onRequestCurrentChannelUri(mIAppServiceId);
}
}
});
}
}
}
@@ -766,8 +862,16 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onRequestCurrentChannelLcn - session not created");
return;
}
if (mCallback != null) {
mCallback.onRequestCurrentChannelLcn(mIAppServiceId);
synchronized (mCallbackLock) {
if (mCallbackExecutor != null) {
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
mCallback.onRequestCurrentChannelLcn(mIAppServiceId);
}
}
});
}
}
}
@@ -780,8 +884,16 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onRequestStreamVolume - session not created");
return;
}
if (mCallback != null) {
mCallback.onRequestStreamVolume(mIAppServiceId);
synchronized (mCallbackLock) {
if (mCallbackExecutor != null) {
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
mCallback.onRequestStreamVolume(mIAppServiceId);
}
}
});
}
}
}
@@ -794,8 +906,16 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onRequestTrackInfoList - session not created");
return;
}
if (mCallback != null) {
mCallback.onRequestTrackInfoList(mIAppServiceId);
synchronized (mCallbackLock) {
if (mCallbackExecutor != null) {
mCallbackExecutor.execute(() -> {
synchronized (mCallbackLock) {
if (mCallback != null) {
mCallback.onRequestTrackInfoList(mIAppServiceId);
}
}
});
}
}
}
}

View File

@@ -1851,18 +1851,19 @@ public final class TvInputManagerService extends SystemService {
}
@Override
public void setIAppNotificationEnabled(IBinder sessionToken, boolean enabled, int userId) {
public void setInteractiveAppNotificationEnabled(
IBinder sessionToken, boolean enabled, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "setIAppNotificationEnabled");
userId, "setInteractiveAppNotificationEnabled");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.setIAppNotificationEnabled(enabled);
.setInteractiveAppNotificationEnabled(enabled);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setIAppNotificationEnabled", e);
Slog.e(TAG, "error in setInteractiveAppNotificationEnabled", e);
}
}
} finally {

View File

@@ -34,15 +34,15 @@ import android.media.tv.AdResponse;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvTrackInfo;
import android.media.tv.interactive.ITvIAppClient;
import android.media.tv.interactive.ITvIAppManager;
import android.media.tv.interactive.ITvIAppManagerCallback;
import android.media.tv.interactive.ITvIAppService;
import android.media.tv.interactive.ITvIAppServiceCallback;
import android.media.tv.interactive.ITvIAppSession;
import android.media.tv.interactive.ITvIAppSessionCallback;
import android.media.tv.interactive.TvIAppInfo;
import android.media.tv.interactive.ITvInteractiveAppClient;
import android.media.tv.interactive.ITvInteractiveAppManagerCallback;
import android.media.tv.interactive.ITvInteractiveAppService;
import android.media.tv.interactive.ITvInteractiveAppServiceCallback;
import android.media.tv.interactive.ITvInteractiveAppSession;
import android.media.tv.interactive.ITvInteractiveAppSessionCallback;
import android.media.tv.interactive.TvIAppService;
import android.media.tv.interactive.TvInteractiveAppInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -112,54 +112,55 @@ public class TvIAppManagerService extends SystemService {
}
@GuardedBy("mLock")
private void buildTvIAppServiceListLocked(int userId, String[] updatedPackages) {
private void buildTvInteractiveAppServiceListLocked(int userId, String[] updatedPackages) {
UserState userState = getOrCreateUserStateLocked(userId);
userState.mPackageSet.clear();
if (DEBUG) {
Slogf.d(TAG, "buildTvIAppServiceListLocked");
Slogf.d(TAG, "buildTvInteractiveAppServiceListLocked");
}
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> services = pm.queryIntentServicesAsUser(
new Intent(TvIAppService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
List<TvIAppInfo> iAppList = new ArrayList<>();
List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
// TODO: add BIND_TV_IAPP permission and check it here
// TODO: add BIND_TV_INTERACTIVE_APP permission and check it here
ComponentName component = new ComponentName(si.packageName, si.name);
try {
TvIAppInfo info = new TvIAppInfo.Builder(mContext, component).build();
TvInteractiveAppInfo info =
new TvInteractiveAppInfo(mContext, component);
iAppList.add(info);
} catch (Exception e) {
Slogf.e(TAG, "failed to load TV IApp service " + si.name, e);
Slogf.e(TAG, "failed to load TV Interactive App service " + si.name, e);
continue;
}
userState.mPackageSet.add(si.packageName);
}
// sort the iApp list by iApp service id
Collections.sort(iAppList, Comparator.comparing(TvIAppInfo::getId));
Map<String, TvIAppState> iAppMap = new HashMap<>();
Collections.sort(iAppList, Comparator.comparing(TvInteractiveAppInfo::getId));
Map<String, TvInteractiveAppState> iAppMap = new HashMap<>();
ArrayMap<String, Integer> tiasAppCount = new ArrayMap<>(iAppMap.size());
for (TvIAppInfo info : iAppList) {
for (TvInteractiveAppInfo info : iAppList) {
String iAppServiceId = info.getId();
if (DEBUG) {
Slogf.d(TAG, "add " + iAppServiceId);
}
// Running count of IApp for each IApp service
// Running count of Interactive App for each Interactive App service
Integer count = tiasAppCount.get(iAppServiceId);
count = count == null ? 1 : count + 1;
tiasAppCount.put(iAppServiceId, count);
TvIAppState iAppState = userState.mIAppMap.get(iAppServiceId);
TvInteractiveAppState iAppState = userState.mIAppMap.get(iAppServiceId);
if (iAppState == null) {
iAppState = new TvIAppState();
iAppState = new TvInteractiveAppState();
}
iAppState.mInfo = info;
iAppState.mUid = getIAppUid(info);
iAppState.mUid = getInteractiveAppUid(info);
iAppState.mComponentName = info.getComponent();
iAppMap.put(iAppServiceId, iAppState);
iAppState.mIAppNumber = count;
@@ -167,14 +168,14 @@ public class TvIAppManagerService extends SystemService {
for (String iAppServiceId : iAppMap.keySet()) {
if (!userState.mIAppMap.containsKey(iAppServiceId)) {
notifyIAppServiceAddedLocked(userState, iAppServiceId);
notifyInteractiveAppServiceAddedLocked(userState, iAppServiceId);
} else if (updatedPackages != null) {
// Notify the package updates
ComponentName component = iAppMap.get(iAppServiceId).mInfo.getComponent();
for (String updatedPackage : updatedPackages) {
if (component.getPackageName().equals(updatedPackage)) {
updateServiceConnectionLocked(component, userId);
notifyIAppServiceUpdatedLocked(userState, iAppServiceId);
notifyInteractiveAppServiceUpdatedLocked(userState, iAppServiceId);
break;
}
}
@@ -183,12 +184,12 @@ public class TvIAppManagerService extends SystemService {
for (String iAppServiceId : userState.mIAppMap.keySet()) {
if (!iAppMap.containsKey(iAppServiceId)) {
TvIAppInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
TvInteractiveAppInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
ServiceState serviceState = userState.mServiceStateMap.get(info.getComponent());
if (serviceState != null) {
abortPendingCreateSessionRequestsLocked(serviceState, iAppServiceId, userId);
}
notifyIAppServiceRemovedLocked(userState, iAppServiceId);
notifyInteractiveAppServiceRemovedLocked(userState, iAppServiceId);
}
}
@@ -197,48 +198,56 @@ public class TvIAppManagerService extends SystemService {
}
@GuardedBy("mLock")
private void notifyIAppServiceAddedLocked(UserState userState, String iAppServiceId) {
private void notifyInteractiveAppServiceAddedLocked(UserState userState, String iAppServiceId) {
if (DEBUG) {
Slog.d(TAG, "notifyIAppServiceAddedLocked(iAppServiceId=" + iAppServiceId + ")");
Slog.d(TAG, "notifyInteractiveAppServiceAddedLocked(iAppServiceId="
+ iAppServiceId + ")");
}
int n = userState.mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
userState.mCallbacks.getBroadcastItem(i).onIAppServiceAdded(iAppServiceId);
userState.mCallbacks.getBroadcastItem(i)
.onInteractiveAppServiceAdded(iAppServiceId);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report added IApp service to callback", e);
Slog.e(TAG, "failed to report added Interactive App service to callback", e);
}
}
userState.mCallbacks.finishBroadcast();
}
@GuardedBy("mLock")
private void notifyIAppServiceRemovedLocked(UserState userState, String iAppServiceId) {
private void notifyInteractiveAppServiceRemovedLocked(
UserState userState, String iAppServiceId) {
if (DEBUG) {
Slog.d(TAG, "notifyIAppServiceRemovedLocked(iAppServiceId=" + iAppServiceId + ")");
Slog.d(TAG, "notifyInteractiveAppServiceRemovedLocked(iAppServiceId="
+ iAppServiceId + ")");
}
int n = userState.mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
userState.mCallbacks.getBroadcastItem(i).onIAppServiceRemoved(iAppServiceId);
userState.mCallbacks.getBroadcastItem(i)
.onInteractiveAppServiceRemoved(iAppServiceId);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report removed IApp service to callback", e);
Slog.e(TAG, "failed to report removed Interactive App service to callback", e);
}
}
userState.mCallbacks.finishBroadcast();
}
@GuardedBy("mLock")
private void notifyIAppServiceUpdatedLocked(UserState userState, String iAppServiceId) {
private void notifyInteractiveAppServiceUpdatedLocked(
UserState userState, String iAppServiceId) {
if (DEBUG) {
Slog.d(TAG, "notifyIAppServiceUpdatedLocked(iAppServiceId=" + iAppServiceId + ")");
Slog.d(TAG, "notifyInteractiveAppServiceUpdatedLocked(iAppServiceId="
+ iAppServiceId + ")");
}
int n = userState.mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
userState.mCallbacks.getBroadcastItem(i).onIAppServiceUpdated(iAppServiceId);
userState.mCallbacks.getBroadcastItem(i)
.onInteractiveAppServiceUpdated(iAppServiceId);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report updated IApp service to callback", e);
Slog.e(TAG, "failed to report updated Interactive App service to callback", e);
}
}
userState.mCallbacks.finishBroadcast();
@@ -262,7 +271,7 @@ public class TvIAppManagerService extends SystemService {
userState.mCallbacks.finishBroadcast();
}
private int getIAppUid(TvIAppInfo info) {
private int getInteractiveAppUid(TvInteractiveAppInfo info) {
try {
return getContext().getPackageManager().getApplicationInfo(
info.getServiceInfo().packageName, 0).uid;
@@ -286,18 +295,18 @@ public class TvIAppManagerService extends SystemService {
registerBroadcastReceivers();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
synchronized (mLock) {
buildTvIAppServiceListLocked(mCurrentUserId, null);
buildTvInteractiveAppServiceListLocked(mCurrentUserId, null);
}
}
}
private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
private void buildTvIAppServiceList(String[] packages) {
private void buildTvInteractiveAppServiceList(String[] packages) {
int userId = getChangingUserId();
synchronized (mLock) {
if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) {
buildTvIAppServiceListLocked(userId, packages);
buildTvInteractiveAppServiceListLocked(userId, packages);
}
}
}
@@ -305,9 +314,9 @@ public class TvIAppManagerService extends SystemService {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
if (DEBUG) Slogf.d(TAG, "onPackageUpdateFinished(packageName=" + packageName + ")");
// This callback is invoked when the TV iApp service is reinstalled.
// This callback is invoked when the TV interactive App service is reinstalled.
// In this case, isReplacing() always returns true.
buildTvIAppServiceList(new String[] { packageName });
buildTvInteractiveAppServiceList(new String[] { packageName });
}
@Override
@@ -318,7 +327,7 @@ public class TvIAppManagerService extends SystemService {
// This callback is invoked when the media on which some packages exist become
// available.
if (isReplacing()) {
buildTvIAppServiceList(packages);
buildTvInteractiveAppServiceList(packages);
}
}
@@ -331,7 +340,7 @@ public class TvIAppManagerService extends SystemService {
+ ")");
}
if (isReplacing()) {
buildTvIAppServiceList(packages);
buildTvInteractiveAppServiceList(packages);
}
}
@@ -339,17 +348,19 @@ public class TvIAppManagerService extends SystemService {
public void onSomePackagesChanged() {
if (DEBUG) Slogf.d(TAG, "onSomePackagesChanged()");
if (isReplacing()) {
if (DEBUG) Slogf.d(TAG, "Skipped building TV iApp list due to replacing");
// When the package is updated, buildTvIAppServiceListLocked is called in other
// methods instead.
if (DEBUG) {
Slogf.d(TAG, "Skipped building TV interactive App list due to replacing");
}
// When the package is updated, buildTvInteractiveAppServiceListLocked is called
// in other methods instead.
return;
}
buildTvIAppServiceList(null);
buildTvInteractiveAppServiceList(null);
}
@Override
public boolean onPackageChanged(String packageName, int uid, String[] components) {
// The iApp list needs to be updated in any cases, regardless of whether
// The interactive App list needs to be updated in any cases, regardless of whether
// it happened to the whole package or a specific component. Returning true so that
// the update can be handled in {@link #onSomePackagesChanged}.
return true;
@@ -401,7 +412,7 @@ public class TvIAppManagerService extends SystemService {
unbindServiceOfUserLocked(mCurrentUserId);
mCurrentUserId = userId;
buildTvIAppServiceListLocked(userId, null);
buildTvInteractiveAppServiceListLocked(userId, null);
}
}
@@ -486,7 +497,7 @@ public class TvIAppManagerService extends SystemService {
@GuardedBy("mLock")
private void startProfileLocked(int userId) {
mRunningProfiles.add(userId);
buildTvIAppServiceListLocked(userId, null);
buildTvInteractiveAppServiceListLocked(userId, null);
}
@GuardedBy("mLock")
@@ -601,13 +612,14 @@ public class TvIAppManagerService extends SystemService {
}
@GuardedBy("mLock")
private ITvIAppSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
private ITvInteractiveAppSession getSessionLocked(
IBinder sessionToken, int callingUid, int userId) {
return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
}
@GuardedBy("mLock")
private ITvIAppSession getSessionLocked(SessionState sessionState) {
ITvIAppSession session = sessionState.mSession;
private ITvInteractiveAppSession getSessionLocked(SessionState sessionState) {
ITvInteractiveAppSession session = sessionState.mSession;
if (session == null) {
throw new IllegalStateException("Session not yet created for token "
+ sessionState.mSessionToken);
@@ -618,15 +630,15 @@ public class TvIAppManagerService extends SystemService {
private final class BinderService extends ITvIAppManager.Stub {
@Override
public List<TvIAppInfo> getTvIAppServiceList(int userId) {
public List<TvInteractiveAppInfo> getTvInteractiveAppServiceList(int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "getTvIAppServiceList");
Binder.getCallingUid(), userId, "getTvInteractiveAppServiceList");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
List<TvIAppInfo> iAppList = new ArrayList<>();
for (TvIAppState state : userState.mIAppMap.values()) {
List<TvInteractiveAppInfo> iAppList = new ArrayList<>();
for (TvInteractiveAppState state : userState.mIAppMap.values()) {
iAppList.add(state.mInfo);
}
return iAppList;
@@ -645,7 +657,7 @@ public class TvIAppManagerService extends SystemService {
try {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
TvIAppState iAppState = userState.mIAppMap.get(tiasId);
TvInteractiveAppState iAppState = userState.mIAppMap.get(tiasId);
if (iAppState == null) {
Slogf.e(TAG, "failed to prepare TIAS - unknown TIAS id " + tiasId);
return;
@@ -680,7 +692,7 @@ public class TvIAppManagerService extends SystemService {
try {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
TvIAppState iAppState = userState.mIAppMap.get(tiasId);
TvInteractiveAppState iAppState = userState.mIAppMap.get(tiasId);
if (iAppState == null) {
Slogf.e(TAG, "failed to notifyAppLinkInfo - unknown TIAS id "
+ tiasId);
@@ -716,7 +728,7 @@ public class TvIAppManagerService extends SystemService {
try {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
TvIAppState iAppState = userState.mIAppMap.get(tiasId);
TvInteractiveAppState iAppState = userState.mIAppMap.get(tiasId);
if (iAppState == null) {
Slogf.e(TAG, "failed to sendAppLinkCommand - unknown TIAS id "
+ tiasId);
@@ -743,7 +755,8 @@ public class TvIAppManagerService extends SystemService {
}
@Override
public void createSession(final ITvIAppClient client, final String iAppServiceId, int type,
public void createSession(
final ITvInteractiveAppClient client, final String iAppServiceId, int type,
int seq, int userId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -760,7 +773,7 @@ public class TvIAppManagerService extends SystemService {
return;
}
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
TvIAppState iAppState = userState.mIAppMap.get(iAppServiceId);
TvInteractiveAppState iAppState = userState.mIAppMap.get(iAppServiceId);
if (iAppState == null) {
Slogf.w(TAG, "Failed to find state for iAppServiceId=" + iAppServiceId);
sendSessionTokenToClientLocked(client, iAppServiceId, null, null, seq);
@@ -994,13 +1007,13 @@ public class TvIAppManagerService extends SystemService {
}
@Override
public void startIApp(IBinder sessionToken, int userId) {
public void startInteractiveApp(IBinder sessionToken, int userId) {
if (DEBUG) {
Slogf.d(TAG, "BinderService#start(userId=%d)", userId);
}
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "startIApp");
userId, "startInteractiveApp");
SessionState sessionState = null;
final long identity = Binder.clearCallingIdentity();
try {
@@ -1008,7 +1021,7 @@ public class TvIAppManagerService extends SystemService {
try {
sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
getSessionLocked(sessionState).startIApp();
getSessionLocked(sessionState).startInteractiveApp();
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in start", e);
}
@@ -1019,13 +1032,13 @@ public class TvIAppManagerService extends SystemService {
}
@Override
public void stopIApp(IBinder sessionToken, int userId) {
public void stopInteractiveApp(IBinder sessionToken, int userId) {
if (DEBUG) {
Slogf.d(TAG, "BinderService#stop(userId=%d)", userId);
}
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "stopIApp");
userId, "stopInteractiveApp");
SessionState sessionState = null;
final long identity = Binder.clearCallingIdentity();
try {
@@ -1033,7 +1046,7 @@ public class TvIAppManagerService extends SystemService {
try {
sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
getSessionLocked(sessionState).stopIApp();
getSessionLocked(sessionState).stopInteractiveApp();
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in stop", e);
}
@@ -1290,7 +1303,7 @@ public class TvIAppManagerService extends SystemService {
}
@Override
public void registerCallback(final ITvIAppManagerCallback callback, int userId) {
public void registerCallback(final ITvInteractiveAppManagerCallback callback, int userId) {
int callingPid = Binder.getCallingPid();
int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
@@ -1309,7 +1322,7 @@ public class TvIAppManagerService extends SystemService {
}
@Override
public void unregisterCallback(ITvIAppManagerCallback callback, int userId) {
public void unregisterCallback(ITvInteractiveAppManagerCallback callback, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "unregisterCallback");
final long identity = Binder.clearCallingIdentity();
@@ -1335,7 +1348,7 @@ public class TvIAppManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.createMediaView(windowToken, frame);
} catch (RemoteException | TvIAppManagerService.SessionNotFoundException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in createMediaView", e);
}
}
@@ -1355,7 +1368,7 @@ public class TvIAppManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.relayoutMediaView(frame);
} catch (RemoteException | TvIAppManagerService.SessionNotFoundException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in relayoutMediaView", e);
}
}
@@ -1375,7 +1388,7 @@ public class TvIAppManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.removeMediaView();
} catch (RemoteException | TvIAppManagerService.SessionNotFoundException e) {
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in removeMediaView", e);
}
}
@@ -1386,8 +1399,9 @@ public class TvIAppManagerService extends SystemService {
}
@GuardedBy("mLock")
private void sendSessionTokenToClientLocked(ITvIAppClient client, String iAppServiceId,
IBinder sessionToken, InputChannel channel, int seq) {
private void sendSessionTokenToClientLocked(
ITvInteractiveAppClient client, String iAppServiceId, IBinder sessionToken,
InputChannel channel, int seq) {
try {
client.onSessionCreated(iAppServiceId, sessionToken, channel, seq);
} catch (RemoteException e) {
@@ -1396,8 +1410,8 @@ public class TvIAppManagerService extends SystemService {
}
@GuardedBy("mLock")
private boolean createSessionInternalLocked(ITvIAppService service, IBinder sessionToken,
int userId) {
private boolean createSessionInternalLocked(
ITvInteractiveAppService service, IBinder sessionToken, int userId) {
UserState userState = getOrCreateUserStateLocked(userId);
SessionState sessionState = userState.mSessionStateMap.get(sessionToken);
if (DEBUG) {
@@ -1407,7 +1421,7 @@ public class TvIAppManagerService extends SystemService {
InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
// Set up a callback to send the session token.
ITvIAppSessionCallback callback = new SessionCallback(sessionState, channels);
ITvInteractiveAppSessionCallback callback = new SessionCallback(sessionState, channels);
boolean created = true;
// Create a session. When failed, send a null token immediately.
@@ -1528,7 +1542,8 @@ public class TvIAppManagerService extends SystemService {
Slogf.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")");
}
Intent i = new Intent(TvIAppService.SERVICE_INTERFACE).setComponent(component);
Intent i =
new Intent(TvIAppService.SERVICE_INTERFACE).setComponent(component);
serviceState.mBound = mContext.bindServiceAsUser(
i, serviceState.mConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
@@ -1546,20 +1561,20 @@ public class TvIAppManagerService extends SystemService {
private static final class UserState {
private final int mUserId;
// A mapping from the TV IApp ID to its TvIAppState.
private Map<String, TvIAppState> mIAppMap = new HashMap<>();
// A mapping from the TV Interactive App ID to its TvInteractiveAppState.
private Map<String, TvInteractiveAppState> mIAppMap = new HashMap<>();
// A mapping from the token of a client to its state.
private final Map<IBinder, ClientState> mClientStateMap = new HashMap<>();
// A mapping from the name of a TV IApp service to its state.
// A mapping from the name of a TV Interactive App service to its state.
private final Map<ComponentName, ServiceState> mServiceStateMap = new HashMap<>();
// A mapping from the token of a TV IApp session to its state.
// A mapping from the token of a TV Interactive App session to its state.
private final Map<IBinder, SessionState> mSessionStateMap = new HashMap<>();
// A set of all TV IApp service packages.
// A set of all TV Interactive App service packages.
private final Set<String> mPackageSet = new HashSet<>();
// A list of callbacks.
private final RemoteCallbackList<ITvIAppManagerCallback> mCallbacks =
private final RemoteCallbackList<ITvInteractiveAppManagerCallback> mCallbacks =
new RemoteCallbackList<>();
private UserState(int userId) {
@@ -1567,20 +1582,20 @@ public class TvIAppManagerService extends SystemService {
}
}
private static final class TvIAppState {
private static final class TvInteractiveAppState {
private String mIAppServiceId;
private ComponentName mComponentName;
private TvIAppInfo mInfo;
private TvInteractiveAppInfo mInfo;
private int mUid;
private int mIAppNumber;
}
private final class SessionState implements IBinder.DeathRecipient {
private final IBinder mSessionToken;
private ITvIAppSession mSession;
private ITvInteractiveAppSession mSession;
private final String mIAppServiceId;
private final int mType;
private final ITvIAppClient mClient;
private final ITvInteractiveAppClient mClient;
private final int mSeq;
private final ComponentName mComponent;
@@ -1595,8 +1610,8 @@ public class TvIAppManagerService extends SystemService {
private final int mUserId;
private SessionState(IBinder sessionToken, String iAppServiceId, int type,
ComponentName componentName, ITvIAppClient client, int seq, int callingUid,
int callingPid, int userId) {
ComponentName componentName, ITvInteractiveAppClient client, int seq,
int callingUid, int callingPid, int userId) {
mSessionToken = sessionToken;
mIAppServiceId = iAppServiceId;
mComponent = componentName;
@@ -1665,7 +1680,7 @@ public class TvIAppManagerService extends SystemService {
private boolean mPendingPrepare = false;
private Integer mPendingPrepareType = null;
private ITvIAppService mService;
private ITvInteractiveAppService mService;
private ServiceCallback mCallback;
private boolean mBound;
private boolean mReconnecting;
@@ -1679,7 +1694,7 @@ public class TvIAppManagerService extends SystemService {
mComponent = component;
mPendingPrepare = pendingPrepare;
mPendingPrepareType = prepareType;
mConnection = new IAppServiceConnection(component, userId);
mConnection = new InteractiveAppServiceConnection(component, userId);
mIAppServiceId = tias;
}
@@ -1692,11 +1707,11 @@ public class TvIAppManagerService extends SystemService {
}
}
private final class IAppServiceConnection implements ServiceConnection {
private final class InteractiveAppServiceConnection implements ServiceConnection {
private final ComponentName mComponent;
private final int mUserId;
private IAppServiceConnection(ComponentName component, int userId) {
private InteractiveAppServiceConnection(ComponentName component, int userId) {
mComponent = component;
mUserId = userId;
}
@@ -1714,7 +1729,7 @@ public class TvIAppManagerService extends SystemService {
return;
}
ServiceState serviceState = userState.mServiceStateMap.get(mComponent);
serviceState.mService = ITvIAppService.Stub.asInterface(service);
serviceState.mService = ITvInteractiveAppService.Stub.asInterface(service);
if (serviceState.mPendingPrepare) {
final long identity = Binder.clearCallingIdentity();
@@ -1803,7 +1818,7 @@ public class TvIAppManagerService extends SystemService {
}
}
private final class ServiceCallback extends ITvIAppServiceCallback.Stub {
private final class ServiceCallback extends ITvInteractiveAppServiceCallback.Stub {
private final ComponentName mComponent;
private final int mUserId;
@@ -1828,7 +1843,7 @@ public class TvIAppManagerService extends SystemService {
}
}
private final class SessionCallback extends ITvIAppSessionCallback.Stub {
private final class SessionCallback extends ITvInteractiveAppSessionCallback.Stub {
private final SessionState mSessionState;
private final InputChannel[] mInputChannels;
@@ -1838,7 +1853,7 @@ public class TvIAppManagerService extends SystemService {
}
@Override
public void onSessionCreated(ITvIAppSession session) {
public void onSessionCreated(ITvInteractiveAppSession session) {
if (DEBUG) {
Slogf.d(TAG, "onSessionCreated(iAppServiceId="
+ mSessionState.mIAppServiceId + ")");
@@ -1916,7 +1931,8 @@ public class TvIAppManagerService extends SystemService {
}
@Override
public void onCommandRequest(@TvIAppService.IAppServiceCommandType String cmdType,
public void onCommandRequest(
@TvIAppService.InteractiveAppServiceCommandType String cmdType,
Bundle parameters) {
synchronized (mLock) {
if (DEBUG) {
@@ -2073,7 +2089,7 @@ public class TvIAppManagerService extends SystemService {
}
@GuardedBy("mLock")
private boolean addSessionTokenToClientStateLocked(ITvIAppSession session) {
private boolean addSessionTokenToClientStateLocked(ITvInteractiveAppSession session) {
try {
session.asBinder().linkToDeath(mSessionState, 0);
} catch (RemoteException e) {