From ee41d4afcb089eac6a6a569557905f71bdd33f6c Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Mon, 21 Nov 2016 08:41:10 -0800 Subject: [PATCH 1/2] Introduced WindowContainer.mConsumerWrapperPool WindowContainer.forAllWindows(Consumer...) requires a lambda to be allocated each time it is called since we need to capture the callback. Switched to using an object pool for the process to reduce allocations. Test: Run the allocation traker and make sure there aren't lambda allocations for WindowContainer.forAllWindows() method. Change-Id: If49c1b0bd2e0a5d6d7a30ff686b5235e69a61750 --- .../android/server/wm/WindowContainer.java | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index f5db0b668c225..03769e97a27f0 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -18,6 +18,8 @@ package com.android.server.wm; import android.annotation.CallSuper; import android.content.res.Configuration; +import android.util.Pools; + import com.android.internal.util.ToBooleanFunction; import java.util.Comparator; @@ -68,6 +70,9 @@ class WindowContainer implements Comparable mConsumerWrapperPool = + new Pools.SynchronizedPool<>(3); + final protected WindowContainer getParent() { return mParent; } @@ -517,10 +522,9 @@ class WindowContainer implements Comparable callback, boolean traverseTopToBottom) { - forAllWindows(w -> { - callback.accept(w); - return false; - }, traverseTopToBottom); + ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback); + forAllWindows(wrapper, traverseTopToBottom); + wrapper.release(); } WindowState getWindow(Predicate callback) { @@ -613,4 +617,32 @@ class WindowContainer implements Comparable consumer) { + ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire(); + if (wrapper == null) { + wrapper = new ForAllWindowsConsumerWrapper(); + } + wrapper.setConsumer(consumer); + return wrapper; + } + + private final class ForAllWindowsConsumerWrapper implements ToBooleanFunction { + + private Consumer mConsumer; + + void setConsumer(Consumer consumer) { + mConsumer = consumer; + } + + @Override + public boolean apply(WindowState w) { + mConsumer.accept(w); + return false; + } + + void release() { + mConsumer = null; + mConsumerWrapperPool.release(this); + } + } } From 1e129a4212ec3b388c65db8f6ce18896362ac35c Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Mon, 21 Nov 2016 13:03:47 -0800 Subject: [PATCH 2/2] Reduce object allocations in WM in some frequently called methods With the use of lambdas to get all windows in the window container hierarchy, we need to be careful in frequently called code paths to make sure the number of objects we allocate isn't crazy. This CL converts some commonly called code paths that use lambda to use a method reference for the lambda so we only need to allocate once vs. each time the code path is executed. Test: Perform some common operations on the phone and make sure the object allocations that show-up in Allocator Tracker for window manager seems reasonable Change-Id: Ie0f245980de96ec68a4e62e76130db7d98c3f7d9 --- .../server/am/ActivityManagerService.java | 8 +- .../com/android/server/wm/AppWindowToken.java | 3 +- .../com/android/server/wm/DisplayContent.java | 818 +++++++++--------- .../com/android/server/wm/InputMonitor.java | 184 ++-- .../server/wm/RootWindowContainer.java | 35 +- .../server/wm/WallpaperController.java | 161 ++-- .../android/server/wm/WindowContainer.java | 3 +- .../server/wm/WindowLayersController.java | 71 +- 8 files changed, 675 insertions(+), 608 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6aa0dc9ab1198..a5b30208a5505 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1386,6 +1386,8 @@ public class ActivityManagerService extends IActivityManager.Stub final long[] mTmpLong = new long[2]; + private final ArraySet mTmpBroadcastQueue = new ArraySet(); + static final class ProcessChangeItem { static final int CHANGE_ACTIVITIES = 1<<0; static final int CHANGE_PROCESS_STATE = 1<<1; @@ -19521,7 +19523,7 @@ public class ActivityManagerService extends IActivityManager.Stub int schedGroup; int procState; boolean foregroundActivities = false; - final ArraySet queues = new ArraySet(); + mTmpBroadcastQueue.clear(); if (app == TOP_APP) { // The last app on the list is the foreground app. adj = ProcessList.FOREGROUND_APP_ADJ; @@ -19535,13 +19537,13 @@ public class ActivityManagerService extends IActivityManager.Stub schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.adjType = "instrumentation"; procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; - } else if (isReceivingBroadcastLocked(app, queues)) { + } else if (isReceivingBroadcastLocked(app, mTmpBroadcastQueue)) { // An app that is currently receiving a broadcast also // counts as being in the foreground for OOM killer purposes. // It's placed in a sched group based on the nature of the // broadcast as reflected by which queue it's active in. adj = ProcessList.FOREGROUND_APP_ADJ; - schedGroup = (queues.contains(mFgBroadcastQueue)) + schedGroup = (mTmpBroadcastQueue.contains(mFgBroadcastQueue)) ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND; app.adjType = "broadcast"; procState = ActivityManager.PROCESS_STATE_RECEIVER; diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index e93081804e176..00c37d2d899ac 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1253,7 +1253,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree mService.mAnimator.mAppWindowAnimating = true; } else if (mAppAnimator.wasAnimating) { // stopped animating, do one more pass through the layout - setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER, "appToken " + this + " done"); + setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER, + DEBUG_LAYOUT_REPEATS ? "appToken " + this + " done" : null); if (DEBUG_ANIM) Slog.v(TAG, "updateWindowsApps...: done animating " + this); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 1df7c66c8cca1..203137d4d481d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -124,6 +124,8 @@ import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; /** * Utility class for keeping track of the WindowStates and other pertinent contents of a @@ -156,6 +158,11 @@ class DisplayContent extends WindowContainer mTokenMap = new HashMap(); @@ -178,7 +185,7 @@ class DisplayContent extends WindowContainer mExitingTokens = new ArrayList<>(); @@ -200,7 +207,7 @@ class DisplayContent extends WindowContainer mTapExcludedWindows = new ArrayList<>(); @@ -231,9 +238,390 @@ class DisplayContent extends WindowContainer mUpdateWindowsForAnimator = w -> { + WindowStateAnimator winAnimator = w.mWinAnimator; + if (winAnimator.hasSurface()) { + final boolean wasAnimating = winAnimator.mWasAnimating; + final boolean nowAnimating = winAnimator.stepAnimationLocked( + mTmpWindowAnimator.mCurrentTime); + winAnimator.mWasAnimating = nowAnimating; + mTmpWindowAnimator.orAnimating(nowAnimating); + + if (DEBUG_WALLPAPER) Slog.v(TAG, + w + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating); + + if (wasAnimating && !winAnimator.mAnimating + && mWallpaperController.isWallpaperTarget(w)) { + mTmpWindowAnimator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE; + pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; + if (DEBUG_LAYOUT_REPEATS) { + mService.mWindowPlacerLocked.debugLayoutRepeats( + "updateWindowsAndWallpaperLocked 2", pendingLayoutChanges); + } + } + } + + final AppWindowToken atoken = w.mAppToken; + if (winAnimator.mDrawState == READY_TO_SHOW) { + if (atoken == null || atoken.allDrawn) { + if (w.performShowLocked()) { + pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM; + if (DEBUG_LAYOUT_REPEATS) { + mService.mWindowPlacerLocked.debugLayoutRepeats( + "updateWindowsAndWallpaperLocked 5", pendingLayoutChanges); + } + } + } + } + final AppWindowAnimator appAnimator = winAnimator.mAppAnimator; + if (appAnimator != null && appAnimator.thumbnail != null) { + if (appAnimator.thumbnailTransactionSeq + != mTmpWindowAnimator.mAnimTransactionSequence) { + appAnimator.thumbnailTransactionSeq = + mTmpWindowAnimator.mAnimTransactionSequence; + appAnimator.thumbnailLayer = 0; + } + if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) { + appAnimator.thumbnailLayer = winAnimator.mAnimLayer; + } + } + }; + + private final Consumer mUpdateWallpaperForAnimator = w -> { + final WindowStateAnimator winAnimator = w.mWinAnimator; + if (winAnimator.mSurfaceController == null || !winAnimator.hasSurface()) { + return; + } + + final int flags = w.mAttrs.flags; + + // If this window is animating, make a note that we have an animating window and take + // care of a request to run a detached wallpaper animation. + if (winAnimator.mAnimating) { + if (winAnimator.mAnimation != null) { + if ((flags & FLAG_SHOW_WALLPAPER) != 0 + && winAnimator.mAnimation.getDetachWallpaper()) { + mTmpWindow = w; + } + final int color = winAnimator.mAnimation.getBackgroundColor(); + if (color != 0) { + final TaskStack stack = w.getStack(); + if (stack != null) { + stack.setAnimationBackground(winAnimator, color); + } + } + } + mTmpWindowAnimator.setAnimating(true); + } + + // If this window's app token is running a detached wallpaper animation, make a note so + // we can ensure the wallpaper is displayed behind it. + final AppWindowAnimator appAnimator = winAnimator.mAppAnimator; + if (appAnimator != null && appAnimator.animation != null + && appAnimator.animating) { + if ((flags & FLAG_SHOW_WALLPAPER) != 0 + && appAnimator.animation.getDetachWallpaper()) { + mTmpWindow = w; + } + + final int color = appAnimator.animation.getBackgroundColor(); + if (color != 0) { + final TaskStack stack = w.getStack(); + if (stack != null) { + stack.setAnimationBackground(winAnimator, color); + } + } + } + }; + + private final Consumer mSetInputMethodAnimLayerAdjustment = + w -> w.adjustAnimLayer(mInputMethodAnimLayerAdjustment); + + private final Consumer mScheduleToastTimeout = w -> { + final int lostFocusUid = mTmpWindow.mOwnerUid; + final Handler handler = mService.mH; + if (w.mAttrs.type == TYPE_TOAST && w.mOwnerUid == lostFocusUid) { + if (!handler.hasMessages(WINDOW_HIDE_TIMEOUT, w)) { + handler.sendMessageDelayed(handler.obtainMessage(WINDOW_HIDE_TIMEOUT, w), + w.mAttrs.hideTimeoutMilliseconds); + } + } + }; + + private final ToBooleanFunction mFindFocusedWindow = w -> { + final AppWindowToken focusedApp = mService.mFocusedApp; + if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + w + + ", flags=" + w.mAttrs.flags + ", canReceive=" + w.canReceiveKeys()); + + if (!w.canReceiveKeys()) { + return false; + } + + final AppWindowToken wtoken = w.mAppToken; + + // If this window's application has been removed, just skip it. + if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) { + if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because " + + (wtoken.removed ? "removed" : "sendingToBottom")); + return false; + } + + if (focusedApp == null) { + if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null" + + " using new focus @ " + w); + mTmpWindow = w; + return true; + } + + if (!focusedApp.windowsAreFocusable()) { + // Current focused app windows aren't focusable... + if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not" + + " focusable using new focus @ " + w); + mTmpWindow = w; + return true; + } + + // Descend through all of the app tokens and find the first that either matches + // win.mAppToken (return win) or mFocusedApp (return null). + if (wtoken != null && w.mAttrs.type != TYPE_APPLICATION_STARTING) { + if (focusedApp.compareTo(wtoken) > 0) { + // App stack below focused app stack. No focus for you!!! + if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, + "findFocusedWindow: Reached focused app=" + focusedApp); + mTmpWindow = null; + return true; + } + } + + if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " + w); + mTmpWindow = w; + return true; + }; + + private final Consumer mPrepareWindowSurfaces = + w -> w.mWinAnimator.prepareSurfaceLocked(true); + + private final Consumer mPerformLayout = w -> { + // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid + // wasting time and funky changes while a window is animating away. + final boolean gone = (mTmpWindow != null && mService.mPolicy.canBeHiddenByKeyguardLw(w)) + || w.isGoneForLayoutLw(); + + if (DEBUG_LAYOUT && !w.mLayoutAttached) { + Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame + + " mLayoutAttached=" + w.mLayoutAttached + + " screen changed=" + w.isConfigChanged()); + final AppWindowToken atoken = w.mAppToken; + if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility + + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.hidden + + " hiddenRequested=" + (atoken != null && atoken.hiddenRequested) + + " parentHidden=" + w.isParentWindowHidden()); + else Slog.v(TAG, " VIS: mViewVisibility=" + w.mViewVisibility + + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.hidden + + " hiddenRequested=" + (atoken != null && atoken.hiddenRequested) + + " parentHidden=" + w.isParentWindowHidden()); + } + + // If this view is GONE, then skip it -- keep the current frame, and let the caller know + // so they can ignore it if they want. (We do the normal layout for INVISIBLE windows, + // since that means "perform layout as normal, just don't display"). + if (!gone || !w.mHaveFrame || w.mLayoutNeeded + || ((w.isConfigChanged() || w.setReportResizeHints()) + && !w.isGoneForLayoutLw() && + ((w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 || + (w.mHasSurface && w.mAppToken != null && + w.mAppToken.layoutConfigChanges)))) { + if (!w.mLayoutAttached) { + if (mTmpInitial) { + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); + w.mContentChanged = false; + } + if (w.mAttrs.type == TYPE_DREAM) { + // Don't layout windows behind a dream, so that if it does stuff like hide + // the status bar we won't get a bad transition when it goes away. + mTmpWindow = w; + } + w.mLayoutNeeded = false; + w.prelayout(); + mService.mPolicy.layoutWindowLw(w, null); + w.mLayoutSeq = mService.mLayoutSeq; + + // Window frames may have changed. Update dim layer with the new bounds. + final Task task = w.getTask(); + if (task != null) { + mDimLayerController.updateDimLayer(task); + } + + if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame + + " mContainingFrame=" + w.mContainingFrame + + " mDisplayFrame=" + w.mDisplayFrame); + } + } + }; + + private final Consumer mPerformLayoutAttached = w -> { + if (w.mLayoutAttached) { + if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame + + " mViewVisibility=" + w.mViewVisibility + + " mRelayoutCalled=" + w.mRelayoutCalled); + // If this view is GONE, then skip it -- keep the current frame, and let the caller + // know so they can ignore it if they want. (We do the normal layout for INVISIBLE + // windows, since that means "perform layout as normal, just don't display"). + if (mTmpWindow != null && mService.mPolicy.canBeHiddenByKeyguardLw(w)) { + return; + } + if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame + || w.mLayoutNeeded) { + if (mTmpInitial) { + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); + w.mContentChanged = false; + } + w.mLayoutNeeded = false; + w.prelayout(); + mService.mPolicy.layoutWindowLw(w, w.getParentWindow()); + w.mLayoutSeq = mService.mLayoutSeq; + if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame + + " mContainingFrame=" + w.mContainingFrame + + " mDisplayFrame=" + w.mDisplayFrame); + } + } else if (w.mAttrs.type == TYPE_DREAM) { + // Don't layout windows behind a dream, so that if it does stuff like hide the + // status bar we won't get a bad transition when it goes away. + mTmpWindow = mTmpWindow2; + } + }; + + private final Predicate mComputeImeTargetPredicate = w -> { + if (DEBUG_INPUT_METHOD && mUpdateImeTarget) Slog.i(TAG_WM, "Checking window @" + w + + " fl=0x" + Integer.toHexString(w.mAttrs.flags)); + return w.canBeImeTarget(); + }; + + private final Consumer mApplyPostLayoutPolicy = + w -> mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(), + mService.mInputMethodTarget); + + private final Consumer mApplySurfaceChangesTransaction = w -> { + final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked; + final boolean obscuredChanged = w.mObscured != + mTmpApplySurfaceChangesTransactionState.obscured; + final RootWindowContainer root = mService.mRoot; + // Only used if default window + final boolean someoneLosingFocus = !mService.mLosingFocus.isEmpty(); + + // Update effect. + w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured; + if (!mTmpApplySurfaceChangesTransactionState.obscured) { + final boolean isDisplayed = w.isDisplayedLw(); + + if (isDisplayed && w.isObscuringDisplay()) { + // This window completely covers everything behind it, so we want to leave all + // of them as undimmed (for performance reasons). + root.mObscuringWindow = w; + mTmpApplySurfaceChangesTransactionState.obscured = true; + } + + mTmpApplySurfaceChangesTransactionState.displayHasContent |= + root.handleNotObscuredLocked(w, + mTmpApplySurfaceChangesTransactionState.obscured, + mTmpApplySurfaceChangesTransactionState.syswin); + + if (w.mHasSurface && isDisplayed) { + final int type = w.mAttrs.type; + if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR + || (w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { + mTmpApplySurfaceChangesTransactionState.syswin = true; + } + if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0 + && w.mAttrs.preferredRefreshRate != 0) { + mTmpApplySurfaceChangesTransactionState.preferredRefreshRate + = w.mAttrs.preferredRefreshRate; + } + if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0 + && w.mAttrs.preferredDisplayModeId != 0) { + mTmpApplySurfaceChangesTransactionState.preferredModeId + = w.mAttrs.preferredDisplayModeId; + } + } + } + + w.applyDimLayerIfNeeded(); + + if (isDefaultDisplay && obscuredChanged && w.isVisibleLw() + && mWallpaperController.isWallpaperTarget(w)) { + // This is the wallpaper target and its obscured state changed... make sure the + // current wallpaper's visibility has been updated accordingly. + mWallpaperController.updateWallpaperVisibility(); + } + + w.handleWindowMovedIfNeeded(); + + final WindowStateAnimator winAnimator = w.mWinAnimator; + + //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); + w.mContentChanged = false; + + // Moved from updateWindowsAndWallpaperLocked(). + if (w.mHasSurface) { + // Take care of the window being ready to display. + final boolean committed = winAnimator.commitFinishDrawingLocked(); + if (isDefaultDisplay && committed) { + if (w.mAttrs.type == TYPE_DREAM) { + // HACK: When a dream is shown, it may at that point hide the lock screen. + // So we need to redo the layout to let the phone window manager make this + // happen. + pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT; + if (DEBUG_LAYOUT_REPEATS) { + surfacePlacer.debugLayoutRepeats( + "dream and commitFinishDrawingLocked true", + pendingLayoutChanges); + } + } + if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) { + if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, + "First draw done in potential wallpaper target " + w); + root.mWallpaperMayChange = true; + pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; + if (DEBUG_LAYOUT_REPEATS) { + surfacePlacer.debugLayoutRepeats( + "wallpaper and commitFinishDrawingLocked true", + pendingLayoutChanges); + } + } + } + if (!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening()) { + // Updates the shown frame before we set up the surface. This is needed + // because the resizing could change the top-left position (in addition to + // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to + // position the surface. + // + // If an animation is being started, we can't call this method because the + // animation hasn't processed its initial transformation yet, but in general + // we do want to update the position if the window is animating. + winAnimator.computeShownFrameLocked(); + } + winAnimator.setSurfaceBoundariesLocked(mTmpRecoveringMemory /* recoveringMemory */); + } + + final AppWindowToken atoken = w.mAppToken; + if (atoken != null) { + final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w); + if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) { + mTmpUpdateAllDrawn.add(atoken); + } + } + + if (isDefaultDisplay && someoneLosingFocus && w == mService.mCurrentFocus + && w.isDisplayedLw()) { + mTmpApplySurfaceChangesTransactionState.focusDisplayed = true; + } + + w.updateResizingWindowIfNeeded(); + }; + /** * @param display May not be null. * @param service You know. @@ -905,9 +1293,8 @@ class DisplayContent extends WindowContainer { - w.adjustAnimLayer(adj); - }, true /* traverseTopToBottom */); + mImeWindowsContainers.forAllWindows(mSetInputMethodAnimLayerAdjustment, + true /* traverseTopToBottom */); } /** @@ -1105,71 +1492,17 @@ class DisplayContent extends WindowContainer { - if (w.mAttrs.type == TYPE_TOAST && w.mOwnerUid == lostFocusUid) { - if (!handler.hasMessages(WINDOW_HIDE_TIMEOUT, w)) { - handler.sendMessageDelayed(handler.obtainMessage(WINDOW_HIDE_TIMEOUT, w), - w.mAttrs.hideTimeoutMilliseconds); - } - } - }, false /* traverseTopToBottom */); + // Used to communicate the old focus to the callback method. + mTmpWindow = oldFocus; + + forAllWindows(mScheduleToastTimeout, false /* traverseTopToBottom */); } WindowState findFocusedWindow() { - final AppWindowToken focusedApp = mService.mFocusedApp; mTmpWindow = null; - forAllWindows(w -> { - if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + w - + ", flags=" + w.mAttrs.flags + ", canReceive=" + w.canReceiveKeys()); - - if (!w.canReceiveKeys()) { - return false; - } - - final AppWindowToken wtoken = w.mAppToken; - - // If this window's application has been removed, just skip it. - if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) { - if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because " - + (wtoken.removed ? "removed" : "sendingToBottom")); - return false; - } - - if (focusedApp == null) { - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null" - + " using new focus @ " + w); - mTmpWindow = w; - return true; - } - - if (!focusedApp.windowsAreFocusable()) { - // Current focused app windows aren't focusable... - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not" - + " focusable using new focus @ " + w); - mTmpWindow = w; - return true; - } - - // Descend through all of the app tokens and find the first that either matches - // win.mAppToken (return win) or mFocusedApp (return null). - if (wtoken != null && w.mAttrs.type != TYPE_APPLICATION_STARTING) { - if (focusedApp.compareTo(wtoken) > 0) { - // App stack below focused app stack. No focus for you!!! - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, - "findFocusedWindow: Reached focused app=" + focusedApp); - mTmpWindow = null; - return true; - } - } - - if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " + w); - mTmpWindow = w; - return true; - }, true /* traverseTopToBottom */); + forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */); if (mTmpWindow == null) { if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows."); @@ -1251,11 +1584,8 @@ class DisplayContent extends WindowContainer { - if (DEBUG_INPUT_METHOD && updateImeTarget) Slog.i(TAG_WM, "Checking window @" - + w + " fl=0x" + Integer.toHexString(w.mAttrs.flags)); - return w.canBeImeTarget(); - }); + mUpdateImeTarget = updateImeTarget; + WindowState target = getWindow(mComputeImeTargetPredicate); // Yet more tricksyness! If this window is a "starting" window, we do actually want @@ -1518,51 +1848,8 @@ class DisplayContent extends WindowContainer { - WindowStateAnimator winAnimator = w.mWinAnimator; - if (winAnimator.hasSurface()) { - final boolean wasAnimating = winAnimator.mWasAnimating; - final boolean nowAnimating = winAnimator.stepAnimationLocked(animator.mCurrentTime); - winAnimator.mWasAnimating = nowAnimating; - animator.orAnimating(nowAnimating); - - if (DEBUG_WALLPAPER) Slog.v(TAG, - w + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating); - - if (wasAnimating && !winAnimator.mAnimating - && mWallpaperController.isWallpaperTarget(w)) { - animator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE; - pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; - if (DEBUG_LAYOUT_REPEATS) { - mService.mWindowPlacerLocked.debugLayoutRepeats( - "updateWindowsAndWallpaperLocked 2", pendingLayoutChanges); - } - } - } - - final AppWindowToken atoken = w.mAppToken; - if (winAnimator.mDrawState == READY_TO_SHOW) { - if (atoken == null || atoken.allDrawn) { - if (w.performShowLocked()) { - pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM; - if (DEBUG_LAYOUT_REPEATS) { - mService.mWindowPlacerLocked.debugLayoutRepeats( - "updateWindowsAndWallpaperLocked 5", pendingLayoutChanges); - } - } - } - } - final AppWindowAnimator appAnimator = winAnimator.mAppAnimator; - if (appAnimator != null && appAnimator.thumbnail != null) { - if (appAnimator.thumbnailTransactionSeq != animator.mAnimTransactionSequence) { - appAnimator.thumbnailTransactionSeq = animator.mAnimTransactionSequence; - appAnimator.thumbnailLayer = 0; - } - if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) { - appAnimator.thumbnailLayer = winAnimator.mAnimLayer; - } - } - }, true /* traverseTopToBottom */); + mTmpWindowAnimator = animator; + forAllWindows(mUpdateWindowsForAnimator, true /* traverseTopToBottom */); } void updateWallpaperForAnimator(WindowAnimator animator) { @@ -1570,53 +1857,9 @@ class DisplayContent extends WindowContainer { - final WindowStateAnimator winAnimator = w.mWinAnimator; - if (winAnimator.mSurfaceController == null || !winAnimator.hasSurface()) { - return; - } - - final int flags = w.mAttrs.flags; - - // If this window is animating, make a note that we have an animating window and take - // care of a request to run a detached wallpaper animation. - if (winAnimator.mAnimating) { - if (winAnimator.mAnimation != null) { - if ((flags & FLAG_SHOW_WALLPAPER) != 0 - && winAnimator.mAnimation.getDetachWallpaper()) { - mTmpWindow = w; - } - final int color = winAnimator.mAnimation.getBackgroundColor(); - if (color != 0) { - final TaskStack stack = w.getStack(); - if (stack != null) { - stack.setAnimationBackground(winAnimator, color); - } - } - } - animator.setAnimating(true); - } - - // If this window's app token is running a detached wallpaper animation, make a note so - // we can ensure the wallpaper is displayed behind it. - final AppWindowAnimator appAnimator = winAnimator.mAppAnimator; - if (appAnimator != null && appAnimator.animation != null - && appAnimator.animating) { - if ((flags & FLAG_SHOW_WALLPAPER) != 0 - && appAnimator.animation.getDetachWallpaper()) { - mTmpWindow = w; - } - - final int color = appAnimator.animation.getBackgroundColor(); - if (color != 0) { - final TaskStack stack = w.getStack(); - if (stack != null) { - stack.setAnimationBackground(winAnimator, color); - } - } - } - }, true /* traverseTopToBottom */); + forAllWindows(mUpdateWallpaperForAnimator, true /* traverseTopToBottom */); if (animator.mWindowDetachedWallpaper != mTmpWindow) { if (DEBUG_WALLPAPER) Slog.v(TAG, "Detached wallpaper changed from " @@ -1627,9 +1870,7 @@ class DisplayContent extends WindowContainer { - w.mWinAnimator.prepareSurfaceLocked(true); - }, false /* traverseTopToBottom */); + forAllWindows(mPrepareWindowSurfaces, false /* traverseTopToBottom */); } boolean inputMethodClientHasFocus(IInputMethodClient client) { @@ -1765,136 +2006,18 @@ class DisplayContent extends WindowContainer { - mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(), - mService.mInputMethodTarget); - }, true /* traverseTopToBottom */); + forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */); pendingLayoutChanges |= mService.mPolicy.finishPostLayoutPolicyLw(); if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats( "after finishPostLayoutPolicyLw", pendingLayoutChanges); } } while (pendingLayoutChanges != 0); - final RootWindowContainer root = mService.mRoot; mTmpApplySurfaceChangesTransactionState.reset(); resetDimming(); - // Only used if default window - final boolean someoneLosingFocus = !mService.mLosingFocus.isEmpty(); - - forAllWindows(w -> { - final boolean obscuredChanged = w.mObscured != - mTmpApplySurfaceChangesTransactionState.obscured; - - // Update effect. - w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured; - if (!mTmpApplySurfaceChangesTransactionState.obscured) { - final boolean isDisplayed = w.isDisplayedLw(); - - if (isDisplayed && w.isObscuringDisplay()) { - // This window completely covers everything behind it, so we want to leave all - // of them as undimmed (for performance reasons). - root.mObscuringWindow = w; - mTmpApplySurfaceChangesTransactionState.obscured = true; - } - - mTmpApplySurfaceChangesTransactionState.displayHasContent |= - root.handleNotObscuredLocked(w, - mTmpApplySurfaceChangesTransactionState.obscured, - mTmpApplySurfaceChangesTransactionState.syswin); - - if (w.mHasSurface && isDisplayed) { - final int type = w.mAttrs.type; - if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR - || (w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { - mTmpApplySurfaceChangesTransactionState.syswin = true; - } - if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0 - && w.mAttrs.preferredRefreshRate != 0) { - mTmpApplySurfaceChangesTransactionState.preferredRefreshRate - = w.mAttrs.preferredRefreshRate; - } - if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0 - && w.mAttrs.preferredDisplayModeId != 0) { - mTmpApplySurfaceChangesTransactionState.preferredModeId - = w.mAttrs.preferredDisplayModeId; - } - } - } - - w.applyDimLayerIfNeeded(); - - if (isDefaultDisplay && obscuredChanged && w.isVisibleLw() - && mWallpaperController.isWallpaperTarget(w)) { - // This is the wallpaper target and its obscured state changed... make sure the - // current wallpaper's visibility has been updated accordingly. - mWallpaperController.updateWallpaperVisibility(); - } - - w.handleWindowMovedIfNeeded(); - - final WindowStateAnimator winAnimator = w.mWinAnimator; - - //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); - w.mContentChanged = false; - - // Moved from updateWindowsAndWallpaperLocked(). - if (w.mHasSurface) { - // Take care of the window being ready to display. - final boolean committed = winAnimator.commitFinishDrawingLocked(); - if (isDefaultDisplay && committed) { - if (w.mAttrs.type == TYPE_DREAM) { - // HACK: When a dream is shown, it may at that point hide the lock screen. - // So we need to redo the layout to let the phone window manager make this - // happen. - pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT; - if (DEBUG_LAYOUT_REPEATS) { - surfacePlacer.debugLayoutRepeats( - "dream and commitFinishDrawingLocked true", - pendingLayoutChanges); - } - } - if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) { - if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, - "First draw done in potential wallpaper target " + w); - root.mWallpaperMayChange = true; - pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; - if (DEBUG_LAYOUT_REPEATS) { - surfacePlacer.debugLayoutRepeats( - "wallpaper and commitFinishDrawingLocked true", - pendingLayoutChanges); - } - } - } - if (!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening()) { - // Updates the shown frame before we set up the surface. This is needed - // because the resizing could change the top-left position (in addition to - // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to - // position the surface. - // - // If an animation is being started, we can't call this method because the - // animation hasn't processed its initial transformation yet, but in general - // we do want to update the position if the window is animating. - winAnimator.computeShownFrameLocked(); - } - winAnimator.setSurfaceBoundariesLocked(recoveringMemory); - } - - final AppWindowToken atoken = w.mAppToken; - if (atoken != null) { - final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w); - if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) { - mTmpUpdateAllDrawn.add(atoken); - } - } - - if (isDefaultDisplay && someoneLosingFocus && w == mService.mCurrentFocus - && w.isDisplayedLw()) { - mTmpApplySurfaceChangesTransactionState.focusDisplayed = true; - } - - w.updateResizingWindowIfNeeded(); - }, true /* traverseTopToBottom */); + mTmpRecoveringMemory = recoveringMemory; + forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */); mService.mDisplayManagerInternal.setDisplayProperties(mDisplayId, mTmpApplySurfaceChangesTransactionState.displayHasContent, @@ -1923,8 +2046,6 @@ class DisplayContent extends WindowContainer