diff options
-rw-r--r-- | api/current.txt | 8 | ||||
-rw-r--r-- | core/java/android/view/IWindowManager.aidl | 9 | ||||
-rw-r--r-- | core/java/android/view/WindowManager.java | 43 | ||||
-rw-r--r-- | core/java/android/view/WindowManagerImpl.java | 79 | ||||
-rw-r--r-- | core/java/android/view/WindowMetrics.java | 58 | ||||
-rw-r--r-- | services/core/java/com/android/server/wm/WindowManagerService.java | 29 |
6 files changed, 226 insertions, 0 deletions
diff --git a/api/current.txt b/api/current.txt index f2755c9f62d6..4c3110c9189c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -54632,7 +54632,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); } @@ -54801,6 +54803,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 { diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 5eb319f19cce..d9c502e14e68 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -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); } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 1333ffe272d3..c8dea43e8f4c 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -437,6 +437,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. * * @hide diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index cdeeaa438acb..4365d1f5194a 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -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; + } } diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java new file mode 100644 index 000000000000..8caf5b7fc725 --- /dev/null +++ b/core/java/android/view/WindowMetrics.java @@ -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; + } +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e82394c5ae27..8d4ad28972e9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -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); + } + } } |