Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(867)

Unified Diff: media/base/android/java/src/org/chromium/media/DialogSurface.java

Issue 1967553002: DO NOT COMMIT - DialogSurface initial implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cleanup Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/base/android/java/src/org/chromium/media/DialogSurface.java
diff --git a/media/base/android/java/src/org/chromium/media/DialogSurface.java b/media/base/android/java/src/org/chromium/media/DialogSurface.java
new file mode 100644
index 0000000000000000000000000000000000000000..666f5adbce83380f72ddc46a75f0f3cfe5f94541
--- /dev/null
+++ b/media/base/android/java/src/org/chromium/media/DialogSurface.java
@@ -0,0 +1,296 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.media;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.view.Gravity;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.Window;
+import android.view.WindowManager;
+
+import org.chromium.base.Log;
+
+/**
+ * Provide access to Dialog-based Surfaces.
+ *
+ * There are two threads involved, which we call "primary" and "looper". The
+ * primary thread is the one that native uses to talk to us, such as the gpu
+ * main thread. All calls to us from native must be on this thread.
+ *
+ * Note that this class may run in the browser or gpu process, depending on
+ * whether we want the gpu process to have the activity window token or not.
+ *
+ * The wrapper class (DialogSurfaceWrapper) always runs locally with
+ * the JNI code that uses it, probably in the gpu process.
+ *
+ * The looper thread is a separate thread which has the looper for the dialogs
+ * that we create. We may call into native on that thread. Note that the
+ * native side handles the resulting race conditions.
+ */
+class DialogSurface extends IDialogSurface.Stub {
+ private static final String TAG = "cr_media";
+
+ /**
+ * Call back into native with a message about our state. This can be called
+ * on any thread. It's okay if it refers to a native object that no longer
+ * exists; we can't really avoid it. The native side handles it.
+ *
+ * IMPORTANT: Do not call this with mLock held. Expect that the callback
+ * may call us.
+ */
+ private final IDialogSurfaceCallback mCallback;
+ private final Handler mHandler;
+ private final Context mContext;
+ private final int mRendererPid;
+ private final int mRenderFrameId;
+
+ // Callback operations.
+ // These must match dialog_surface.h .
+ private static final int OP_CREATED = 0;
+ private static final int OP_DESTROYED = 1;
+
+ private DialogSurfaceManager mOwner;
+
+ ////// Either thread, protected by mLock
+ private final Object mLock = new Object();
+ private Dialog mDialog;
+ private boolean mReleased;
+ private Surface mSurface;
+
+ /**
+ * Called from primary thread.
+ * Note that (pid, frameId) might be replaced by a token.
+ * @param rendererPid pid of owning renderer process
+ * @param renderFrameId render frame ID owned by Pid
+ * @param context Context that we use.
+ * @param owner Owning manager that we'll notify on release().
+ * @param handler handler for a thread with a looper.
+ * @param callback callback object to notify about state changes.
+ * @param x initial x position in chrome compositor (not screen) coords.
+ * @param y initial y position in chrome compositor (not screen) coords.
+ * @param width initial width.
+ * @param height initial height.
+ */
+ public DialogSurface(int rendererPid, int renderFrameId, Context context,
+ DialogSurfaceManager owner, Handler handler, IDialogSurfaceCallback callback, int x,
+ int y, int width, int height) {
+ mRendererPid = rendererPid;
+ mRenderFrameId = renderFrameId;
+ mContext = context;
+ mOwner = owner;
+ mHandler = handler;
+ mCallback = callback;
+
+ mReleased = false;
+
+ scheduleCreateDialog(x, y, width, height);
+ }
+
+ // Note that the native wrapper should call release() anyway on destruction.
+ protected void finalize() throws Throwable {
+ synchronized (mLock) {
+ if (!mReleased) {
+ Log.w(TAG, "Not released before finalization, releasing now");
+ }
+ }
+ release();
+ }
+
+ /**
+ * Release the underlying surface, and generally clean up.
+ */
+ @Override
+ public void release() {
+ synchronized (mLock) {
+ if (!mReleased) mOwner.notifyReleased(this);
+ mOwner = null;
+
+ // Note that we can't prevent callbacks; they must execute without
+ // the lock held so that the callback can do things that requires
+ // the lock (e.g., GetSurface). However, the native side handles
+ // races with deleted objects, not us.
+
+ // Prevent any in-flight create from succeeding, and hide any dialog
+ // that we currently have.
+ mReleased = true;
+ if (mDialog != null) {
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ }
+ };
+ mHandler.post(r);
+ }
+ }
+ }
+
+ @Override
+ public Surface getSurface() {
+ synchronized (mLock) {
+ return mSurface;
+ }
+ }
+
+ @Override
+ public void scheduleLayoutSurface(final int x, final int y, final int width, final int height) {
+ synchronized (mLock) {
+ final Dialog dialog = mDialog;
+ // Note that mDialog might be replaced, but that means that
+ // somebody called scheduleLayoutSurface while a create was pending
+ // before they got notification that the surface was ready.
+
+ if (dialog == null) return;
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ layoutDialog(dialog, x, y, width, height);
+ }
+ };
+
+ mHandler.post(r);
+ }
+ }
+
+ /**
+ * Callbacks for finding out about the Dialog's Surface.
+ * These happen on the looper thread.
+ */
+ private class Callbacks implements SurfaceHolder.Callback2 {
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ synchronized (mLock) {
+ mSurface = holder.getSurface();
+ }
+
+ try {
+ mCallback.onCallback(OP_CREATED);
+ } catch (Exception e) {
+ Log.e(TAG, "SurfaceCreated: callback failed: " + e);
+ release();
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ synchronized (mLock) {
+ mSurface = null;
+ }
+
+ try {
+ mCallback.onCallback(OP_DESTROYED);
+ } catch (Exception e) {
+ Log.e(TAG, "SurfaceDestroyed: callback failed: " + e);
+ release();
+ }
+ }
+
+ @Override
+ public void surfaceRedrawNeeded(SurfaceHolder holder) {}
+ }
+
+ /**
+ * Schedule creation of the dialog on our looper thread. Sets mThread
+ * asynchronously. If release() occurs before then, then the dialog will
+ * not be created.
+ */
+ private void scheduleCreateDialog(final int x, final int y, final int width, final int height) {
+ synchronized (mLock) {
+ mDialog = null;
+ }
+
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ Dialog dialog = new Dialog(mContext, android.R.style.Theme_NoDisplay);
+ dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ dialog.setCancelable(false);
+ layoutDialog(dialog, x, y, width, height);
+ dialog.getWindow().takeSurface(new Callbacks());
+ synchronized (mLock) {
+ // If we've been released in the interim, then stop here.
+ if (mReleased) return;
+
+ dialog.show();
+ mDialog = dialog;
+ }
+ }
+ }; // new Runnable
+
+ // Post it to our dedicated thread.
+ mHandler.post(r);
+ }
+
+ /**
+ * Layout the dialog on the current thread. This should be called from the
+ * looper thread.
+ * Call scheduleLayoutDialog from anywhere else.
+ */
+ private void layoutDialog(Dialog dialog, int x, int y, int width, int height) {
+ // Rather than using getAttributes, we just create them from scratch.
+ // The default dialog attributes aren't what we want.
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+
+ // TODO(liberato): adjust for CompositorView screen location here if we
+ // want to support non-full screen use cases.
+ layoutParams.x = x;
+ layoutParams.y = y;
+ layoutParams.width = width;
+ layoutParams.height = height;
+ layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
+
+ // Use a panel, which is over the compositor view, until we get the
+ // compositor to switch to a transparent output surface.
+ // layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+
+ // Don't set FLAG_SCALED. in addition to not being sure what it does
+ // (SV uses it), it also causes a crash in WindowManager when we hide
+ // (not dismiss), navigate, and/or exit the app without hide/dismiss.
+ // There's a missing null check in WindowManagerService.java@3170
+ // on M MR2. To repro, change dimiss() to hide(), bring up a SV, and
+ // navigate away or press home.
+
+ // Turn off the position animation, so that it doesn't animate from one
+ // position to the next.
+ try {
+ int currentFlags =
+ (Integer) layoutParams.getClass().getField("privateFlags").get(layoutParams);
+ layoutParams.getClass()
+ .getField("privateFlags")
+ .set(layoutParams, currentFlags | 0x00000040);
+ } catch (Exception e) {
+ }
+
+ layoutParams.token = getWindowToken();
+
+ dialog.getWindow().setAttributes(layoutParams);
+ }
+
+ private IBinder getWindowToken() {
+ IBinder token = null;
+ try {
+ token = mOwner.getMapper().getWindowToken(mRendererPid, mRenderFrameId);
+ } catch (Exception e) {
+ }
+ return token;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698