diff options
| author | 2017-08-07 22:31:33 +0000 | |
|---|---|---|
| committer | 2017-08-07 22:31:33 +0000 | |
| commit | 5c6f9676cb6d9d62b22e77f62daf47d9cb117188 (patch) | |
| tree | 2d061243fc9ced6cf457316d4ab387678af4b35f | |
| parent | ff9914ee5637bf6c152be6d3f78b2dfee7ec60ec (diff) | |
| parent | cdea2b5ab81558687e95ec82b03e8d08b4c6180d (diff) | |
Merge "Merge "Add black frame behind app window" into oc-dr1-dev am: cbdaf04101 am: cdcc9dd0dd" into oc-mr1-dev-plus-aosp
6 files changed, 351 insertions, 21 deletions
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 44c88e146879..1a2968f6345f 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -65,7 +65,8 @@ public class SurfaceControl { private static native void nativeSetSize(long nativeObject, int w, int h); private static native void nativeSetTransparentRegionHint(long nativeObject, Region region); private static native void nativeSetAlpha(long nativeObject, float alpha); - private static native void nativeSetMatrix(long nativeObject, float dsdx, float dtdx, float dsdy, float dtdy); + private static native void nativeSetMatrix(long nativeObject, float dsdx, float dtdx, + float dtdy, float dsdy); private static native void nativeSetFlags(long nativeObject, int flags, int mask); private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b); private static native void nativeSetFinalCrop(long nativeObject, int l, int t, int r, int b); diff --git a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java index 0508fdff531a..a12c2c40152d 100644 --- a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java +++ b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java @@ -32,7 +32,7 @@ import java.io.DataOutputStream; // the surface control. // // See cts/hostsidetests/../../SurfaceTraceReceiver.java for parsing side. -class RemoteSurfaceTrace extends SurfaceControl { +class RemoteSurfaceTrace extends SurfaceControlWithBackground { static final String TAG = "RemoteSurfaceTrace"; final FileDescriptor mWriteFd; @@ -41,7 +41,8 @@ class RemoteSurfaceTrace extends SurfaceControl { final WindowManagerService mService; final WindowState mWindow; - RemoteSurfaceTrace(FileDescriptor fd, SurfaceControl wrapped, WindowState window) { + RemoteSurfaceTrace(FileDescriptor fd, SurfaceControlWithBackground wrapped, + WindowState window) { super(wrapped); mWriteFd = fd; diff --git a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java new file mode 100644 index 000000000000..f5ef2e66f0a6 --- /dev/null +++ b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.wm; + +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.Region; +import android.os.IBinder; +import android.os.Parcel; +import android.view.Surface; +import android.view.Surface.OutOfResourcesException; +import android.view.SurfaceControl; +import android.view.SurfaceSession; + +/** + * SurfaceControl extension that has background sized to match its container. + */ +class SurfaceControlWithBackground extends SurfaceControl { + // SurfaceControl that holds the background behind opaque letterboxed app windows. + private SurfaceControl mBackgroundControl; + + // Flags that define whether the background should be shown. + private boolean mOpaque; + private boolean mVisible; + + // Way to communicate with corresponding window. + private WindowSurfaceController mWindowSurfaceController; + + // Rect to hold task bounds when computing metrics for background. + private Rect mTmpContainerRect = new Rect(); + + // Last metrics applied to the main SurfaceControl. + private float mLastWidth, mLastHeight; + private float mLastDsDx = 1, mLastDsDy = 1; + private float mLastX, mLastY; + + public SurfaceControlWithBackground(SurfaceControlWithBackground other) { + super(other); + mBackgroundControl = other.mBackgroundControl; + mOpaque = other.mOpaque; + mVisible = other.mVisible; + mWindowSurfaceController = other.mWindowSurfaceController; + } + + public SurfaceControlWithBackground(SurfaceSession s, String name, int w, int h, int format, + int flags, int windowType, int ownerUid, + WindowSurfaceController windowSurfaceController) throws OutOfResourcesException { + super(s, name, w, h, format, flags, windowType, ownerUid); + + // We should only show background when the window is letterboxed in a task. + if (!windowSurfaceController.mAnimator.mWin.isLetterboxedAppWindow()) { + return; + } + mWindowSurfaceController = windowSurfaceController; + mLastWidth = w; + mLastHeight = h; + mOpaque = (flags & SurfaceControl.OPAQUE) != 0; + mWindowSurfaceController.getContainerRect(mTmpContainerRect); + mBackgroundControl = new SurfaceControl(s, "Background for - " + name, + mTmpContainerRect.width(), mTmpContainerRect.height(), PixelFormat.OPAQUE, + flags | SurfaceControl.FX_SURFACE_DIM); + } + + @Override + public void setAlpha(float alpha) { + super.setAlpha(alpha); + + if (mBackgroundControl == null) { + return; + } + mBackgroundControl.setAlpha(alpha); + } + + @Override + public void setLayer(int zorder) { + super.setLayer(zorder); + + if (mBackgroundControl == null) { + return; + } + // TODO: Use setRelativeLayer(Integer.MIN_VALUE) when it's fixed. + mBackgroundControl.setLayer(zorder - 1); + } + + @Override + public void setPosition(float x, float y) { + super.setPosition(x, y); + + if (mBackgroundControl == null) { + return; + } + mLastX = x; + mLastY = y; + updateBgPosition(); + } + + private void updateBgPosition() { + mWindowSurfaceController.getContainerRect(mTmpContainerRect); + final Rect winFrame = mWindowSurfaceController.mAnimator.mWin.mFrame; + final float offsetX = (mTmpContainerRect.left - winFrame.left) * mLastDsDx; + final float offsetY = (mTmpContainerRect.top - winFrame.top) * mLastDsDy; + mBackgroundControl.setPosition(mLastX + offsetX, mLastY + offsetY); + } + + @Override + public void setSize(int w, int h) { + super.setSize(w, h); + + if (mBackgroundControl == null) { + return; + } + mLastWidth = w; + mLastHeight = h; + mWindowSurfaceController.getContainerRect(mTmpContainerRect); + mBackgroundControl.setSize(mTmpContainerRect.width(), mTmpContainerRect.height()); + } + + @Override + public void setWindowCrop(Rect crop) { + super.setWindowCrop(crop); + + if (mBackgroundControl == null) { + return; + } + if (crop.width() < mLastWidth || crop.height() < mLastHeight) { + // We're animating and cropping window, compute the appropriate crop for background. + calculateBgCrop(crop); + mBackgroundControl.setWindowCrop(mTmpContainerRect); + } else { + // When not animating just set crop to container rect. + mWindowSurfaceController.getContainerRect(mTmpContainerRect); + mBackgroundControl.setWindowCrop(mTmpContainerRect); + } + } + + @Override + public void setFinalCrop(Rect crop) { + super.setFinalCrop(crop); + + if (mBackgroundControl == null) { + return; + } + if (crop.width() < mLastWidth || crop.height() < mLastHeight) { + // We're animating and cropping window, compute the appropriate crop for background. + calculateBgCrop(crop); + mBackgroundControl.setFinalCrop(mTmpContainerRect); + } else { + // When not animating just set crop to container rect. + mWindowSurfaceController.getContainerRect(mTmpContainerRect); + mBackgroundControl.setFinalCrop(mTmpContainerRect); + } + } + + /** Compute background crop based on current animation progress for main surface control. */ + private void calculateBgCrop(Rect crop) { + // Track overall progress of animation by computing cropped portion of status bar. + final Rect contentInsets = mWindowSurfaceController.mAnimator.mWin.mContentInsets; + float d = contentInsets.top == 0 ? 0 : (float) crop.top / contentInsets.top; + + // Compute additional offset for the background when app window is positioned not at (0,0). + // E.g. landscape with navigation bar on the left. + final Rect winFrame = mWindowSurfaceController.mAnimator.mWin.mFrame; + final int offsetX = (int) (winFrame.left * mLastDsDx * d + 0.5); + final int offsetY = (int) (winFrame.top * mLastDsDy * d + 0.5); + + // Compute new scaled width and height for background that will depend on current animation + // progress. Those consist of current crop rect for the main surface + scaled areas outside + // of letterboxed area. + mWindowSurfaceController.getContainerRect(mTmpContainerRect); + final int backgroundWidth = + (int) (crop.width() + (mTmpContainerRect.width() - mLastWidth) * (1 - d) + 0.5); + final int backgroundHeight = + (int) (crop.height() + (mTmpContainerRect.height() - mLastHeight) * (1 - d) + 0.5); + + mTmpContainerRect.set(crop); + // Make sure that part of background to left/top is visible and scaled. + mTmpContainerRect.offset(offsetX, offsetY); + // Set correct width/height, so that area to right/bottom is cropped properly. + mTmpContainerRect.right = mTmpContainerRect.left + backgroundWidth; + mTmpContainerRect.bottom = mTmpContainerRect.top + backgroundHeight; + } + + @Override + public void setLayerStack(int layerStack) { + super.setLayerStack(layerStack); + + if (mBackgroundControl == null) { + return; + } + mBackgroundControl.setLayerStack(layerStack); + } + + @Override + public void setOpaque(boolean isOpaque) { + super.setOpaque(isOpaque); + mOpaque = isOpaque; + updateBackgroundVisibility(); + } + + @Override + public void setSecure(boolean isSecure) { + super.setSecure(isSecure); + } + + @Override + public void setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) { + super.setMatrix(dsdx, dtdx, dtdy, dsdy); + + if (mBackgroundControl == null) { + return; + } + mBackgroundControl.setMatrix(dsdx, dtdx, dtdy, dsdy); + mLastDsDx = dsdx; + mLastDsDy = dsdy; + updateBgPosition(); + } + + @Override + public void hide() { + super.hide(); + mVisible = false; + updateBackgroundVisibility(); + } + + @Override + public void show() { + super.show(); + mVisible = true; + updateBackgroundVisibility(); + } + + @Override + public void destroy() { + super.destroy(); + + if (mBackgroundControl == null) { + return; + } + mBackgroundControl.destroy(); + } + + @Override + public void release() { + super.release(); + + if (mBackgroundControl == null) { + return; + } + mBackgroundControl.release(); + } + + @Override + public void setTransparentRegionHint(Region region) { + super.setTransparentRegionHint(region); + + if (mBackgroundControl == null) { + return; + } + mBackgroundControl.setTransparentRegionHint(region); + } + + @Override + public void deferTransactionUntil(IBinder handle, long frame) { + super.deferTransactionUntil(handle, frame); + + if (mBackgroundControl == null) { + return; + } + mBackgroundControl.deferTransactionUntil(handle, frame); + } + + @Override + public void deferTransactionUntil(Surface barrier, long frame) { + super.deferTransactionUntil(barrier, frame); + + if (mBackgroundControl == null) { + return; + } + mBackgroundControl.deferTransactionUntil(barrier, frame); + } + + private void updateBackgroundVisibility() { + if (mBackgroundControl == null) { + return; + } + if (mOpaque && mVisible) { + mBackgroundControl.show(); + } else { + mBackgroundControl.hide(); + } + } +} diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 0c217caf2dba..90a2892a1ac5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3244,6 +3244,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return !isInMultiWindowMode(); } + /** @return true when the window is in fullscreen task, but has non-fullscreen bounds set. */ + boolean isLetterboxedAppWindow() { + final Task task = getTask(); + final boolean taskIsFullscreen = task != null && task.isFullscreen(); + final boolean appWindowIsFullscreen = mAppToken != null && !mAppToken.hasBounds(); + + return taskIsFullscreen && !appWindowIsFullscreen; + } + /** Returns the appropriate bounds to use for computing frames. */ private void getContainerBounds(Rect outBounds) { if (isInMultiWindowMode()) { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 0cc505ea9d05..86265c297b1b 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1200,7 +1200,8 @@ class WindowStateAnimator { if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame=" + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect); - final boolean fullscreen = w.fillsDisplay(); + final Task task = w.getTask(); + final boolean fullscreen = w.fillsDisplay() || (task != null && task.isFullscreen()); final boolean isFreeformResizing = w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM; @@ -1526,6 +1527,19 @@ class WindowStateAnimator { } } + /** + * Get rect of the task this window is currently in. If there is no task, rect will be set to + * empty. + */ + void getContainerRect(Rect rect) { + final Task task = mWin.getTask(); + if (task != null) { + task.getDimBounds(rect); + } else { + rect.left = rect.top = rect.right = rect.bottom = 0; + } + } + void prepareSurfaceLocked(final boolean recoveringMemory) { final WindowState w = mWin; if (!hasSurface()) { diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 1728cfbb6ef0..110d5cb90f45 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -50,7 +50,7 @@ class WindowSurfaceController { final WindowStateAnimator mAnimator; - private SurfaceControl mSurfaceControl; + private SurfaceControlWithBackground mSurfaceControl; // Should only be set from within setShown(). private boolean mSurfaceShown = false; @@ -97,15 +97,10 @@ class WindowSurfaceController { mWindowType = windowType; mWindowSession = win.mSession; - if (DEBUG_SURFACE_TRACE) { - mSurfaceControl = new SurfaceTrace( - s, name, w, h, format, flags, windowType, ownerUid); - } else { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl"); - mSurfaceControl = new SurfaceControl( - s, name, w, h, format, flags, windowType, ownerUid); - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - } + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl"); + mSurfaceControl = new SurfaceControlWithBackground( + s, name, w, h, format, flags, windowType, ownerUid, this); + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (mService.mRoot.mSurfaceTraceEnabled) { mSurfaceControl = new RemoteSurfaceTrace( @@ -118,7 +113,7 @@ class WindowSurfaceController { } void removeRemoteTrace() { - mSurfaceControl = new SurfaceControl(mSurfaceControl); + mSurfaceControl = new SurfaceControlWithBackground(mSurfaceControl); } @@ -291,30 +286,30 @@ class WindowSurfaceController { mSurfaceControl.setGeometryAppliesWithResize(); } - void setMatrixInTransaction(float dsdx, float dtdx, float dsdy, float dtdy, + void setMatrixInTransaction(float dsdx, float dtdx, float dtdy, float dsdy, boolean recoveringMemory) { final boolean matrixChanged = mLastDsdx != dsdx || mLastDtdx != dtdx || - mLastDsdy != dsdy || mLastDtdy != dtdy; + mLastDtdy != dtdy || mLastDsdy != dsdy; if (!matrixChanged) { return; } mLastDsdx = dsdx; mLastDtdx = dtdx; - mLastDsdy = dsdy; mLastDtdy = dtdy; + mLastDsdy = dsdy; try { if (SHOW_TRANSACTIONS) logSurface( - "MATRIX [" + dsdx + "," + dtdx + "," + dsdy + "," + dtdy + "]", null); + "MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null); mSurfaceControl.setMatrix( - dsdx, dtdx, dsdy, dtdy); + dsdx, dtdx, dtdy, dsdy); } catch (RuntimeException e) { // If something goes wrong with the surface (such // as running out of memory), don't take down the // entire system. Slog.e(TAG, "Error setting matrix on surface surface" + title - + " MATRIX [" + dsdx + "," + dtdx + "," + dsdy + "," + dtdy + "]", null); + + " MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null); if (!recoveringMemory) { mAnimator.reclaimSomeSurfaceMemory("matrix", true); } @@ -421,6 +416,10 @@ class WindowSurfaceController { } } + void getContainerRect(Rect rect) { + mAnimator.getContainerRect(rect); + } + boolean showRobustlyInTransaction() { if (SHOW_TRANSACTIONS) logSurface( "SHOW (performLayout)", null); |