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

Commit e9f859d4 authored by Charles Chen's avatar Charles Chen Committed by Android (Google) Code Review
Browse files

Merge "Extract WindowMetrics logic to WindowMetricsController"

parents fb7ddf3e c1f3375e
Loading
Loading
Loading
Loading
+9 −104
Original line number Diff line number Diff line
@@ -16,11 +16,8 @@

package android.view;

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.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.window.WindowProviderService.isWindowProviderService;

import android.annotation.CallbackExecutor;
@@ -28,12 +25,9 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
import android.app.ResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
@@ -42,6 +36,7 @@ import android.os.StrictMode;
import android.window.ITaskFpsCallback;
import android.window.TaskFpsCallback;
import android.window.WindowContext;
import android.window.WindowMetricsController;
import android.window.WindowProvider;

import com.android.internal.annotations.GuardedBy;
@@ -49,7 +44,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -107,6 +101,10 @@ public final class WindowManagerImpl implements WindowManager {
    private final ArrayList<OnFpsCallbackListenerProxy> mOnFpsCallbackListenerProxies =
            new ArrayList<>();

    /** A controller to handle {@link WindowMetrics} related APIs */
    @NonNull
    private final WindowMetricsController mWindowMetricsController;

    public WindowManagerImpl(Context context) {
        this(context, null /* parentWindow */, null /* clientToken */);
    }
@@ -116,6 +114,7 @@ public final class WindowManagerImpl implements WindowManager {
        mContext = context;
        mParentWindow = parentWindow;
        mWindowContextToken = windowContextToken;
        mWindowMetricsController = new WindowMetricsController(mContext);
    }

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
@@ -293,112 +292,18 @@ public final class WindowManagerImpl implements WindowManager {

    @Override
    public WindowMetrics getCurrentWindowMetrics() {
        final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
        final Rect bounds = getCurrentBounds(context);

        return new WindowMetrics(bounds, computeWindowInsets(bounds));
    }

    private static Rect getCurrentBounds(Context context) {
        synchronized (ResourcesManager.getInstance()) {
            return context.getResources().getConfiguration().windowConfiguration.getBounds();
        }
        return mWindowMetricsController.getCurrentWindowMetrics();
    }

    @Override
    public WindowMetrics getMaximumWindowMetrics() {
        final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
        final Rect maxBounds = getMaximumBounds(context);

        return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds));
    }

    private static Rect getMaximumBounds(Context context) {
        synchronized (ResourcesManager.getInstance()) {
            return context.getResources().getConfiguration().windowConfiguration.getMaxBounds();
        }
    }

    private WindowInsets computeWindowInsets(Rect bounds) {
        // Initialize params which used for obtaining all system insets.
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        final Context context = (mParentWindow != null) ? mParentWindow.getContext() : mContext;
        params.token = Context.getToken(context);
        return getWindowInsetsFromServerForCurrentDisplay(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());
    }

    /**
     * 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, 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 */);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return mWindowMetricsController.getMaximumWindowMetrics();
    }

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

        Set<WindowMetrics> maxMetrics = new HashSet<>();
        WindowInsets windowInsets;
        DisplayInfo currentDisplayInfo;
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        for (int i = 0; i < possibleDisplayInfos.size(); i++) {
            currentDisplayInfo = possibleDisplayInfos.get(i);

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

            // Calculate insets for the rotated max bounds.
            final boolean isScreenRound = (currentDisplayInfo.flags & Display.FLAG_ROUND) != 0;
            // Initialize insets based upon display rotation. Note any window-provided insets
            // will not be set.
            windowInsets = getWindowInsetsFromServerForDisplay(
                    currentDisplayInfo.displayId, params,
                    new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
                            currentDisplayInfo.getNaturalHeight()), isScreenRound,
                    WINDOWING_MODE_FULLSCREEN);
            // Set the hardware-provided insets.
            windowInsets = new WindowInsets.Builder(windowInsets).setRoundedCorners(
                    currentDisplayInfo.roundedCorners)
                    .setDisplayCutout(currentDisplayInfo.displayCutout).build();

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

    @Override
