diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl index 1cfb6efbd1721..599922c2bafb8 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppManager.aidl @@ -37,6 +37,7 @@ import android.view.Surface; */ interface ITvInteractiveAppManager { List getTvInteractiveAppServiceList(int userId); + List getAppLinkInfoList(int userId); void registerAppLinkInfo(String tiasId, in AppLinkInfo info, int userId); void unregisterAppLinkInfo(String tiasId, in AppLinkInfo info, int userId); void sendAppLinkCommand(String tiasId, in Bundle command, int userId); diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java index 3647a9ccd5ccd..7c91844519dbf 100755 --- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java @@ -864,6 +864,24 @@ public final class TvInteractiveAppManager { } } + /** + * Returns a list of available app link information. + * + *

A package must declare its app link info in its manifest using meta-data tag, so the info + * can be detected by the system. + * + * @return List of {@link AppLinkInfo} for each package that deslares its app link information. + * @hide + */ + @NonNull + public List getAppLinkInfoList() { + try { + return mService.getAppLinkInfoList(mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Registers an Android application link info record which can be used to launch the specific * Android application by TV interactive App RTE. diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java index 3e0885214dcd9..acc2444e12138 100644 --- a/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppServiceInfo.java @@ -57,6 +57,8 @@ public final class TvInteractiveAppServiceInfo implements Parcelable { INTERACTIVE_APP_TYPE_HBBTV, INTERACTIVE_APP_TYPE_ATSC, INTERACTIVE_APP_TYPE_GINGA, + INTERACTIVE_APP_TYPE_TARGETED_AD, + INTERACTIVE_APP_TYPE_OTHER }) public @interface InteractiveAppType {} @@ -66,10 +68,21 @@ public final class TvInteractiveAppServiceInfo implements Parcelable { public static final int INTERACTIVE_APP_TYPE_ATSC = 0x2; /** Ginga interactive app type */ public static final int INTERACTIVE_APP_TYPE_GINGA = 0x4; + /** + * Targeted Advertisement interactive app type + * @hide + */ + public static final int INTERACTIVE_APP_TYPE_TARGETED_AD = 0x8; + /** + * Other interactive app type + * @hide + */ + public static final int INTERACTIVE_APP_TYPE_OTHER = 0x80000000; private final ResolveInfo mService; private final String mId; private int mTypes; + private final List mExtraTypes = new ArrayList<>(); /** * Constructs a TvInteractiveAppServiceInfo object. @@ -98,18 +111,21 @@ public final class TvInteractiveAppServiceInfo implements Parcelable { mService = resolveInfo; mId = id; - mTypes = toTypesFlag(types); + toTypesFlag(types); } - private TvInteractiveAppServiceInfo(ResolveInfo service, String id, int types) { + private TvInteractiveAppServiceInfo( + ResolveInfo service, String id, int types, List extraTypes) { mService = service; mId = id; mTypes = types; + mExtraTypes.addAll(extraTypes); } private TvInteractiveAppServiceInfo(@NonNull Parcel in) { mService = ResolveInfo.CREATOR.createFromParcel(in); mId = in.readString(); mTypes = in.readInt(); + in.readStringList(mExtraTypes); } public static final @NonNull Creator CREATOR = @@ -135,6 +151,7 @@ public final class TvInteractiveAppServiceInfo implements Parcelable { mService.writeToParcel(dest, flags); dest.writeString(mId); dest.writeInt(mTypes); + dest.writeStringList(mExtraTypes); } /** @@ -171,6 +188,17 @@ public final class TvInteractiveAppServiceInfo implements Parcelable { return mTypes; } + /** + * Gets extra supported interactive app types which are not listed. + * + * @see #getSupportedTypes() + * @hide + */ + @NonNull + public List getExtraSupportedTypes() { + return mExtraTypes; + } + private static String generateInteractiveAppServiceId(ComponentName name) { return name.flattenToShortString(); } @@ -219,23 +247,27 @@ public final class TvInteractiveAppServiceInfo implements Parcelable { } } - private static int toTypesFlag(List types) { - int flag = 0; + private void toTypesFlag(List types) { + mTypes = 0; + mExtraTypes.clear(); for (String type : types) { switch (type) { case "hbbtv": - flag |= INTERACTIVE_APP_TYPE_HBBTV; + mTypes |= INTERACTIVE_APP_TYPE_HBBTV; break; case "atsc": - flag |= INTERACTIVE_APP_TYPE_ATSC; + mTypes |= INTERACTIVE_APP_TYPE_ATSC; break; case "ginga": - flag |= INTERACTIVE_APP_TYPE_GINGA; + mTypes |= INTERACTIVE_APP_TYPE_GINGA; break; + case "targeted_ad": + mTypes |= INTERACTIVE_APP_TYPE_TARGETED_AD; default: + mTypes |= INTERACTIVE_APP_TYPE_OTHER; + mExtraTypes.add(type); break; } } - return flag; } } diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java index 6dc4b731ac777..50b7fd21cf843 100644 --- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java +++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java @@ -24,6 +24,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -86,6 +87,11 @@ import java.util.Set; public class TvInteractiveAppManagerService extends SystemService { private static final boolean DEBUG = false; private static final String TAG = "TvInteractiveAppManagerService"; + + private static final String METADATA_CLASS_NAME = + "android.media.tv.interactive.AppLinkInfo.ClassName"; + private static final String METADATA_URI = + "android.media.tv.interactive.AppLinkInfo.Uri"; // A global lock. private final Object mLock = new Object(); private final Context mContext; @@ -102,6 +108,8 @@ public class TvInteractiveAppManagerService extends SystemService { // TODO: remove mGetServiceListCalled if onBootPhrase work correctly @GuardedBy("mLock") private boolean mGetServiceListCalled = false; + @GuardedBy("mLock") + private boolean mGetAppLinkInfoListCalled = false; private final UserManager mUserManager; @@ -120,6 +128,41 @@ public class TvInteractiveAppManagerService extends SystemService { mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE); } + @GuardedBy("mLock") + private void buildAppLinkInfoLocked(int userId) { + UserState userState = getOrCreateUserStateLocked(userId); + if (DEBUG) { + Slogf.d(TAG, "buildAppLinkInfoLocked"); + } + PackageManager pm = mContext.getPackageManager(); + List appInfos = pm.getInstalledApplicationsAsUser( + PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA), userId); + List appLinkInfos = new ArrayList<>(); + for (ApplicationInfo appInfo : appInfos) { + AppLinkInfo info = buildAppLinkInfoLocked(appInfo); + if (info != null) { + appLinkInfos.add(info); + } + } + // sort the list by package name + Collections.sort(appLinkInfos, Comparator.comparing(AppLinkInfo::getComponentName)); + userState.mAppLinkInfoList.clear(); + userState.mAppLinkInfoList.addAll(appLinkInfos); + } + + @GuardedBy("mLock") + private AppLinkInfo buildAppLinkInfoLocked(ApplicationInfo appInfo) { + if (appInfo.metaData == null || appInfo.packageName == null) { + return null; + } + String className = appInfo.metaData.getString(METADATA_CLASS_NAME, null); + String uri = appInfo.metaData.getString(METADATA_URI, null); + if (className == null || uri == null) { + return null; + } + return new AppLinkInfo(appInfo.packageName, className, uri); + } + @GuardedBy("mLock") private void buildTvInteractiveAppServiceListLocked(int userId, String[] updatedPackages) { UserState userState = getOrCreateUserStateLocked(userId); @@ -311,6 +354,7 @@ public class TvInteractiveAppManagerService extends SystemService { } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { synchronized (mLock) { buildTvInteractiveAppServiceListLocked(mCurrentUserId, null); + buildAppLinkInfoLocked(mCurrentUserId); } } } @@ -322,6 +366,7 @@ public class TvInteractiveAppManagerService extends SystemService { synchronized (mLock) { if (mCurrentUserId == userId || mRunningProfiles.contains(userId)) { buildTvInteractiveAppServiceListLocked(userId, packages); + buildAppLinkInfoLocked(userId); } } } @@ -428,6 +473,7 @@ public class TvInteractiveAppManagerService extends SystemService { mCurrentUserId = userId; buildTvInteractiveAppServiceListLocked(userId, null); + buildAppLinkInfoLocked(userId); } } @@ -513,6 +559,7 @@ public class TvInteractiveAppManagerService extends SystemService { private void startProfileLocked(int userId) { mRunningProfiles.add(userId); buildTvInteractiveAppServiceListLocked(userId, null); + buildAppLinkInfoLocked(userId); } @GuardedBy("mLock") @@ -667,6 +714,26 @@ public class TvInteractiveAppManagerService extends SystemService { } } + @Override + public List getAppLinkInfoList(int userId) { + final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), + Binder.getCallingUid(), userId, "getAppLinkInfoList"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + if (!mGetAppLinkInfoListCalled) { + buildAppLinkInfoLocked(userId); + mGetAppLinkInfoListCalled = true; + } + UserState userState = getOrCreateUserStateLocked(resolvedUserId); + List appLinkInfos = new ArrayList<>(userState.mAppLinkInfoList); + return appLinkInfos; + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public void registerAppLinkInfo(String tiasId, AppLinkInfo appLinkInfo, int userId) { final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), @@ -1996,6 +2063,8 @@ public class TvInteractiveAppManagerService extends SystemService { // A set of all TV Interactive App service packages. private final Set mPackageSet = new HashSet<>(); + // A list of all app link infos. + private final List mAppLinkInfoList = new ArrayList<>(); // A list of callbacks. private final RemoteCallbackList mCallbacks =