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

Commit f70f8ece authored by Naomi Musgrave's avatar Naomi Musgrave
Browse files

[1/n] Introduce API for all available max WindowMetrics

New API provides all maximum WindowMetrics, for all
possible rotations in each DeviceState. This information
allows launcher apps to determine different device
layouts ahead of time, without having to reload the
grid model on every device state change (fold/unfold).

Done:
* WindowManager calculates bounds for the given display, in
  possible rotations
* Defining API surface

Not started:
* WindowManager calculates insets for each rotation
* Display stack builds collection of DisplayInfo, for all
  possible display states (folded, unfolded)
* Display stack pushing set of DisplayInfos to WindowManager

Bug: 181127261
Test: atest FrameworksCoreTests:WindowMetricsTest
Test: atest FrameworksCoreTests:WindowInsetsTest
Change-Id: Ic4580f9c1ee919e5e93cd96b8f11c743fa42f9f1
parent 0bce8531
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.os.Bundle;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.ICrossWindowBlurEnabledListener;
@@ -735,6 +736,17 @@ interface IWindowManager
    boolean getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
            out InsetsState outInsetsState);

    /**
     * Returns a list of {@link android.view.DisplayInfo} for the logical display. This is not
     * guaranteed to include all possible device states. The list items are unique.
     *
     * If invoked through a package other than a launcher app, returns an empty list.
     *
     * @param displayId the id of the logical display
     * @param packageName the name of the calling package
     */
    List<DisplayInfo> getPossibleDisplayInfo(int displayId, String packageName);

    /**
     * Called to show global actions.
     */
