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

Side by Side Diff: media/base/android/java/src/org/chromium/media/DialogSurfaceCore.java

Issue 2178973004: DialogSurfaceManager implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: removed IDialogSurfaceActivityMapper from common.aidl Created 4 years 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 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.media;
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
18 /**
19 * Core class for control of a single DialogSurface instance. Everything runs
20 * on a single thread, that's probably not the UI thread.
21 *
22 * Note that this does not implement IDialogSurface; we assume that, and the
23 * associated thread-hopping, is handled elsewhere.
24 */
25 class DialogSurfaceCore {
26 private static final String TAG = "cr_media";
boliu 2017/01/04 01:48:44 generally, this is just the name of the class, the
liberato (no reviews please) 2017/01/11 22:17:57 not sure. i copied the pattern from MediaCodecBri
boliu 2017/01/12 20:24:19 fwiw, it's dynamic: https://cs.chromium.org/chromi
liberato (no reviews please) 2017/02/03 21:28:32 Acknowledged.
27
28 /**
29 * Call back into native with a message about our state. This can be called
30 * on any thread. It's okay if it refers to a native object that no longer
31 * exists; we can't really avoid it. The native side handles it.
32 *
33 * The callback cannot recursively call back into us; the IDialogSurface
34 * implementation must prevent that.
35 */
36 private IDialogSurfaceCallback mClientCallback;
37
38 // Callback operations.
39 // These must match dialog_surface.h .
40 private static final int OP_CREATED = 0;
41 private static final int OP_DESTROYED = 1;
42
43 // When initialized via Init, we'll create mDialog. We'll clear it when
44 // we send SURFACE_DESTROYED to the client. In general, when this is null,
45 // either we haven't been initialized yet, or we've been torn down. It
46 // shouldn't be the case that anything calls methods after construction but
47 // before Init, though.
48 private Dialog mDialog;
49
50 private Callbacks mDialogCallbacks;
51 private IBinder mToken;
52
53 // Initial position and size.
54 private int mInitialX;
55 private int mInitialY;
56 private int mInitialWidth;
57 private int mInitialHeight;
58
59 /**
60 * Construction may be called from a random thread, for simplicity. Call
61 * Init from the proper thread before doing anything else.
62 */
63 public DialogSurfaceCore() {}
64
65 /**
66 * Finish init on the proper thread. We'll use this thread for the Dialog
67 * Looper thread.
68 * @param context Context that we use.
69 * @param callback callback object to notify about state changes.
70 * @param x initial x position in chrome compositor (not screen) coords.
71 * @param y initial y position in chrome compositor (not screen) coords.
72 * @param width initial width.
73 * @param height initial height.
74 */
75 public void initialize(
76 Context context, IDialogSurfaceCallback callback, int x, int y, int width, int height) {
77 mClientCallback = callback;
78 mInitialX = x;
79 mInitialY = y;
80 mInitialWidth = width;
81 mInitialHeight = height;
82
83 // Create the dialog, but don't lay it out or show it yet. We'll do
84 // that when we get a window token.
85 mDialog = new Dialog(context, android.R.style.Theme_NoDisplay);
86 mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
87 mDialog.setCancelable(false);
88 }
89
90 /**
91 * Release the underlying surface, and generally clean up, in response to
92 * the client releasing the IDialogSurface.
93 */
94 public void release() {
95 // If we've not released the dialog yet, then do so.
96 if (mDialog != null) {
97 // TODO(liberato): is this safe if we haven't shown the dialog yet?
98 mDialog.dismiss();
99 mDialog = null;
100 mDialogCallbacks = null;
101 }
102 }
103
104 /**
105 * Layout the DialogSurface. If we don't have a token, then we ignore it,
106 * since a well-behaved client shouldn't call us before OP_CREATED anyway.
107 */
108 @SuppressLint("RtlHardcoded")
109 public void layoutSurface(final int x, final int y, final int width, final i nt height) {
110 if (mDialog == null || mToken == null) return;
111
112 // Rather than using getAttributes, we just create them from scratch.
113 // The default dialog attributes aren't what we want.
114 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams ();
boliu 2017/01/04 01:48:44 ditto about allocating java objects in calls that
liberato (no reviews please) 2017/01/11 22:17:57 Done.
115
116 // TODO(liberato): adjust for CompositorView screen location here if we
117 // want to support non-full screen use cases.
118
119 layoutParams.x = x;
120 layoutParams.y = y;
121 layoutParams.width = width;
122 layoutParams.height = height;
123 layoutParams.token = mToken;
124
125 // NOTE: we really do want LEFT here, since we're dealing in compositor
126 // coordinates. Those are always from the left.
127 layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
128
129 // Use a media surface, which is what SurfaceView uses by default. For
130 // debugging overlay drawing, consider using TYPE_APPLICATION_PANEL to
131 // move the dialog over the CompositorView.
132 layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
133
134 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
135 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
136 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
137 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
138
139 // Don't set FLAG_SCALED. in addition to not being sure what it does
140 // (SV uses it), it also causes a crash in WindowManager when we hide
141 // (not dismiss), navigate, and/or exit the app without hide/dismiss.
142 // There's a missing null check in WindowManagerService.java@3170
143 // on M MR2. To repro, change dimiss() to hide(), bring up a SV, and
144 // navigate away or press home.
145
146 // Turn off the position animation, so that it doesn't animate from one
147 // position to the next. Ignore errors.
148 try {
149 int currentFlags =
150 (Integer) layoutParams.getClass().getField("privateFlags").g et(layoutParams);
boliu 2017/01/04 01:48:44 err, reflection? hard coded values?
liberato (no reviews please) 2017/01/11 22:17:57 PRIVATE_FLAG_NO_MOVE_ANIMATION -- there's no other
boliu 2017/01/12 20:24:19 The bar for using private APIs is very high, ie it
liberato (no reviews please) 2017/02/03 21:28:32 i'd really like to do this. we can chat offline a
151 layoutParams.getClass()
152 .getField("privateFlags")
153 .set(layoutParams, currentFlags | 0x00000040);
154 // It would be nice to just catch Exception, but findbugs doesn't
155 // allow it. If we cannot set the flag, then that's okay too.
156 } catch (NoSuchFieldException e) {
157 } catch (NullPointerException e) {
158 } catch (SecurityException e) {
159 } catch (IllegalAccessException e) {
160 } catch (IllegalArgumentException e) {
161 } catch (ExceptionInInitializerError e) {
162 }
163
164 mDialog.getWindow().setAttributes(layoutParams);
165 }
166
167 /**
168 * Callbacks for finding out about the Dialog's Surface.
169 * These happen on the looper thread.
170 */
171 private class Callbacks implements SurfaceHolder.Callback2 {
172 @Override
173 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
174
175 @Override
176 public void surfaceCreated(SurfaceHolder holder) {
177 // Make sure that we haven't torn down the dialog yet.
178 if (mDialog == null) return;
179
180 try {
181 mClientCallback.onCreated(holder.getSurface());
182 } catch (Exception e) {
183 Log.e(TAG, "surfaceCreated: callback failed: " + e);
184 enterDestroyedState();
185 }
186 }
187
188 @Override
189 public void surfaceDestroyed(SurfaceHolder holder) {
190 if (mDialog == null) return;
191
192 enterDestroyedState();
193 }
194
195 @Override
196 public void surfaceRedrawNeeded(SurfaceHolder holder) {}
197 }
198
199 /**
200 * Notify the client about surface destruction, and clean up. Multiple
201 * calls to us do nothing.
202 */
203 private void enterDestroyedState() {
204 if (mDialog == null) return;
205
206 try {
207 mClientCallback.onDestroyed();
208 } catch (Exception e) {
209 Log.e(TAG, "enterDestroyedState: callback failed: " + e);
boliu 2017/01/04 01:48:44 all logs probably should be .d so they get strippe
liberato (no reviews please) 2017/01/11 22:17:57 Done.
210 release();
211 }
212
213 // Dismiss the dialog, if needed
214 // TODO(liberato): is it safe to call dismiss without show? we don't
215 // know that we've shown the dialog yet. maybe if mToken? isShowing?
216 mDialog.dismiss();
217 mDialog = null;
218 mDialogCallbacks = null;
219 mToken = null;
220 }
221
222 public void onWindowToken(IBinder token) {
223 if (mDialog == null) return;
224
225 if (token == null || (mToken != null && token != mToken)) {
226 // We've lost the token, if we had one, or we got a new one.
227 // Notify the client.
228 enterDestroyedState();
229 return;
230 }
231
232 if (mToken == token) {
233 // Same token, do nothing.
boliu 2017/01/04 01:48:44 haven't read the window token stuff yet.. but is t
liberato (no reviews please) 2017/01/11 22:17:57 i don't think that it should, but it seemed harmle
boliu 2017/01/12 20:24:19 but this is silencing a potential problem in the f
234 return;
235 }
236
237 // We have a token, so layout the dialog.
238 mToken = token;
239 layoutSurface(mInitialX, mInitialY, mInitialWidth, mInitialHeight);
boliu 2017/01/04 01:48:44 what if an layout happens before window token is r
liberato (no reviews please) 2017/01/11 22:17:57 it's okay, since the application shouldn't be posi
240 mDialogCallbacks = new Callbacks();
241 mDialog.getWindow().takeSurface(mDialogCallbacks);
242 mDialog.show();
243
244 // We don't notify the client here. We'll wait until the Android
245 // Surface is created.
246 }
247 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698