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

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

Powered by Google App Engine
This is Rietveld 408576698