+1 −1
Original line number Diff line number Diff line
@@ -202,7 +202,7 @@ public class InsetsState implements Parcelable {
            @Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
        Insets[] typeInsetsMap = new Insets[Type.SIZE];
        Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
        boolean[] typeVisibilityMap = new boolean[SIZE];
        boolean[] typeVisibilityMap = new boolean[Type.SIZE];
        final Rect relativeFrame = new Rect(frame);
        final Rect relativeFrameMax = new Rect(frame);
        for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+10 −0
Original line number Diff line number Diff line
@@ -903,6 +903,16 @@ public final class WindowInsets {
        result.append(mPrivacyIndicatorBounds != null ? "privacyIndicatorBounds="
                + mPrivacyIndicatorBounds : "");
        result.append("\n    ");
        result.append("compatInsetsTypes=" + mCompatInsetsTypes);
        result.append("\n    ");
        result.append("compatIgnoreVisibility=" + mCompatIgnoreVisibility);
        result.append("\n    ");
        result.append("systemWindowInsetsConsumed=" + mSystemWindowInsetsConsumed);
        result.append("\n    ");
        result.append("stableInsetsConsumed=" + mStableInsetsConsumed);
        result.append("\n    ");
        result.append("displayCutoutConsumed=" + mDisplayCutoutConsumed);
        result.append("\n    ");
        result.append(isRound() ? "round" : "");
        result.append("}");
        return result.toString();
+15 −0
Original line number Diff line number Diff line
@@ -123,6 +123,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

@@ -713,6 +714,20 @@ public interface WindowManager extends ViewManager {
        throw new UnsupportedOperationException();
    }

    /**
     * Returns a set of {@link WindowMetrics} for the given display. Each WindowMetrics instance
     * is the maximum WindowMetrics for a device state, including rotations. This is not guaranteed
     * to include all possible device states.
     *
     * This API can only be used by Launcher.
     *
     * @param displayId the id of the logical display
     * @hide
     */
    default @NonNull Set<WindowMetrics> getPossibleMaximumWindowMetrics(int displayId) {
        throw new UnsupportedOperationException();
    }

    /**
     * Used to asynchronously request Keyboard Shortcuts from the focused window.
     *
+70 −16
Original line number Diff line number Diff line
@@ -16,12 +16,9 @@

package android.view;

import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.window.WindowProviderService.isWindowProviderService;
@@ -46,7 +43,9 @@ import android.window.WindowProvider;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Consumer;

@@ -304,31 +303,86 @@ public final class WindowManagerImpl implements WindowManager {
    private WindowInsets computeWindowInsets(Rect bounds) {
        // Initialize params which used for obtaining all system insets.
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
        final Context context = (mParentWindow != null) ? mParentWindow.getContext() : mContext;
        params.token = Context.getToken(context);
        params.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
        params.setFitInsetsTypes(0);
        params.setFitInsetsSides(0);
        return getWindowInsetsFromServerForCurrentDisplay(params, bounds);
    }

        return getWindowInsetsFromServer(params, bounds);
    private WindowInsets getWindowInsetsFromServerForCurrentDisplay(
            WindowManager.LayoutParams attrs, Rect bounds) {
        final Configuration config = mContext.getResources().getConfiguration();
        return getWindowInsetsFromServerForDisplay(mContext.getDisplayId(), attrs, bounds,
                config.isScreenRound(), config.windowConfiguration.getWindowingMode());
    }

    private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds) {
    /**
     * Retrieves WindowInsets for the given context and display, given the window bounds.
     *
     * @param displayId the ID of the logical display to calculate insets for
     * @param attrs the LayoutParams for the calling app
     * @param bounds the window bounds to calculate insets for
     * @param isScreenRound if the display identified by displayId is round
     * @param windowingMode the windowing mode of the window to calculate insets for
     * @return WindowInsets calculated for the given window bounds, on the given display
     */
    private static WindowInsets getWindowInsetsFromServerForDisplay(int displayId,
            WindowManager.LayoutParams attrs, Rect bounds, boolean isScreenRound,
            int windowingMode) {
        try {
            final InsetsState insetsState = new InsetsState();
            final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
                    .getWindowInsets(attrs, mContext.getDisplayId(), insetsState);
            final Configuration config = mContext.getResources().getConfiguration();
            final boolean isScreenRound = config.isScreenRound();
            final int windowingMode = config.windowConfiguration.getWindowingMode();
                    .getWindowInsets(attrs, displayId, insetsState);
            return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
                    isScreenRound, alwaysConsumeSystemBars, SOFT_INPUT_ADJUST_NOTHING, attrs.flags,
                    SYSTEM_UI_FLAG_VISIBLE, attrs.type, windowingMode, null /* typeSideMap */);
                    SYSTEM_UI_FLAG_VISIBLE, attrs.type, windowingMode,
                    null /* typeSideMap */);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    @NonNull
    public Set<WindowMetrics> getPossibleMaximumWindowMetrics(int displayId) {
        List<DisplayInfo> possibleDisplayInfos;
        try {
            possibleDisplayInfos = WindowManagerGlobal.getWindowManagerService()
                    .getPossibleDisplayInfo(displayId, mContext.getPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        int size = possibleDisplayInfos.size();
        DisplayInfo currentDisplayInfo;
        WindowInsets windowInsets = null;
        if (size > 0) {
            currentDisplayInfo = possibleDisplayInfos.get(0);

            final WindowManager.LayoutParams params =  new WindowManager.LayoutParams();
            final boolean isScreenRound = (currentDisplayInfo.flags & Display.FLAG_ROUND) != 0;
            // TODO(181127261) not computing insets correctly - need to have underlying
            // frame reflect the faked orientation.
            windowInsets = getWindowInsetsFromServerForDisplay(
                    currentDisplayInfo.displayId, params,
                    new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
                            currentDisplayInfo.getNaturalHeight()), isScreenRound,
                    WINDOWING_MODE_FULLSCREEN);
        }

        Set<WindowMetrics> maxMetrics = new HashSet<>();
        for (int i = 0; i < size; i++) {
            currentDisplayInfo = possibleDisplayInfos.get(i);

            // Calculate max bounds for this rotation and state.
            Rect maxBounds = new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
                    currentDisplayInfo.getNaturalHeight());

            // Calculate insets for the rotated max bounds.
            // TODO(181127261) calculate insets for each display rotation and state.

            maxMetrics.add(new WindowMetrics(maxBounds, windowInsets));
        }
        return maxMetrics;
    }

    @Override
Loading