Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/androidoverlay/DialogOverlayCore.java

Issue 2765443004: AndroidOverlay implementation using Dialog. (Closed)
Patch Set: fixed test Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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.annotation.SuppressLint;
8 import android.app.Dialog;
9 import android.content.Context;
10 import android.os.IBinder;
11 import android.view.Gravity;
12 import android.view.Surface;
13 import android.view.SurfaceHolder;
14 import android.view.Window;
15 import android.view.WindowManager;
16
17 import org.chromium.gfx.mojom.Rect;
18 import org.chromium.media.mojom.AndroidOverlayConfig;
19
20 /**
21 * Core class for control of a single Dialog-based AndroidOverlay instance. Eve rything runs on the
22 * overlay thread, which is not the Browser UI thread.
23 *
24 * Note that this does not implement AndroidOverlay; we assume that, and the ass ociated thread-
25 * hopping, is handled elsewhere (DialogOverlayImpl).
26 */
27 class DialogOverlayCore {
28 private static final String TAG = "DSCore";
29
30 // Host interface, since we're on the wrong thread to talk to mojo, or anyth ing else, really.
31 public interface Host {
32 // Notify the host that we have a surface.
33 void onSurfaceReady(Surface surface);
34
35 // Notify the host that we have failed to get a surface or the surface w as destroyed.
36 void onOverlayDestroyed();
37
38 // Wait until the host has been told to clean up. We are allowed to let surfaceDestroyed
39 // proceed once this happens.
40 void waitForCleanup();
41 }
42
43 private Host mHost;
44
45 // When initialized via Init, we'll create mDialog. We'll clear it when we send
46 // onOverlayDestroyed to the host. In general, when this is null, either we haven't been
47 // initialized yet, or we've been torn down. It shouldn't be the case that anything calls
48 // methods after construction but before |initialize()|, though.
49 private Dialog mDialog;
50
51 private Callbacks mDialogCallbacks;
52
53 // Most recent layout parameters.
54 private WindowManager.LayoutParams mLayoutParams;
55
56 /**
57 * Construction may be called from a random thread, for simplicity. Call in itialize from the
58 * proper thread before doing anything else.
59 */
60 public DialogOverlayCore() {}
61
62 /**
63 * Finish init on the proper thread. We'll use this thread for the Dialog L ooper thread.
64 * @param dialog the dialog, which uses our current thread as the UI thread.
65 * @param config initial config.
66 * @param host host interface, for sending messages that (probably) need to thread hop.
67 */
68 public void initialize(Context context, AndroidOverlayConfig config, Host ho st) {
69 mHost = host;
70
71 mDialog = new Dialog(context, android.R.style.Theme_NoDisplay);
72 mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
73 mDialog.setCancelable(false);
74
75 mLayoutParams = createLayoutParams(config.secure);
76 copyRectToLayoutParams(config.rect);
77 }
78
79 /**
80 * Release the underlying surface, and generally clean up, in response to
81 * the client releasing the AndroidOverlay.
82 */
83 public void release() {
84 // If we've not released the dialog yet, then do so.
85 if (mDialog != null) {
86 if (mDialog.isShowing()) mDialog.dismiss();
87 mDialog = null;
88 mDialogCallbacks = null;
89 }
90
91 mLayoutParams.token = null;
92
93 // We don't bother to notify |mHost| that we've been destroyed; it told us.
94 mHost = null;
95 }
96
97 private void copyRectToLayoutParams(final Rect rect) {
98 // TODO(liberato): adjust for CompositorView screen location here if we want to support
99 // non-full screen use cases.
100 mLayoutParams.x = rect.x;
101 mLayoutParams.y = rect.y;
102 mLayoutParams.width = rect.width;
103 mLayoutParams.height = rect.height;
104 }
105
106 /**
107 * Layout the AndroidOverlay. If we don't have a token, then we ignore it, since a well-behaved
108 * client shouldn't call us before getting the surface anyway.
109 */
110 public void layoutSurface(final Rect rect) {
111 if (mDialog == null || mLayoutParams.token == null) return;
112
113 copyRectToLayoutParams(rect);
114 mDialog.getWindow().setAttributes(mLayoutParams);
115 }
116
117 /**
118 * Callbacks for finding out about the Dialog's Surface.
119 * These happen on the looper thread.
120 */
121 private class Callbacks implements SurfaceHolder.Callback2 {
122 @Override
123 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
124
125 @Override
126 public void surfaceCreated(SurfaceHolder holder) {
127 // Make sure that we haven't torn down the dialog yet.
128 if (mDialog == null) return;
129
130 if (mHost != null) mHost.onSurfaceReady(holder.getSurface());
131 }
132
133 @Override
134 public void surfaceDestroyed(SurfaceHolder holder) {
135 if (mDialog == null || mHost == null) return;
136
137 // Notify the host that we've been destroyed, and wait for it to cle an up.
138 mHost.onOverlayDestroyed();
139 mHost.waitForCleanup();
140 mHost = null;
141 }
142
143 @Override
144 public void surfaceRedrawNeeded(SurfaceHolder holder) {}
145 }
146
147 public void onWindowToken(IBinder token) {
148 if (mDialog == null || mHost == null) return;
149
150 if (token == null || (mLayoutParams.token != null && token != mLayoutPar ams.token)) {
151 // We've lost the token, if we had one, or we got a new one.
152 // Notify the client.
153 mHost.onOverlayDestroyed();
154 mHost = null;
155 if (mDialog.isShowing()) mDialog.dismiss();
156 return;
157 }
158
159 if (mLayoutParams.token == token) {
160 // Same token, do nothing.
161 return;
162 }
163
164 // We have a token, so layout the dialog.
165 mLayoutParams.token = token;
166 mDialog.getWindow().setAttributes(mLayoutParams);
167 mDialogCallbacks = new Callbacks();
168 mDialog.getWindow().takeSurface(mDialogCallbacks);
169 mDialog.show();
170
171 // We don't notify the client here. We'll wait until the Android Surfac e is created.
172 }
173
174 @SuppressLint("RtlHardcoded")
175 private WindowManager.LayoutParams createLayoutParams(boolean secure) {
176 // Rather than using getAttributes, we just create them from scratch.
177 // The default dialog attributes aren't what we want.
178 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams ();
179
180 // NOTE: we really do want LEFT here, since we're dealing in compositor
181 // coordinates. Those are always from the left.
182 layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
183
184 // Use a media surface, which is what SurfaceView uses by default. For
185 // debugging overlay drawing, consider using TYPE_APPLICATION_PANEL to
186 // move the dialog over the CompositorView.
187 layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
188
189 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
190 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
191 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
192 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
193
194 if (secure) {
195 layoutParams.flags |= WindowManager.LayoutParams.FLAG_SECURE;
196 }
197
198 // Don't set FLAG_SCALED. in addition to not being sure what it does
199 // (SV uses it), it also causes a crash in WindowManager when we hide
200 // (not dismiss), navigate, and/or exit the app without hide/dismiss.
201 // There's a missing null check in WindowManagerService.java@3170
202 // on M MR2. To repro, change dimiss() to hide(), bring up a SV, and
203 // navigate away or press home.
204
205 // Turn off the position animation, so that it doesn't animate from one
206 // position to the next. Ignore errors.
207 // 0x40 is PRIVATE_FLAG_NO_MOVE_ANIMATION.
208 try {
209 int currentFlags =
210 (Integer) layoutParams.getClass().getField("privateFlags").g et(layoutParams);
211 layoutParams.getClass()
212 .getField("privateFlags")
213 .set(layoutParams, currentFlags | 0x00000040);
214 // It would be nice to just catch Exception, but findbugs doesn't
215 // allow it. If we cannot set the flag, then that's okay too.
216 } catch (NoSuchFieldException e) {
217 } catch (NullPointerException e) {
218 } catch (SecurityException e) {
219 } catch (IllegalAccessException e) {
220 } catch (IllegalArgumentException e) {
221 } catch (ExceptionInInitializerError e) {
222 }
223
224 return layoutParams;
225 }
226
227 /**
228 * Package-private to retrieve our current dialog for tests.
229 */
230 Dialog getDialog() {
231 return mDialog;
232 }
233 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698