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