Chromium Code Reviews| 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); |
| +} |