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 |