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

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: removed a TODO that wouldn't work 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 Dialog dialog = new Dialog(context, android.R.style.Theme_NoDisplay);
72 dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
73 dialog.setCancelable(false);
74
75 mLayoutParams = createLayoutParams(config.secure);
76 layoutSurface(config.rect);
77
78 // Set this after calling layoutSurface(), so that it doesn't try to use it. We haven't
79 // shown |dialog| yet!
80 mDialog = dialog;
81 }
82
83 /**
84 * Release the underlying surface, and generally clean up, in response to
85 * the client releasing the AndroidOverlay.
86 */
87 public void release() {
88 // If we've not released the dialog yet, then do so.
89 if (mDialog != null) {
90 if (mDialog.isShowing()) mDialog.dismiss();
91 mDialog = null;
92 mDialogCallbacks = null;
93 }
94
95 mLayoutParams.token = null;
96
97 // We don't bother to notify |mHost| that we've been destroyed; it told us.
98 mHost = null;
99 }
100
101 /**
102 * Layout the AndroidOverlay. If we don't have a token, then we ignore it, since a well-behaved
103 * client shouldn't call us before getting the surface anyway.
104 */
105 public void layoutSurface(final Rect rect) {
106 if (mDialog == null || mLayoutParams.token == null) return;
107
108 // TODO(liberato): adjust for CompositorView screen location here if we want to support
109 // non-full screen use cases.
110 mLayoutParams.x = rect.x;
111 mLayoutParams.y = rect.y;
112 mLayoutParams.width = rect.width;
113 mLayoutParams.height = rect.height;
114
115 mDialog.getWindow().setAttributes(mLayoutParams);
116 }
117
118 /**
119 * Callbacks for finding out about the Dialog's Surface.
120 * These happen on the looper thread.
121 */
122 private class Callbacks implements SurfaceHolder.Callback2 {
123 @Override
124 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
125
126 @Override
127 public void surfaceCreated(SurfaceHolder holder) {
128 // Make sure that we haven't torn down the dialog yet.
129 if (mDialog == null) return;
130
131 if (mHost != null) mHost.onSurfaceReady(holder.getSurface());
132 }
133
134 @Override
135 public void surfaceDestroyed(SurfaceHolder holder) {
136 if (mDialog == null || mHost == null) return;
137
138 // Notify the host that we've been destroyed, and wait for it to cle an up.
139 mHost.onOverlayDestroyed();
140 mHost.waitForCleanup();
141 mHost = null;
142 }
143
144 @Override
145 public void surfaceRedrawNeeded(SurfaceHolder holder) {}
146 }
147
148 public void onWindowToken(IBinder token) {
149 if (mDialog == null || mHost == null) return;
150
151 if (token == null || (mLayoutParams.token != null && token != mLayoutPar ams.token)) {
152 // We've lost the token, if we had one, or we got a new one.
153 // Notify the client.
154 mHost.onOverlayDestroyed();
155 mHost = null;
156 if (mDialog.isShowing()) mDialog.dismiss();
157 return;
158 }
159
160 if (mLayoutParams.token == token) {
161 // Same token, do nothing.
162 return;
163 }
164
165 // We have a token, so layout the dialog.
166 mLayoutParams.token = token;
167 mDialog.getWindow().setAttributes(mLayoutParams);
168 mDialogCallbacks = new Callbacks();
169 mDialog.getWindow().takeSurface(mDialogCallbacks);
170 mDialog.show();
171
172 // We don't notify the client here. We'll wait until the Android Surfac e is created.
173 }
174
175 @SuppressLint("RtlHardcoded")
176 private WindowManager.LayoutParams createLayoutParams(boolean secure) {
177 // Rather than using getAttributes, we just create them from scratch.
178 // The default dialog attributes aren't what we want.
179 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams ();
180
181 // NOTE: we really do want LEFT here, since we're dealing in compositor
182 // coordinates. Those are always from the left.
183 layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
184
185 // Use a media surface, which is what SurfaceView uses by default. For
186 // debugging overlay drawing, consider using TYPE_APPLICATION_PANEL to
187 // move the dialog over the CompositorView.
188 layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
189
190 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
191 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
192 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
193 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
194
195 if (secure) {
196 layoutParams.flags |= WindowManager.LayoutParams.FLAG_SECURE;
197 }
198
199 // Don't set FLAG_SCALED. in addition to not being sure what it does
200 // (SV uses it), it also causes a crash in WindowManager when we hide
201 // (not dismiss), navigate, and/or exit the app without hide/dismiss.
202 // There's a missing null check in WindowManagerService.java@3170
203 // on M MR2. To repro, change dimiss() to hide(), bring up a SV, and
204 // navigate away or press home.
205
206 // Turn off the position animation, so that it doesn't animate from one
207 // position to the next. Ignore errors.
208 // 0x40 is PRIVATE_FLAG_NO_MOVE_ANIMATION.
209 try {
210 int currentFlags =
211 (Integer) layoutParams.getClass().getField("privateFlags").g et(layoutParams);
212 layoutParams.getClass()
213 .getField("privateFlags")
214 .set(layoutParams, currentFlags | 0x00000040);
215 // It would be nice to just catch Exception, but findbugs doesn't
216 // allow it. If we cannot set the flag, then that's okay too.
217 } catch (NoSuchFieldException e) {
218 } catch (NullPointerException e) {
219 } catch (SecurityException e) {
220 } catch (IllegalAccessException e) {
221 } catch (IllegalArgumentException e) {
222 } catch (ExceptionInInitializerError e) {
223 }
224
225 return layoutParams;
226 }
227
228 /**
229 * Package-private to retrieve our current dialog for tests.
230 */
231 Dialog getDialog() {
232 return mDialog;
233 }
234 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698