Introduce WindowMetrics and WM#getCurrent/MaximumWindowMetrics

Bug: 128338354
Bug: 146820733
Test: atest WindowMetricsTests

Change-Id: I328b1b5a2296e470072a439e412276c1b6008789
This commit is contained in:
Charles Chen
2020-01-17 11:51:34 +08:00
committed by Andrii Kulian
parent 4a31697319
commit f65e022caa
6 changed files with 226 additions and 0 deletions

View File

@@ -54148,7 +54148,9 @@ package android.view {
}
public interface WindowManager extends android.view.ViewManager {
method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics();
method @Deprecated public android.view.Display getDefaultDisplay();
method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
method public void removeViewImmediate(android.view.View);
}
@@ -54311,6 +54313,12 @@ package android.view {
field @android.view.ViewDebug.ExportedProperty public int y;
}
public final class WindowMetrics {
ctor public WindowMetrics(@NonNull android.util.Size, @NonNull android.view.WindowInsets);
method @NonNull public android.util.Size getSize();
method @NonNull public android.view.WindowInsets getWindowInsets();
}
}
package android.view.accessibility {

View File

@@ -32,6 +32,7 @@ import android.graphics.Region;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IDockedStackListener;
@@ -739,4 +740,12 @@ interface IWindowManager
* Called when a remote process modifies insets on a display window container.
*/
void modifyDisplayWindowInsets(int displayId, in InsetsState state);
/**
* Called to get the expected window insets.
* TODO(window-context): Remove when new insets flag is available.
*/
void getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
out Rect outContentInsets, out Rect outStableInsets,
out DisplayCutout.ParcelableWrapper displayCutout);
}

View File

