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

Unified Diff: content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java

Issue 2765443004: AndroidOverlay implementation using Dialog. (Closed)
Patch Set: fixed test Created 3 years, 8 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: content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..52d90d2fbc8d8e92921123ca4cba2b57f6771731
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java
@@ -0,0 +1,275 @@
+// Copyright 2017 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.content.browser.androidoverlay;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.view.Surface;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.gfx.mojom.Rect;
+import org.chromium.media.mojom.AndroidOverlay;
+import org.chromium.media.mojom.AndroidOverlayClient;
+import org.chromium.media.mojom.AndroidOverlayConfig;
+import org.chromium.mojo.system.MojoException;
+
+/**
+ * Default AndroidOverlay impl. Uses a separate (shared) overlay thread to own a Dialog instance,
+ * probably via a separate object that operates only on that thread. We will post messages to /
+ * from that thread from the UI thread.
+ */
+@JNINamespace("content")
+public class DialogOverlayImpl implements AndroidOverlay, DialogOverlayCore.Host {
+ private static final String TAG = "DialogOverlayImpl";
+
+ private AndroidOverlayClient mClient;
+ private Handler mOverlayHandler;
+ // Runnable that we'll run when the overlay notifies us that it's been released.
+ private Runnable mReleasedRunnable;
+
+ private final ThreadHoppingHost mHoppingHost;
+
+ private DialogOverlayCore mDialogCore;
+
+ private long mNativeHandle;
+
+ // If nonzero, then we have registered a surface with this ID.
+ private int mSurfaceId;
+
+ /**
+ * @param client Mojo client interface.
+ * @param config initial overlay configuration.
+ * @param handler handler that posts to the overlay thread. This is the android UI thread that
+ * the dialog uses, not the browser UI thread.
+ * @param provider the overlay provider that owns us.
+ */
+ public DialogOverlayImpl(AndroidOverlayClient client, final AndroidOverlayConfig config,
+ Handler overlayHandler, Runnable releasedRunnable) {
+ ThreadUtils.assertOnUiThread();
+
+ mClient = client;
+ mReleasedRunnable = releasedRunnable;
+ mOverlayHandler = overlayHandler;
+
+ mDialogCore = new DialogOverlayCore();
+ mHoppingHost = new ThreadHoppingHost(this);
+
+ // Post init to the overlay thread.
+ final DialogOverlayCore dialogCore = mDialogCore;
+ final Context context = ContextUtils.getApplicationContext();
+ mOverlayHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ dialogCore.initialize(context, config, mHoppingHost);
+ }
+ });
+
+ // Register to get token updates.
+ mNativeHandle = nativeInit(config.routingToken.high, config.routingToken.low);
+ assert mNativeHandle != 0;
+ }
+
+ // AndroidOverlay impl.
+ // Client is done with this overlay.
+ @Override
+ public void close() {
+ ThreadUtils.assertOnUiThread();
+
+ // TODO(liberato): verify that this actually works, else add an explicit shutdown and hope
+ // that the client calls it.
+
+ // Allow surfaceDestroyed to proceed, if it's waiting.
+ mHoppingHost.onCleanup();
+
+ // Notify |mDialogCore| that it has been released. This might not be called if it notifies
+ // us that it's been destroyed. We still might send it in that case if the client closes
+ // the connection before we find out that it's been destroyed on the overlay thread.
+ if (mDialogCore != null) {
+ final DialogOverlayCore dialogCore = mDialogCore;
+ mOverlayHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ dialogCore.release();
+ }
+ });
+
+ // Note that we might get messagaes from |mDialogCore| after this, since they might be
+ // dispatched before |r| arrives. Clearing |mDialogCore| causes us to ignore them.
+ cleanup();
+ }
+
+ // Notify the provider that we've been released by the client. Note that the surface might
+ // not have been destroyed yet, but that's okay. We could wait for a callback from the
+ // dialog core before proceeding, but this makes it easier for the client to destroy and
+ // re-create an overlay without worrying about an intermittent failure due to having too
+ // many overlays open at once.
+ mReleasedRunnable.run();
+ }
+
+ // AndroidOverlay impl.
+ @Override
+ public void onConnectionError(MojoException e) {
+ ThreadUtils.assertOnUiThread();
+
+ close();
+ }
+
+ // AndroidOverlay impl.
+ @Override
+ public void scheduleLayout(final Rect rect) {
+ ThreadUtils.assertOnUiThread();
+
+ if (mDialogCore == null) return;
+
+ final DialogOverlayCore dialogCore = mDialogCore;
+ mOverlayHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ dialogCore.layoutSurface(rect);
+ }
+ });
+ }
+
+ // DialogOverlayCore.Host impl.
+ // |surface| is now ready. Register it with the surface tracker, and notify the client.
+ @Override
+ public void onSurfaceReady(Surface surface) {
+ ThreadUtils.assertOnUiThread();
+
+ if (mDialogCore == null || mClient == null) return;
+
+ mSurfaceId = nativeRegisterSurface(surface);
+ mClient.onSurfaceReady(mSurfaceId);
+ }
+
+ // DialogOverlayCore.Host impl.
+ @Override
+ public void onOverlayDestroyed() {
+ ThreadUtils.assertOnUiThread();
+
+ if (mDialogCore == null) return;
+
+ // Notify the client that the overlay is gone.
+ if (mClient != null) mClient.onDestroyed();
+
+ // Also clear out |mDialogCore| to prevent us from sending useless messages to it. Note
+ // that we might have already sent useless messages to it, and it should be robust against
+ // that sort of thing.
+ cleanup();
+
+ // Note that we don't notify |mReleasedRunnable| yet, though we could. We wait for the
+ // client to close their connection first.
+ }
+
+ // DialogOverlayCore.Host impl.
+ // Due to threading issues, |mHoppingHost| doesn't forward this.
+ @Override
+ public void waitForCleanup() {
+ assert false : "Not reached";
+ }
+
+ /**
+ * Send |token| to the |mDialogCore| on the overlay thread.
+ */
+ private void sendWindowTokenToCore(final IBinder token) {
+ ThreadUtils.assertOnUiThread();
+
+ final DialogOverlayCore dialogCore = mDialogCore;
+ mOverlayHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ dialogCore.onWindowToken(token);
+ }
+ });
+ }
+
+ /**
+ * Callback from native that the window token has changed.
+ */
+ @CalledByNative
+ public void onWindowToken(final IBinder token) {
+ ThreadUtils.assertOnUiThread();
+
+ if (mDialogCore == null) return;
+
+ // Forward this change.
+ // Note that if we don't have a window token, then we could wait until we do, simply by
+ // skipping sending null if we haven't sent any non-null token yet. If we're transitioning
+ // between windows, that might make the client's job easier. It wouldn't have to guess when
+ // a new token is available.
+ sendWindowTokenToCore(token);
+ }
+
+ /**
+ * Callback from native that we will be getting no additional tokens.
+ */
+ @CalledByNative
+ public void onDismissed() {
+ ThreadUtils.assertOnUiThread();
+
+ // Notify the client that the overlay is going away.
+ if (mClient != null) mClient.onDestroyed();
+
+ // Notify |mDialogCore| that it lost the token, if it had one.
+ sendWindowTokenToCore(null);
+
+ cleanup();
+ }
+
+ /**
+ * Unregister for callbacks, unregister any surface that we have, and forget about
+ * |mDialogCore|. Multiple calls are okay.
+ */
+ private void cleanup() {
+ ThreadUtils.assertOnUiThread();
+
+ if (mSurfaceId != 0) {
+ nativeUnregisterSurface(mSurfaceId);
+ mSurfaceId = 0;
+ }
+
+ // Note that we might not be registered for a token.
+ if (mNativeHandle != 0) {
+ nativeDestroy(mNativeHandle);
+ mNativeHandle = 0;
+ }
+
+ // Also clear out |mDialogCore| to prevent us from sending useless messages to it. Note
+ // that we might have already sent useless messages to it, and it should be robust against
+ // that sort of thing.
+ mDialogCore = null;
+
+ // If we wanted to send any message to |mClient|, we should have done so already.
+ mClient = null;
+ }
+
+ /**
+ * Initializes native side. Will register for onWindowToken callbacks on |this|. Returns a
+ * handle that should be provided to nativeDestroy.
+ */
+ private native long nativeInit(long high, long low);
+
+ /**
+ * Stops native side and deallocates |handle|.
+ */
+ private native void nativeDestroy(long nativeDialogOverlayImpl);
+
+ /**
+ * Register a surface and return the surface id for it.
+ * @param surface Surface that we should register.
+ * @return surface id that we associated with |surface|.
+ */
+ private static native int nativeRegisterSurface(Surface surface);
+
+ /**
+ * Unregister a surface.
+ * @param surfaceId Id that was returned by registerSurface.
+ */
+ private static native void nativeUnregisterSurface(int surfaceId);
+}

Powered by Google App Engine
This is Rietveld 408576698