OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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; | |
6 | |
7 import android.app.Activity; | |
8 import android.os.IBinder; | |
9 | |
10 import org.chromium.base.annotations.CalledByNative; | |
11 import org.chromium.base.annotations.JNINamespace; | |
12 import org.chromium.media.DialogSurfaceWindowTokenProvider; | |
13 import org.chromium.ui.base.WindowAndroid; | |
14 | |
15 import java.util.HashMap; | |
16 import java.util.HashSet; | |
17 | |
18 /** | |
19 * Implementation of DialogSurfaceWindowTokenProvider. Asks ContentViewCore to | |
20 * provide updates on token changes. | |
21 */ | |
22 @JNINamespace("content") | |
23 public class DialogSurfaceWindowTokenProviderImpl | |
boliu
2017/01/04 23:14:39
I can see why the Manager is singleton, but I don'
liberato (no reviews please)
2017/01/11 22:17:56
most of the code is to look up WebContents given (
boliu
2017/01/12 20:24:18
You can put it in a static method or something.
liberato (no reviews please)
2017/02/03 21:28:32
per our offline discussion, this class is not in P
| |
24 implements DialogSurfaceWindowTokenProvider, ContentViewCore.Observer { | |
25 private static final String TAG = "cr_DialogSurfaceWTP"; | |
26 | |
27 private class ClientSet extends HashSet<DialogSurfaceWindowTokenProvider.Cli ent> {} | |
boliu
2017/01/04 01:48:43
these classes should be static
liberato (no reviews please)
2017/01/11 22:17:56
Done.
| |
28 private class ClientMap extends HashMap<ContentViewCore, ClientSet> {} | |
29 private class ReverseClientMap | |
30 extends HashMap<DialogSurfaceWindowTokenProvider.Client, ContentView Core> {} | |
31 | |
32 // Access |mClients| and |mReverseClients| with |mClientLock| held. These | |
33 // let us associate clients with the ContentViewCore that they're interested | |
34 // in listening to. | |
35 private final Object mClientLock = new Object(); | |
36 private final ClientMap mClients = new ClientMap(); | |
37 private final ReverseClientMap mReverseClients = new ReverseClientMap(); | |
38 | |
39 // This may be called on any thread. | |
40 @Override | |
41 public void registerClient( | |
42 int rendererPid, int renderFrameId, DialogSurfaceWindowTokenProvider .Client client) { | |
43 nativeCallBackWithContentViewCore(rendererPid, renderFrameId, this, clie nt); | |
44 } | |
45 | |
46 // This may be called on any thread. | |
47 @Override | |
48 public void unregisterClient(DialogSurfaceWindowTokenProvider.Client client) { | |
49 synchronized (mClientLock) { | |
50 unregisterClientLocked(client); | |
51 } | |
52 } | |
53 | |
54 // Unregister |client| for updates, with |mClientLock| held. This may be | |
55 // called on any thread. | |
56 private void unregisterClientLocked(DialogSurfaceWindowTokenProvider.Client client) { | |
57 // If we switched threads here, then we could remove mClientLock and | |
58 // also unregister for callbacks with CVC. | |
59 // Remove client from both the forward and reverse tables. | |
60 ContentViewCore cvc = mReverseClients.get(client); | |
61 if (cvc == null) return; | |
62 | |
63 mReverseClients.remove(client); | |
64 | |
65 ClientSet clients = mClients.get(cvc); | |
66 if (clients != null) { | |
67 clients.remove(client); | |
68 if (clients.size() == 0) { | |
69 // We can't cvc.removeObserver(this) here, since we can be on | |
70 // the wrong thread. Instead, simply ignore it and skip the | |
71 // callbacks if needed. We could probably remove it on the | |
72 // next callback, which will be on the correct thread. | |
73 // Do not post a remove, though, since we might re-attach in | |
74 // the interim. | |
75 mClients.remove(cvc); | |
76 } | |
77 } | |
78 } | |
79 | |
80 /** | |
81 * Receive a callback from native with a previously requested ContentViewCor e. | |
82 * This is called on the UI thread. | |
83 */ | |
84 @CalledByNative | |
85 private void onContentViewCore( | |
86 DialogSurfaceWindowTokenProvider.Client client, ContentViewCore cvc) { | |
87 IBinder token = null; | |
88 | |
89 if (cvc != null) { | |
90 WindowAndroid windowAndroid = cvc.getWindowAndroid(); | |
91 if (windowAndroid != null) { | |
92 token = windowAndroid.getWindowToken(); | |
93 } | |
94 | |
95 // Register to get updates about window changes, so that we know | |
96 // when the token changes. | |
97 // Note that we might actually already be a client of this, if we | |
98 // unregistered the last client for |cvc| and then a new one came | |
99 // along before we got around to unregistering. That's okay. We | |
100 // could prevent it, but it's not worth the book-keeping right now. | |
101 // We're the only observer anyway. | |
102 cvc.addObserver(this); | |
103 } | |
104 | |
105 client.onWindowToken(token); | |
106 addClient(cvc, client); | |
107 } | |
108 | |
109 // This will be called on the UI thread. | |
110 @Override | |
111 public void onContentViewCoreDestroyed(ContentViewCore cvc) { | |
112 synchronized (mClientLock) { | |
113 onContentViewCoreDestroyedLocked(cvc); | |
114 } | |
115 } | |
116 | |
117 private void onContentViewCoreDestroyedLocked(ContentViewCore cvc) { | |
118 ClientSet clients = mClients.get(cvc); | |
119 if (clients == null) return; | |
120 | |
121 // Why not just send back the CVC, and have the client manager setting | |
122 // up callbacks? It's only a little weird, because (a) media/ can't | |
123 // access ContentViewCore. So, we do it here. Plus, if we ever want | |
124 // to move the DialogSurface implementation into the gpu process, we'll | |
125 // be still running in the browser anyway. So, we do it here. | |
126 for (DialogSurfaceWindowTokenProvider.Client client : clients) { | |
127 mReverseClients.remove(client); | |
128 // We might want to notify them that the CVC was destroyed, | |
129 // rather than telling them that there's simply no token. | |
130 client.onWindowToken(null); | |
131 } | |
132 | |
133 mClients.remove(cvc); | |
134 } | |
135 | |
136 // This will be called on the UI thread. | |
137 @Override | |
138 public void onAttachedToWindowAndroid(ContentViewCore cvc) { | |
139 Activity activity = cvc.getWindowAndroid().getActivity().get(); | |
boliu
2017/01/04 23:14:39
call getWindowToken?
liberato (no reviews please)
2017/01/11 22:17:56
erm, good point.
| |
140 IBinder token = null; | |
141 if (activity != null) { | |
142 token = activity.getWindow().getDecorView().getRootView().getWindowT oken(); | |
143 } | |
144 | |
145 // Don't bother to call back if there's no token anyway. | |
146 if (token == null) return; | |
147 | |
148 synchronized (mClientLock) { | |
149 ClientSet clients = mClients.get(cvc); | |
150 if (clients == null) { | |
151 // We no longer have any clients, so remove this observer. | |
152 cvc.removeObserver(this); | |
153 return; | |
154 } | |
155 | |
156 for (DialogSurfaceWindowTokenProvider.Client client : clients) { | |
157 client.onWindowToken(token); | |
158 } | |
159 } | |
160 } | |
161 | |
162 // This will be called on the UI thread. | |
163 @Override | |
164 public void onDetachedFromWindowAndroid(ContentViewCore cvc) { | |
165 synchronized (mClientLock) { | |
166 ClientSet clients = mClients.get(cvc); | |
167 if (clients == null) { | |
168 // We no longer have any clients, so remove this observer. | |
169 cvc.removeObserver(this); | |
170 return; | |
171 } | |
172 | |
173 for (DialogSurfaceWindowTokenProvider.Client client : clients) { | |
174 client.onWindowToken(null); | |
175 } | |
176 } | |
177 } | |
178 | |
179 // |client| is now a client of |cvc|, so that it receives future updates | |
180 // about the window token for |cvc|'s activity. | |
181 // This will be called on the UI thread. | |
182 private void addClient(ContentViewCore cvc, DialogSurfaceWindowTokenProvider .Client client) { | |
183 synchronized (mClientLock) { | |
184 ClientSet clients = mClients.get(cvc); | |
185 if (clients == null) { | |
186 clients = new ClientSet(); | |
187 mClients.put(cvc, clients); | |
188 } | |
189 clients.add(client); | |
190 mReverseClients.put(client, cvc); | |
191 } | |
192 } | |
193 | |
194 // Look up the ContentViewCore for (rendererPid, renderFrameId), and call | |
195 // back onContentViewCore with it and |client|. The callback will happen | |
196 // on the browser UI thread. | |
197 private static native void nativeCallBackWithContentViewCore(int rendererPid , int renderFrameId, | |
198 DialogSurfaceWindowTokenProvider provider, | |
199 DialogSurfaceWindowTokenProvider.Client client); | |
200 } | |
OLD | NEW |