| Index: content/public/android/java/src/org/chromium/content/browser/DialogSurfaceActivityMapper.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/DialogSurfaceActivityMapper.java b/content/public/android/java/src/org/chromium/content/browser/DialogSurfaceActivityMapper.java
|
| index 915b20c04e486a3128cbeacd2ea8bd60b69bd3ca..61e76cf623d1538403742a5056d4798965e2c3f4 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/DialogSurfaceActivityMapper.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/DialogSurfaceActivityMapper.java
|
| @@ -10,10 +10,12 @@ import android.os.RemoteException;
|
|
|
| import org.chromium.base.Log;
|
| import org.chromium.base.annotations.CalledByNative;
|
| -import org.chromium.base.Log;
|
| import org.chromium.media.IDialogSurfaceActivityMapper;
|
| import org.chromium.media.IDialogSurfaceHolder;
|
|
|
| +import java.util.HashMap;
|
| +import java.util.HashSet;
|
| +
|
| /**
|
| * Implementation of IDialogSurfaceActivityMapper.
|
| * Note that this doesn't have to be exposed via binder if the surfaces are
|
| @@ -21,16 +23,53 @@ import org.chromium.media.IDialogSurfaceHolder;
|
| * process, since that's where the information about the activity is.
|
| * Provided by ChildProcessLauncher to DialogSurfaceManager.
|
| */
|
| -public class DialogSurfaceActivityMapper extends IDialogSurfaceActivityMapper.Stub {
|
| +public class DialogSurfaceActivityMapper
|
| + extends IDialogSurfaceActivityMapper.Stub implements ContentViewCore.Observer {
|
| private static final String TAG = "cr_DialogSurfaceAM";
|
|
|
| + private class ClientSet extends HashSet<IDialogSurfaceHolder> {}
|
| + private class ClientMap extends HashMap<ContentViewCore, ClientSet> {}
|
| + private class ReverseClientMap extends HashMap<IDialogSurfaceHolder, ContentViewCore> {}
|
| + // Access mClients with mClientLock held.
|
| + 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 postWindowToken(int rendererPid, int renderFrameId, IDialogSurfaceHolder holder) {
|
| + public void registerHolder(int rendererPid, int renderFrameId, IDialogSurfaceHolder holder) {
|
| nativeCallBackWithContentViewCore(rendererPid, renderFrameId, this, holder);
|
| }
|
|
|
| + // This may be called on any thread.
|
| + @Override
|
| + public void unregisterHolder(IDialogSurfaceHolder holder) {
|
| + // If we switched threads here, then we could remove mClientLock and
|
| + // also unregister for callbacks with CVC.
|
| + synchronized (mClientLock) {
|
| + // Remove holder from both the forward and reverse tables.
|
| + ContentViewCore cvc = mReverseClients.get(holder);
|
| + if (cvc == null) return;
|
| +
|
| + mReverseClients.remove(holder);
|
| +
|
| + ClientSet clients = mClients.get(cvc);
|
| + if (clients != null) {
|
| + clients.remove(holder);
|
| + if (clients.size() == 0) {
|
| + // We could cvc.removeObserver(this) here, but we're 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.
|
| + mClients.remove(cvc);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| /**
|
| * Receive a callback from native with a previously requested ContentViewCore.
|
| + * This is called on the UI thread.
|
| */
|
| @CalledByNative
|
| private void onContentViewCore(IDialogSurfaceHolder holder, ContentViewCore cvc) {
|
| @@ -41,15 +80,94 @@ public class DialogSurfaceActivityMapper extends IDialogSurfaceActivityMapper.St
|
| if (activity != null) {
|
| token = activity.getWindow().getDecorView().getRootView().getWindowToken();
|
| }
|
| +
|
| + // Register to get updates about window changes, so that we know
|
| + // when the token changes.
|
| + cvc.addObserver(this);
|
| }
|
|
|
| try {
|
| holder.onWindowToken(token);
|
| + addClient(cvc, holder);
|
| + // TODO(liberato): clean up if holder exits.
|
| } catch (RemoteException e) {
|
| Log.e(TAG, "Unable to post token " + token + " to DialogSurfaceHolder", e);
|
| }
|
| }
|
|
|
| + // This will be called on the UI thread.
|
| + @Override
|
| + public void onContentViewCoreDestroyed(ContentViewCore cvc) {
|
| + ClientSet clients = mClients.get(cvc);
|
| + if (clients == null) return;
|
| +
|
| + // Why not just send back the CVC, and have the holder manager setting
|
| + // up callbacks? It's only a little weird, because (a) media/ can't
|
| + // access ContentViewCore, and (b) we're guaranteed to run in the
|
| + // browser, while DialogSurface might not.
|
| + for (IDialogSurfaceHolder holder : clients) {
|
| + try {
|
| + holder.onWindowToken(null);
|
| + } catch (RemoteException e) {
|
| + }
|
| + }
|
| +
|
| + mClients.remove(cvc);
|
| + }
|
| +
|
| + // This will be called on the UI thread.
|
| + @Override
|
| + public void onAttachedToWindowAndroid(ContentViewCore cvc) {
|
| + Activity activity = cvc.getWindowAndroid().getActivity().get();
|
| + 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) return;
|
| +
|
| + for (IDialogSurfaceHolder holder : clients) {
|
| + try {
|
| + holder.onWindowToken(token);
|
| + } catch (RemoteException e) {
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + // This will be called on the UI thread.
|
| + @Override
|
| + public void onDetachedFromWindowAndroid(ContentViewCore cvc) {
|
| + synchronized (mClientLock) {
|
| + ClientSet clients = mClients.get(cvc);
|
| + if (clients == null) return;
|
| +
|
| + for (IDialogSurfaceHolder holder : clients) {
|
| + try {
|
| + holder.onWindowToken(null);
|
| + } catch (RemoteException e) {
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + private void addClient(ContentViewCore cvc, IDialogSurfaceHolder holder) {
|
| + synchronized (mClientLock) {
|
| + ClientSet clients = mClients.get(cvc);
|
| + if (clients == null) {
|
| + clients = new ClientSet();
|
| + mClients.put(cvc, clients);
|
| + }
|
| + clients.add(holder);
|
| + mReverseClients.put(holder, cvc);
|
| + }
|
| + }
|
| +
|
| // Look up the ContentViewCore for (rendererPid, renderFrameId), and call
|
| // back onContentViewCore with it and |holder|. The callback will happen
|
| // on the browser UI thread.
|
|
|