Loading core/java/android/view/SurfaceControl.java +2 −1 Original line number Diff line number Diff line Loading @@ -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); Loading services/core/java/com/android/server/wm/RemoteSurfaceTrace.java +3 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading services/core/java/com/android/server/wm/SurfaceControlWithBackground.java 0 → 100644 +306 −0 Original line number Diff line number Diff line /* * 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(); } } } services/core/java/com/android/server/wm/WindowState.java +9 −0 Original line number Diff line number Diff line Loading @@ -3219,6 +3219,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()) { Loading services/core/java/com/android/server/wm/WindowStateAnimator.java +15 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()) { Loading Loading
core/java/android/view/SurfaceControl.java +2 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
services/core/java/com/android/server/wm/RemoteSurfaceTrace.java +3 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading
services/core/java/com/android/server/wm/SurfaceControlWithBackground.java 0 → 100644 +306 −0 Original line number Diff line number Diff line /* * 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(); } } }
services/core/java/com/android/server/wm/WindowState.java +9 −0 Original line number Diff line number Diff line Loading @@ -3219,6 +3219,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()) { Loading
services/core/java/com/android/server/wm/WindowStateAnimator.java +15 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()) { Loading