From 5098159ae31bc59aa3857fecb1847f8d7bb73e54 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Tue, 29 Dec 2015 17:54:12 +0100 Subject: [PATCH] Dim stack while dismissing When dismissing the docked or fullscreen stack, a dim layer is introduced for a nicer visual effect. Change-Id: I9f12e331e978208aa9fd9e9883b3c8a36d4da3a0 --- core/java/android/view/IWindowManager.aidl | 9 +++++ .../stackdivider/DividerSnapAlgorithm.java | 18 +++++++++ .../android/systemui/stackdivider/DividerView.java | 19 +++++++++ .../systemui/stackdivider/WindowManagerProxy.java | 24 +++++++++++ .../server/wm/DockedStackDividerController.java | 46 +++++++++++++++++++++- .../android/server/wm/WindowLayersController.java | 39 +++++++++++++++--- .../android/server/wm/WindowManagerService.java | 8 ++++ 7 files changed, 157 insertions(+), 6 deletions(-) diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index ae823cfd6372..84d312d59b64 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -361,4 +361,13 @@ interface IWindowManager * the docked stack gets added/removed. */ void registerDockedStackListener(IDockedStackListener listener); + + /** + * Updates the dim layer used while resizing. + * + * @param visible Whether the dim layer should be visible. + * @param targetStackId The id of the task stack the dim layer should be placed on. + * @param alpha The translucency of the dim layer, between 0 and 1. + */ + void setResizeDimLayer(boolean visible, int targetStackId, float alpha); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java index 9c704079d8a2..8d4279236b8e 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java @@ -100,6 +100,24 @@ public class DividerSnapAlgorithm { } } + public float calculateDismissingFraction(int position) { + if (position < mFirstSplitTarget.position) { + return 1f - (float) position / mFirstSplitTarget.position; + } else if (position > mLastSplitTarget.position) { + return (float) (position - mLastSplitTarget.position) + / (mDismissEndTarget.position - mLastSplitTarget.position); + } + return 0f; + } + + public SnapTarget getClosestDismissTarget(int position) { + if (position - mDismissStartTarget.position < mDismissEndTarget.position - position) { + return mDismissStartTarget; + } else { + return mDismissEndTarget; + } + } + private SnapTarget snap(int position) { int minIndex = -1; int minDistance = Integer.MAX_VALUE; diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 23e5a1743c71..8d94d5e1cf3e 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.annotation.Nullable; +import android.app.ActivityManager.StackId; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; @@ -60,6 +61,8 @@ public class DividerView extends FrameLayout implements OnTouchListener, private static final String TAG = "DividerView"; private static final int TASK_POSITION_SAME = Integer.MAX_VALUE; + private static final float DIM_START_FRACTION = 0.5f; + private static final float DIM_DAMP_FACTOR = 1.7f; private ImageButton mHandle; private View mBackground; @@ -264,6 +267,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, } else { mWindowManagerProxy.maximizeDockedStack(); } + mWindowManagerProxy.setResizeDimLayer(false, -1, 0f); } private void liftBackground() { @@ -420,6 +424,21 @@ public class DividerView extends FrameLayout implements OnTouchListener, } else { mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null); } + float fraction = mSnapAlgorithm.calculateDismissingFraction(position); + fraction = Math.max(0, + Math.min((fraction / DIM_START_FRACTION - 1f) / DIM_DAMP_FACTOR, 1f)); + mWindowManagerProxy.setResizeDimLayer(fraction != 0f, + getStackIdForDismissTarget(mSnapAlgorithm.getClosestDismissTarget(position)), + fraction); + } + + private int getStackIdForDismissTarget(SnapTarget dismissTarget) { + if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START && + (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) { + return StackId.DOCKED_STACK_ID; + } else { + return StackId.FULLSCREEN_WORKSPACE_STACK_ID; + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index 933d05ce2b89..2791dfc3972e 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -51,6 +51,11 @@ public class WindowManagerProxy { private final Rect mTmpRect3 = new Rect(); private final Rect mTmpRect4 = new Rect(); private final Rect mTmpRect5 = new Rect(); + + private boolean mDimLayerVisible; + private int mDimLayerTargetStack; + private float mDimLayerAlpha; + private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(); private final Runnable mResizeRunnable = new Runnable() { @@ -98,6 +103,18 @@ public class WindowManagerProxy { } }; + private final Runnable mDimLayerRunnable = new Runnable() { + @Override + public void run() { + try { + WindowManagerGlobal.getWindowManagerService().setResizeDimLayer(mDimLayerVisible, + mDimLayerTargetStack, mDimLayerAlpha); + } catch (RemoteException e) { + Log.w(TAG, "Failed to resize stack: " + e); + } + } + }; + private WindowManagerProxy() { } @@ -162,4 +179,11 @@ public class WindowManagerProxy { } return DOCKED_INVALID; } + + public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) { + mDimLayerVisible = visible; + mDimLayerTargetStack = targetStackId; + mDimLayerAlpha = alpha; + mExecutor.execute(mDimLayerRunnable); + } } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index dd8774fc3646..27ff5bc8e977 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -21,9 +21,14 @@ import android.graphics.Rect; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.Slog; +import android.view.DisplayInfo; import android.view.IDockedStackListener; +import android.view.SurfaceControl; + +import com.android.server.wm.DimLayer.DimLayerUser; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_RIGHT; @@ -34,7 +39,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; /** * Keeps information about the docked stack divider. */ -public class DockedStackDividerController { +public class DockedStackDividerController implements DimLayerUser { private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM; @@ -48,6 +53,7 @@ public class DockedStackDividerController { private boolean mLastVisibility = false; private final RemoteCallbackList mDockedStackListeners = new RemoteCallbackList<>(); + private final DimLayer mDimLayer; DockedStackDividerController(Context context, DisplayContent displayContent) { mDisplayContent = displayContent; @@ -55,6 +61,7 @@ public class DockedStackDividerController { com.android.internal.R.dimen.docked_stack_divider_thickness); mDividerInsets = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.docked_stack_divider_insets); + mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId()); } boolean isResizing() { @@ -85,6 +92,9 @@ public class DockedStackDividerController { } mLastVisibility = visible; notifyDockedDividerVisibilityChanged(visible); + if (!visible) { + setResizeDimLayer(false, INVALID_STACK_ID, 0f); + } } boolean wasVisible() { @@ -158,4 +168,38 @@ public class DockedStackDividerController { notifyDockedStackExistsChanged( mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null); } + + void setResizeDimLayer(boolean visible, int targetStackId, float alpha) { + SurfaceControl.openTransaction(); + TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId); + if (visible && stack != null) { + stack.getDimBounds(mTmpRect); + mDimLayer.setBounds(mTmpRect); + mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(), alpha, + 0 /* duration */); + } else { + mDimLayer.hide(); + } + SurfaceControl.closeTransaction(); + } + + @Override + public boolean isFullscreen() { + return false; + } + + @Override + public DisplayInfo getDisplayInfo() { + return mDisplayContent.getDisplayInfo(); + } + + @Override + public void getDimBounds(Rect outBounds) { + // This dim layer user doesn't need this. + } + + @Override + public String toShortString() { + return TAG; + } } diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java index 263b411097d8..59af0cd2a5ea 100644 --- a/services/core/java/com/android/server/wm/WindowLayersController.java +++ b/services/core/java/com/android/server/wm/WindowLayersController.java @@ -1,9 +1,20 @@ -package com.android.server.wm; +/* + * Copyright (C) 2015 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. + */ -import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS; -import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER; +package com.android.server.wm; import android.app.ActivityManager.StackId; import android.util.Slog; @@ -11,6 +22,11 @@ import android.view.Display; import java.io.PrintWriter; +import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS; +import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER; + /** * Controller for assigning layers to windows on the display. * @@ -133,6 +149,14 @@ public class WindowLayersController { return 0; } + /** + * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just + * above all application surfaces. + */ + int getResizeDimLayer() { + return mDockDivider.mLayer - 1; + } + private void logDebugLayers(WindowList windows) { for (int i = 0, n = windows.size(); i < n; i++) { final WindowState w = windows.get(i); @@ -175,6 +199,11 @@ public class WindowLayersController { // For pinned and docked stack window, we want to make them above other windows // also when these windows are animating. layer = assignAndIncreaseLayerIfNeeded(mDockedWindow, layer); + + // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space + // below the divider but above the app windows. It needs to be below the divider in because + // the divider sometimes overlaps the app windows. + layer++; layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer); // We know that we will be animating a relaunching window in the near future, // which will receive a z-order increase. We want the replaced window to diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 155d37def4b5..f7b81cb9634e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -10209,6 +10209,14 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) { + synchronized (mWindowMap) { + getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer( + visible, targetStackId, alpha); + } + } + public void setTaskResizeable(int taskId, boolean resizeable) { synchronized (mWindowMap) { Task task = mTaskIdToTask.get(taskId); -- 2.11.0