Loading services/core/java/com/android/server/wm/DimBehindController.java 0 → 100644 +291 −0 Original line number Diff line number Diff line package com.android.server.wm; import static com.android.server.wm.WindowManagerService.DEBUG_DIM_LAYER; import android.graphics.Rect; import android.util.ArrayMap; import android.util.Slog; import android.util.TypedValue; import java.io.PrintWriter; /** * Centralizes the control of dim layers used for * {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}. */ class DimBehindController { private static final String TAG = "DimBehindController"; /** Amount of time in milliseconds to animate the dim surface from one value to another, * when no window animation is driving it. */ private static final int DEFAULT_DIM_DURATION = 200; // Shared dim layer for fullscreen users. {@link DimBehindState#dimLayer} will point to this // instead of creating a new object per fullscreen task on a display. private DimLayer mSharedFullScreenDimLayer; private ArrayMap<DimLayer.DimLayerUser, DimBehindState> mState = new ArrayMap<>(); private DisplayContent mDisplayContent; private Rect mTmpBounds = new Rect(); DimBehindController(DisplayContent displayContent) { mDisplayContent = displayContent; } /** Updates the dim layer bounds, recreating it if needed. */ void updateDimLayer(DimLayer.DimLayerUser dimLayerUser) { DimBehindState state = getOrCreateDimBehindState(dimLayerUser); final boolean previousFullscreen = state.dimLayer != null && state.dimLayer == mSharedFullScreenDimLayer; DimLayer newDimLayer; final int displayId = mDisplayContent.getDisplayId(); if (dimLayerUser.isFullscreen()) { if (previousFullscreen) { // Nothing to do here... return; } // Use shared fullscreen dim layer newDimLayer = mSharedFullScreenDimLayer; if (newDimLayer == null) { if (state.dimLayer != null) { // Re-purpose the previous dim layer. newDimLayer = state.dimLayer; } else { // Create new full screen dim layer. newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId); } dimLayerUser.getBounds(mTmpBounds); newDimLayer.setBounds(mTmpBounds); mSharedFullScreenDimLayer = newDimLayer; } else if (state.dimLayer != null) { state.dimLayer. destroySurface(); } } else { newDimLayer = (state.dimLayer == null || previousFullscreen) ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId) : state.dimLayer; dimLayerUser.getBounds(mTmpBounds); newDimLayer.setBounds(mTmpBounds); } state.dimLayer = newDimLayer; } private DimBehindState getOrCreateDimBehindState(DimLayer.DimLayerUser dimLayerUser) { if (DEBUG_DIM_LAYER) Slog.v(TAG, "getDimBehindState, dimLayerUser=" + dimLayerUser.toShortString()); DimBehindState state = mState.get(dimLayerUser); if (state == null) { state = new DimBehindState(); mState.put(dimLayerUser, state); } return state; } private void setContinueDimming(DimLayer.DimLayerUser dimLayerUser) { DimBehindState state = mState.get(dimLayerUser); if (state == null) { if (DEBUG_DIM_LAYER) Slog.w(TAG, "setContinueDimming, no state for: " + dimLayerUser.toShortString()); return; } state.continueDimming = true; } boolean isDimming() { for (int i = mState.size() - 1; i >= 0; i--) { DimBehindState state = mState.valueAt(i); if (state.dimLayer != null && state.dimLayer.isDimming()) { return true; } } return false; } void resetDimming() { for (int i = mState.size() - 1; i >= 0; i--) { mState.valueAt(i).continueDimming = false; } } private boolean getContinueDimming(DimLayer.DimLayerUser dimLayerUser) { DimBehindState state = mState.get(dimLayerUser); return state != null && state.continueDimming; } void startDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator newWinAnimator) { // Only set dim params on the highest dimmed layer. // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. DimBehindState state = getOrCreateDimBehindState(dimLayerUser); if (DEBUG_DIM_LAYER) Slog.v(TAG, "startDimmingIfNeeded," + " dimLayerUser=" + dimLayerUser.toShortString() + " newWinAnimator=" + newWinAnimator + " state.animator=" + state.animator); if (newWinAnimator.mSurfaceShown && (state.animator == null || !state.animator.mSurfaceShown || state.animator.mAnimLayer <= newWinAnimator.mAnimLayer)) { state.animator = newWinAnimator; if (state.animator.mWin.mAppToken == null && !dimLayerUser.isFullscreen()) { // Dim should cover the entire screen for system windows. mDisplayContent.getLogicalDisplayRect(mTmpBounds); state.dimLayer.setBounds(mTmpBounds); } } } void stopDimmingIfNeeded() { if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded, mState.size()=" + mState.size()); for (int i = mState.size() - 1; i >= 0; i--) { DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i); stopDimmingIfNeeded(dimLayerUser); } } private void stopDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser) { // No need to check if state is null, we know the key has a value. DimBehindState state = mState.get(dimLayerUser); if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded," + " dimLayerUser=" + dimLayerUser.toShortString() + " state.continueDimming=" + state.continueDimming + " state.dimLayer.isDimming=" + state.dimLayer.isDimming()); if (!state.continueDimming && state.dimLayer.isDimming()) { state.animator = null; dimLayerUser.getBounds(mTmpBounds); state.dimLayer.setBounds(mTmpBounds); } } boolean animateDimLayers() { int fullScreen = -1; for (int i = mState.size() - 1; i >= 0; i--) { DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i); if (dimLayerUser.isFullscreen()) { fullScreen = i; if (mState.valueAt(i).continueDimming) { break; } } } if (fullScreen != -1) { return animateDimLayers(mState.keyAt(fullScreen)); } else { boolean result = false; for (int i = mState.size() - 1; i >= 0; i--) { result |= animateDimLayers(mState.keyAt(i)); } return result; } } private boolean animateDimLayers(DimLayer.DimLayerUser dimLayerUser) { DimBehindState state = mState.get(dimLayerUser); if (DEBUG_DIM_LAYER) Slog.v(TAG, "animateDimLayers," + " dimLayerUser=" + dimLayerUser.toShortString() + " state.animator=" + state.animator + " state.continueDimming=" + state.continueDimming); final int dimLayer; final float dimAmount; if (state.animator == null) { dimLayer = state.dimLayer.getLayer(); dimAmount = 0; } else { dimLayer = state.animator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; dimAmount = state.animator.mWin.mAttrs.dimAmount; } final float targetAlpha = state.dimLayer.getTargetAlpha(); if (targetAlpha != dimAmount) { if (state.animator == null) { state.dimLayer.hide(DEFAULT_DIM_DURATION); } else { long duration = (state.animator.mAnimating && state.animator.mAnimation != null) ? state.animator.mAnimation.computeDurationHint() : DEFAULT_DIM_DURATION; if (targetAlpha > dimAmount) { duration = getDimBehindFadeDuration(duration); } state.dimLayer.show(dimLayer, dimAmount, duration); } } else if (state.dimLayer.getLayer() != dimLayer) { state.dimLayer.setLayer(dimLayer); } if (state.dimLayer.isAnimating()) { if (!mDisplayContent.mService.okToDisplay()) { // Jump to the end of the animation. state.dimLayer.show(); } else { return state.dimLayer.stepAnimation(); } } return false; } boolean isDimming(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator winAnimator) { DimBehindState state = mState.get(dimLayerUser); return state != null && state.animator == winAnimator && state.dimLayer.isDimming(); } private long getDimBehindFadeDuration(long duration) { TypedValue tv = new TypedValue(); mDisplayContent.mService.mContext.getResources().getValue( com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); if (tv.type == TypedValue.TYPE_FRACTION) { duration = (long) tv.getFraction(duration, duration); } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { duration = tv.data; } return duration; } void close() { for (int i = mState.size() - 1; i >= 0; i--) { DimBehindState state = mState.valueAt(i); state.dimLayer.destroySurface(); } mState.clear(); mSharedFullScreenDimLayer = null; } void removeDimLayerUser(DimLayer.DimLayerUser dimLayerUser) { mState.remove(dimLayerUser); } void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) { if (dimLayerUser == null) { Slog.e(TAG, "Trying to apply dim layer for: " + this + ", but no dim layer user found."); return; } if (!getContinueDimming(dimLayerUser)) { setContinueDimming(dimLayerUser); if (!isDimming(dimLayerUser, animator)) { if (DEBUG_DIM_LAYER) Slog.v(TAG, "Win " + this + " start dimming."); startDimmingIfNeeded(dimLayerUser, animator); } } } private static class DimBehindState { // The particular window with FLAG_DIM_BEHIND set. If null, hide dimLayer. WindowStateAnimator animator; // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the // end then stop any dimming. boolean continueDimming; DimLayer dimLayer; } void dump(String prefix, PrintWriter pw) { pw.println(prefix + "DimBehindController"); for (int i = 0, n = mState.size(); i < n; i++) { pw.println(prefix + " " + mState.keyAt(i).toShortString()); pw.print(prefix + " "); DimBehindState state = mState.valueAt(i); pw.print("dimLayer=" + (state.dimLayer == mSharedFullScreenDimLayer ? "shared" : state.dimLayer)); pw.print(", animator=" + state.animator); pw.println(", continueDimming=" + state.continueDimming + "}"); } } } services/core/java/com/android/server/wm/DimLayer.java +5 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,9 @@ public class DimLayer { boolean isFullscreen(); /** Returns the display info. of the dim layer user. */ DisplayInfo getDisplayInfo(); /** Gets the bounds of the dim layer user. */ void getBounds(Rect outBounds); String toShortString(); } /** The user of this dim layer. */ final DimLayerUser mUser; Loading Loading @@ -239,8 +242,9 @@ public class DimLayer { mDuration = duration; } } if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime); mTargetAlpha = alpha; if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime + " mTargetAlpha=" + mTargetAlpha); } /** Immediate hide. Loading services/core/java/com/android/server/wm/DisplayContent.java +10 −36 Original line number Diff line number Diff line Loading @@ -115,6 +115,8 @@ class DisplayContent { final DockedStackDividerController mDividerControllerLocked; final DimBehindController mDimBehindController; /** * @param display May not be null. * @param service You know. Loading @@ -128,6 +130,7 @@ class DisplayContent { mService = service; initializeDisplayBaseInfo(); mDividerControllerLocked = new DockedStackDividerController(service.mContext, this); mDimBehindController = new DimBehindController(this); } int getDisplayId() { Loading Loading @@ -246,6 +249,7 @@ class DisplayContent { } void detachStack(TaskStack stack) { mDimBehindController.removeDimLayerUser(stack); mStacks.remove(stack); } Loading Loading @@ -382,54 +386,23 @@ class DisplayContent { } boolean animateDimLayers() { boolean result = false; for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final Task task = tasks.get(taskNdx); result |= task.animateDimLayers(); if (task.isFullscreen()) { // No point in continuing as this task covers the entire screen. // Also, fullscreen tasks all share the same dim layer, so we don't want // processing of fullscreen task below this one affecting the dim layer state. return result; } } } return result; return mDimBehindController.animateDimLayers(); } void resetDimming() { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { tasks.get(taskNdx).clearContinueDimming(); } } mDimBehindController.resetDimming(); } boolean isDimming() { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { if (tasks.get(taskNdx).isDimming()) { return true; } } } return false; return mDimBehindController.isDimming(); } void stopDimmingIfNeeded() { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { tasks.get(taskNdx).stopDimmingIfNeeded(); } } mDimBehindController.stopDimmingIfNeeded(); } void close() { mDimBehindController.close(); for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { mStacks.get(stackNdx).close(); } Loading Loading @@ -576,6 +549,7 @@ class DisplayContent { } } pw.println(); mDimBehindController.dump(prefix + " ", pw); } @Override Loading services/core/java/com/android/server/wm/Task.java +14 −158 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.graphics.Rect; import android.util.EventLog; import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.view.DisplayInfo; import android.view.Surface; Loading @@ -39,10 +38,6 @@ import java.io.PrintWriter; import java.util.ArrayList; class Task implements DimLayer.DimLayerUser { /** Amount of time in milliseconds to animate the dim surface from one value to another, * when no window animation is driving it. */ private static final int DEFAULT_DIM_DURATION = 200; // Return value from {@link setBounds} indicating no change was made to the Task bounds. static final int BOUNDS_CHANGE_NONE = 0; // Return value from {@link setBounds} indicating the position of the Task bounds changed. Loading Loading @@ -78,17 +73,6 @@ class Task implements DimLayer.DimLayerUser { // Whether the task is currently being drag-resized private boolean mDragResizing; // The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. WindowStateAnimator mDimWinAnimator; // Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} private DimLayer mDimLayer; // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end // then stop any dimming. private boolean mContinueDimming; // Shared dim layer for fullscreen tasks. {@link #mDimLayer} will point to this instead // of creating a new object per fullscreen task on a display. private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>(); Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, Configuration config) { mTaskId = taskId; Loading Loading @@ -128,6 +112,10 @@ class Task implements DimLayer.DimLayerUser { if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask"); mDeferRemoval = false; DisplayContent content = getDisplayContent(); if (content != null) { content.mDimBehindController.removeDimLayerUser(this); } mStack.removeTask(this); mService.mTaskIdToTask.delete(mTaskId); } Loading Loading @@ -228,7 +216,9 @@ class Task implements DimLayer.DimLayerUser { mBounds.set(bounds); mRotation = rotation; updateDimLayer(); if (displayContent != null) { displayContent.mDimBehindController.updateDimLayer(this); } mOverrideConfig = mFullscreen ? Configuration.EMPTY : config; return boundsChange; } Loading Loading @@ -261,7 +251,8 @@ class Task implements DimLayer.DimLayerUser { } /** Bounds of the task with other system factors taken into consideration. */ void getBounds(Rect out) { @Override public void getBounds(Rect out) { if (useCurrentBounds()) { // No need to adjust the output bounds if fullscreen or the docked stack is visible // since it is already what we want to represent to the rest of the system. Loading Loading @@ -309,139 +300,6 @@ class Task implements DimLayer.DimLayerUser { } } /** Updates the dim layer bounds, recreating it if needed. */ private void updateDimLayer() { DimLayer newDimLayer; final boolean previousFullscreen = mDimLayer != null && sSharedFullscreenDimLayers.indexOfValue(mDimLayer) > -1; final int displayId = mStack.getDisplayContent().getDisplayId(); if (mFullscreen) { if (previousFullscreen) { // Nothing to do here... return; } // Use shared fullscreen dim layer newDimLayer = sSharedFullscreenDimLayers.get(displayId); if (newDimLayer == null) { if (mDimLayer != null) { // Re-purpose the previous dim layer. newDimLayer = mDimLayer; } else { // Create new full screen dim layer. newDimLayer = new DimLayer(mService, this, displayId); } newDimLayer.setBounds(mBounds); sSharedFullscreenDimLayers.put(displayId, newDimLayer); } else if (mDimLayer != null) { mDimLayer.destroySurface(); } } else { newDimLayer = (mDimLayer == null || previousFullscreen) ? new DimLayer(mService, this, displayId) : mDimLayer; newDimLayer.setBounds(mBounds); } mDimLayer = newDimLayer; } boolean animateDimLayers() { final int dimLayer; final float dimAmount; if (mDimWinAnimator == null) { dimLayer = mDimLayer.getLayer(); dimAmount = 0; } else { dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount; } final float targetAlpha = mDimLayer.getTargetAlpha(); if (targetAlpha != dimAmount) { if (mDimWinAnimator == null) { mDimLayer.hide(DEFAULT_DIM_DURATION); } else { long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null) ? mDimWinAnimator.mAnimation.computeDurationHint() : DEFAULT_DIM_DURATION; if (targetAlpha > dimAmount) { duration = getDimBehindFadeDuration(duration); } mDimLayer.show(dimLayer, dimAmount, duration); } } else if (mDimLayer.getLayer() != dimLayer) { mDimLayer.setLayer(dimLayer); } if (mDimLayer.isAnimating()) { if (!mService.okToDisplay()) { // Jump to the end of the animation. mDimLayer.show(); } else { return mDimLayer.stepAnimation(); } } return false; } private long getDimBehindFadeDuration(long duration) { TypedValue tv = new TypedValue(); mService.mContext.getResources().getValue( com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); if (tv.type == TypedValue.TYPE_FRACTION) { duration = (long)tv.getFraction(duration, duration); } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { duration = tv.data; } return duration; } void clearContinueDimming() { mContinueDimming = false; } void setContinueDimming() { mContinueDimming = true; } boolean getContinueDimming() { return mContinueDimming; } boolean isDimming() { return mDimLayer.isDimming(); } boolean isDimming(WindowStateAnimator winAnimator) { return mDimWinAnimator == winAnimator && isDimming(); } void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) { // Only set dim params on the highest dimmed layer. // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null || !mDimWinAnimator.mSurfaceShown || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) { mDimWinAnimator = newWinAnimator; if (mDimWinAnimator.mWin.mAppToken == null && !mFullscreen && mStack.getDisplayContent() != null) { // Dim should cover the entire screen for system windows. mStack.getDisplayContent().getLogicalDisplayRect(mTmpRect); mDimLayer.setBounds(mTmpRect); } } } void stopDimmingIfNeeded() { if (!mContinueDimming && isDimming()) { mDimWinAnimator = null; mDimLayer.setBounds(mBounds); } } void close() { if (mDimLayer != null) { mDimLayer.destroySurface(); mDimLayer = null; } } void resizeWindows() { final ArrayList<WindowState> resizingWindows = mService.mResizingWindows; for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { Loading Loading @@ -491,16 +349,14 @@ class Task implements DimLayer.DimLayerUser { return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}"; } @Override public String toShortString() { return "Task=" + mTaskId; } public void printTo(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("taskId="); pw.print(mTaskId); pw.print(prefix); pw.print("appTokens="); pw.print(mAppTokens); pw.print(prefix); pw.print("mdr="); pw.println(mDeferRemoval); if (mDimLayer.isDimming()) { pw.print(prefix); pw.println("mDimLayer:"); mDimLayer.printTo(prefix + " ", pw); pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator); } else { pw.println(); } } } services/core/java/com/android/server/wm/TaskPositioner.java +10 −0 Original line number Diff line number Diff line Loading @@ -468,6 +468,16 @@ class TaskPositioner implements DimLayer.DimLayerUser { return mTask.mStack.getDisplayInfo(); } @Override public void getBounds(Rect out) { // This dim layer user doesn't need this. } @Override public String toShortString() { return TAG; } private int getDragLayerLocked() { return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG) * WindowManagerService.TYPE_LAYER_MULTIPLIER Loading Loading
services/core/java/com/android/server/wm/DimBehindController.java 0 → 100644 +291 −0 Original line number Diff line number Diff line package com.android.server.wm; import static com.android.server.wm.WindowManagerService.DEBUG_DIM_LAYER; import android.graphics.Rect; import android.util.ArrayMap; import android.util.Slog; import android.util.TypedValue; import java.io.PrintWriter; /** * Centralizes the control of dim layers used for * {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}. */ class DimBehindController { private static final String TAG = "DimBehindController"; /** Amount of time in milliseconds to animate the dim surface from one value to another, * when no window animation is driving it. */ private static final int DEFAULT_DIM_DURATION = 200; // Shared dim layer for fullscreen users. {@link DimBehindState#dimLayer} will point to this // instead of creating a new object per fullscreen task on a display. private DimLayer mSharedFullScreenDimLayer; private ArrayMap<DimLayer.DimLayerUser, DimBehindState> mState = new ArrayMap<>(); private DisplayContent mDisplayContent; private Rect mTmpBounds = new Rect(); DimBehindController(DisplayContent displayContent) { mDisplayContent = displayContent; } /** Updates the dim layer bounds, recreating it if needed. */ void updateDimLayer(DimLayer.DimLayerUser dimLayerUser) { DimBehindState state = getOrCreateDimBehindState(dimLayerUser); final boolean previousFullscreen = state.dimLayer != null && state.dimLayer == mSharedFullScreenDimLayer; DimLayer newDimLayer; final int displayId = mDisplayContent.getDisplayId(); if (dimLayerUser.isFullscreen()) { if (previousFullscreen) { // Nothing to do here... return; } // Use shared fullscreen dim layer newDimLayer = mSharedFullScreenDimLayer; if (newDimLayer == null) { if (state.dimLayer != null) { // Re-purpose the previous dim layer. newDimLayer = state.dimLayer; } else { // Create new full screen dim layer. newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId); } dimLayerUser.getBounds(mTmpBounds); newDimLayer.setBounds(mTmpBounds); mSharedFullScreenDimLayer = newDimLayer; } else if (state.dimLayer != null) { state.dimLayer. destroySurface(); } } else { newDimLayer = (state.dimLayer == null || previousFullscreen) ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId) : state.dimLayer; dimLayerUser.getBounds(mTmpBounds); newDimLayer.setBounds(mTmpBounds); } state.dimLayer = newDimLayer; } private DimBehindState getOrCreateDimBehindState(DimLayer.DimLayerUser dimLayerUser) { if (DEBUG_DIM_LAYER) Slog.v(TAG, "getDimBehindState, dimLayerUser=" + dimLayerUser.toShortString()); DimBehindState state = mState.get(dimLayerUser); if (state == null) { state = new DimBehindState(); mState.put(dimLayerUser, state); } return state; } private void setContinueDimming(DimLayer.DimLayerUser dimLayerUser) { DimBehindState state = mState.get(dimLayerUser); if (state == null) { if (DEBUG_DIM_LAYER) Slog.w(TAG, "setContinueDimming, no state for: " + dimLayerUser.toShortString()); return; } state.continueDimming = true; } boolean isDimming() { for (int i = mState.size() - 1; i >= 0; i--) { DimBehindState state = mState.valueAt(i); if (state.dimLayer != null && state.dimLayer.isDimming()) { return true; } } return false; } void resetDimming() { for (int i = mState.size() - 1; i >= 0; i--) { mState.valueAt(i).continueDimming = false; } } private boolean getContinueDimming(DimLayer.DimLayerUser dimLayerUser) { DimBehindState state = mState.get(dimLayerUser); return state != null && state.continueDimming; } void startDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator newWinAnimator) { // Only set dim params on the highest dimmed layer. // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. DimBehindState state = getOrCreateDimBehindState(dimLayerUser); if (DEBUG_DIM_LAYER) Slog.v(TAG, "startDimmingIfNeeded," + " dimLayerUser=" + dimLayerUser.toShortString() + " newWinAnimator=" + newWinAnimator + " state.animator=" + state.animator); if (newWinAnimator.mSurfaceShown && (state.animator == null || !state.animator.mSurfaceShown || state.animator.mAnimLayer <= newWinAnimator.mAnimLayer)) { state.animator = newWinAnimator; if (state.animator.mWin.mAppToken == null && !dimLayerUser.isFullscreen()) { // Dim should cover the entire screen for system windows. mDisplayContent.getLogicalDisplayRect(mTmpBounds); state.dimLayer.setBounds(mTmpBounds); } } } void stopDimmingIfNeeded() { if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded, mState.size()=" + mState.size()); for (int i = mState.size() - 1; i >= 0; i--) { DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i); stopDimmingIfNeeded(dimLayerUser); } } private void stopDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser) { // No need to check if state is null, we know the key has a value. DimBehindState state = mState.get(dimLayerUser); if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded," + " dimLayerUser=" + dimLayerUser.toShortString() + " state.continueDimming=" + state.continueDimming + " state.dimLayer.isDimming=" + state.dimLayer.isDimming()); if (!state.continueDimming && state.dimLayer.isDimming()) { state.animator = null; dimLayerUser.getBounds(mTmpBounds); state.dimLayer.setBounds(mTmpBounds); } } boolean animateDimLayers() { int fullScreen = -1; for (int i = mState.size() - 1; i >= 0; i--) { DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i); if (dimLayerUser.isFullscreen()) { fullScreen = i; if (mState.valueAt(i).continueDimming) { break; } } } if (fullScreen != -1) { return animateDimLayers(mState.keyAt(fullScreen)); } else { boolean result = false; for (int i = mState.size() - 1; i >= 0; i--) { result |= animateDimLayers(mState.keyAt(i)); } return result; } } private boolean animateDimLayers(DimLayer.DimLayerUser dimLayerUser) { DimBehindState state = mState.get(dimLayerUser); if (DEBUG_DIM_LAYER) Slog.v(TAG, "animateDimLayers," + " dimLayerUser=" + dimLayerUser.toShortString() + " state.animator=" + state.animator + " state.continueDimming=" + state.continueDimming); final int dimLayer; final float dimAmount; if (state.animator == null) { dimLayer = state.dimLayer.getLayer(); dimAmount = 0; } else { dimLayer = state.animator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; dimAmount = state.animator.mWin.mAttrs.dimAmount; } final float targetAlpha = state.dimLayer.getTargetAlpha(); if (targetAlpha != dimAmount) { if (state.animator == null) { state.dimLayer.hide(DEFAULT_DIM_DURATION); } else { long duration = (state.animator.mAnimating && state.animator.mAnimation != null) ? state.animator.mAnimation.computeDurationHint() : DEFAULT_DIM_DURATION; if (targetAlpha > dimAmount) { duration = getDimBehindFadeDuration(duration); } state.dimLayer.show(dimLayer, dimAmount, duration); } } else if (state.dimLayer.getLayer() != dimLayer) { state.dimLayer.setLayer(dimLayer); } if (state.dimLayer.isAnimating()) { if (!mDisplayContent.mService.okToDisplay()) { // Jump to the end of the animation. state.dimLayer.show(); } else { return state.dimLayer.stepAnimation(); } } return false; } boolean isDimming(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator winAnimator) { DimBehindState state = mState.get(dimLayerUser); return state != null && state.animator == winAnimator && state.dimLayer.isDimming(); } private long getDimBehindFadeDuration(long duration) { TypedValue tv = new TypedValue(); mDisplayContent.mService.mContext.getResources().getValue( com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); if (tv.type == TypedValue.TYPE_FRACTION) { duration = (long) tv.getFraction(duration, duration); } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { duration = tv.data; } return duration; } void close() { for (int i = mState.size() - 1; i >= 0; i--) { DimBehindState state = mState.valueAt(i); state.dimLayer.destroySurface(); } mState.clear(); mSharedFullScreenDimLayer = null; } void removeDimLayerUser(DimLayer.DimLayerUser dimLayerUser) { mState.remove(dimLayerUser); } void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) { if (dimLayerUser == null) { Slog.e(TAG, "Trying to apply dim layer for: " + this + ", but no dim layer user found."); return; } if (!getContinueDimming(dimLayerUser)) { setContinueDimming(dimLayerUser); if (!isDimming(dimLayerUser, animator)) { if (DEBUG_DIM_LAYER) Slog.v(TAG, "Win " + this + " start dimming."); startDimmingIfNeeded(dimLayerUser, animator); } } } private static class DimBehindState { // The particular window with FLAG_DIM_BEHIND set. If null, hide dimLayer. WindowStateAnimator animator; // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the // end then stop any dimming. boolean continueDimming; DimLayer dimLayer; } void dump(String prefix, PrintWriter pw) { pw.println(prefix + "DimBehindController"); for (int i = 0, n = mState.size(); i < n; i++) { pw.println(prefix + " " + mState.keyAt(i).toShortString()); pw.print(prefix + " "); DimBehindState state = mState.valueAt(i); pw.print("dimLayer=" + (state.dimLayer == mSharedFullScreenDimLayer ? "shared" : state.dimLayer)); pw.print(", animator=" + state.animator); pw.println(", continueDimming=" + state.continueDimming + "}"); } } }
services/core/java/com/android/server/wm/DimLayer.java +5 −1 Original line number Diff line number Diff line Loading @@ -65,6 +65,9 @@ public class DimLayer { boolean isFullscreen(); /** Returns the display info. of the dim layer user. */ DisplayInfo getDisplayInfo(); /** Gets the bounds of the dim layer user. */ void getBounds(Rect outBounds); String toShortString(); } /** The user of this dim layer. */ final DimLayerUser mUser; Loading Loading @@ -239,8 +242,9 @@ public class DimLayer { mDuration = duration; } } if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime); mTargetAlpha = alpha; if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime + " mTargetAlpha=" + mTargetAlpha); } /** Immediate hide. Loading
services/core/java/com/android/server/wm/DisplayContent.java +10 −36 Original line number Diff line number Diff line Loading @@ -115,6 +115,8 @@ class DisplayContent { final DockedStackDividerController mDividerControllerLocked; final DimBehindController mDimBehindController; /** * @param display May not be null. * @param service You know. Loading @@ -128,6 +130,7 @@ class DisplayContent { mService = service; initializeDisplayBaseInfo(); mDividerControllerLocked = new DockedStackDividerController(service.mContext, this); mDimBehindController = new DimBehindController(this); } int getDisplayId() { Loading Loading @@ -246,6 +249,7 @@ class DisplayContent { } void detachStack(TaskStack stack) { mDimBehindController.removeDimLayerUser(stack); mStacks.remove(stack); } Loading Loading @@ -382,54 +386,23 @@ class DisplayContent { } boolean animateDimLayers() { boolean result = false; for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final Task task = tasks.get(taskNdx); result |= task.animateDimLayers(); if (task.isFullscreen()) { // No point in continuing as this task covers the entire screen. // Also, fullscreen tasks all share the same dim layer, so we don't want // processing of fullscreen task below this one affecting the dim layer state. return result; } } } return result; return mDimBehindController.animateDimLayers(); } void resetDimming() { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { tasks.get(taskNdx).clearContinueDimming(); } } mDimBehindController.resetDimming(); } boolean isDimming() { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { if (tasks.get(taskNdx).isDimming()) { return true; } } } return false; return mDimBehindController.isDimming(); } void stopDimmingIfNeeded() { for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { tasks.get(taskNdx).stopDimmingIfNeeded(); } } mDimBehindController.stopDimmingIfNeeded(); } void close() { mDimBehindController.close(); for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { mStacks.get(stackNdx).close(); } Loading Loading @@ -576,6 +549,7 @@ class DisplayContent { } } pw.println(); mDimBehindController.dump(prefix + " ", pw); } @Override Loading
services/core/java/com/android/server/wm/Task.java +14 −158 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.graphics.Rect; import android.util.EventLog; import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.view.DisplayInfo; import android.view.Surface; Loading @@ -39,10 +38,6 @@ import java.io.PrintWriter; import java.util.ArrayList; class Task implements DimLayer.DimLayerUser { /** Amount of time in milliseconds to animate the dim surface from one value to another, * when no window animation is driving it. */ private static final int DEFAULT_DIM_DURATION = 200; // Return value from {@link setBounds} indicating no change was made to the Task bounds. static final int BOUNDS_CHANGE_NONE = 0; // Return value from {@link setBounds} indicating the position of the Task bounds changed. Loading Loading @@ -78,17 +73,6 @@ class Task implements DimLayer.DimLayerUser { // Whether the task is currently being drag-resized private boolean mDragResizing; // The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. WindowStateAnimator mDimWinAnimator; // Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} private DimLayer mDimLayer; // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end // then stop any dimming. private boolean mContinueDimming; // Shared dim layer for fullscreen tasks. {@link #mDimLayer} will point to this instead // of creating a new object per fullscreen task on a display. private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>(); Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds, Configuration config) { mTaskId = taskId; Loading Loading @@ -128,6 +112,10 @@ class Task implements DimLayer.DimLayerUser { if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId); EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask"); mDeferRemoval = false; DisplayContent content = getDisplayContent(); if (content != null) { content.mDimBehindController.removeDimLayerUser(this); } mStack.removeTask(this); mService.mTaskIdToTask.delete(mTaskId); } Loading Loading @@ -228,7 +216,9 @@ class Task implements DimLayer.DimLayerUser { mBounds.set(bounds); mRotation = rotation; updateDimLayer(); if (displayContent != null) { displayContent.mDimBehindController.updateDimLayer(this); } mOverrideConfig = mFullscreen ? Configuration.EMPTY : config; return boundsChange; } Loading Loading @@ -261,7 +251,8 @@ class Task implements DimLayer.DimLayerUser { } /** Bounds of the task with other system factors taken into consideration. */ void getBounds(Rect out) { @Override public void getBounds(Rect out) { if (useCurrentBounds()) { // No need to adjust the output bounds if fullscreen or the docked stack is visible // since it is already what we want to represent to the rest of the system. Loading Loading @@ -309,139 +300,6 @@ class Task implements DimLayer.DimLayerUser { } } /** Updates the dim layer bounds, recreating it if needed. */ private void updateDimLayer() { DimLayer newDimLayer; final boolean previousFullscreen = mDimLayer != null && sSharedFullscreenDimLayers.indexOfValue(mDimLayer) > -1; final int displayId = mStack.getDisplayContent().getDisplayId(); if (mFullscreen) { if (previousFullscreen) { // Nothing to do here... return; } // Use shared fullscreen dim layer newDimLayer = sSharedFullscreenDimLayers.get(displayId); if (newDimLayer == null) { if (mDimLayer != null) { // Re-purpose the previous dim layer. newDimLayer = mDimLayer; } else { // Create new full screen dim layer. newDimLayer = new DimLayer(mService, this, displayId); } newDimLayer.setBounds(mBounds); sSharedFullscreenDimLayers.put(displayId, newDimLayer); } else if (mDimLayer != null) { mDimLayer.destroySurface(); } } else { newDimLayer = (mDimLayer == null || previousFullscreen) ? new DimLayer(mService, this, displayId) : mDimLayer; newDimLayer.setBounds(mBounds); } mDimLayer = newDimLayer; } boolean animateDimLayers() { final int dimLayer; final float dimAmount; if (mDimWinAnimator == null) { dimLayer = mDimLayer.getLayer(); dimAmount = 0; } else { dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM; dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount; } final float targetAlpha = mDimLayer.getTargetAlpha(); if (targetAlpha != dimAmount) { if (mDimWinAnimator == null) { mDimLayer.hide(DEFAULT_DIM_DURATION); } else { long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null) ? mDimWinAnimator.mAnimation.computeDurationHint() : DEFAULT_DIM_DURATION; if (targetAlpha > dimAmount) { duration = getDimBehindFadeDuration(duration); } mDimLayer.show(dimLayer, dimAmount, duration); } } else if (mDimLayer.getLayer() != dimLayer) { mDimLayer.setLayer(dimLayer); } if (mDimLayer.isAnimating()) { if (!mService.okToDisplay()) { // Jump to the end of the animation. mDimLayer.show(); } else { return mDimLayer.stepAnimation(); } } return false; } private long getDimBehindFadeDuration(long duration) { TypedValue tv = new TypedValue(); mService.mContext.getResources().getValue( com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); if (tv.type == TypedValue.TYPE_FRACTION) { duration = (long)tv.getFraction(duration, duration); } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { duration = tv.data; } return duration; } void clearContinueDimming() { mContinueDimming = false; } void setContinueDimming() { mContinueDimming = true; } boolean getContinueDimming() { return mContinueDimming; } boolean isDimming() { return mDimLayer.isDimming(); } boolean isDimming(WindowStateAnimator winAnimator) { return mDimWinAnimator == winAnimator && isDimming(); } void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) { // Only set dim params on the highest dimmed layer. // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer. if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null || !mDimWinAnimator.mSurfaceShown || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) { mDimWinAnimator = newWinAnimator; if (mDimWinAnimator.mWin.mAppToken == null && !mFullscreen && mStack.getDisplayContent() != null) { // Dim should cover the entire screen for system windows. mStack.getDisplayContent().getLogicalDisplayRect(mTmpRect); mDimLayer.setBounds(mTmpRect); } } } void stopDimmingIfNeeded() { if (!mContinueDimming && isDimming()) { mDimWinAnimator = null; mDimLayer.setBounds(mBounds); } } void close() { if (mDimLayer != null) { mDimLayer.destroySurface(); mDimLayer = null; } } void resizeWindows() { final ArrayList<WindowState> resizingWindows = mService.mResizingWindows; for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { Loading Loading @@ -491,16 +349,14 @@ class Task implements DimLayer.DimLayerUser { return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}"; } @Override public String toShortString() { return "Task=" + mTaskId; } public void printTo(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("taskId="); pw.print(mTaskId); pw.print(prefix); pw.print("appTokens="); pw.print(mAppTokens); pw.print(prefix); pw.print("mdr="); pw.println(mDeferRemoval); if (mDimLayer.isDimming()) { pw.print(prefix); pw.println("mDimLayer:"); mDimLayer.printTo(prefix + " ", pw); pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator); } else { pw.println(); } } }
services/core/java/com/android/server/wm/TaskPositioner.java +10 −0 Original line number Diff line number Diff line Loading @@ -468,6 +468,16 @@ class TaskPositioner implements DimLayer.DimLayerUser { return mTask.mStack.getDisplayInfo(); } @Override public void getBounds(Rect out) { // This dim layer user doesn't need this. } @Override public String toShortString() { return TAG; } private int getDragLayerLocked() { return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG) * WindowManagerService.TYPE_LAYER_MULTIPLIER Loading