Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc8dbe12 authored by Riddle Hsu's avatar Riddle Hsu
Browse files

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
parent 26ef4c4c
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -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}.
 * <p>
@@ -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<WindowInsets> 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<WindowInsets> 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,8 +139,11 @@ public final class WindowMetrics {
     */
    @NonNull
    public WindowInsets getWindowInsets() {
        if (mWindowInsets != null) {
            return mWindowInsets;
        }
        return mWindowInsets = mWindowInsetsSupplier.get();
    }

    /**
     * Returns the density of the area associated with this window or
+9 −10
Original line number Diff line number Diff line
@@ -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<WindowInsets> 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);
    }

    /**