diff --git a/core/java/com/android/internal/util/ToBooleanFunction.java b/core/java/com/android/internal/util/ToBooleanFunction.java new file mode 100644 index 0000000000000..83866c22976ff --- /dev/null +++ b/core/java/com/android/internal/util/ToBooleanFunction.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 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.internal.util; + +import java.util.function.Function; + +/** + * Represents a function that produces an boolean-valued result. This is the + * {@code boolean}-producing primitive specialization for {@link Function}. + * + *

This is a functional interface + * whose functional method is {@link #apply(Object)}. + * + * @param the type of the input to the function + * + * @see Function + * @since 1.8 + */ +@FunctionalInterface +public interface ToBooleanFunction { + + /** + * Applies this function to the given argument. + * + * @param value the function argument + * @return the function result + */ + boolean apply(T value); +} diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 05e6f96b1b0c4..0844d48b86696 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -47,6 +47,7 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE import static com.android.server.wm.WindowManagerService.logWithStack; import android.os.Debug; +import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; @@ -66,7 +67,7 @@ import android.view.animation.Animation; import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.function.Consumer; +import java.util.function.Function; class AppTokenList extends ArrayList { } @@ -1270,19 +1271,20 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree } @Override - void forAllWindows(Consumer callback, boolean traverseTopToBottom) { + boolean forAllWindows(ToBooleanFunction callback, boolean traverseTopToBottom) { // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent // before the non-exiting app tokens. So, we skip the exiting app tokens here. // TODO: Investigate if we need to continue to do this or if we can just process them // in-order. if (mIsExiting && !waitingForReplacement()) { - return; + return false; } - forAllWindowsUnchecked(callback, traverseTopToBottom); + return forAllWindowsUnchecked(callback, traverseTopToBottom); } - void forAllWindowsUnchecked(Consumer callback, boolean traverseTopToBottom) { - super.forAllWindows(callback, traverseTopToBottom); + boolean forAllWindowsUnchecked(ToBooleanFunction callback, + boolean traverseTopToBottom) { + return super.forAllWindows(callback, traverseTopToBottom); } @Override diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ff39853833dab..c8e35eb0c0f8f 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -127,6 +127,7 @@ import android.view.SurfaceControl; import android.view.WindowManagerPolicy; import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.ToBooleanFunction; import com.android.internal.view.IInputMethodClient; import com.android.server.input.InputWindowHandle; @@ -141,6 +142,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; +import java.util.function.Function; /** * Utility class for keeping track of the WindowStates and other pertinent contents of a @@ -1407,9 +1409,7 @@ class DisplayContent extends WindowContainer callback, boolean traverseTopToBottom) { + boolean forAllWindows(ToBooleanFunction callback, + boolean traverseTopToBottom) { if (traverseTopToBottom) { - super.forAllWindows(callback, traverseTopToBottom); - forAllExitingAppTokenWindows(callback, traverseTopToBottom); + if (super.forAllWindows(callback, traverseTopToBottom)) { + return true; + } + if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) { + return true; + } } else { - forAllExitingAppTokenWindows(callback, traverseTopToBottom); - super.forAllWindows(callback, traverseTopToBottom); + if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) { + return true; + } + if (super.forAllWindows(callback, traverseTopToBottom)) { + return true; + } } + return false; } - private void forAllExitingAppTokenWindows(Consumer callback, + private boolean forAllExitingAppTokenWindows(ToBooleanFunction callback, boolean traverseTopToBottom) { // For legacy reasons we process the TaskStack.mExitingAppTokens first here before the // app tokens. @@ -3255,7 +3265,10 @@ class DisplayContent extends WindowContainer= 0; --i) { final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens; for (int j = appTokens.size() - 1; j >= 0; --j) { - appTokens.get(j).forAllWindowsUnchecked(callback, traverseTopToBottom); + if (appTokens.get(j).forAllWindowsUnchecked(callback, + traverseTopToBottom)) { + return true; + } } } } else { @@ -3264,10 +3277,14 @@ class DisplayContent extends WindowContainer sendDragStartedLw(w, touchX, touchY, mDataDescription), - false /* traverseTopToBottom */ ); + mDisplayContent.forAllWindows(w -> { + sendDragStartedLw(w, touchX, touchY, mDataDescription); + }, false /* traverseTopToBottom */ ); } /* helper - send a ACTION_DRAG_STARTED event, if the diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index d3e8e8eba8805..8dbf2b3e019ff 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -17,9 +17,9 @@ package com.android.server.wm; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; @@ -30,8 +30,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIG import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT; -import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; -import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET; import android.os.Bundle; import android.os.Debug; @@ -61,11 +59,8 @@ class WallpaperController { // with the wallpaper. private WindowState mWallpaperTarget = null; // If non-null, we are in the middle of animating from one wallpaper target - // to another, and this is the lower one in Z-order. - private WindowState mLowerWallpaperTarget = null; - // If non-null, we are in the middle of animating from one wallpaper target - // to another, and this is the higher one in Z-order. - private WindowState mUpperWallpaperTarget = null; + // to another, and this is the previous wallpaper target. + private WindowState mPrevWallpaperTarget = null; private int mWallpaperAnimLayerAdjustment; @@ -78,7 +73,7 @@ class WallpaperController { // This is set when we are waiting for a wallpaper to tell us it is done // changing its scroll position. - WindowState mWaitingOnWallpaper; + private WindowState mWaitingOnWallpaper; // The last time we had a timeout when waiting for a wallpaper. private long mLastWallpaperTimeoutTime; @@ -110,14 +105,6 @@ class WallpaperController { return mWallpaperTarget; } - WindowState getLowerWallpaperTarget() { - return mLowerWallpaperTarget; - } - - WindowState getUpperWallpaperTarget() { - return mUpperWallpaperTarget; - } - boolean isWallpaperTarget(WindowState win) { return win == mWallpaperTarget; } @@ -145,13 +132,11 @@ class WallpaperController { + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??") + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null) ? wallpaperTarget.mAppToken.mAppAnimator.animation : null) - + " upper=" + mUpperWallpaperTarget - + " lower=" + mLowerWallpaperTarget); + + " prev=" + mPrevWallpaperTarget); return (wallpaperTarget != null && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null && wallpaperTarget.mAppToken.mAppAnimator.animation != null))) - || mUpperWallpaperTarget != null - || mLowerWallpaperTarget != null; + || mPrevWallpaperTarget != null; } boolean isWallpaperTargetAnimating() { @@ -177,7 +162,7 @@ class WallpaperController { void hideWallpapers(final WindowState winGoingAway) { if (mWallpaperTarget != null - && (mWallpaperTarget != winGoingAway || mLowerWallpaperTarget != null)) { + && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) { return; } if (mService.mAppTransition.isRunning()) { @@ -192,8 +177,8 @@ class WallpaperController { final WallpaperWindowToken token = mWallpaperTokens.get(i); token.hideWallpaperToken(wasDeferred, "hideWallpapers"); if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token - + " from " + winGoingAway + " target=" + mWallpaperTarget + " lower=" - + mLowerWallpaperTarget + "\n" + Debug.getCallers(5, " ")); + + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev=" + + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " ")); } } @@ -299,9 +284,7 @@ class WallpaperController { Bundle sendWindowWallpaperCommand( WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) { - if (window == mWallpaperTarget - || window == mLowerWallpaperTarget - || window == mUpperWallpaperTarget) { + if (window == mWallpaperTarget || window == mPrevWallpaperTarget) { boolean doWait = sync; for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); @@ -388,51 +371,52 @@ class WallpaperController { return mWallpaperAnimLayerAdjustment; } - private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) { + private void findWallpaperTarget(DisplayContent dc , FindWallpaperTargetResult result) { final WindowAnimator winAnimator = mService.mAnimator; result.reset(); - WindowState w = null; - int windowDetachedI = -1; - boolean resetTopWallpaper = false; - boolean inFreeformSpace = false; - boolean replacing = false; - boolean keyguardGoingAwayWithWallpaper = false; - boolean needsShowWhenLockedWallpaper = false; + if (mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) { + // In freeform mode we set the wallpaper as its own target, so we don't need an + // additional window to make it visible. + result.setUseTopWallpaperAsTarget(true); + } - for (int i = windows.size() - 1; i >= 0; i--) { - w = windows.get(i); + dc.forAllWindows(w -> { if ((w.mAttrs.type == TYPE_WALLPAPER)) { - if (result.topWallpaper == null || resetTopWallpaper) { - result.setTopWallpaper(w, i); - resetTopWallpaper = false; + if (result.topWallpaper == null || result.resetTopWallpaper) { + result.setTopWallpaper(w); + result.resetTopWallpaper = false; } - continue; + return false; } - resetTopWallpaper = true; + + result.resetTopWallpaper = true; if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) { // If this window's app token is hidden and not animating, // it is of no interest to us. if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w); - continue; + return false; } } - if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen=" - + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState); + if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen() + + " mDrawState=" + w.mWinAnimator.mDrawState); - if (!inFreeformSpace) { - TaskStack stack = w.getStack(); - inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID; + if (w.mWillReplaceWindow && mWallpaperTarget == null + && !result.useTopWallpaperAsTarget) { + // When we are replacing a window and there was wallpaper before replacement, we + // want to keep the window until the new windows fully appear and can determine the + // visibility, to avoid flickering. + result.setUseTopWallpaperAsTarget(true); } - replacing |= w.mWillReplaceWindow; - keyguardGoingAwayWithWallpaper |= (w.mAppToken != null + final boolean keyguardGoingAwayWithWallpaper = (w.mAppToken != null && AppTransition.isKeyguardGoingAwayTransit( w.mAppToken.mAppAnimator.getTransit()) && (w.mAppToken.mAppAnimator.getTransitFlags() & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0); + boolean needsShowWhenLockedWallpaper = false; if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && mService.mPolicy.isKeyguardLocked() && mService.mPolicy.isKeyguardOccluded()) { @@ -442,248 +426,147 @@ class WallpaperController { || (w.mAppToken != null && !w.mAppToken.fillsParent()); } + if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) { + // Keep the wallpaper during Keyguard exit but also when it's needed for a + // non-fullscreen show when locked activity. + result.setUseTopWallpaperAsTarget(true); + } + final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0; if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) { - if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w); - result.setWallpaperTarget(w, i); + if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w); + result.setWallpaperTarget(w); if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) { // The current wallpaper target is animating, so we'll look behind it for // another possible target and figure out what is going on later. if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": token animating, looking behind."); - continue; } - break; + // Found a target! End search. + return true; } else if (w == winAnimator.mWindowDetachedWallpaper) { - windowDetachedI = i; + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, + "Found animating detached wallpaper target win: " + w); + result.setUseTopWallpaperAsTarget(true); } - } + return false; + }, true /* traverseTopToBottom */); - if (result.wallpaperTarget != null) { - return; - } - - if (windowDetachedI >= 0) { - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w); - result.setWallpaperTarget(w, windowDetachedI); - } else if (inFreeformSpace || (replacing && mWallpaperTarget != null)) { - // In freeform mode we set the wallpaper as its own target, so we don't need an - // additional window to make it visible. When we are replacing a window and there was - // wallpaper before replacement, we want to keep the window until the new windows fully - // appear and can determine the visibility, to avoid flickering. - result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex); - - } else if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) { - // Keep the wallpaper during Keyguard exit but also when it's needed for a - // non-fullscreen show when locked activity. - result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex); + if (result.wallpaperTarget == null && result.useTopWallpaperAsTarget) { + result.setWallpaperTarget(result.topWallpaper); } } private boolean isFullscreen(WindowManager.LayoutParams attrs) { return attrs.x == 0 && attrs.y == 0 - && attrs.width == WindowManager.LayoutParams.MATCH_PARENT - && attrs.height == WindowManager.LayoutParams.MATCH_PARENT; + && attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT; } /** Updates the target wallpaper if needed and returns true if an update happened. */ - private boolean updateWallpaperWindowsTarget( - WindowList windows, FindWallpaperTargetResult result) { + private void updateWallpaperWindowsTarget(DisplayContent dc, + FindWallpaperTargetResult result) { WindowState wallpaperTarget = result.wallpaperTarget; - int wallpaperTargetIndex = result.wallpaperTargetIndex; if (mWallpaperTarget == wallpaperTarget - || (mLowerWallpaperTarget != null && mLowerWallpaperTarget == wallpaperTarget)) { + || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == wallpaperTarget)) { - if (mLowerWallpaperTarget != null) { - // Is it time to stop animating? - if (!mLowerWallpaperTarget.isAnimatingLw() - || !mUpperWallpaperTarget.isAnimatingLw()) { - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "No longer animating wallpaper targets!"); - mLowerWallpaperTarget = null; - mUpperWallpaperTarget = null; - mWallpaperTarget = wallpaperTarget; - return true; - } + if (mPrevWallpaperTarget == null) { + return; } - return false; + // Is it time to stop animating? + if (!mPrevWallpaperTarget.isAnimatingLw()) { + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!"); + mPrevWallpaperTarget = null; + mWallpaperTarget = wallpaperTarget; + } + return; } if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget); + "New wallpaper target: " + wallpaperTarget + " prevTarget: " + mWallpaperTarget); - mLowerWallpaperTarget = null; - mUpperWallpaperTarget = null; + mPrevWallpaperTarget = null; - WindowState oldW = mWallpaperTarget; + final WindowState prevWallpaperTarget = mWallpaperTarget; mWallpaperTarget = wallpaperTarget; - if (wallpaperTarget == null || oldW == null) { - return true; + if (wallpaperTarget == null || prevWallpaperTarget == null) { + return; } // Now what is happening... if the current and new targets are animating, // then we are in our super special mode! - boolean oldAnim = oldW.isAnimatingLw(); + boolean oldAnim = prevWallpaperTarget.isAnimatingLw(); boolean foundAnim = wallpaperTarget.isAnimatingLw(); if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "New animation: " + foundAnim + " old animation: " + oldAnim); if (!foundAnim || !oldAnim) { - return true; + return; } - int oldI = windows.indexOf(oldW); - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "New i: " + wallpaperTargetIndex + " old i: " + oldI); - - if (oldI < 0) { - return true; + if (dc.getWindow(w -> w == prevWallpaperTarget) == null) { + return; } final boolean newTargetHidden = wallpaperTarget.mAppToken != null && wallpaperTarget.mAppToken.hiddenRequested; - final boolean oldTargetHidden = oldW.mAppToken != null - && oldW.mAppToken.hiddenRequested; + final boolean oldTargetHidden = prevWallpaperTarget.mAppToken != null + && prevWallpaperTarget.mAppToken.hiddenRequested; - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old#" + oldI + "=" - + oldW + " hidden=" + oldTargetHidden + " new#" + wallpaperTargetIndex + "=" - + wallpaperTarget + " hidden=" + newTargetHidden); + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: " + + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget + + " hidden=" + newTargetHidden); - // Set the upper and lower wallpaper targets correctly, - // and make sure that we are positioning the wallpaper below the lower. - if (wallpaperTargetIndex > oldI) { - // The new target is on top of the old one. - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target above old target."); - mUpperWallpaperTarget = wallpaperTarget; - mLowerWallpaperTarget = oldW; - - wallpaperTarget = oldW; - wallpaperTargetIndex = oldI; - } else { - // The new target is below the old one. - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target below old target."); - mUpperWallpaperTarget = oldW; - mLowerWallpaperTarget = wallpaperTarget; - } + mPrevWallpaperTarget = prevWallpaperTarget; if (newTargetHidden && !oldTargetHidden) { if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target."); // Use the old target if new target is hidden but old target // is not. If they're both hidden, still use the new target. - mWallpaperTarget = oldW; + mWallpaperTarget = prevWallpaperTarget; } else if (newTargetHidden == oldTargetHidden && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken) - && (mService.mOpeningApps.contains(oldW.mAppToken) - || mService.mClosingApps.contains(oldW.mAppToken))) { + && (mService.mOpeningApps.contains(prevWallpaperTarget.mAppToken) + || mService.mClosingApps.contains(prevWallpaperTarget.mAppToken))) { // If they're both hidden (or both not hidden), prefer the one that's currently in // opening or closing app list, this allows transition selection logic to better // determine the wallpaper status of opening/closing apps. - mWallpaperTarget = oldW; + mWallpaperTarget = prevWallpaperTarget; } - result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex); - return true; + result.setWallpaperTarget(wallpaperTarget); } - private boolean updateWallpaperWindowsTargetByLayer(WindowList windows, - FindWallpaperTargetResult result) { - - WindowState wallpaperTarget = result.wallpaperTarget; - int wallpaperTargetIndex = result.wallpaperTargetIndex; - boolean visible = wallpaperTarget != null; - - if (visible) { - // The window is visible to the compositor...but is it visible to the user? - // That is what the wallpaper cares about. - visible = isWallpaperVisible(wallpaperTarget); - if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); - - // If the wallpaper target is animating, we may need to copy its layer adjustment. - // Only do this if we are not transferring between two wallpaper targets. - mWallpaperAnimLayerAdjustment = - (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null) - ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0; - - final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER) - + TYPE_LAYER_OFFSET; - - // Now w is the window we are supposed to be behind... but we - // need to be sure to also be behind any of its attached windows, - // AND any starting window associated with it, AND below the - // maximum layer the policy allows for wallpapers. - while (wallpaperTargetIndex > 0) { - final WindowState wb = windows.get(wallpaperTargetIndex - 1); - final WindowState wbParentWindow = wb.getParentWindow(); - final WindowState wallpaperParentWindow = wallpaperTarget.getParentWindow(); - if (wb.mBaseLayer < maxLayer - && wbParentWindow != wallpaperTarget - && (wallpaperParentWindow == null || wbParentWindow != wallpaperParentWindow) - && (wb.mAttrs.type != TYPE_APPLICATION_STARTING - || wallpaperTarget.mToken == null - || wb.mToken != wallpaperTarget.mToken)) { - // This window is not related to the previous one in any - // interesting way, so stop here. - break; - } - wallpaperTarget = wb; - wallpaperTargetIndex--; - } - } else { - if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target"); - } - - result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex); - return visible; - } - - private boolean updateWallpaperWindowsPlacement(WindowList windows, - WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) { - - // TODO(multidisplay): Wallpapers on main screen only. - final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo(); - final int dw = displayInfo.logicalWidth; - final int dh = displayInfo.logicalHeight; - - // Start stepping backwards from here, ensuring that our wallpaper windows are correctly placed. - boolean changed = false; + private void updateWallpaperTokens(boolean visible) { for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); - changed |= token.updateWallpaperWindowsPlacement(windows, wallpaperTarget, - wallpaperTargetIndex, visible, dw, dh, mWallpaperAnimLayerAdjustment); + token.updateWallpaperWindows(visible, mWallpaperAnimLayerAdjustment); } - - return changed; } - boolean adjustWallpaperWindows(WindowList windows) { + void adjustWallpaperWindows(DisplayContent dc) { mService.mRoot.mWallpaperMayChange = false; // First find top-most window that has asked to be on top of the wallpaper; // all wallpapers go behind it. - findWallpaperTarget(windows, mFindResults); - final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults); - final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults); - WindowState wallpaperTarget = mFindResults.wallpaperTarget; - int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex; + findWallpaperTarget(dc, mFindResults); + updateWallpaperWindowsTarget(dc, mFindResults); - if (wallpaperTarget == null && mFindResults.topWallpaper != null) { - // There is no wallpaper target, so it goes at the bottom. - // We will assume it is the same place as last time, if known. - wallpaperTarget = mFindResults.topWallpaper; - wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1; - } else { - // Okay i is the position immediately above the wallpaper. - // Look at what is below it for later. - wallpaperTarget = wallpaperTargetIndex > 0 - ? windows.get(wallpaperTargetIndex - 1) : null; - } + // The window is visible to the compositor...but is it visible to the user? + // That is what the wallpaper cares about. + final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget); + if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); if (visible) { + // If the wallpaper target is animating, we may need to copy its layer adjustment. + // Only do this if we are not transferring between two wallpaper targets. + mWallpaperAnimLayerAdjustment = + (mPrevWallpaperTarget == null && mWallpaperTarget.mAppToken != null) + ? mWallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0; + if (mWallpaperTarget.mWallpaperX >= 0) { mLastWallpaperX = mWallpaperTarget.mWallpaperX; mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep; @@ -700,14 +583,10 @@ class WallpaperController { } } - final boolean changed = updateWallpaperWindowsPlacement( - windows, wallpaperTarget, wallpaperTargetIndex, visible); + updateWallpaperTokens(visible); - if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" - + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper=" - + mUpperWallpaperTarget); - - return changed; + if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget + + " prev=" + mPrevWallpaperTarget); } boolean processWallpaperDrawPendingTimeout() { @@ -773,7 +652,7 @@ class WallpaperController { } if (adjust) { - dc.adjustWallpaperWindows(); + adjustWallpaperWindows(dc); } } @@ -787,9 +666,8 @@ class WallpaperController { void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget); - if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) { - pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); - pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); + if (mPrevWallpaperTarget != null) { + pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget); } pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX); pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); @@ -825,26 +703,28 @@ class WallpaperController { /** Helper class for storing the results of a wallpaper target find operation. */ final private static class FindWallpaperTargetResult { - int topWallpaperIndex = 0; WindowState topWallpaper = null; - int wallpaperTargetIndex = 0; + boolean useTopWallpaperAsTarget = false; WindowState wallpaperTarget = null; + boolean resetTopWallpaper = false; - void setTopWallpaper(WindowState win, int index) { + void setTopWallpaper(WindowState win) { topWallpaper = win; - topWallpaperIndex = index; } - void setWallpaperTarget(WindowState win, int index) { + void setWallpaperTarget(WindowState win) { wallpaperTarget = win; - wallpaperTargetIndex = index; + } + + void setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget) { + useTopWallpaperAsTarget = topWallpaperAsTarget; } void reset() { - topWallpaperIndex = 0; topWallpaper = null; - wallpaperTargetIndex = 0; wallpaperTarget = null; + useTopWallpaperAsTarget = false; + resetTopWallpaper = false; } } } diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 3a76cd4d1bded..8ea1b3b1355a6 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -119,11 +119,8 @@ class WallpaperWindowToken extends WindowToken { } } - boolean updateWallpaperWindowsPlacement(WindowList windowList, - WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible, int dw, int dh, - int wallpaperAnimLayerAdj) { + void updateWallpaperWindows(boolean visible, int animLayerAdj) { - boolean changed = false; if (hidden == visible) { if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "Wallpaper token " + token + " hidden=" + !visible); @@ -132,6 +129,9 @@ class WallpaperWindowToken extends WindowToken { mDisplayContent.setLayoutNeeded(); } + final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); + final int dw = displayInfo.logicalWidth; + final int dh = displayInfo.logicalHeight; final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { final WindowState wallpaper = mChildren.get(wallpaperNdx); @@ -142,66 +142,11 @@ class WallpaperWindowToken extends WindowToken { // First, make sure the client has the current visibility state. wallpaper.dispatchWallpaperVisibility(visible); - wallpaper.adjustAnimLayer(wallpaperAnimLayerAdj); + wallpaper.adjustAnimLayer(animLayerAdj); if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win " + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); - - // First, if this window is at the current index, then all is well. - if (wallpaper == wallpaperTarget) { - wallpaperTargetIndex--; - wallpaperTarget = wallpaperTargetIndex > 0 - ? windowList.get(wallpaperTargetIndex - 1) : null; - continue; - } - - // The window didn't match... the current wallpaper window, - // wherever it is, is in the wrong place, so make sure it is not in the list. - int oldIndex = windowList.indexOf(wallpaper); - if (oldIndex >= 0) { - if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, - "Wallpaper removing at " + oldIndex + ": " + wallpaper); - mDisplayContent.removeFromWindowList(wallpaper); - if (oldIndex < wallpaperTargetIndex) { - wallpaperTargetIndex--; - } - } - - // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost - // layer. For keyguard over wallpaper put the wallpaper under the lowest window that - // is currently on screen, i.e. not hidden by policy. - int insertionIndex = 0; - if (visible && wallpaperTarget != null) { - final int privateFlags = wallpaperTarget.mAttrs.privateFlags; - if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { - insertionIndex = Math.min(windowList.indexOf(wallpaperTarget), - findLowestWindowOnScreen(windowList)); - } - } - if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT - || (DEBUG_ADD_REMOVE && oldIndex != insertionIndex)) Slog.v(TAG, - "Moving wallpaper " + wallpaper + " from " + oldIndex + " to " + insertionIndex); - - mDisplayContent.addToWindowList(wallpaper, insertionIndex); - changed = true; } - - return changed; - } - - /** - * @return The index in {@param windows} of the lowest window that is currently on screen and - * not hidden by the policy. - */ - private int findLowestWindowOnScreen(WindowList windowList) { - final int size = windowList.size(); - for (int index = 0; index < size; index++) { - final WindowState win = windowList.get(index); - if (win.isOnScreen()) { - return index; - } - } - return Integer.MAX_VALUE; } boolean hasVisibleNotDrawnWallpaper() { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 150160c3302e9..a6a907cd50fb0 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -19,10 +19,12 @@ package com.android.server.wm; import android.annotation.CallSuper; import android.content.res.Configuration; import android.view.animation.Animation; +import com.android.internal.util.ToBooleanFunction; import java.util.Comparator; import java.util.LinkedList; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; @@ -496,17 +498,38 @@ class WindowContainer implements Comparable callback, boolean traverseTopToBottom) { + /** + * For all windows at or below this container call the callback. + * @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and + * stops the search if {@link ToBooleanFunction#apply} returns true. + * @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of + * z-order, else from bottom-to-top. + * @return True if the search ended before we reached the end of the hierarchy due to + * {@link Function#apply} returning true. + */ + boolean forAllWindows(ToBooleanFunction callback, boolean traverseTopToBottom) { if (traverseTopToBottom) { for (int i = mChildren.size() - 1; i >= 0; --i) { - mChildren.get(i).forAllWindows(callback, traverseTopToBottom); + if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { + return true; + } } } else { final int count = mChildren.size(); for (int i = 0; i < count; i++) { - mChildren.get(i).forAllWindows(callback, traverseTopToBottom); + if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) { + return true; + } } } + return false; + } + + void forAllWindows(Consumer callback, boolean traverseTopToBottom) { + forAllWindows(w -> { + callback.accept(w); + return false; + }, traverseTopToBottom); } WindowState getWindow(Predicate callback) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c4c4bcd7da0f5..83d6e371bdf9f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4906,9 +4906,9 @@ public class WindowManagerService extends IWindowManager.Stub } if (rotateSeamlessly) { - dc.forAllWindows((w) -> - w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation), - true /* traverseTopToBottom */); + dc.forAllWindows(w -> { + w.mWinAnimator.seamlesslyRotateWindow(oldRotation, mRotation); + }, true /* traverseTopToBottom */); } mDisplayManagerInternal.performTraversalInTransactionFromWindowManager(); @@ -4921,7 +4921,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - dc.forAllWindows((w) -> { + dc.forAllWindows(w -> { // Discard surface after orientation change, these can't be reused. if (w.mAppToken != null) { w.mAppToken.destroySavedSurfaces(); @@ -5184,7 +5184,9 @@ public class WindowManagerService extends IWindowManager.Stub final WindowList windows = new WindowList(); synchronized (mWindowMap) { - mRoot.forAllWindows(windows::add, false /* traverseTopToBottom */); + mRoot.forAllWindows(w -> { + windows.add(w); + }, false /* traverseTopToBottom */); } BufferedWriter out = null; @@ -8261,7 +8263,7 @@ public class WindowManagerService extends IWindowManager.Stub mRoot.dumpChildrenNames(output, " "); pw.println(output.toString()); pw.println(" "); - mRoot.forAllWindows(pw::println, true /* traverseTopToBottom */); + mRoot.forAllWindows(w -> {pw.println(w);}, true /* traverseTopToBottom */); } return; } else { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 5e65aec28c400..c0b3f27fd1ef1 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -53,6 +53,7 @@ import android.view.WindowInfo; import android.view.WindowManager; import android.view.WindowManagerPolicy; +import com.android.internal.util.ToBooleanFunction; import com.android.server.input.InputWindowHandle; import java.io.PrintWriter; @@ -60,6 +61,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedList; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; import static android.app.ActivityManager.StackId; @@ -3833,21 +3835,20 @@ class WindowState extends WindowContainer implements WindowManagerP } @Override - void forAllWindows(Consumer callback, boolean traverseTopToBottom) { + boolean forAllWindows(ToBooleanFunction callback, boolean traverseTopToBottom) { if (mChildren.isEmpty()) { // The window has no children so we just return it. - callback.accept(this); - return; + return callback.apply(this); } if (traverseTopToBottom) { - forAllWindowTopToBottom(callback); + return forAllWindowTopToBottom(callback); } else { - forAllWindowBottomToTop(callback); + return forAllWindowBottomToTop(callback); } } - private void forAllWindowBottomToTop(Consumer callback) { + private boolean forAllWindowBottomToTop(ToBooleanFunction callback) { // We want to consumer the negative sublayer children first because they need to appear // below the parent, then this window (the parent), and then the positive sublayer children // because they need to appear above the parent. @@ -3856,7 +3857,9 @@ class WindowState extends WindowContainer implements WindowManagerP WindowState child = mChildren.get(i); while (i < count && child.mSubLayer < 0) { - callback.accept(child); + if (callback.apply(child)) { + return true; + } i++; if (i >= count) { break; @@ -3864,19 +3867,25 @@ class WindowState extends WindowContainer implements WindowManagerP child = mChildren.get(i); } - callback.accept(this); + if (callback.apply(this)) { + return true; + } while (i < count) { - callback.accept(child); + if (callback.apply(child)) { + return true; + } i++; if (i >= count) { break; } child = mChildren.get(i); } + + return false; } - private void forAllWindowTopToBottom(Consumer callback) { + private boolean forAllWindowTopToBottom(ToBooleanFunction callback) { // We want to consumer the positive sublayer children first because they need to appear // above the parent, then this window (the parent), and then the negative sublayer children // because they need to appear above the parent. @@ -3884,7 +3893,9 @@ class WindowState extends WindowContainer implements WindowManagerP WindowState child = mChildren.get(i); while (i >= 0 && child.mSubLayer >= 0) { - callback.accept(child); + if (callback.apply(child)) { + return true; + } --i; if (i < 0) { break; @@ -3892,16 +3903,22 @@ class WindowState extends WindowContainer implements WindowManagerP child = mChildren.get(i); } - callback.accept(this); + if (callback.apply(this)) { + return true; + } while (i >= 0) { - callback.accept(child); + if (callback.apply(child)) { + return true; + } --i; if (i < 0) { break; } child = mChildren.get(i); } + + return false; } WindowState getWindow(Predicate callback) { diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index f2682baea6140..7e1880fb65d6a 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -266,21 +266,9 @@ class WindowSurfacePlacer { mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(displayContent, mService.mOpeningApps); - final WindowState lowerWallpaperTarget = - mWallpaperControllerLocked.getLowerWallpaperTarget(); - final WindowState upperWallpaperTarget = - mWallpaperControllerLocked.getUpperWallpaperTarget(); - + final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); boolean openingAppHasWallpaper = false; boolean closingAppHasWallpaper = false; - final AppWindowToken lowerWallpaperAppToken; - final AppWindowToken upperWallpaperAppToken; - if (lowerWallpaperTarget == null) { - lowerWallpaperAppToken = upperWallpaperAppToken = null; - } else { - lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken; - upperWallpaperAppToken = upperWallpaperTarget.mAppToken; - } // Do a first pass through the tokens for two things: // (1) Determine if both the closing and opening app token sets are wallpaper targets, in @@ -294,12 +282,12 @@ class WindowSurfacePlacer { final AppWindowToken wtoken; if (i < closingAppsCount) { wtoken = mService.mClosingApps.valueAt(i); - if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) { + if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) { closingAppHasWallpaper = true; } } else { wtoken = mService.mOpeningApps.valueAt(i - closingAppsCount); - if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) { + if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) { openingAppHasWallpaper = true; } } @@ -307,14 +295,14 @@ class WindowSurfacePlacer { voiceInteraction |= wtoken.voiceInteraction; if (wtoken.fillsParent()) { - WindowState ws = wtoken.findMainWindow(); + final WindowState ws = wtoken.findMainWindow(); if (ws != null) { animLp = ws.mAttrs; bestAnimLayer = ws.mLayer; fullscreenAnim = true; } } else if (!fullscreenAnim) { - WindowState ws = wtoken.findMainWindow(); + final WindowState ws = wtoken.findMainWindow(); if (ws != null) { if (ws.mLayer > bestAnimLayer) { animLp = ws.mAttrs; @@ -325,7 +313,7 @@ class WindowSurfacePlacer { } transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper, - closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget); + closingAppHasWallpaper); // If all closing windows are obscured, then there is no need to do an animation. This is // the case, for example, when this transition is being done behind the lock screen. @@ -578,8 +566,7 @@ class WindowSurfacePlacer { } private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper, - boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget, - WindowState upperWallpaperTarget) { + boolean closingAppHasWallpaper) { // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating() @@ -590,8 +577,6 @@ class WindowSurfacePlacer { if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New wallpaper target=" + wallpaperTarget + ", oldWallpaper=" + oldWallpaper - + ", lower target=" + lowerWallpaperTarget - + ", upper target=" + upperWallpaperTarget + ", openingApps=" + openingApps + ", closingApps=" + closingApps); mService.mAnimateWallpaperWithTarget = false; diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java index 0533efc6d8627..225dc5d2d66ae 100644 --- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java @@ -98,7 +98,7 @@ public class DisplayContentTests { final ArrayList windows = new ArrayList(); // Test forward traversal. - dc.forAllWindows(windows::add, false /* traverseTopToBottom */); + dc.forAllWindows(w -> {windows.add(w);}, false /* traverseTopToBottom */); assertEquals(wallpaperWindow, windows.get(0)); assertEquals(exitingAppWindow, windows.get(1)); @@ -112,7 +112,7 @@ public class DisplayContentTests { // Test backward traversal. windows.clear(); - dc.forAllWindows(windows::add, true /* traverseTopToBottom */); + dc.forAllWindows(w -> {windows.add(w);}, true /* traverseTopToBottom */); assertEquals(wallpaperWindow, windows.get(8)); assertEquals(exitingAppWindow, windows.get(7));