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

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

Issue 2178973004: DialogSurfaceManager implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cleanup Created 3 years, 10 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.SurfaceHolder;
13 import android.view.Window;
14 import android.view.WindowManager;
15
16 import org.chromium.base.Log;
17 import org.chromium.media.IAndroidOverlayCallback;
18 import org.chromium.media.IAndroidOverlayCompletion;
19
20 import java.util.concurrent.Semaphore;
21
22 /**
23 * Core class for control of a single AndroidOverlay instance. Everything runs
24 * on a single thread, that's probably not the UI thread.
25 *
26 * Note that this does not implement IAndroidOverlay; we assume that, and the
27 * associated thread-hopping, is handled elsewhere.
28 */
29 class DialogAndroidOverlayCore {
30 private static final String TAG = "DSCore";
31
32 /**
33 * Call back into native with a message about our state. This can be called
34 * on any thread. It's okay if it refers to a native object that no longer
35 * exists; we can't really avoid it. The native side handles it.
36 *
37 * The callback cannot recursively call back into us; the IAndroidOverlay
38 * implementation must prevent that.
39 */
40 private IAndroidOverlayCallback mClientCallback;
41
42 // Callback to let DialogAndroidOverlay know that we've shut down. Sometime s, we call this in
43 // response to it telling us to shut down, but sometimes we start shutdown.
44 private Runnable mReleaseCallback;
45
46 // Callback operations.
47 // These must match dialog_surface.h .
48 private static final int OP_CREATED = 0;
49 private static final int OP_DESTROYED = 1;
50
51 // When initialized via Init, we'll create mDialog. We'll clear it when
52 // we send SURFACE_DESTROYED to the client. In general, when this is null,
53 // either we haven't been initialized yet, or we've been torn down. It
54 // shouldn't be the case that anything calls methods after construction but
55 // before Init, though.
56 private Dialog mDialog;
57
58 private Callbacks mDialogCallbacks;
59
60 // Most recent layout parameters.
61 private WindowManager.LayoutParams mLayoutParams;
62
63 /**
64 * Construction may be called from a random thread, for simplicity. Call
65 * Init from the proper thread before doing anything else.
66 */
67 public DialogAndroidOverlayCore() {}
68
69 /**
70 * Finish init on the proper thread. We'll use this thread for the Dialog
71 * Looper thread.
72 * @param context Context that we use.
73 * @param callback callback object to notify about state changes.
74 * @param x initial x position in chrome compositor (not screen) coords.
75 * @param y initial y position in chrome compositor (not screen) coords.
76 * @param width initial width.
77 * @param height initial height.
78 */
79 public void initialize(Context context, IAndroidOverlayCallback callback, in t x, int y,
80 int width, int height, Runnable releaseCallback) {
81 mClientCallback = callback;
82 mLayoutParams = createLayoutParams();
83 mReleaseCallback = releaseCallback;
84 layoutSurface(x, y, width, height);
85
86 // Create the dialog, but don't lay it out or show it yet. We'll do
87 // that when we get a window token.
88 mDialog = new Dialog(context, android.R.style.Theme_NoDisplay);
89 mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
90 mDialog.setCancelable(false);
91 }
92
93 /**
94 * Release the underlying surface, and generally clean up, in response to
95 * the client releasing the IAndroidOverlay.
96 */
97 public void release() {
98 // If we've not released the dialog yet, then do so.
99 if (mDialog != null) {
100 // TODO(liberato): is this safe if we haven't shown the dialog yet?
101 mDialog.dismiss();
102 mDialog = null;
103 mDialogCallbacks = null;
104 }
105
106 mLayoutParams.token = null;
107
108 if (mReleaseCallback != null) {
109 mReleaseCallback.run();
110 mReleaseCallback = null;
111 }
112 }
113
114 /**
115 * Layout the AndroidOverlay. If we don't have a token, then we ignore it,
116 * since a well-behaved client shouldn't call us before OP_CREATED anyway.
117 */
118 public void layoutSurface(final int x, final int y, final int width, final i nt height) {
119 // TODO(liberato): adjust for CompositorView screen location here if we
120 // want to support non-full screen use cases.
121 mLayoutParams.x = x;
122 mLayoutParams.y = y;
123 mLayoutParams.width = width;
124 mLayoutParams.height = height;
125
126 if (mDialog == null || mLayoutParams.token == null) return;
127
128 mDialog.getWindow().setAttributes(mLayoutParams);
129 }
130
131 /**
132 * Callbacks for finding out about the Dialog's Surface.
133 * These happen on the looper thread.
134 */
135 private class Callbacks implements SurfaceHolder.Callback2 {
136 @Override
137 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
138
139 @Override
140 public void surfaceCreated(SurfaceHolder holder) {
141 // Make sure that we haven't torn down the dialog yet.
142 if (mDialog == null) return;
143
144 try {
145 mClientCallback.onCreated(holder.getSurface());
146 } catch (Exception e) {
147 Log.d(TAG, "surfaceCreated: callback failed: " + e);
148 enterDestroyedState();
149 }
150 }
151
152 private class CompletionCallback extends IAndroidOverlayCompletion.Stub {
153 private Semaphore mSemaphore = new Semaphore(0);
154
155 @Override
156 public void signalComplete() {
157 mSemaphore.release(1);
158 }
159
160 public void waitForSignal() {
161 try {
162 mSemaphore.acquire();
163 } catch (InterruptedException e) {
164 }
165 }
166 }
167
168 @Override
169 public void surfaceDestroyed(SurfaceHolder holder) {
170 if (mDialog == null) return;
171
172 CompletionCallback completion = new CompletionCallback();
173 enterDestroyedStateWithCallback(completion);
174 completion.waitForSignal();
175 }
176
177 @Override
178 public void surfaceRedrawNeeded(SurfaceHolder holder) {}
179 }
180
181 /**
182 * Notify the client about surface destruction, and clean up. Multiple
183 * calls to us do nothing.
184 */
185 private void enterDestroyedStateImpl(IAndroidOverlayCompletion completion) {
186 if (mDialog == null) return;
187
188 try {
189 mClientCallback.onDestroyed(completion);
190 } catch (Exception e) {
191 Log.d(TAG, "enterDestroyedState: callback failed: " + e);
192 release();
193 }
194
195 release();
196 }
197
198 private void enterDestroyedState() {
199 enterDestroyedStateImpl(null);
200 }
201
202 private void enterDestroyedStateWithCallback(IAndroidOverlayCompletion compl etion) {
203 enterDestroyedStateImpl(completion);
204 }
205
206 public void onWindowToken(IBinder token) {
207 if (mDialog == null) return;
208
209 if (token == null || (mLayoutParams.token != null && token != mLayoutPar ams.token)) {
210 // We've lost the token, if we had one, or we got a new one.
211 // Notify the client.
212 enterDestroyedState();
213 return;
214 }
215
216 if (mLayoutParams.token == token) {
217 // Same token, do nothing.
218 return;
219 }
220
221 // We have a token, so layout the dialog.
222 mLayoutParams.token = token;
223 mDialog.getWindow().setAttributes(mLayoutParams);
224 mDialogCallbacks = new Callbacks();
225 mDialog.getWindow().takeSurface(mDialogCallbacks);
226 mDialog.show();
227
228 // We don't notify the client here. We'll wait until the Android
229 // Surface is created.
230 }
231
232 @SuppressLint("RtlHardcoded")
233 private WindowManager.LayoutParams createLayoutParams() {
234 // Rather than using getAttributes, we just create them from scratch.
235 // The default dialog attributes aren't what we want.
236 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams ();
237
238 // NOTE: we really do want LEFT here, since we're dealing in compositor
239 // coordinates. Those are always from the left.
240 layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
241
242 // Use a media surface, which is what SurfaceView uses by default. For
243 // debugging overlay drawing, consider using TYPE_APPLICATION_PANEL to
244 // move the dialog over the CompositorView.
245 layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
246
247 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
248 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
249 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
250 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
251
252 // Don't set FLAG_SCALED. in addition to not being sure what it does
253 // (SV uses it), it also causes a crash in WindowManager when we hide
254 // (not dismiss), navigate, and/or exit the app without hide/dismiss.
255 // There's a missing null check in WindowManagerService.java@3170
256 // on M MR2. To repro, change dimiss() to hide(), bring up a SV, and
257 // navigate away or press home.
258
259 // Turn off the position animation, so that it doesn't animate from one
260 // position to the next. Ignore errors.
261 // 0x40 is PRIVATE_FLAG_NO_MOVE_ANIMATION.
262 try {
263 int currentFlags =
264 (Integer) layoutParams.getClass().getField("privateFlags").g et(layoutParams);
265 layoutParams.getClass()
266 .getField("privateFlags")
267 .set(layoutParams, currentFlags | 0x00000040);
268 // It would be nice to just catch Exception, but findbugs doesn't
269 // allow it. If we cannot set the flag, then that's okay too.
270 } catch (NoSuchFieldException e) {
271 } catch (NullPointerException e) {
272 } catch (SecurityException e) {
273 } catch (IllegalAccessException e) {
274 } catch (IllegalArgumentException e) {
275 } catch (ExceptionInInitializerError e) {
276 }
277
278 return layoutParams;
279 }
280 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698