@@ -436,6 +436,49 @@ public interface WindowManager extends ViewManager {
*/
public void removeViewImmediate(View view);
/**
* Returns the {@link WindowMetrics} according to the current system state.
* <p>
* The metrics describe the size of the area the window would occupy with
* {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets}
* such a window would have.
* <p>
* The value of this is based on the <b>current</b> windowing state of the system.
*
* For example, for activities in multi-window mode, the metrics returned are based on the
* current bounds that the user has selected for the {@link android.app.Activity Activity}'s
* task.
*
* @see #getMaximumWindowMetrics()
* @see WindowMetrics
*/
default @NonNull WindowMetrics getCurrentWindowMetrics() {
throw new UnsupportedOperationException();
}
/**
* Returns the largets {@link WindowMetrics} an app may expect in the current system state.
* <p>
* The metrics describe the size of the largest potential area the window might occupy with
* {@link LayoutParams#MATCH_PARENT MATCH_PARENT} width and height, and the {@link WindowInsets}
* such a window would have.
* <p>
* The value of this is based on the largest <b>potential</b> windowing state of the system.
*
* For example, for activities in multi-window mode, the metrics returned are based on the
* what the bounds would be if the user expanded the {@link android.app.Activity Activity}'s
* task to cover the entire screen.
*
* Note that this might still be smaller than the size of the physical display if certain areas
* of the display are not available to windows created in this {@link Context}.
*
* @see #getMaximumWindowMetrics()
* @see WindowMetrics
*/
default @NonNull WindowMetrics getMaximumWindowMetrics() {
throw new UnsupportedOperationException();
}
/**
* Used to asynchronously request Keyboard Shortcuts from the focused window.
*

View File

@@ -17,12 +17,17 @@
package android.view;
import android.annotation.NonNull;
import android.app.ResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Size;
import com.android.internal.os.IResultReceiver;
@@ -62,6 +67,10 @@ public final class WindowManagerImpl implements WindowManager {
private IBinder mDefaultToken;
private boolean mIsViewAdded;
private View mLastView;
private WindowManager.LayoutParams mLastParams;
public WindowManagerImpl(Context context) {
this(context, null);
}
@@ -93,6 +102,9 @@ public final class WindowManagerImpl implements WindowManager {
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
mIsViewAdded = true;
mLastView = view;
mLastParams = (WindowManager.LayoutParams) params;
}
@Override
@@ -201,4 +213,71 @@ public final class WindowManagerImpl implements WindowManager {
}
return false;
}
@Override
public WindowMetrics getCurrentWindowMetrics() {
final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
final Rect bound = getCurrentBounds(context);
return new WindowMetrics(toSize(bound), computeWindowInsets());
}
private static Rect getCurrentBounds(Context context) {
synchronized (ResourcesManager.getInstance()) {
return context.getResources().getConfiguration().windowConfiguration.getBounds();
}
}
@Override
public WindowMetrics getMaximumWindowMetrics() {
return new WindowMetrics(toSize(getMaximumBounds()), computeWindowInsets());
}
private Size toSize(Rect frame) {
return new Size(frame.width(), frame.height());
}
private Rect getMaximumBounds() {
// TODO(b/128338354): Current maximum bound is display size, but it should be displayArea
// bound after displayArea feature is finished.
final Display display = mContext.getDisplay();
final Point displaySize = new Point();
display.getRealSize(displaySize);
return new Rect(0, 0, displaySize.x, displaySize.y);
}
private WindowInsets computeWindowInsets() {
// TODO(window-context): This can only be properly implemented
// once we flip the new insets mode flag.
if (mParentWindow != null) {
if (mParentWindow.getDecorView().isAttachedToWindow()) {
return mParentWindow.getDecorView().getViewRootImpl()
.getWindowInsets(true /* forceConstruct */);
}
return getWindowInsetsFromServer(mParentWindow.getAttributes());
}
if (mIsViewAdded) {
return mLastView.getViewRootImpl().getWindowInsets(true /* forceConstruct */);
} else {
return getWindowInsetsFromServer(new WindowManager.LayoutParams());
}
}
private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs) {
try {
final Rect systemWindowInsets = new Rect();
final Rect stableInsets = new Rect();
final DisplayCutout.ParcelableWrapper displayCutout =
new DisplayCutout.ParcelableWrapper();
WindowManagerGlobal.getWindowManagerService().getWindowInsets(attrs,
mContext.getDisplayId(), systemWindowInsets, stableInsets, displayCutout);
return new WindowInsets.Builder()
.setSystemWindowInsets(Insets.of(systemWindowInsets))
.setStableInsets(Insets.of(stableInsets))
.setDisplayCutout(displayCutout.get()).build();
} catch (RemoteException e) {
}
return null;
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2020 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.view;
import android.annotation.NonNull;
import android.util.Size;
/**
* Metrics about a Window, consisting of the size and {@link WindowInsets}.
* <p>
* This is usually obtained from {@link WindowManager#getCurrentWindowMetrics()} and
* {@link WindowManager#getMaximumWindowMetrics()}.
*
* @see WindowInsets#getInsets(int)
* @see WindowManager#getCurrentWindowMetrics()
* @see WindowManager#getMaximumWindowMetrics()
*/
public final class WindowMetrics {
private final @NonNull Size mSize;
private final @NonNull WindowInsets mWindowInsets;
public WindowMetrics(@NonNull Size size, @NonNull WindowInsets windowInsets) {
mSize = size;
mWindowInsets = windowInsets;
}
/**
* Returns the size of the window.
*
* @return window size in pixel.
*/
public @NonNull Size getSize() {
return mSize;
}
/**
* Returns the {@link WindowInsets} of the window.
*
* @return the {@link WindowInsets} of the window.
*/
public @NonNull WindowInsets getWindowInsets() {
return mWindowInsets;
}
}

View File

@@ -7927,4 +7927,33 @@ public class WindowManagerService extends IWindowManager.Stub
return mDisplayWindowSettings.shouldShowImeLocked(displayContent)
|| mForceDesktopModeOnExternalDisplays;
}
@Override
public void getWindowInsets(WindowManager.LayoutParams attrs,
int displayId, Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper displayCutout) {
synchronized (mGlobalLock) {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
final WindowToken windowToken = dc.getWindowToken(attrs.token);
final ActivityRecord activity;
if (windowToken != null && windowToken.asActivityRecord() != null) {
activity = windowToken.asActivityRecord();
} else {
activity = null;
}
final Rect taskBounds = new Rect();
final boolean floatingStack;
if (activity != null && activity.getTask() != null) {
final Task task = activity.getTask();
task.getBounds(taskBounds);
floatingStack = task.isFloating();
} else {
floatingStack = false;
}
final DisplayFrames displayFrames = dc.mDisplayFrames;
final DisplayPolicy policy = dc.getDisplayPolicy();
policy.getLayoutHintLw(attrs, taskBounds, displayFrames, floatingStack,
new Rect(), outContentInsets, outStableInsets, displayCutout);
}
}
}