Chromium Code Reviews| 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..82b6f0984592e20593eba8c2bcf1a57d1712df90 |
| --- /dev/null |
| +++ b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayImpl.java |
| @@ -0,0 +1,207 @@ |
| +// 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.app.Dialog; |
| +import android.content.Context; |
| +import android.os.IBinder; |
| +import android.view.Surface; |
| + |
| +import org.chromium.base.ContextUtils; |
| +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-ui 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 main thread. |
| + */ |
| +public class DialogOverlayImpl implements AndroidOverlay, DialogOverlayCore.Host, |
| + DialogOverlayOperations.WindowTokenListener { |
| + private static final String TAG = "DialogOverlayImpl"; |
| + |
| + private AndroidOverlayClient mClient; |
|
boliu
2017/03/30 22:42:02
any/all of this can be final?
liberato (no reviews please)
2017/04/04 17:49:29
client, dialogcore: no, cleared when they're clean
|
| + private DialogOverlayOperations mOps; |
| + private DialogOverlayCore mDialogCore; |
| + private ThreadHoppingHost mHoppingHost; |
| + |
| + // If nonzero, then we have registered a surface with this ID. |
| + private int mSurfaceId; |
| + |
| + // Are we currently registered with |mOps| to receive token updates? |
| + private boolean mRegisteredForToken; |
| + |
| + /** |
| + * @param client Mojo client interface. |
| + * @param config initial overlay configuration. |
| + * @param handler handler that posts to the overlay-ui 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, |
| + DialogOverlayOperations ops) { |
| + mClient = client; |
|
boliu
2017/03/30 22:42:03
probably worth asserting what thread each method r
liberato (no reviews please)
2017/04/04 17:49:29
Done.
|
| + mOps = ops; |
| + mDialogCore = new DialogOverlayCore(); |
| + mHoppingHost = new ThreadHoppingHost(this); |
| + |
| + // Post init to the proper (overlay-ui) thread. |
| + final DialogOverlayCore dialogCore = mDialogCore; |
| + final Context context = ContextUtils.getApplicationContext(); |
| + mOps.getOverlayUiHandler().post(new Runnable() { |
| + @Override |
| + public void run() { |
| + Dialog dialog = mOps.createDialog(context); |
| + dialogCore.initialize(dialog, config, mHoppingHost); |
| + } |
| + }); |
| + |
| + // Register to get token updates. |
| + mOps.registerWindowTokenListener(config.routingToken, this); |
| + mRegisteredForToken = true; |
| + } |
| + |
| + @Override |
| + public void onSurfaceReady(Surface surface) { |
| + if (mDialogCore == null || mClient == null) return; |
| + |
| + mSurfaceId = mOps.registerSurface(surface); |
| + mClient.onSurfaceReady(mSurfaceId); |
| + } |
| + |
| + @Override |
| + public void onOverlayDestroyed() { |
| + 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 |mOps| yet, though we could. We wait for the client to close |
| + // their connection first. |
| + } |
| + |
| + // Due to threading issues, |mHoppingHost| doesn't forward this. |
| + @Override |
| + public void waitForCleanup() { |
| + assert false : "Not reached"; |
| + } |
| + |
| + // Client is done with this overlay. |
| + @Override |
| + public void close() { |
| + // 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-ui thread. |
| + if (mDialogCore != null) { |
| + final DialogOverlayCore dialogCore = mDialogCore; |
| + mOps.getOverlayUiHandler().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. |
| + mOps.notifyReleased(); |
| + } |
| + |
| + private void sendWindowTokenToCore(final IBinder token) { |
| + final DialogOverlayCore dialogCore = mDialogCore; |
| + mOps.getOverlayUiHandler().post(new Runnable() { |
| + @Override |
| + public void run() { |
| + dialogCore.onWindowToken(token); |
| + } |
| + }); |
| + } |
| + |
| + @Override |
| + public void onWindowToken(final IBinder token) { |
| + 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); |
| + } |
| + |
| + @Override |
| + public void onDismissed() { |
| + // 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(); |
| + } |
| + |
| + @Override |
| + public void onConnectionError(MojoException e) { |
| + close(); |
| + } |
| + |
| + @Override |
| + public void scheduleLayout(final Rect rect) { |
| + if (mDialogCore == null) return; |
| + |
| + final DialogOverlayCore dialogCore = mDialogCore; |
| + mOps.getOverlayUiHandler().post(new Runnable() { |
| + @Override |
| + public void run() { |
| + dialogCore.layoutSurface(rect); |
| + } |
| + }); |
| + } |
| + |
| + /** |
| + * Unregister for callbacks, unregister any surface that we have, and forget about |
| + * |mDialogCore|. Multiple calls are okay. |
| + */ |
| + private void cleanup() { |
| + if (mSurfaceId != 0) { |
| + mOps.unregisterSurface(mSurfaceId); |
| + mSurfaceId = 0; |
| + } |
| + |
| + if (mRegisteredForToken) { |
| + mOps.unregisterWindowTokenListener(); |
| + mRegisteredForToken = false; |
| + } |
| + |
| + // 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. |
| + if (mDialogCore != null) mDialogCore = null; |
|
boliu
2017/03/30 22:42:03
redundant check
liberato (no reviews please)
2017/04/04 17:49:29
Done.
|
| + |
| + // If we wanted to send any message to |mClient|, we should have done so already. |
| + mClient = null; |
| + } |
| +} |