summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/tv/interactive/ITvIAppManager.aidl6
-rw-r--r--media/java/android/media/tv/interactive/ITvIAppSession.aidl5
-rw-r--r--media/java/android/media/tv/interactive/TvIAppManager.java63
-rw-r--r--media/java/android/media/tv/interactive/TvIAppService.java230
-rw-r--r--media/java/android/media/tv/interactive/TvIAppView.java73
-rw-r--r--services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java67
6 files changed, 442 insertions, 2 deletions
diff --git a/media/java/android/media/tv/interactive/ITvIAppManager.aidl b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
index 25e1acea226d..2027626893c0 100644
--- a/media/java/android/media/tv/interactive/ITvIAppManager.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppManager.aidl
@@ -16,6 +16,7 @@
package android.media.tv.interactive;
+import android.graphics.Rect;
import android.media.tv.interactive.ITvIAppClient;
import android.media.tv.interactive.ITvIAppManagerCallback;
import android.media.tv.interactive.TvIAppInfo;
@@ -38,6 +39,11 @@ interface ITvIAppManager {
void notifyBroadcastInfoResponse(in IBinder sessionToken, in BroadcastInfoResponse response,
int UserId);
+ void createMediaView(in IBinder sessionToken, in IBinder windowToken, in Rect frame,
+ int userId);
+ 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);
} \ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/ITvIAppSession.aidl b/media/java/android/media/tv/interactive/ITvIAppSession.aidl
index 440b3d30c068..ef35c68beb6f 100644
--- a/media/java/android/media/tv/interactive/ITvIAppSession.aidl
+++ b/media/java/android/media/tv/interactive/ITvIAppSession.aidl
@@ -16,6 +16,7 @@
package android.media.tv.interactive;
+import android.graphics.Rect;
import android.view.Surface;
import android.media.tv.BroadcastInfoResponse;
@@ -29,4 +30,8 @@ oneway interface ITvIAppSession {
void setSurface(in Surface surface);
void dispatchSurfaceChanged(int format, int width, int height);
void notifyBroadcastInfoResponse(in BroadcastInfoResponse response);
+
+ void createMediaView(in IBinder windowToken, in Rect frame);
+ void relayoutMediaView(in Rect frame);
+ void removeMediaView();
} \ No newline at end of file
diff --git a/media/java/android/media/tv/interactive/TvIAppManager.java b/media/java/android/media/tv/interactive/TvIAppManager.java
index ae35edc7ef8a..5c7f0b9fe8a2 100644
--- a/media/java/android/media/tv/interactive/TvIAppManager.java
+++ b/media/java/android/media/tv/interactive/TvIAppManager.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemService;
import android.content.Context;
+import android.graphics.Rect;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvInputManager;
@@ -35,6 +36,7 @@ import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventSender;
import android.view.Surface;
+import android.view.View;
import com.android.internal.util.Preconditions;
@@ -443,6 +445,67 @@ public final class TvIAppManager {
}
/**
+ * Creates a media view. Once the media view is created, {@link #relayoutMediaView}
+ * should be called whenever the layout of its containing view is changed.
+ * {@link #removeMediaView()} should be called to remove the media view.
+ * Since a session can have only one media view, this method should be called only once
+ * or it can be called again after calling {@link #removeMediaView()}.
+ *
+ * @param view A view for interactive app.
+ * @param frame A position of the media view.
+ * @throws IllegalStateException if {@code view} is not attached to a window.
+ */
+ void createMediaView(@NonNull View view, @NonNull Rect frame) {
+ Preconditions.checkNotNull(view);
+ Preconditions.checkNotNull(frame);
+ if (view.getWindowToken() == null) {
+ throw new IllegalStateException("view must be attached to a window");
+ }
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.createMediaView(mToken, view.getWindowToken(), frame, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Relayouts the current media view.
+ *
+ * @param frame A new position of the media view.
+ */
+ void relayoutMediaView(@NonNull Rect frame) {
+ Preconditions.checkNotNull(frame);
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.relayoutMediaView(mToken, frame, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes the current media view.
+ */
+ void removeMediaView() {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.removeMediaView(mToken, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Notifies of any structural changes (format or size) of the surface passed in
* {@link #setSurface}.
*
diff --git a/media/java/android/media/tv/interactive/TvIAppService.java b/media/java/android/media/tv/interactive/TvIAppService.java
index fe087ca564d0..7b30f6e0d0af 100644
--- a/media/java/android/media/tv/interactive/TvIAppService.java
+++ b/media/java/android/media/tv/interactive/TvIAppService.java
@@ -20,18 +20,24 @@ import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.app.ActivityManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
+import android.view.Gravity;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -39,6 +45,9 @@ import android.view.InputEventReceiver;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
import com.android.internal.os.SomeArgs;
@@ -52,6 +61,8 @@ public abstract class TvIAppService extends Service {
private static final boolean DEBUG = false;
private static final String TAG = "TvIAppService";
+ private static final int DETACH_MEDIA_VIEW_TIMEOUT_MS = 5000;
+
// TODO: cleanup and unhide APIs.
/**
@@ -141,8 +152,16 @@ public abstract class TvIAppService extends Service {
private final List<Runnable> mPendingActions = new ArrayList<>();
private final Context mContext;
- private final Handler mHandler;
+ final Handler mHandler;
+ private final WindowManager mWindowManager;
+ private WindowManager.LayoutParams mWindowParams;
private Surface mSurface;
+ private FrameLayout mMediaViewContainer;
+ private View mMediaView;
+ private MediaViewCleanUpTask mMediaViewCleanUpTask;
+ private boolean mMediaViewEnabled;
+ private IBinder mWindowToken;
+ private Rect mMediaFrame;
/**
* Creates a new Session.
@@ -151,10 +170,41 @@ public abstract class TvIAppService extends Service {
*/
public Session(Context context) {
mContext = context;
+ mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mHandler = new Handler(context.getMainLooper());
}
/**
+ * Enables or disables the media view.
+ *
+ * <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.
+ *
+ * @param enable {@code true} if you want to enable the media view. {@code false}
+ * otherwise.
+ */
+ public void setMediaViewEnabled(final boolean enable) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (enable == mMediaViewEnabled) {
+ return;
+ }
+ mMediaViewEnabled = enable;
+ if (enable) {
+ if (mWindowToken != null) {
+ createMediaView(mWindowToken, mMediaFrame);
+ }
+ } else {
+ removeMediaView(false);
+ }
+ }
+ });
+ }
+
+ /**
* Starts TvIAppService session.
* @hide
*/
@@ -195,6 +245,30 @@ public abstract class TvIAppService extends Service {
}
/**
+ * Called when the size of the media view is changed by the application.
+ *
+ * <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}.
+ *
+ * @param width The width of the media view.
+ * @param height The height of the media view.
+ */
+ public void onMediaViewSizeChanged(int width, int height) {
+ }
+
+ /**
+ * Called when the application requests to create an media view. Each session
+ * implementation can override this method and return its own view.
+ *
+ * @return a view attached to the media window
+ */
+ public View onCreateMediaView() {
+ return null;
+ }
+
+ /**
* Releases TvIAppService session.
* @hide
*/
@@ -318,6 +392,13 @@ public abstract class TvIAppService extends Service {
mSurface.release();
mSurface = null;
}
+ synchronized (mLock) {
+ mSessionCallback = null;
+ mPendingActions.clear();
+ }
+ // Removes the media view lastly so that any hanging on the main thread can be handled
+ // in {@link #scheduleMediaViewCleanup}.
+ removeMediaView(true);
}
/**
@@ -413,6 +494,137 @@ public abstract class TvIAppService extends Service {
}
}
}
+
+ /**
+ * Creates an media view. This calls {@link #onCreateMediaView} to get a view to attach
+ * to the media window.
+ *
+ * @param windowToken A window token of the application.
+ * @param frame A position of the media view.
+ */
+ void createMediaView(IBinder windowToken, Rect frame) {
+ if (mMediaViewContainer != null) {
+ removeMediaView(false);
+ }
+ if (DEBUG) Log.d(TAG, "create media view(" + frame + ")");
+ mWindowToken = windowToken;
+ mMediaFrame = frame;
+ onMediaViewSizeChanged(frame.right - frame.left, frame.bottom - frame.top);
+ if (!mMediaViewEnabled) {
+ return;
+ }
+ mMediaView = onCreateMediaView();
+ if (mMediaView == null) {
+ return;
+ }
+ if (mMediaViewCleanUpTask != null) {
+ mMediaViewCleanUpTask.cancel(true);
+ mMediaViewCleanUpTask = null;
+ }
+ // Creates a container view to check hanging on the media view detaching.
+ // Adding/removing the media view to/from the container make the view attach/detach
+ // logic run on the main thread.
+ mMediaViewContainer = new FrameLayout(mContext.getApplicationContext());
+ mMediaViewContainer.addView(mMediaView);
+
+ int type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ // We make the overlay view non-focusable and non-touchable so that
+ // the application that owns the window token can decide whether to consume or
+ // dispatch the input events.
+ int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+ if (ActivityManager.isHighEndGfx()) {
+ flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ }
+ mWindowParams = new WindowManager.LayoutParams(
+ frame.right - frame.left, frame.bottom - frame.top,
+ frame.left, frame.top, type, flags, PixelFormat.TRANSPARENT);
+ mWindowParams.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ mWindowParams.gravity = Gravity.START | Gravity.TOP;
+ mWindowParams.token = windowToken;
+ mWindowManager.addView(mMediaViewContainer, mWindowParams);
+ }
+
+ /**
+ * Relayouts the current media view.
+ *
+ * @param frame A new position of the media view.
+ */
+ void relayoutMediaView(Rect frame) {
+ 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.
+ onMediaViewSizeChanged(frame.right - frame.left, frame.bottom - frame.top);
+ }
+ mMediaFrame = frame;
+ if (!mMediaViewEnabled || mMediaViewContainer == null) {
+ return;
+ }
+ mWindowParams.x = frame.left;
+ mWindowParams.y = frame.top;
+ mWindowParams.width = frame.right - frame.left;
+ mWindowParams.height = frame.bottom - frame.top;
+ mWindowManager.updateViewLayout(mMediaViewContainer, mWindowParams);
+ }
+
+ /**
+ * Removes the current media view.
+ */
+ void removeMediaView(boolean clearWindowToken) {
+ if (DEBUG) Log.d(TAG, "removeMediaView(" + mMediaViewContainer + ")");
+ if (clearWindowToken) {
+ mWindowToken = null;
+ mMediaFrame = null;
+ }
+ if (mMediaViewContainer != null) {
+ // Removes the media view from the view hierarchy in advance so that it can be
+ // cleaned up in the {@link MediaViewCleanUpTask} if the remove process is
+ // hanging.
+ mMediaViewContainer.removeView(mMediaView);
+ mMediaView = null;
+ mWindowManager.removeView(mMediaViewContainer);
+ mMediaViewContainer = null;
+ mWindowParams = null;
+ }
+ }
+
+ /**
+ * Schedules a task which checks whether the media view is detached and kills the process
+ * if it is not. Note that this method is expected to be called in a non-main thread.
+ */
+ void scheduleMediaViewCleanup() {
+ View mediaViewParent = mMediaViewContainer;
+ if (mediaViewParent != null) {
+ mMediaViewCleanUpTask = new MediaViewCleanUpTask();
+ mMediaViewCleanUpTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
+ mediaViewParent);
+ }
+ }
+ }
+
+ private static final class MediaViewCleanUpTask extends AsyncTask<View, Void, Void> {
+ @Override
+ protected Void doInBackground(View... views) {
+ View mediaViewParent = views[0];
+ try {
+ Thread.sleep(DETACH_MEDIA_VIEW_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ return null;
+ }
+ if (isCancelled()) {
+ return null;
+ }
+ if (mediaViewParent.isAttachedToWindow()) {
+ Log.e(TAG, "Time out on releasing media view. Killing "
+ + mediaViewParent.getContext().getPackageName());
+ android.os.Process.killProcess(Process.myPid());
+ }
+ return null;
+ }
}
/**
@@ -440,6 +652,7 @@ public abstract class TvIAppService extends Service {
@Override
public void release() {
+ mSessionImpl.scheduleMediaViewCleanup();
mSessionImpl.release();
}
@@ -458,6 +671,21 @@ public abstract class TvIAppService extends Service {
mSessionImpl.notifyBroadcastInfoResponse(response);
}
+ @Override
+ public void createMediaView(IBinder windowToken, Rect frame) {
+ mSessionImpl.createMediaView(windowToken, frame);
+ }
+
+ @Override
+ public void relayoutMediaView(Rect frame) {
+ mSessionImpl.relayoutMediaView(frame);
+ }
+
+ @Override
+ public void removeMediaView() {
+ mSessionImpl.removeMediaView(true);
+ }
+
private final class TvIAppEventReceiver extends InputEventReceiver {
TvIAppEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
diff --git a/media/java/android/media/tv/interactive/TvIAppView.java b/media/java/android/media/tv/interactive/TvIAppView.java
index 1b25c23deea0..803198162d30 100644
--- a/media/java/android/media/tv/interactive/TvIAppView.java
+++ b/media/java/android/media/tv/interactive/TvIAppView.java
@@ -20,6 +20,8 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.media.tv.TvInputManager;
import android.media.tv.TvView;
import android.media.tv.interactive.TvIAppManager.Session;
@@ -65,6 +67,9 @@ public class TvIAppView extends ViewGroup {
private int mSurfaceViewTop;
private int mSurfaceViewBottom;
+ private boolean mMediaViewCreated;
+ private Rect mMediaViewFrame;
+
private final AttributeSet mAttrs;
private final int mDefStyleAttr;
private final XmlResourceParser mParser;
@@ -119,6 +124,18 @@ public class TvIAppView extends ViewGroup {
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ createSessionMediaView();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ removeSessionMediaView();
+ super.onDetachedFromWindow();
+ }
+
+ @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (DEBUG) {
Log.d(TAG, "onLayout (left=" + left + ", top=" + top + ", right=" + right
@@ -147,6 +164,11 @@ public class TvIAppView extends ViewGroup {
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
mSurfaceView.setVisibility(visibility);
+ if (visibility == View.VISIBLE) {
+ createSessionMediaView();
+ } else {
+ removeSessionMediaView();
+ }
}
private void resetSurfaceView() {
@@ -155,7 +177,12 @@ public class TvIAppView extends ViewGroup {
removeView(mSurfaceView);
}
mSurface = null;
- mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr);
+ mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
+ @Override
+ protected void updateSurface() {
+ super.updateSurface();
+ relayoutSessionMediaView();
+ }};
// The surface view's content should be treated as secure all the time.
mSurfaceView.setSecure(true);
mSurfaceView.getHolder().addCallback(mSurfaceHolderCallback);
@@ -170,6 +197,46 @@ public class TvIAppView extends ViewGroup {
resetInternal();
}
+ private void createSessionMediaView() {
+ // TODO: handle z-order
+ if (mSession == null || !isAttachedToWindow() || mMediaViewCreated) {
+ return;
+ }
+ mMediaViewFrame = getViewFrameOnScreen();
+ mSession.createMediaView(this, mMediaViewFrame);
+ mMediaViewCreated = true;
+ }
+
+ private void removeSessionMediaView() {
+ if (mSession == null || !mMediaViewCreated) {
+ return;
+ }
+ mSession.removeMediaView();
+ mMediaViewCreated = false;
+ mMediaViewFrame = null;
+ }
+
+ private void relayoutSessionMediaView() {
+ if (mSession == null || !isAttachedToWindow() || !mMediaViewCreated) {
+ return;
+ }
+ Rect viewFrame = getViewFrameOnScreen();
+ if (viewFrame.equals(mMediaViewFrame)) {
+ return;
+ }
+ mSession.relayoutMediaView(viewFrame);
+ mMediaViewFrame = viewFrame;
+ }
+
+ private Rect getViewFrameOnScreen() {
+ Rect frame = new Rect();
+ getGlobalVisibleRect(frame);
+ RectF frameF = new RectF(frame);
+ getMatrix().mapRect(frameF);
+ frameF.round(frame);
+ return frame;
+ }
+
private void setSessionSurface(Surface surface) {
if (mSession == null) {
return;
@@ -214,6 +281,7 @@ public class TvIAppView extends ViewGroup {
mSessionCallback = null;
if (mSession != null) {
setSessionSurface(null);
+ removeSessionMediaView();
mUseRequestedSurfaceLayout = false;
mSession.release();
mSession = null;
@@ -287,6 +355,7 @@ public class TvIAppView extends ViewGroup {
dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight);
}
}
+ createSessionMediaView();
} else {
// Failed to create
// Todo: forward error to Tv App
@@ -303,6 +372,8 @@ public class TvIAppView extends ViewGroup {
Log.w(TAG, "onSessionReleased - session not created");
return;
}
+ mMediaViewCreated = false;
+ mMediaViewFrame = null;
mSessionCallback = null;
mSession = null;
}
diff --git a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
index c7b6421cd0c9..cd757d2a626e 100644
--- a/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvIAppManagerService.java
@@ -28,6 +28,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
+import android.graphics.Rect;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.interactive.ITvIAppClient;
@@ -570,6 +571,11 @@ public class TvIAppManagerService extends SystemService {
}
@GuardedBy("mLock")
+ private ITvIAppSession getSessionLocked(IBinder sessionToken, int callingUid, int userId) {
+ return getSessionLocked(getSessionStateLocked(sessionToken, callingUid, userId));
+ }
+
+ @GuardedBy("mLock")
private ITvIAppSession getSessionLocked(SessionState sessionState) {
ITvIAppSession session = sessionState.mSession;
if (session == null) {
@@ -802,6 +808,67 @@ public class TvIAppManagerService extends SystemService {
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public void createMediaView(IBinder sessionToken, IBinder windowToken, Rect frame,
+ int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "createMediaView");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId)
+ .createMediaView(windowToken, frame);
+ } catch (RemoteException | TvIAppManagerService.SessionNotFoundException e) {
+ Slog.e(TAG, "error in createMediaView", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void relayoutMediaView(IBinder sessionToken, Rect frame, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "relayoutMediaView");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId)
+ .relayoutMediaView(frame);
+ } catch (RemoteException | TvIAppManagerService.SessionNotFoundException e) {
+ Slog.e(TAG, "error in relayoutMediaView", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void removeMediaView(IBinder sessionToken, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "removeMediaView");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId)
+ .removeMediaView();
+ } catch (RemoteException | TvIAppManagerService.SessionNotFoundException e) {
+ Slog.e(TAG, "error in removeMediaView", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
}
@GuardedBy("mLock")