Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.content.browser.androidoverlay; | |
| 6 | |
| 7 import android.content.Context; | |
| 8 import android.os.Handler; | |
| 9 import android.os.IBinder; | |
| 10 import android.view.Surface; | |
| 11 | |
| 12 import org.chromium.base.ContextUtils; | |
| 13 import org.chromium.base.ThreadUtils; | |
| 14 import org.chromium.base.annotations.CalledByNative; | |
| 15 import org.chromium.base.annotations.JNINamespace; | |
| 16 import org.chromium.gfx.mojom.Rect; | |
| 17 import org.chromium.media.mojom.AndroidOverlay; | |
| 18 import org.chromium.media.mojom.AndroidOverlayClient; | |
| 19 import org.chromium.media.mojom.AndroidOverlayConfig; | |
| 20 import org.chromium.mojo.system.MojoException; | |
| 21 | |
| 22 /** | |
| 23 * Default AndroidOverlay impl. Uses a separate (shared) overlay thread to own a Dialog instance, | |
| 24 * probably via a separate object that operates only on that thread. We will po st messages to / | |
| 25 * from that thread from the UI thread. | |
| 26 */ | |
| 27 @JNINamespace("content") | |
| 28 public class DialogOverlayImpl implements AndroidOverlay, DialogOverlayCore.Host { | |
| 29 private static final String TAG = "DialogOverlayImpl"; | |
| 30 | |
| 31 private AndroidOverlayClient mClient; | |
| 32 private Handler mOverlayHandler; | |
| 33 // Runnable that we'll run when the overlay notifies us that it's been relea sed. | |
| 34 private Runnable mReleasedRunnable; | |
| 35 | |
| 36 private final ThreadHoppingHost mHoppingHost; | |
| 37 | |
| 38 private DialogOverlayCore mDialogCore; | |
| 39 | |
| 40 private long mNativeHandle; | |
| 41 | |
| 42 // If nonzero, then we have registered a surface with this ID. | |
| 43 private int mSurfaceId; | |
| 44 | |
| 45 /** | |
| 46 * @param client Mojo client interface. | |
| 47 * @param config initial overlay configuration. | |
| 48 * @param handler handler that posts to the overlay thread. This is the and roid UI thread that | |
| 49 * the dialog uses, not the browser UI thread. | |
| 50 * @param provider the overlay provider that owns us. | |
| 51 */ | |
| 52 public DialogOverlayImpl(AndroidOverlayClient client, final AndroidOverlayCo nfig config, | |
| 53 Handler overlayHandler, Runnable releasedRunnable) { | |
| 54 ThreadUtils.assertOnUiThread(); | |
| 55 | |
| 56 mClient = client; | |
| 57 mReleasedRunnable = releasedRunnable; | |
| 58 mOverlayHandler = overlayHandler; | |
| 59 | |
| 60 mDialogCore = new DialogOverlayCore(); | |
| 61 mHoppingHost = new ThreadHoppingHost(this); | |
| 62 | |
| 63 // Post init to the overlay thread. | |
| 64 final DialogOverlayCore dialogCore = mDialogCore; | |
| 65 final Context context = ContextUtils.getApplicationContext(); | |
| 66 mOverlayHandler.post(new Runnable() { | |
| 67 @Override | |
| 68 public void run() { | |
| 69 dialogCore.initialize(context, config, mHoppingHost); | |
| 70 } | |
| 71 }); | |
| 72 | |
| 73 // Register to get token updates. | |
| 74 mNativeHandle = nativeRegisterForTokens(config.routingToken.high, config .routingToken.low); | |
| 75 assert mNativeHandle != 0; | |
| 76 } | |
| 77 | |
| 78 // AndroidOverlay impl. | |
| 79 // Client is done with this overlay. | |
| 80 @Override | |
| 81 public void close() { | |
| 82 ThreadUtils.assertOnUiThread(); | |
| 83 | |
| 84 // TODO(liberato): verify that this actually works, else add an explicit shutdown and hope | |
| 85 // that the client calls it. | |
| 86 | |
| 87 // Allow surfaceDestroyed to proceed, if it's waiting. | |
| 88 mHoppingHost.onCleanup(); | |
| 89 | |
| 90 // Notify |mDialogCore| that it has been released. This might not be ca lled if it notifies | |
| 91 // us that it's been destroyed. We still might send it in that case if the client closes | |
| 92 // the connection before we find out that it's been destroyed on the ove rlay thread. | |
| 93 if (mDialogCore != null) { | |
| 94 final DialogOverlayCore dialogCore = mDialogCore; | |
| 95 mOverlayHandler.post(new Runnable() { | |
| 96 @Override | |
| 97 public void run() { | |
| 98 dialogCore.release(); | |
| 99 } | |
| 100 }); | |
| 101 | |
| 102 // Note that we might get messagaes from |mDialogCore| after this, s ince they might be | |
| 103 // dispatched before |r| arrives. Clearing |mDialogCore| causes us to ignore them. | |
| 104 cleanup(); | |
| 105 } | |
| 106 | |
| 107 // Notify the provider that we've been released by the client. Note tha t the surface might | |
| 108 // not have been destroyed yet, but that's okay. We could wait for a ca llback from the | |
| 109 // dialog core before proceeding, but this makes it easier for the clien t to destroy and | |
| 110 // re-create an overlay without worrying about an intermittent failure d ue to having too | |
| 111 // many overlays open at once. | |
| 112 mReleasedRunnable.run(); | |
| 113 } | |
| 114 | |
| 115 // AndroidOverlay impl. | |
| 116 @Override | |
| 117 public void onConnectionError(MojoException e) { | |
| 118 ThreadUtils.assertOnUiThread(); | |
| 119 | |
| 120 close(); | |
| 121 } | |
| 122 | |
| 123 // AndroidOverlay impl. | |
| 124 @Override | |
| 125 public void scheduleLayout(final Rect rect) { | |
| 126 ThreadUtils.assertOnUiThread(); | |
| 127 | |
| 128 if (mDialogCore == null) return; | |
| 129 | |
| 130 final DialogOverlayCore dialogCore = mDialogCore; | |
| 131 mOverlayHandler.post(new Runnable() { | |
| 132 @Override | |
| 133 public void run() { | |
| 134 dialogCore.layoutSurface(rect); | |
| 135 } | |
| 136 }); | |
| 137 } | |
| 138 | |
| 139 // DialogOverlayCore.Host impl. | |
| 140 // |surface| is now ready. Register it with the surface tracker, and notify the client. | |
| 141 @Override | |
| 142 public void onSurfaceReady(Surface surface) { | |
| 143 ThreadUtils.assertOnUiThread(); | |
| 144 | |
| 145 if (mDialogCore == null || mClient == null) return; | |
| 146 | |
| 147 mSurfaceId = nativeRegisterSurface(surface); | |
| 148 mClient.onSurfaceReady(mSurfaceId); | |
| 149 } | |
| 150 | |
| 151 // DialogOverlayCore.Host impl. | |
| 152 @Override | |
| 153 public void onOverlayDestroyed() { | |
| 154 ThreadUtils.assertOnUiThread(); | |
| 155 | |
| 156 if (mDialogCore == null) return; | |
| 157 | |
| 158 // Notify the client that the overlay is gone. | |
| 159 if (mClient != null) mClient.onDestroyed(); | |
| 160 | |
| 161 // Also clear out |mDialogCore| to prevent us from sending useless messa ges to it. Note | |
| 162 // that we might have already sent useless messages to it, and it should be robust against | |
| 163 // that sort of thing. | |
| 164 cleanup(); | |
| 165 | |
| 166 // Note that we don't notify |mReleasedRunnable| yet, though we could. We wait for the | |
| 167 // client to close their connection first. | |
| 168 } | |
| 169 | |
| 170 // DialogOverlayCore.Host impl. | |
| 171 // Due to threading issues, |mHoppingHost| doesn't forward this. | |
| 172 @Override | |
| 173 public void waitForCleanup() { | |
| 174 assert false : "Not reached"; | |
| 175 } | |
| 176 | |
| 177 /** | |
| 178 * Send |token| to the |mDialogCore| on the overlay thread. | |
| 179 */ | |
| 180 private void sendWindowTokenToCore(final IBinder token) { | |
| 181 ThreadUtils.assertOnUiThread(); | |
| 182 | |
| 183 final DialogOverlayCore dialogCore = mDialogCore; | |
| 184 mOverlayHandler.post(new Runnable() { | |
| 185 @Override | |
| 186 public void run() { | |
| 187 dialogCore.onWindowToken(token); | |
| 188 } | |
| 189 }); | |
| 190 } | |
| 191 | |
| 192 /** | |
| 193 * Callback from native that the window token has changed. | |
| 194 */ | |
| 195 @CalledByNative | |
| 196 public void onWindowToken(final IBinder token) { | |
| 197 ThreadUtils.assertOnUiThread(); | |
| 198 | |
| 199 if (mDialogCore == null) return; | |
| 200 | |
| 201 // Forward this change. | |
| 202 // Note that if we don't have a window token, then we could wait until w e do, simply by | |
| 203 // skipping sending null if we haven't sent any non-null token yet. If we're transitioning | |
| 204 // between windows, that might make the client's job easier. It wouldn't have to guess when | |
| 205 // a new token is available. | |
| 206 sendWindowTokenToCore(token); | |
| 207 } | |
| 208 | |
| 209 /** | |
| 210 * Callback from native that we will be getting no additional tokens. | |
| 211 */ | |
| 212 @CalledByNative | |
| 213 public void onDismissed() { | |
| 214 ThreadUtils.assertOnUiThread(); | |
| 215 | |
| 216 // Notify the client that the overlay is going away. | |
| 217 if (mClient != null) mClient.onDestroyed(); | |
| 218 | |
| 219 // Notify |mDialogCore| that it lost the token, if it had one. | |
| 220 sendWindowTokenToCore(null); | |
| 221 | |
| 222 cleanup(); | |
| 223 } | |
| 224 | |
| 225 /** | |
| 226 * Unregister for callbacks, unregister any surface that we have, and forget about | |
| 227 * |mDialogCore|. Multiple calls are okay. | |
| 228 */ | |
| 229 private void cleanup() { | |
| 230 ThreadUtils.assertOnUiThread(); | |
| 231 | |
| 232 if (mSurfaceId != 0) { | |
| 233 nativeUnregisterSurface(mSurfaceId); | |
| 234 mSurfaceId = 0; | |
| 235 } | |
| 236 | |
| 237 // Note that we might not be registered for a token. | |
| 238 if (mNativeHandle != 0) { | |
| 239 nativeUnregisterForTokens(mNativeHandle); | |
| 240 mNativeHandle = 0; | |
| 241 } | |
| 242 | |
| 243 // Also clear out |mDialogCore| to prevent us from sending useless messa ges to it. Note | |
| 244 // that we might have already sent useless messages to it, and it should be robust against | |
| 245 // that sort of thing. | |
| 246 mDialogCore = null; | |
| 247 | |
| 248 // If we wanted to send any message to |mClient|, we should have done so already. | |
| 249 mClient = null; | |
| 250 } | |
| 251 | |
| 252 /** | |
| 253 * Initializes native side. Will register for onWindowToken callbacks on |t his|. Returns a | |
| 254 * handle that should be provided to nativeUnregisterForTokens. | |
| 255 */ | |
| 256 private native long nativeRegisterForTokens(long high, long low); | |
|
boliu
2017/04/26 00:19:08
maybe should rename these to make it should like j
liberato (no reviews please)
2017/04/26 17:26:35
Done.
| |
| 257 | |
| 258 /** | |
| 259 * Stops native side and deallocates |handle|. | |
| 260 */ | |
| 261 private static native void nativeUnregisterForTokens(long handle); | |
|
boliu
2017/04/26 00:19:08
if you name the parameter "long nativeDialogOverla
liberato (no reviews please)
2017/04/26 17:26:35
Done.
| |
| 262 | |
| 263 /** | |
| 264 * Register a surface and return the surface id for it. | |
| 265 * @param surface Surface that we should register. | |
| 266 * @return surface id that we associated with |surface|. | |
| 267 */ | |
| 268 private static native int nativeRegisterSurface(Surface surface); | |
| 269 | |
| 270 /** | |
| 271 * Unregister a surface. | |
| 272 * @param surfaceId Id that was returned by registerSurface. | |
| 273 */ | |
| 274 private static native void nativeUnregisterSurface(int surfaceId); | |
| 275 } | |
| OLD | NEW |