script-astra/Android/Sdk/sources/android-35/android/window/WindowMetricsController.java

182 lines
8.1 KiB
Java
Raw Normal View History

2025-01-20 15:15:20 +00:00
/*
* 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.ACTIVITY_TYPE_UNDEFINED;
import static android.view.Surface.ROTATION_0;
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.app.WindowConfiguration;
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.DisplayCutout;
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;
import java.util.function.Supplier;
/**
* 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() {
return getWindowMetricsInternal(false /* isMaximum */);
}
/** @see WindowManager#getMaximumWindowMetrics() */
public WindowMetrics getMaximumWindowMetrics() {
return getWindowMetricsInternal(true /* isMaximum */);
}
/**
* The core implementation to obtain {@link WindowMetrics}
*
* @param isMaximum {@code true} to obtain {@link WindowManager#getCurrentWindowMetrics()}.
* {@code false} to obtain {@link WindowManager#getMaximumWindowMetrics()}.
*/
private WindowMetrics getWindowMetricsInternal(boolean isMaximum) {
final Rect bounds;
final float density;
final boolean isScreenRound;
final int activityType;
synchronized (ResourcesManager.getInstance()) {
final Configuration config = mContext.getResources().getConfiguration();
final WindowConfiguration winConfig = config.windowConfiguration;
bounds = (isMaximum) ? winConfig.getMaxBounds() : winConfig.getBounds();
// Multiply default density scale because WindowMetrics provide the density value with
// the scaling factor for the Density Independent Pixel unit, which is the same unit
// as DisplayMetrics#density
density = config.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
isScreenRound = config.isScreenRound();
activityType = winConfig.getActivityType();
}
final IBinder token = Context.getToken(mContext);
final Supplier<WindowInsets> insetsSupplier = () -> getWindowInsetsFromServerForDisplay(
mContext.getDisplayId(), token, bounds, isScreenRound, activityType);
return new WindowMetrics(new Rect(bounds), insetsSupplier, density);
}
/**
* 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 token the token of Activity or WindowContext
* @param bounds the window bounds to calculate insets for
* @param isScreenRound if the display identified by displayId is round
* @param activityType the activity type 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, IBinder token,
Rect bounds, boolean isScreenRound, int activityType) {
try {
final InsetsState insetsState = new InsetsState();
WindowManagerGlobal.getWindowManagerService().getWindowInsets(
displayId, token, insetsState);
final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale();
if (overrideInvScale != 1f) {
insetsState.scale(overrideInvScale);
}
return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState */,
isScreenRound, SOFT_INPUT_ADJUST_NOTHING, 0 /* flags */, SYSTEM_UI_FLAG_VISIBLE,
WindowManager.LayoutParams.INVALID_WINDOW_TYPE, activityType,
null /* idSideMap */);
} 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;
for (int i = 0; i < possibleDisplayInfos.size(); i++) {
currentDisplayInfo = possibleDisplayInfos.get(i);
// Calculate max bounds for natural rotation and state.
Rect maxBounds = new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
currentDisplayInfo.getNaturalHeight());
// Calculate insets for the natural max bounds.
final boolean isScreenRound = (currentDisplayInfo.flags & Display.FLAG_ROUND) != 0;
// Initialize insets based on Surface.ROTATION_0. Note any window-provided insets
// will not be set.
windowInsets = getWindowInsetsFromServerForDisplay(
currentDisplayInfo.displayId, null /* token */,
new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
currentDisplayInfo.getNaturalHeight()), isScreenRound,
ACTIVITY_TYPE_UNDEFINED);
// Set the hardware-provided insets. Always with the ROTATION_0 result.
DisplayCutout cutout = currentDisplayInfo.displayCutout;
if (cutout != null && currentDisplayInfo.rotation != ROTATION_0) {
cutout = cutout.getRotated(
currentDisplayInfo.logicalWidth, currentDisplayInfo.logicalHeight,
currentDisplayInfo.rotation, ROTATION_0);
}
windowInsets = new WindowInsets.Builder(windowInsets).setRoundedCorners(
currentDisplayInfo.roundedCorners).setDisplayCutout(cutout).build();
// Multiply default density scale because WindowMetrics provide the density value with
// the scaling factor for the Density Independent Pixel unit, which is the same unit
// as DisplayMetrics#density
final float density = currentDisplayInfo.logicalDensityDpi
* DisplayMetrics.DENSITY_DEFAULT_SCALE;
maxMetrics.add(new WindowMetrics(maxBounds, windowInsets, density));
}
return maxMetrics;
}
}