Merge "Add TvIAppManagerCallback"
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
package android.media.tv.interactive;
|
||||
|
||||
import android.media.tv.interactive.ITvIAppClient;
|
||||
import android.media.tv.interactive.ITvIAppManagerCallback;
|
||||
import android.media.tv.interactive.TvIAppInfo;
|
||||
import android.view.Surface;
|
||||
|
||||
/**
|
||||
@@ -24,6 +26,7 @@ import android.view.Surface;
|
||||
* @hide
|
||||
*/
|
||||
interface ITvIAppManager {
|
||||
List<TvIAppInfo> getTvIAppServiceList(int userId);
|
||||
void startIApp(in IBinder sessionToken, int userId);
|
||||
void createSession(
|
||||
in ITvIAppClient client, in String iAppServiceId, int type, int seq, int userId);
|
||||
@@ -31,4 +34,7 @@ interface ITvIAppManager {
|
||||
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
|
||||
void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
|
||||
int userId);
|
||||
|
||||
void registerCallback(in ITvIAppManagerCallback callback, int userId);
|
||||
void unregisterCallback(in ITvIAppManagerCallback callback, int userId);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.media.tv.interactive.TvIAppInfo;
|
||||
|
||||
/**
|
||||
* Interface to receive callbacks from ITvIAppManager 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);
|
||||
}
|
||||
19
media/java/android/media/tv/interactive/TvIAppInfo.aidl
Normal file
19
media/java/android/media/tv/interactive/TvIAppInfo.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
parcelable TvIAppInfo;
|
||||
@@ -89,6 +89,14 @@ public final class TvIAppInfo implements Parcelable {
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -30,6 +30,10 @@ import android.view.Surface;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Central system API to the overall TV interactive application framework (TIAF) architecture, which
|
||||
* arbitrates interaction between applications and interactive apps.
|
||||
@@ -46,10 +50,15 @@ public final class TvIAppManager {
|
||||
private final SparseArray<SessionCallbackRecord> mSessionCallbackRecordMap =
|
||||
new SparseArray<>();
|
||||
|
||||
// @GuardedBy("mLock")
|
||||
private final List<TvIAppCallbackRecord> mCallbackRecords = new LinkedList<>();
|
||||
|
||||
// A sequence number for the next session to be created. Should be protected by a lock
|
||||
// {@code mSessionCallbackRecordMap}.
|
||||
private int mNextSeq;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private final ITvIAppClient mClient;
|
||||
|
||||
/** @hide */
|
||||
@@ -103,6 +112,154 @@ public final class TvIAppManager {
|
||||
}
|
||||
}
|
||||
};
|
||||
ITvIAppManagerCallback managerCallback = new ITvIAppManagerCallback.Stub() {
|
||||
// TODO: handle IApp service state changes
|
||||
@Override
|
||||
public void onIAppServiceAdded(String iAppServiceId) {
|
||||
synchronized (mLock) {
|
||||
for (TvIAppCallbackRecord record : mCallbackRecords) {
|
||||
record.postIAppServiceAdded(iAppServiceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIAppServiceRemoved(String iAppServiceId) {
|
||||
synchronized (mLock) {
|
||||
for (TvIAppCallbackRecord record : mCallbackRecords) {
|
||||
record.postIAppServiceRemoved(iAppServiceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIAppServiceUpdated(String iAppServiceId) {
|
||||
synchronized (mLock) {
|
||||
for (TvIAppCallbackRecord record : mCallbackRecords) {
|
||||
record.postIAppServiceUpdated(iAppServiceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
|
||||
// TODO: add public API updateIAppInfo()
|
||||
synchronized (mLock) {
|
||||
for (TvIAppCallbackRecord record : mCallbackRecords) {
|
||||
record.postTvIAppInfoUpdated(iAppInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
try {
|
||||
if (mService != null) {
|
||||
mService.registerCallback(managerCallback, mUserId);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback used to monitor status of the TV IApp.
|
||||
* @hide
|
||||
*/
|
||||
public abstract static class TvIAppCallback {
|
||||
/**
|
||||
* This is called when a TV IApp 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.
|
||||
*
|
||||
* @param iAppServiceId The ID of the TV IApp service.
|
||||
*/
|
||||
public void onIAppServiceAdded(String iAppServiceId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when a TV IApp service is removed from the system.
|
||||
*
|
||||
* <p>Normally it happens when the user uninstalls the previously installed TV IApp service
|
||||
* package.
|
||||
*
|
||||
* @param iAppServiceId The ID of the TV IApp service.
|
||||
*/
|
||||
public void onIAppServiceRemoved(String iAppServiceId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when a TV IApp service is updated on the system.
|
||||
*
|
||||
* <p>Normally it happens when a previously installed TV IApp 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.
|
||||
*/
|
||||
public void onIAppServiceUpdated(String iAppServiceId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the information about an existing TV IApp 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
|
||||
* <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.
|
||||
*/
|
||||
public void onTvIAppInfoUpdated(TvIAppInfo iAppInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TvIAppCallbackRecord {
|
||||
private final TvIAppCallback mCallback;
|
||||
private final Handler mHandler;
|
||||
|
||||
TvIAppCallbackRecord(TvIAppCallback callback, Handler handler) {
|
||||
mCallback = callback;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
public TvIAppCallback getCallback() {
|
||||
return mCallback;
|
||||
}
|
||||
|
||||
public void postIAppServiceAdded(final String iAppServiceId) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.onIAppServiceAdded(iAppServiceId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void postIAppServiceRemoved(final String iAppServiceId) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.onIAppServiceRemoved(iAppServiceId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void postIAppServiceUpdated(final String iAppServiceId) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.onIAppServiceUpdated(iAppServiceId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void postTvIAppInfoUpdated(final TvIAppInfo iAppInfo) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mCallback.onTvIAppInfoUpdated(iAppInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,6 +296,56 @@ public final class TvIAppManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete list of TV IApp service on the system.
|
||||
*
|
||||
* @return List of {@link TvIAppInfo} for each TV IApp service that describes its meta
|
||||
* information.
|
||||
* @hide
|
||||
*/
|
||||
public List<TvIAppInfo> getTvIAppServiceList() {
|
||||
try {
|
||||
return mService.getTvIAppServiceList(mUserId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a {@link TvIAppManager.TvIAppCallback}.
|
||||
*
|
||||
* @param callback A callback used to monitor status of the TV IApp services.
|
||||
* @param handler A {@link Handler} that the status change will be delivered to.
|
||||
* @hide
|
||||
*/
|
||||
public void registerCallback(@NonNull TvIAppCallback callback, @NonNull Handler handler) {
|
||||
Preconditions.checkNotNull(callback);
|
||||
Preconditions.checkNotNull(handler);
|
||||
synchronized (mLock) {
|
||||
mCallbackRecords.add(new TvIAppCallbackRecord(callback, handler));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the existing {@link TvIAppManager.TvIAppCallback}.
|
||||
*
|
||||
* @param callback The existing callback to remove.
|
||||
* @hide
|
||||
*/
|
||||
public void unregisterCallback(@NonNull final TvIAppCallback callback) {
|
||||
Preconditions.checkNotNull(callback);
|
||||
synchronized (mLock) {
|
||||
for (Iterator<TvIAppCallbackRecord> it = mCallbackRecords.iterator();
|
||||
it.hasNext(); ) {
|
||||
TvIAppCallbackRecord record = it.next();
|
||||
if (record.getCallback() == callback) {
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Session provides the per-session functionality of interactive app.
|
||||
* @hide
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
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;
|
||||
@@ -38,9 +39,11 @@ import android.media.tv.interactive.TvIAppService;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Surface;
|
||||
|
||||
@@ -145,12 +148,85 @@ public class TvIAppManagerService extends SystemService {
|
||||
iAppState.mIAppNumber = count;
|
||||
}
|
||||
|
||||
// TODO: notify iApp added / removed
|
||||
for (String iAppServiceId : iAppMap.keySet()) {
|
||||
if (!userState.mIAppMap.containsKey(iAppServiceId)) {
|
||||
notifyIAppServiceAddedLocked(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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String iAppServiceId : userState.mIAppMap.keySet()) {
|
||||
if (!iAppMap.containsKey(iAppServiceId)) {
|
||||
TvIAppInfo info = userState.mIAppMap.get(iAppServiceId).mInfo;
|
||||
ServiceState serviceState = userState.mServiceStateMap.get(info.getComponent());
|
||||
if (serviceState != null) {
|
||||
abortPendingCreateSessionRequestsLocked(serviceState, iAppServiceId, userId);
|
||||
}
|
||||
notifyIAppServiceRemovedLocked(userState, iAppServiceId);
|
||||
}
|
||||
}
|
||||
|
||||
userState.mIAppMap.clear();
|
||||
userState.mIAppMap = iAppMap;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void notifyIAppServiceAddedLocked(UserState userState, String iAppServiceId) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "notifyIAppServiceAddedLocked(iAppServiceId=" + iAppServiceId + ")");
|
||||
}
|
||||
int n = userState.mCallbacks.beginBroadcast();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
try {
|
||||
userState.mCallbacks.getBroadcastItem(i).onIAppServiceAdded(iAppServiceId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "failed to report added IApp service to callback", e);
|
||||
}
|
||||
}
|
||||
userState.mCallbacks.finishBroadcast();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void notifyIAppServiceRemovedLocked(UserState userState, String iAppServiceId) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "notifyIAppServiceRemovedLocked(iAppServiceId=" + iAppServiceId + ")");
|
||||
}
|
||||
int n = userState.mCallbacks.beginBroadcast();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
try {
|
||||
userState.mCallbacks.getBroadcastItem(i).onIAppServiceRemoved(iAppServiceId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "failed to report removed IApp service to callback", e);
|
||||
}
|
||||
}
|
||||
userState.mCallbacks.finishBroadcast();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void notifyIAppServiceUpdatedLocked(UserState userState, String iAppServiceId) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "notifyIAppServiceUpdatedLocked(iAppServiceId=" + iAppServiceId + ")");
|
||||
}
|
||||
int n = userState.mCallbacks.beginBroadcast();
|
||||
for (int i = 0; i < n; ++i) {
|
||||
try {
|
||||
userState.mCallbacks.getBroadcastItem(i).onIAppServiceUpdated(iAppServiceId);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "failed to report updated IApp service to callback", e);
|
||||
}
|
||||
}
|
||||
userState.mCallbacks.finishBroadcast();
|
||||
}
|
||||
|
||||
private int getIAppUid(TvIAppInfo info) {
|
||||
try {
|
||||
return getContext().getPackageManager().getApplicationInfo(
|
||||
@@ -318,6 +394,25 @@ public class TvIAppManagerService extends SystemService {
|
||||
|
||||
private final class BinderService extends ITvIAppManager.Stub {
|
||||
|
||||
@Override
|
||||
public List<TvIAppInfo> getTvIAppServiceList(int userId) {
|
||||
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
|
||||
Binder.getCallingUid(), userId, "getTvIAppServiceList");
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
|
||||
List<TvIAppInfo> iAppList = new ArrayList<>();
|
||||
for (TvIAppState state : userState.mIAppMap.values()) {
|
||||
iAppList.add(state.mInfo);
|
||||
}
|
||||
return iAppList;
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSession(final ITvIAppClient client, final String iAppServiceId, int type,
|
||||
int seq, int userId) {
|
||||
@@ -463,6 +558,40 @@ public class TvIAppManagerService extends SystemService {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCallback(final ITvIAppManagerCallback callback, int userId) {
|
||||
int callingPid = Binder.getCallingPid();
|
||||
int callingUid = Binder.getCallingUid();
|
||||
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId,
|
||||
"registerCallback");
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
|
||||
if (!userState.mCallbacks.register(callback)) {
|
||||
Slog.e(TAG, "client process has already died");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterCallback(ITvIAppManagerCallback callback, int userId) {
|
||||
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
|
||||
Binder.getCallingUid(), userId, "unregisterCallback");
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
|
||||
userState.mCallbacks.unregister(callback);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
@@ -634,6 +763,10 @@ public class TvIAppManagerService extends SystemService {
|
||||
// A set of all TV IApp service packages.
|
||||
private final Set<String> mPackageSet = new HashSet<>();
|
||||
|
||||
// A list of callbacks.
|
||||
private final RemoteCallbackList<ITvIAppManagerCallback> mCallbacks =
|
||||
new RemoteCallbackList<>();
|
||||
|
||||
private UserState(int userId) {
|
||||
mUserId = userId;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user