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

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

Issue 1967553002: DO NOT COMMIT - DialogSurface initial implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cleanup Created 4 years, 4 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 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.app.Dialog;
8 import android.content.Context;
9 import android.os.Handler;
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.base.Log;
18
19 /**
20 * Provide access to Dialog-based Surfaces.
21 *
22 * There are two threads involved, which we call "primary" and "looper". The
23 * primary thread is the one that native uses to talk to us, such as the gpu
24 * main thread. All calls to us from native must be on this thread.
25 *
26 * Note that this class may run in the browser or gpu process, depending on
27 * whether we want the gpu process to have the activity window token or not.
28 *
29 * The wrapper class (DialogSurfaceWrapper) always runs locally with
30 * the JNI code that uses it, probably in the gpu process.
31 *
32 * The looper thread is a separate thread which has the looper for the dialogs
33 * that we create. We may call into native on that thread. Note that the
34 * native side handles the resulting race conditions.
35 */
36 class DialogSurface extends IDialogSurface.Stub {
37 private static final String TAG = "cr_media";
38
39 /**
40 * Call back into native with a message about our state. This can be called
41 * on any thread. It's okay if it refers to a native object that no longer
42 * exists; we can't really avoid it. The native side handles it.
43 *
44 * IMPORTANT: Do not call this with mLock held. Expect that the callback
45 * may call us.
46 */
47 private final IDialogSurfaceCallback mCallback;
48 private final Handler mHandler;
49 private final Context mContext;
50 private final int mRendererPid;
51 private final int mRenderFrameId;
52
53 // Callback operations.
54 // These must match dialog_surface.h .
55 private static final int OP_CREATED = 0;
56 private static final int OP_DESTROYED = 1;
57
58 private DialogSurfaceManager mOwner;
59
60 ////// Either thread, protected by mLock
61 private final Object mLock = new Object();
62 private Dialog mDialog;
63 private boolean mReleased;
64 private Surface mSurface;
65
66 /**
67 * Called from primary thread.
68 * Note that (pid, frameId) might be replaced by a token.
69 * @param rendererPid pid of owning renderer process
70 * @param renderFrameId render frame ID owned by Pid
71 * @param context Context that we use.
72 * @param owner Owning manager that we'll notify on release().
73 * @param handler handler for a thread with a looper.
74 * @param callback callback object to notify about state changes.
75 * @param x initial x position in chrome compositor (not screen) coords.
76 * @param y initial y position in chrome compositor (not screen) coords.
77 * @param width initial width.
78 * @param height initial height.
79 */
80 public DialogSurface(int rendererPid, int renderFrameId, Context context,
81 DialogSurfaceManager owner, Handler handler, IDialogSurfaceCallback callback, int x,
82 int y, int width, int height) {
83 mRendererPid = rendererPid;
84 mRenderFrameId = renderFrameId;
85 mContext = context;
86 mOwner = owner;
87 mHandler = handler;
88 mCallback = callback;
89
90 mReleased = false;
91
92 scheduleCreateDialog(x, y, width, height);
93 }
94
95 // Note that the native wrapper should call release() anyway on destruction.
96 protected void finalize() throws Throwable {
97 synchronized (mLock) {
98 if (!mReleased) {
99 Log.w(TAG, "Not released before finalization, releasing now");
100 }
101 }
102 release();
103 }
104
105 /**
106 * Release the underlying surface, and generally clean up.
107 */
108 @Override
109 public void release() {
110 synchronized (mLock) {
111 if (!mReleased) mOwner.notifyReleased(this);
112 mOwner = null;
113
114 // Note that we can't prevent callbacks; they must execute without
115 // the lock held so that the callback can do things that requires
116 // the lock (e.g., GetSurface). However, the native side handles
117 // races with deleted objects, not us.
118
119 // Prevent any in-flight create from succeeding, and hide any dialog
120 // that we currently have.
121 mReleased = true;
122 if (mDialog != null) {
123 Runnable r = new Runnable() {
124 @Override
125 public void run() {
126 synchronized (mLock) {
127 mDialog.dismiss();
128 mDialog = null;
129 }
130 }
131 };
132 mHandler.post(r);
133 }
134 }
135 }
136
137 @Override
138 public Surface getSurface() {
139 synchronized (mLock) {
140 return mSurface;
141 }
142 }
143
144 @Override
145 public void scheduleLayoutSurface(final int x, final int y, final int width, final int height) {
146 synchronized (mLock) {
147 final Dialog dialog = mDialog;
148 // Note that mDialog might be replaced, but that means that
149 // somebody called scheduleLayoutSurface while a create was pending
150 // before they got notification that the surface was ready.
151
152 if (dialog == null) return;
153
154 Runnable r = new Runnable() {
155 @Override
156 public void run() {
157 layoutDialog(dialog, x, y, width, height);
158 }
159 };
160
161 mHandler.post(r);
162 }
163 }
164
165 /**
166 * Callbacks for finding out about the Dialog's Surface.
167 * These happen on the looper thread.
168 */
169 private class Callbacks implements SurfaceHolder.Callback2 {
170 @Override
171 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
172
173 @Override
174 public void surfaceCreated(SurfaceHolder holder) {
175 synchronized (mLock) {
176 mSurface = holder.getSurface();
177 }
178
179 try {
180 mCallback.onCallback(OP_CREATED);
181 } catch (Exception e) {
182 Log.e(TAG, "SurfaceCreated: callback failed: " + e);
183 release();
184 }
185 }
186
187 @Override
188 public void surfaceDestroyed(SurfaceHolder holder) {
189 synchronized (mLock) {
190 mSurface = null;
191 }
192
193 try {
194 mCallback.onCallback(OP_DESTROYED);
195 } catch (Exception e) {
196 Log.e(TAG, "SurfaceDestroyed: callback failed: " + e);
197 release();
198 }
199 }
200
201 @Override
202 public void surfaceRedrawNeeded(SurfaceHolder holder) {}
203 }
204
205 /**
206 * Schedule creation of the dialog on our looper thread. Sets mThread
207 * asynchronously. If release() occurs before then, then the dialog will
208 * not be created.
209 */
210 private void scheduleCreateDialog(final int x, final int y, final int width, final int height) {
211 synchronized (mLock) {
212 mDialog = null;
213 }
214
215 Runnable r = new Runnable() {
216 @Override
217 public void run() {
218 Dialog dialog = new Dialog(mContext, android.R.style.Theme_NoDis play);
219 dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
220 dialog.setCancelable(false);
221 layoutDialog(dialog, x, y, width, height);
222 dialog.getWindow().takeSurface(new Callbacks());
223 synchronized (mLock) {
224 // If we've been released in the interim, then stop here.
225 if (mReleased) return;
226
227 dialog.show();
228 mDialog = dialog;
229 }
230 }
231 }; // new Runnable
232
233 // Post it to our dedicated thread.
234 mHandler.post(r);
235 }
236
237 /**
238 * Layout the dialog on the current thread. This should be called from the
239 * looper thread.
240 * Call scheduleLayoutDialog from anywhere else.
241 */
242 private void layoutDialog(Dialog dialog, int x, int y, int width, int height ) {
243 // Rather than using getAttributes, we just create them from scratch.
244 // The default dialog attributes aren't what we want.
245 WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams ();
246
247 // TODO(liberato): adjust for CompositorView screen location here if we
248 // want to support non-full screen use cases.
249 layoutParams.x = x;
250 layoutParams.y = y;
251 layoutParams.width = width;
252 layoutParams.height = height;
253 layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
254
255 // Use a panel, which is over the compositor view, until we get the
256 // compositor to switch to a transparent output surface.
257 // layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA ;
258 layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
259
260 layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
261 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
262 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
263 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
264
265 // Don't set FLAG_SCALED. in addition to not being sure what it does
266 // (SV uses it), it also causes a crash in WindowManager when we hide
267 // (not dismiss), navigate, and/or exit the app without hide/dismiss.
268 // There's a missing null check in WindowManagerService.java@3170
269 // on M MR2. To repro, change dimiss() to hide(), bring up a SV, and
270 // navigate away or press home.
271
272 // Turn off the position animation, so that it doesn't animate from one
273 // position to the next.
274 try {
275 int currentFlags =
276 (Integer) layoutParams.getClass().getField("privateFlags").g et(layoutParams);
277 layoutParams.getClass()
278 .getField("privateFlags")
279 .set(layoutParams, currentFlags | 0x00000040);
280 } catch (Exception e) {
281 }
282
283 layoutParams.token = getWindowToken();
284
285 dialog.getWindow().setAttributes(layoutParams);
286 }
287
288 private IBinder getWindowToken() {
289 IBinder token = null;
290 try {
291 token = mOwner.getMapper().getWindowToken(mRendererPid, mRenderFrame Id);
292 } catch (Exception e) {
293 }
294 return token;
295 }
296 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698