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

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

Issue 2178973004: DialogSurfaceManager implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: removed IDialogSurfaceActivityMapper from common.aidl Created 4 years 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/DialogSurfaceCore.java
diff --git a/media/base/android/java/src/org/chromium/media/DialogSurfaceCore.java b/media/base/android/java/src/org/chromium/media/DialogSurfaceCore.java
new file mode 100644
index 0000000000000000000000000000000000000000..79db2458c2c75b4019b7410b588e4fdab06ed70c
--- /dev/null
+++ b/media/base/android/java/src/org/chromium/media/DialogSurfaceCore.java
@@ -0,0 +1,247 @@
+// 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.annotation.SuppressLint;
+import android.app.Dialog;
+import android.content.Context;
+import android.os.IBinder;
+import android.view.Gravity;
+import android.view.SurfaceHolder;
+import android.view.Window;
+import android.view.WindowManager;
+
+import org.chromium.base.Log;
+
+/**
+ * Core class for control of a single DialogSurface instance. Everything runs
+ * on a single thread, that's probably not the UI thread.
+ *
+ * Note that this does not implement IDialogSurface; we assume that, and the
+ * associated thread-hopping, is handled elsewhere.
+ */
+class DialogSurfaceCore {
+ private static final String TAG = "cr_media";
boliu 2017/01/04 01:48:44 generally, this is just the name of the class, the
liberato (no reviews please) 2017/01/11 22:17:57 not sure. i copied the pattern from MediaCodecBri
boliu 2017/01/12 20:24:19 fwiw, it's dynamic: https://cs.chromium.org/chromi
liberato (no reviews please) 2017/02/03 21:28:32 Acknowledged.
+
+ /**
+ * 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.
+ *
+ * The callback cannot recursively call back into us; the IDialogSurface
+ * implementation must prevent that.
+ */
+ private IDialogSurfaceCallback mClientCallback;
+
+ // Callback operations.
+ // These must match dialog_surface.h .
+ private static final int OP_CREATED = 0;
+ private static final int OP_DESTROYED = 1;
+
+ // When initialized via Init, we'll create mDialog. We'll clear it when
+ // we send SURFACE_DESTROYED to the client. In general, when this is null,
+ // either we haven't been initialized yet, or we've been torn down. It
+ // shouldn't be the case that anything calls methods after construction but
+ // before Init, though.
+ private Dialog mDialog;
+
+ private Callbacks mDialogCallbacks;
+ private IBinder mToken;
+
+ // Initial position and size.
+ private int mInitialX;
+ private int mInitialY;
+ private int mInitialWidth;
+ private int mInitialHeight;
+
+ /**
+ * Construction may be called from a random thread, for simplicity. Call
+ * Init from the proper thread before doing anything else.
+ */
+ public DialogSurfaceCore() {}
+
+ /**
+ * Finish init on the proper thread. We'll use this thread for the Dialog
+ * Looper thread.
+ * @param context Context that we use.
+ * @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 void initialize(
+ Context context, IDialogSurfaceCallback callback, int x, int y, int width, int height) {
+ mClientCallback = callback;
+ mInitialX = x;
+ mInitialY = y;
+ mInitialWidth = width;
+ mInitialHeight = height;
+
+ // Create the dialog, but don't lay it out or show it yet. We'll do
+ // that when we get a window token.
+ mDialog = new Dialog(context, android.R.style.Theme_NoDisplay);
+ mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ mDialog.setCancelable(false);
+ }
+
+ /**
+ * Release the underlying surface, and generally clean up, in response to
+ * the client releasing the IDialogSurface.
+ */
+ public void release() {
+ // If we've not released the dialog yet, then do so.
+ if (mDialog != null) {
+ // TODO(liberato): is this safe if we haven't shown the dialog yet?
+ mDialog.dismiss();
+ mDialog = null;
+ mDialogCallbacks = null;
+ }
+ }
+
+ /**
+ * Layout the DialogSurface. If we don't have a token, then we ignore it,
+ * since a well-behaved client shouldn't call us before OP_CREATED anyway.
+ */
+ @SuppressLint("RtlHardcoded")
+ public void layoutSurface(final int x, final int y, final int width, final int height) {
+ if (mDialog == null || mToken == null) return;
+
+ // 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();
boliu 2017/01/04 01:48:44 ditto about allocating java objects in calls that
liberato (no reviews please) 2017/01/11 22:17:57 Done.
+
+ // 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.token = mToken;
+
+ // NOTE: we really do want LEFT here, since we're dealing in compositor
+ // coordinates. Those are always from the left.
+ layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
+
+ // Use a media surface, which is what SurfaceView uses by default. For
+ // debugging overlay drawing, consider using TYPE_APPLICATION_PANEL to
+ // move the dialog over the CompositorView.
+ layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+
+ 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. Ignore errors.
+ try {
+ int currentFlags =
+ (Integer) layoutParams.getClass().getField("privateFlags").get(layoutParams);
boliu 2017/01/04 01:48:44 err, reflection? hard coded values?
liberato (no reviews please) 2017/01/11 22:17:57 PRIVATE_FLAG_NO_MOVE_ANIMATION -- there's no other
boliu 2017/01/12 20:24:19 The bar for using private APIs is very high, ie it
liberato (no reviews please) 2017/02/03 21:28:32 i'd really like to do this. we can chat offline a
+ layoutParams.getClass()
+ .getField("privateFlags")
+ .set(layoutParams, currentFlags | 0x00000040);
+ // It would be nice to just catch Exception, but findbugs doesn't
+ // allow it. If we cannot set the flag, then that's okay too.
+ } catch (NoSuchFieldException e) {
+ } catch (NullPointerException e) {
+ } catch (SecurityException e) {
+ } catch (IllegalAccessException e) {
+ } catch (IllegalArgumentException e) {
+ } catch (ExceptionInInitializerError e) {
+ }
+
+ mDialog.getWindow().setAttributes(layoutParams);
+ }
+
+ /**
+ * 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) {
+ // Make sure that we haven't torn down the dialog yet.
+ if (mDialog == null) return;
+
+ try {
+ mClientCallback.onCreated(holder.getSurface());
+ } catch (Exception e) {
+ Log.e(TAG, "surfaceCreated: callback failed: " + e);
+ enterDestroyedState();
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ if (mDialog == null) return;
+
+ enterDestroyedState();
+ }
+
+ @Override
+ public void surfaceRedrawNeeded(SurfaceHolder holder) {}
+ }
+
+ /**
+ * Notify the client about surface destruction, and clean up. Multiple
+ * calls to us do nothing.
+ */
+ private void enterDestroyedState() {
+ if (mDialog == null) return;
+
+ try {
+ mClientCallback.onDestroyed();
+ } catch (Exception e) {
+ Log.e(TAG, "enterDestroyedState: callback failed: " + e);
boliu 2017/01/04 01:48:44 all logs probably should be .d so they get strippe
liberato (no reviews please) 2017/01/11 22:17:57 Done.
+ release();
+ }
+
+ // Dismiss the dialog, if needed
+ // TODO(liberato): is it safe to call dismiss without show? we don't
+ // know that we've shown the dialog yet. maybe if mToken? isShowing?
+ mDialog.dismiss();
+ mDialog = null;
+ mDialogCallbacks = null;
+ mToken = null;
+ }
+
+ public void onWindowToken(IBinder token) {
+ if (mDialog == null) return;
+
+ if (token == null || (mToken != null && token != mToken)) {
+ // We've lost the token, if we had one, or we got a new one.
+ // Notify the client.
+ enterDestroyedState();
+ return;
+ }
+
+ if (mToken == token) {
+ // Same token, do nothing.
boliu 2017/01/04 01:48:44 haven't read the window token stuff yet.. but is t
liberato (no reviews please) 2017/01/11 22:17:57 i don't think that it should, but it seemed harmle
boliu 2017/01/12 20:24:19 but this is silencing a potential problem in the f
+ return;
+ }
+
+ // We have a token, so layout the dialog.
+ mToken = token;
+ layoutSurface(mInitialX, mInitialY, mInitialWidth, mInitialHeight);
boliu 2017/01/04 01:48:44 what if an layout happens before window token is r
liberato (no reviews please) 2017/01/11 22:17:57 it's okay, since the application shouldn't be posi
+ mDialogCallbacks = new Callbacks();
+ mDialog.getWindow().takeSurface(mDialogCallbacks);
+ mDialog.show();
+
+ // We don't notify the client here. We'll wait until the Android
+ // Surface is created.
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698