Index: content/public/android/java/src/org/chromium/content/browser/DialogSurfaceWindowTokenProviderImpl.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/DialogSurfaceWindowTokenProviderImpl.java b/content/public/android/java/src/org/chromium/content/browser/DialogSurfaceWindowTokenProviderImpl.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..eceb851da19e3dde3cc956fd1de8ef500d2a1651 |
--- /dev/null |
+++ b/content/public/android/java/src/org/chromium/content/browser/DialogSurfaceWindowTokenProviderImpl.java |
@@ -0,0 +1,200 @@ |
+// 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.content.browser; |
+ |
+import android.app.Activity; |
+import android.os.IBinder; |
+ |
+import org.chromium.base.annotations.CalledByNative; |
+import org.chromium.base.annotations.JNINamespace; |
+import org.chromium.media.DialogSurfaceWindowTokenProvider; |
+import org.chromium.ui.base.WindowAndroid; |
+ |
+import java.util.HashMap; |
+import java.util.HashSet; |
+ |
+/** |
+ * Implementation of DialogSurfaceWindowTokenProvider. Asks ContentViewCore to |
+ * provide updates on token changes. |
+ */ |
+@JNINamespace("content") |
+public class DialogSurfaceWindowTokenProviderImpl |
boliu
2017/01/04 23:14:39
I can see why the Manager is singleton, but I don'
liberato (no reviews please)
2017/01/11 22:17:56
most of the code is to look up WebContents given (
boliu
2017/01/12 20:24:18
You can put it in a static method or something.
liberato (no reviews please)
2017/02/03 21:28:32
per our offline discussion, this class is not in P
|
+ implements DialogSurfaceWindowTokenProvider, ContentViewCore.Observer { |
+ private static final String TAG = "cr_DialogSurfaceWTP"; |
+ |
+ private class ClientSet extends HashSet<DialogSurfaceWindowTokenProvider.Client> {} |
boliu
2017/01/04 01:48:43
these classes should be static
liberato (no reviews please)
2017/01/11 22:17:56
Done.
|
+ private class ClientMap extends HashMap<ContentViewCore, ClientSet> {} |
+ private class ReverseClientMap |
+ extends HashMap<DialogSurfaceWindowTokenProvider.Client, ContentViewCore> {} |
+ |
+ // Access |mClients| and |mReverseClients| with |mClientLock| held. These |
+ // let us associate clients with the ContentViewCore that they're interested |
+ // in listening to. |
+ private final Object mClientLock = new Object(); |
+ private final ClientMap mClients = new ClientMap(); |
+ private final ReverseClientMap mReverseClients = new ReverseClientMap(); |
+ |
+ // This may be called on any thread. |
+ @Override |
+ public void registerClient( |
+ int rendererPid, int renderFrameId, DialogSurfaceWindowTokenProvider.Client client) { |
+ nativeCallBackWithContentViewCore(rendererPid, renderFrameId, this, client); |
+ } |
+ |
+ // This may be called on any thread. |
+ @Override |
+ public void unregisterClient(DialogSurfaceWindowTokenProvider.Client client) { |
+ synchronized (mClientLock) { |
+ unregisterClientLocked(client); |
+ } |
+ } |
+ |
+ // Unregister |client| for updates, with |mClientLock| held. This may be |
+ // called on any thread. |
+ private void unregisterClientLocked(DialogSurfaceWindowTokenProvider.Client client) { |
+ // If we switched threads here, then we could remove mClientLock and |
+ // also unregister for callbacks with CVC. |
+ // Remove client from both the forward and reverse tables. |
+ ContentViewCore cvc = mReverseClients.get(client); |
+ if (cvc == null) return; |
+ |
+ mReverseClients.remove(client); |
+ |
+ ClientSet clients = mClients.get(cvc); |
+ if (clients != null) { |
+ clients.remove(client); |
+ if (clients.size() == 0) { |
+ // We can't cvc.removeObserver(this) here, since we can be on |
+ // the wrong thread. Instead, simply ignore it and skip the |
+ // callbacks if needed. We could probably remove it on the |
+ // next callback, which will be on the correct thread. |
+ // Do not post a remove, though, since we might re-attach in |
+ // the interim. |
+ mClients.remove(cvc); |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Receive a callback from native with a previously requested ContentViewCore. |
+ * This is called on the UI thread. |
+ */ |
+ @CalledByNative |
+ private void onContentViewCore( |
+ DialogSurfaceWindowTokenProvider.Client client, ContentViewCore cvc) { |
+ IBinder token = null; |
+ |
+ if (cvc != null) { |
+ WindowAndroid windowAndroid = cvc.getWindowAndroid(); |
+ if (windowAndroid != null) { |
+ token = windowAndroid.getWindowToken(); |
+ } |
+ |
+ // Register to get updates about window changes, so that we know |
+ // when the token changes. |
+ // Note that we might actually already be a client of this, if we |
+ // unregistered the last client for |cvc| and then a new one came |
+ // along before we got around to unregistering. That's okay. We |
+ // could prevent it, but it's not worth the book-keeping right now. |
+ // We're the only observer anyway. |
+ cvc.addObserver(this); |
+ } |
+ |
+ client.onWindowToken(token); |
+ addClient(cvc, client); |
+ } |
+ |
+ // This will be called on the UI thread. |
+ @Override |
+ public void onContentViewCoreDestroyed(ContentViewCore cvc) { |
+ synchronized (mClientLock) { |
+ onContentViewCoreDestroyedLocked(cvc); |
+ } |
+ } |
+ |
+ private void onContentViewCoreDestroyedLocked(ContentViewCore cvc) { |
+ ClientSet clients = mClients.get(cvc); |
+ if (clients == null) return; |
+ |
+ // Why not just send back the CVC, and have the client manager setting |
+ // up callbacks? It's only a little weird, because (a) media/ can't |
+ // access ContentViewCore. So, we do it here. Plus, if we ever want |
+ // to move the DialogSurface implementation into the gpu process, we'll |
+ // be still running in the browser anyway. So, we do it here. |
+ for (DialogSurfaceWindowTokenProvider.Client client : clients) { |
+ mReverseClients.remove(client); |
+ // We might want to notify them that the CVC was destroyed, |
+ // rather than telling them that there's simply no token. |
+ client.onWindowToken(null); |
+ } |
+ |
+ mClients.remove(cvc); |
+ } |
+ |
+ // This will be called on the UI thread. |
+ @Override |
+ public void onAttachedToWindowAndroid(ContentViewCore cvc) { |
+ Activity activity = cvc.getWindowAndroid().getActivity().get(); |
boliu
2017/01/04 23:14:39
call getWindowToken?
liberato (no reviews please)
2017/01/11 22:17:56
erm, good point.
|
+ IBinder token = null; |
+ if (activity != null) { |
+ token = activity.getWindow().getDecorView().getRootView().getWindowToken(); |
+ } |
+ |
+ // Don't bother to call back if there's no token anyway. |
+ if (token == null) return; |
+ |
+ synchronized (mClientLock) { |
+ ClientSet clients = mClients.get(cvc); |
+ if (clients == null) { |
+ // We no longer have any clients, so remove this observer. |
+ cvc.removeObserver(this); |
+ return; |
+ } |
+ |
+ for (DialogSurfaceWindowTokenProvider.Client client : clients) { |
+ client.onWindowToken(token); |
+ } |
+ } |
+ } |
+ |
+ // This will be called on the UI thread. |
+ @Override |
+ public void onDetachedFromWindowAndroid(ContentViewCore cvc) { |
+ synchronized (mClientLock) { |
+ ClientSet clients = mClients.get(cvc); |
+ if (clients == null) { |
+ // We no longer have any clients, so remove this observer. |
+ cvc.removeObserver(this); |
+ return; |
+ } |
+ |
+ for (DialogSurfaceWindowTokenProvider.Client client : clients) { |
+ client.onWindowToken(null); |
+ } |
+ } |
+ } |
+ |
+ // |client| is now a client of |cvc|, so that it receives future updates |
+ // about the window token for |cvc|'s activity. |
+ // This will be called on the UI thread. |
+ private void addClient(ContentViewCore cvc, DialogSurfaceWindowTokenProvider.Client client) { |
+ synchronized (mClientLock) { |
+ ClientSet clients = mClients.get(cvc); |
+ if (clients == null) { |
+ clients = new ClientSet(); |
+ mClients.put(cvc, clients); |
+ } |
+ clients.add(client); |
+ mReverseClients.put(client, cvc); |
+ } |
+ } |
+ |
+ // Look up the ContentViewCore for (rendererPid, renderFrameId), and call |
+ // back onContentViewCore with it and |client|. The callback will happen |
+ // on the browser UI thread. |
+ private static native void nativeCallBackWithContentViewCore(int rendererPid, int renderFrameId, |
+ DialogSurfaceWindowTokenProvider provider, |
+ DialogSurfaceWindowTokenProvider.Client client); |
+} |