From bc8dbe129d07012fac8be425f27a071f4b18d735 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Fri, 23 Dec 2022 14:21:43 +0000 Subject: [PATCH] Add lazy evaluation for getWindowInsets() It is very common that apps call windowManager.getCurrentWindowMetrics().getBounds(); windowManager.getMaximumWindowMetrics().getBounds(); without calling WindowMetrics#getWindowInsets(). Then the heavy operations IWindowManager#getWindowInsets and InsetsState#calculateInsets are wasteful. This change makes the calculation only be called if WindowMetrics#getWindowInsets() is called. Though it may make the result invalid if the interval between creating WindowMetrics and calling getWindowInsets() is long, the common usage should get the result immediately instead of storing the WindowMetrics and get the outdated state later. Bug: 151908239 Test: atest android.view.WindowMetricsTest Change-Id: I28230adcdf004eed60a9fcd4481639f5c04b7c2c --- core/java/android/view/WindowMetrics.java | 27 ++++++++++++++++--- .../window/WindowMetricsController.java | 19 +++++++------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java index 141849f0593a0..b74b80eeec2cf 100644 --- a/core/java/android/view/WindowMetrics.java +++ b/core/java/android/view/WindowMetrics.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.graphics.Point; import android.graphics.Rect; +import java.util.function.Supplier; + /** * Metrics about a Window, consisting of the bounds and {@link WindowInsets}. *

@@ -50,8 +52,9 @@ import android.graphics.Rect; public final class WindowMetrics { @NonNull private final Rect mBounds; - @NonNull - private final WindowInsets mWindowInsets; + + private WindowInsets mWindowInsets; + private Supplier mWindowInsetsSupplier; /** @see android.util.DisplayMetrics#density */ private final float mDensity; @@ -80,6 +83,21 @@ public final class WindowMetrics { mDensity = density; } + /** + * Similar to {@link #WindowMetrics(Rect, WindowInsets, float)} but the window insets are + * computed when {@link #getWindowInsets()} is first time called. This reduces unnecessary + * calculation and the overhead of obtaining insets state from server side because most + * callers are usually only interested in {@link #getBounds()}. + * + * @hide + */ + public WindowMetrics(@NonNull Rect bounds, @NonNull Supplier windowInsetsSupplier, + float density) { + mBounds = bounds; + mWindowInsetsSupplier = windowInsetsSupplier; + mDensity = density; + } + /** * Returns the bounds of the area associated with this window or * {@link android.annotation.UiContext}. @@ -121,7 +139,10 @@ public final class WindowMetrics { */ @NonNull public WindowInsets getWindowInsets() { - return mWindowInsets; + if (mWindowInsets != null) { + return mWindowInsets; + } + return mWindowInsets = mWindowInsetsSupplier.get(); } /** diff --git a/core/java/android/window/WindowMetricsController.java b/core/java/android/window/WindowMetricsController.java index 06449d519f689..11bd47da97745 100644 --- a/core/java/android/window/WindowMetricsController.java +++ b/core/java/android/window/WindowMetricsController.java @@ -41,6 +41,7 @@ import android.view.WindowMetrics; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Supplier; /** * A controller to handle {@link android.view.WindowMetrics} related APIs, which are @@ -53,6 +54,9 @@ import java.util.Set; * @hide */ public final class WindowMetricsController { + // TODO(b/151908239): Remove and always enable this if it is stable. + private static final boolean LAZY_WINDOW_INSETS = android.os.SystemProperties.getBoolean( + "persist.wm.debug.win_metrics_lazy_insets", false); private final Context mContext; public WindowMetricsController(@NonNull Context context) { @@ -92,16 +96,11 @@ public final class WindowMetricsController { windowingMode = winConfig.getWindowingMode(); } final IBinder token = Context.getToken(mContext); - final WindowInsets windowInsets = getWindowInsetsFromServerForCurrentDisplay(token, - bounds, isScreenRound, windowingMode); - return new WindowMetrics(bounds, windowInsets, density); - } - - private WindowInsets getWindowInsetsFromServerForCurrentDisplay( - IBinder token, Rect bounds, boolean isScreenRound, - @WindowConfiguration.WindowingMode int windowingMode) { - return getWindowInsetsFromServerForDisplay(mContext.getDisplayId(), token, bounds, - isScreenRound, windowingMode); + final Supplier insetsSupplier = () -> getWindowInsetsFromServerForDisplay( + mContext.getDisplayId(), token, bounds, isScreenRound, windowingMode); + return LAZY_WINDOW_INSETS + ? new WindowMetrics(new Rect(bounds), insetsSupplier, density) + : new WindowMetrics(new Rect(bounds), insetsSupplier.get(), density); } /**