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 |