diff options
| author | 2015-09-28 10:26:16 -0700 | |
|---|---|---|
| committer | 2015-10-15 22:35:48 +0000 | |
| commit | 6104dc95606b3399356dd011ca6d71fcd954154c (patch) | |
| tree | e129b3e054c38034fc4bef1e79d84b205c6f18c1 | |
| parent | 446433da24b7cfb7e7625675bb9dc4e17b05f3ba (diff) | |
Sync SurfaceView position changes to parent render.
In order to provide pixel perfect movement of SurfaceViews
'within' other views (e.g. scrolling) we need to be able to
synchronize the attached (parent window) painting with the
movement of the SurfaceView (recall, SurfaceViews are positioned
behind their attached windows and the parent must render a
transparent region for the SurfaceView to appear). Provide
a new WindowManager method to reposition an attaching window
(that is to say, a window which has an attached window like
SurfaceView) and defer the transaction until the parent frame.
SurfaceView is hooked up to use this for movement. This is still
'racy' in the hardware accelerated case as the render thread
could be on either side of dequeing the frame we are working on.
Change-Id: Ic33915043380ab8cd9eb4920e224b35234ed867d
| -rw-r--r-- | core/java/android/view/IWindowSession.aidl | 17 | ||||
| -rw-r--r-- | core/java/android/view/Surface.java | 14 | ||||
| -rw-r--r-- | core/java/android/view/SurfaceControl.java | 11 | ||||
| -rw-r--r-- | core/java/android/view/SurfaceView.java | 14 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 14 | ||||
| -rw-r--r-- | core/jni/android_view_Surface.cpp | 5 | ||||
| -rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 19 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/Session.java | 6 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowManagerService.java | 53 |
9 files changed, 151 insertions, 2 deletions
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 017364a5a0b1..427284be100e 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -96,6 +96,23 @@ interface IWindowSession { out Rect outOutsets, out Configuration outConfig, out Surface outSurface); /** + * Position a window relative to it's parent (attached) window without triggering + * a full relayout. This action may be deferred until a given frame number + * for the parent window appears. This allows for synchronizing movement of a child + * to repainting the contents of the parent. + * + * @param window The window being modified. Must be attached to a parent window + * or this call will fail. + * @param x The new x position + * @param y The new y position + * @param deferTransactionUntilFrame Frame number from our parent (attached) to + * defer this action until. + * @param outFrame Rect in which is placed the new position/size on screen. + */ + void repositionChild(IWindow childWindow, int x, int y, long deferTransactionUntilFrame, + out Rect outFrame); + + /** * If a call to relayout() asked to have the surface destroy deferred, * it must call this once it is okay to destroy that surface. */ diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 6de4d3e4e4c3..394660fb538b 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -56,6 +56,8 @@ public class Surface implements Parcelable { private static native int nativeGetWidth(long nativeObject); private static native int nativeGetHeight(long nativeObject); + private static native long nativeGetNextFrameNumber(long nativeObject); + public static final Parcelable.Creator<Surface> CREATOR = new Parcelable.Creator<Surface>() { @Override @@ -220,6 +222,18 @@ public class Surface implements Parcelable { } /** + * Returns the next frame number which will be dequeued for rendering. + * Intended for use with SurfaceFlinger's deferred transactions API. + * + * @hide + */ + public long getNextFrameNumber() { + synchronized (mLock) { + return nativeGetNextFrameNumber(mNativeObject); + } + } + + /** * Returns true if the consumer of this Surface is running behind the producer. * * @return True if the consumer is more than one buffer ahead of the producer. diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index bcf9b2c7fe7c..b58c68f782ee 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -81,6 +81,9 @@ public class SurfaceControl { private static native boolean nativeSetActiveConfig(IBinder displayToken, int id); private static native void nativeSetDisplayPowerMode( IBinder displayToken, int mode); + private static native void nativeDeferTransactionUntil(long nativeObject, + IBinder handle, long frame); + private static native IBinder nativeGetHandle(long nativeObject); private final CloseGuard mCloseGuard = CloseGuard.get(); @@ -358,6 +361,14 @@ public class SurfaceControl { nativeCloseTransaction(); } + public void deferTransactionUntil(IBinder handle, long frame) { + nativeDeferTransactionUntil(mNativeObject, handle, frame); + } + + public IBinder getHandle() { + return nativeGetHandle(mNativeObject); + } + /** flag the transaction as an animation */ public static void setAnimationTransaction() { nativeSetAnimationTransaction(); diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index db68c29d025f..dddea210ed83 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -448,11 +448,10 @@ public class SurfaceView extends View { final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; final boolean visibleChanged = mVisible != mRequestedVisible; final boolean layoutSizeChanged = getWidth() != mLayout.width || getHeight() != mLayout.height; + final boolean positionChanged = mLeft != mLocation[0] || mTop != mLocation[1]; if (force || creating || formatChanged || sizeChanged || visibleChanged - || mLeft != mLocation[0] || mTop != mLocation[1] || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded || layoutSizeChanged) { - if (DEBUG) Log.i(TAG, "Changes: creating=" + creating + " format=" + formatChanged + " size=" + sizeChanged + " visible=" + visibleChanged @@ -616,11 +615,22 @@ public class SurfaceView extends View { mSession.performDeferredDestroy(mWindow); } } catch (RemoteException ex) { + Log.e(TAG, "Exception from relayout", ex); } if (DEBUG) Log.v( TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y + " w=" + mLayout.width + " h=" + mLayout.height + ", frame=" + mSurfaceFrame); + } else if (positionChanged) { // Only the position has changed + mLeft = mLocation[0]; + mTop = mLocation[1]; + try { + mSession.repositionChild(mWindow, mLeft, mTop, + viewRoot != null ? viewRoot.getNextFrameNumber() : -1, + mWinFrame); + } catch (RemoteException ex) { + Log.e(TAG, "Exception from relayout", ex); + } } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 14e7d6c4e81e..e6a845c2c6b1 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6555,6 +6555,20 @@ public final class ViewRootImpl implements ViewParent, } } + long getNextFrameNumber() { + long frameNumber = -1; + if (mSurfaceHolder != null) { + mSurfaceHolder.mSurfaceLock.lock(); + } + if (mSurface.isValid()) { + frameNumber = mSurface.getNextFrameNumber(); + } + if (mSurfaceHolder != null) { + mSurfaceHolder.mSurfaceLock.unlock(); + } + return frameNumber; + } + class TakenSurfaceHolder extends BaseSurfaceHolder { @Override public boolean onAllowLockCanvas() { diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 24055e76234e..b4e52f4281ad 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -461,6 +461,10 @@ static jint nativeGetHeight(JNIEnv* env, jclass clazz, jlong nativeObject) { anw->query(anw, NATIVE_WINDOW_HEIGHT, &value); return value; } +static jlong nativeGetNextFrameNumber(JNIEnv *env, jclass clazz, jlong nativeObject) { + Surface* surface = reinterpret_cast<Surface*>(nativeObject); + return surface->getNextFrameNumber(); +} namespace uirenderer { @@ -537,6 +541,7 @@ static const JNINativeMethod gSurfaceMethods[] = { (void*)nativeWriteToParcel }, {"nativeGetWidth", "(J)I", (void*)nativeGetWidth }, {"nativeGetHeight", "(J)I", (void*)nativeGetHeight }, + {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber }, // HWUI context {"nHwuiCreate", "(JJ)J", (void*) hwui::create }, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 65ebb6633a8f..43a6b78ffdde 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -570,6 +570,21 @@ static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject return JNI_TRUE; } + +static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject, + jobject handleObject, jlong frameNumber) { + auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); + sp<IBinder> handle = ibinderForJavaObject(env, handleObject); + + ctrl->deferTransactionUntil(handle, frameNumber); +} + +static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) { + auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); + + return javaObjectForIBinder(env, ctrl->getHandle()); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { @@ -637,6 +652,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetAnimationFrameStats }, {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V", (void*)nativeSetDisplayPowerMode }, + {"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V", + (void*)nativeDeferTransactionUntil }, + {"nativeGetHandle", "(J)Landroid/os/IBinder;", + (void*)nativeGetHandle } }; int register_android_view_SurfaceControl(JNIEnv* env) diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 1f62bc15024e..c47c377f4cb8 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -187,6 +187,12 @@ final class Session extends IWindowSession.Stub mService.removeWindow(this, window); } + @Override + public void repositionChild(IWindow window, int x, int y, long deferTransactionUntilFrame, + Rect outFrame) { + mService.repositionChild(this, window, x, y, deferTransactionUntilFrame, outFrame); + } + public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewFlags, int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0170bb965540..72d5f5973e3d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2460,6 +2460,59 @@ public class WindowManagerService extends IWindowManager.Stub } } + private void repositionChildInner(Session session, IWindow client, + int x, int y, long deferTransactionUntilFrame, Rect outFrame) { + synchronized(mWindowMap) { + WindowState win = windowForClientLocked(session, client, false); + if (win == null) { + return; + } + if (win.mAttachedWindow == null) { + throw new IllegalArgumentException( + "repositionChild called but window is not" + + "attached to a parent win=" + win); + } + + win.mFrame.left = x; + win.mFrame.top = y; + + win.mWinAnimator.computeShownFrameLocked(); + + if (SHOW_TRANSACTIONS) { + Slog.i(TAG, ">>> OPEN TRANSACTION repositionChild"); + } + + SurfaceControl.openTransaction(); + + if (deferTransactionUntilFrame > 0) { + win.mWinAnimator.mSurfaceControl.deferTransactionUntil( + win.mAttachedWindow.mWinAnimator.mSurfaceControl.getHandle(), + deferTransactionUntilFrame); + } + win.mWinAnimator.setSurfaceBoundariesLocked(false); + + SurfaceControl.closeTransaction(); + if (SHOW_TRANSACTIONS) { + Slog.i(TAG, "<<< CLOSE TRANSACTION repositionChild"); + } + + outFrame = win.mCompatFrame; + } + } + + public void repositionChild(Session session, IWindow client, + int x, int y, long deferTransactionUntilFrame, Rect outFrame) { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "repositionChild"); + long origId = Binder.clearCallingIdentity(); + + try { + repositionChildInner(session, client, x, y, deferTransactionUntilFrame, outFrame); + } finally { + Binder.restoreCallingIdentity(origId); + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + } + public int relayoutWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, |