+172 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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 android.window;

import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;

import android.annotation.NonNull;
import android.app.ResourcesManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.InsetsState;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.WindowMetrics;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * A controller to handle {@link android.view.WindowMetrics} related APIs, which are
 * <ol>
 *     <li>{@link WindowManager#getCurrentWindowMetrics()}</li>
 *     <li>{@link WindowManager#getMaximumWindowMetrics()}</li>
 *     <li>{@link WindowManager#getPossibleMaximumWindowMetrics(int)}</li>
 * </ol>
 *
 * @hide
 */
public final class WindowMetricsController {
    private final Context mContext;

    public WindowMetricsController(@NonNull Context context) {
        mContext = context;
    }

    /** @see WindowManager#getCurrentWindowMetrics() */
    public WindowMetrics getCurrentWindowMetrics() {
        final Rect bounds = getCurrentBounds(mContext);

        // TODO(b/187712731): Provide density for WindowMetrics.
        return new WindowMetrics(bounds, computeWindowInsets(bounds));
    }

    private static Rect getCurrentBounds(Context context) {
        synchronized (ResourcesManager.getInstance()) {
            return context.getResources().getConfiguration().windowConfiguration.getBounds();
        }
    }

    /** @see WindowManager#getMaximumWindowMetrics() */
    public WindowMetrics getMaximumWindowMetrics() {
        final Rect maxBounds = getMaximumBounds(mContext);

        // TODO(b/187712731): Provide density for WindowMetrics.
        return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds));
    }

    private static Rect getMaximumBounds(Context context) {
        synchronized (ResourcesManager.getInstance()) {
            return context.getResources().getConfiguration().windowConfiguration.getMaxBounds();
        }
    }

    private WindowInsets computeWindowInsets(Rect bounds) {
        // Initialize params which used for obtaining all system insets.
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        params.token = Context.getToken(mContext);
        return getWindowInsetsFromServerForCurrentDisplay(params, bounds);
    }

    private WindowInsets getWindowInsetsFromServerForCurrentDisplay(
            WindowManager.LayoutParams attrs, Rect bounds) {
        final boolean isScreenRound;
        final int windowingMode;
        synchronized (ResourcesManager.getInstance()) {
            final Configuration config = mContext.getResources().getConfiguration();
            isScreenRound = config.isScreenRound();
            windowingMode = config.windowConfiguration.getWindowingMode();
        }
        return getWindowInsetsFromServerForDisplay(mContext.getDisplayId(), attrs, bounds,
                isScreenRound, windowingMode);
    }

    /**
     * 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, 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 */);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /** @see WindowManager#getPossibleMaximumWindowMetrics(int) */
    @NonNull
    public Set<WindowMetrics> getPossibleMaximumWindowMetrics(int displayId) {
        List<DisplayInfo> possibleDisplayInfos;
        try {
            possibleDisplayInfos = WindowManagerGlobal.getWindowManagerService()
                    .getPossibleDisplayInfo(displayId);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        Set<WindowMetrics> maxMetrics = new HashSet<>();
        WindowInsets windowInsets;
        DisplayInfo currentDisplayInfo;
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
        for (int i = 0; i < possibleDisplayInfos.size(); i++) {
            currentDisplayInfo = possibleDisplayInfos.get(i);

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

            // Calculate insets for the rotated max bounds.
            final boolean isScreenRound = (currentDisplayInfo.flags & Display.FLAG_ROUND) != 0;
            // Initialize insets based upon display rotation. Note any window-provided insets
            // will not be set.
            windowInsets = getWindowInsetsFromServerForDisplay(
                    currentDisplayInfo.displayId, params,
                    new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
                            currentDisplayInfo.getNaturalHeight()), isScreenRound,
                    WINDOWING_MODE_FULLSCREEN);
            // Set the hardware-provided insets.
            windowInsets = new WindowInsets.Builder(windowInsets).setRoundedCorners(
                            currentDisplayInfo.roundedCorners)
                    .setDisplayCutout(currentDisplayInfo.displayCutout).build();

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