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.app.Dialog; | |
| 8 import android.content.Context; | |
| 9 import android.os.IBinder; | |
| 10 import android.view.Surface; | |
| 11 import android.view.Window; | |
| 12 | |
| 13 import org.chromium.base.ContextUtils; | |
| 14 import org.chromium.base.ThreadUtils; | |
| 15 import org.chromium.gfx.mojom.Rect; | |
| 16 import org.chromium.media.mojom.AndroidOverlay; | |
| 17 import org.chromium.media.mojom.AndroidOverlayClient; | |
| 18 import org.chromium.media.mojom.AndroidOverlayConfig; | |
| 19 import org.chromium.mojo.system.MojoException; | |
| 20 | |
| 21 /** | |
| 22 * Default AndroidOverlay impl. Uses a separate (shared) overlay thread to own a Dialog instance, | |
| 23 * probably via a separate object that operates only on that thread. We will po st messages to / | |
| 24 * from that thread from the main thread. | |
| 25 */ | |
| 26 public class DialogOverlayImpl implements AndroidOverlay, DialogOverlayCore.Host , | |
| 27 DialogOverlayOperations.WindowTokenLis tener { | |
| 28 private static final String TAG = "DialogOverlayImpl"; | |
| 29 | |
| 30 private final DialogOverlayOperations mOps; | |
| 31 private final ThreadHoppingHost mHoppingHost; | |
| 32 private AndroidOverlayClient mClient; | |
| 33 private DialogOverlayCore mDialogCore; | |
| 34 | |
| 35 // If nonzero, then we have registered a surface with this ID. | |
| 36 private int mSurfaceId; | |
| 37 | |
| 38 /** | |
| 39 * @param client Mojo client interface. | |
| 40 * @param config initial overlay configuration. | |
| 41 * @param handler handler that posts to the overlay thread. This is the and roid UI thread that | |
| 42 * the dialog uses, not the browser UI thread. | |
| 43 * @param provider the overlay provider that owns us. | |
| 44 */ | |
| 45 public DialogOverlayImpl(AndroidOverlayClient client, final AndroidOverlayCo nfig config, | |
| 46 DialogOverlayOperations ops) { | |
| 47 ThreadUtils.assertOnUiThread(); | |
| 48 | |
| 49 mClient = client; | |
| 50 mOps = ops; | |
| 51 mDialogCore = new DialogOverlayCore(); | |
| 52 mHoppingHost = new ThreadHoppingHost(this); | |
| 53 | |
| 54 // Post init to the overlay thread. | |
| 55 final DialogOverlayCore dialogCore = mDialogCore; | |
| 56 final Context context = ContextUtils.getApplicationContext(); | |
| 57 mOps.getOverlayHandler().post(new Runnable() { | |
| 58 @Override | |
| 59 public void run() { | |
| 60 // Create the dialog, but don't lay it out or show it yet. |dia logCore| will do | |
| 61 // that when we get a window token. | |
| 62 Dialog dialog = new Dialog(context, android.R.style.Theme_NoDisp lay); | |
|
boliu
2017/04/22 00:22:43
do this stuff in dialogcore? seems odd this is her
liberato (no reviews please)
2017/04/24 22:19:41
it was originally to allow DialogOverlayCoreTest t
| |
| 63 dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); | |
| 64 dialog.setCancelable(false); | |
| 65 dialogCore.initialize(dialog, config, mHoppingHost); | |
| 66 } | |
| 67 }); | |
| 68 | |
| 69 // Register to get token updates. | |
| 70 mOps.registerWindowTokenListener(config.routingToken, this); | |
| 71 } | |
| 72 | |
| 73 @Override | |
| 74 public void onSurfaceReady(Surface surface) { | |
| 75 ThreadUtils.assertOnUiThread(); | |
| 76 | |
| 77 if (mDialogCore == null || mClient == null) return; | |
| 78 | |
| 79 mSurfaceId = mOps.registerSurface(surface); | |
| 80 mClient.onSurfaceReady(mSurfaceId); | |
| 81 } | |
| 82 | |
| 83 @Override | |
| 84 public void onOverlayDestroyed() { | |
| 85 ThreadUtils.assertOnUiThread(); | |
| 86 | |
| 87 if (mDialogCore == null) return; | |
| 88 | |
| 89 // Notify the client that the overlay is gone. | |
| 90 if (mClient != null) mClient.onDestroyed(); | |
| 91 | |
| 92 // Also clear out |mDialogCore| to prevent us from sending useless messa ges to it. Note | |
| 93 // that we might have already sent useless messages to it, and it should be robust against | |
| 94 // that sort of thing. | |
| 95 cleanup(); | |
| 96 | |
| 97 // Note that we don't notify |mOps| yet, though we could. We wait for t he client to close | |
| 98 // their connection first. | |
| 99 } | |
| 100 | |
| 101 // Due to threading issues, |mHoppingHost| doesn't forward this. | |
| 102 @Override | |
| 103 public void waitForCleanup() { | |
| 104 assert false : "Not reached"; | |
| 105 } | |
| 106 | |
| 107 // Client is done with this overlay. | |
| 108 @Override | |
| 109 public void close() { | |
| 110 ThreadUtils.assertOnUiThread(); | |
| 111 | |
| 112 // TODO(liberato): verify that this actually works, else add an explicit shutdown and hope | |
| 113 // that the client calls it. | |
| 114 | |
| 115 // Allow surfaceDestroyed to proceed, if it's waiting. | |
| 116 mHoppingHost.onCleanup(); | |
| 117 | |
| 118 // Notify |mDialogCore| that it has been released. This might not be ca lled if it notifies | |
| 119 // us that it's been destroyed. We still might send it in that case if the client closes | |
| 120 // the connection before we find out that it's been destroyed on the ove rlay thread. | |
| 121 if (mDialogCore != null) { | |
| 122 final DialogOverlayCore dialogCore = mDialogCore; | |
| 123 mOps.getOverlayHandler().post(new Runnable() { | |
| 124 @Override | |
| 125 public void run() { | |
| 126 dialogCore.release(); | |
| 127 } | |
| 128 }); | |
| 129 | |
| 130 // Note that we might get messagaes from |mDialogCore| after this, s ince they might be | |
| 131 // dispatched before |r| arrives. Clearing |mDialogCore| causes us to ignore them. | |
| 132 cleanup(); | |
| 133 } | |
| 134 | |
| 135 // Notify the provider that we've been released by the client. Note tha t the surface might | |
| 136 // not have been destroyed yet, but that's okay. We could wait for a ca llback from the | |
| 137 // dialog core before proceeding, but this makes it easier for the clien t to destroy and | |
| 138 // re-create an overlay without worrying about an intermittent failure d ue to having too | |
| 139 // many overlays open at once. | |
| 140 mOps.notifyReleased(); | |
| 141 } | |
| 142 | |
| 143 private void sendWindowTokenToCore(final IBinder token) { | |
| 144 ThreadUtils.assertOnUiThread(); | |
| 145 | |
| 146 final DialogOverlayCore dialogCore = mDialogCore; | |
| 147 mOps.getOverlayHandler().post(new Runnable() { | |
| 148 @Override | |
| 149 public void run() { | |
| 150 dialogCore.onWindowToken(token); | |
| 151 } | |
| 152 }); | |
| 153 } | |
| 154 | |
| 155 @Override | |
| 156 public void onWindowToken(final IBinder token) { | |
|
boliu
2017/04/22 00:22:43
this class is implementing three interfaces, and i
liberato (no reviews please)
2017/04/24 22:19:42
i've merged Ops, so WindowTokenListener is gone no
| |
| 157 ThreadUtils.assertOnUiThread(); | |
| 158 | |
| 159 if (mDialogCore == null) return; | |
| 160 | |
| 161 // Forward this change. | |
| 162 // Note that if we don't have a window token, then we could wait until w e do, simply by | |
| 163 // skipping sending null if we haven't sent any non-null token yet. If we're transitioning | |
| 164 // between windows, that might make the client's job easier. It wouldn't have to guess when | |
| 165 // a new token is available. | |
| 166 sendWindowTokenToCore(token); | |
| 167 } | |
| 168 | |
| 169 @Override | |
| 170 public void onDismissed() { | |
| 171 ThreadUtils.assertOnUiThread(); | |
| 172 | |
| 173 // Notify the client that the overlay is going away. | |
| 174 if (mClient != null) mClient.onDestroyed(); | |
| 175 | |
| 176 // Notify |mDialogCore| that it lost the token, if it had one. | |
| 177 sendWindowTokenToCore(null); | |
| 178 | |
| 179 cleanup(); | |
| 180 } | |
| 181 | |
| 182 @Override | |
| 183 public void onConnectionError(MojoException e) { | |
| 184 ThreadUtils.assertOnUiThread(); | |
| 185 | |
| 186 close(); | |
| 187 } | |
| 188 | |
| 189 @Override | |
| 190 public void scheduleLayout(final Rect rect) { | |
| 191 ThreadUtils.assertOnUiThread(); | |
| 192 | |
| 193 if (mDialogCore == null) return; | |
| 194 | |
| 195 final DialogOverlayCore dialogCore = mDialogCore; | |
| 196 mOps.getOverlayHandler().post(new Runnable() { | |
| 197 @Override | |
| 198 public void run() { | |
| 199 dialogCore.layoutSurface(rect); | |
| 200 } | |
| 201 }); | |
| 202 } | |
| 203 | |
| 204 /** | |
| 205 * Unregister for callbacks, unregister any surface that we have, and forget about | |
| 206 * |mDialogCore|. Multiple calls are okay. | |
| 207 */ | |
| 208 private void cleanup() { | |
| 209 ThreadUtils.assertOnUiThread(); | |
| 210 | |
| 211 if (mSurfaceId != 0) { | |
| 212 mOps.unregisterSurface(mSurfaceId); | |
| 213 mSurfaceId = 0; | |
| 214 } | |
| 215 | |
| 216 // Note that we might not be registered for a token. | |
| 217 mOps.unregisterWindowTokenListenerIfNeeded(); | |
| 218 | |
| 219 // Also clear out |mDialogCore| to prevent us from sending useless messa ges to it. Note | |
| 220 // that we might have already sent useless messages to it, and it should be robust against | |
| 221 // that sort of thing. | |
| 222 mDialogCore = null; | |
| 223 | |
| 224 // If we wanted to send any message to |mClient|, we should have done so already. | |
| 225 mClient = null; | |
| 226 } | |
| 227 } | |
| OLD | NEW |