Extract WindowMetrics logic to WindowMetricsController

We would add some mechanisms to improve WindowMetrics performance,
which will introduce more WindowMetrics logic.
Extracting it to a separate module will make the WindowMetrics logic
easier to maintain. No logic changes.

Bug: 187712731
Test: atest WindowMetricsActivityTests WindowMetricsWindowContextTests
Change-Id: Ic35501efc4e2b73af80593f3b1911be35c2f0e48
This commit is contained in:
Charles Chen
2022-09-16 14:00:05 +08:00
parent 68cfa17232
commit c1f3375e1f
2 changed files with 181 additions and 104 deletions

View File

@@ -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

View File

@@ -0,0 +1,172 @@
/*
* 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;
}
}