1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 
19 import android.annotation.NonNull;
20 import android.graphics.Point;
21 import android.graphics.Rect;
22 
23 import java.util.function.Supplier;
24 
25 /**
26  * Metrics about a Window, consisting of the bounds and {@link WindowInsets}.
27  * <p>
28  * This is usually obtained from {@link WindowManager#getCurrentWindowMetrics()} and
29  * {@link WindowManager#getMaximumWindowMetrics()}.
30  * </p>
31  * After {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, it also provides density.
32  * <h3>Obtains Window Dimensions in Density-independent Pixel(DP)</h3>
33  * <p>
34  * While {@link #getDensity()} is provided, the dimension in density-independent pixel could also be
35  * calculated with {@code WindowMetrics} properties, which is similar to
36  * {@link android.content.res.Configuration#screenWidthDp}
37  * <pre class="prettyprint">
38  * float widthInDp = windowMetrics.getBounds().width() / windowMetrics.getDensity();
39  * float heightInDp = windowMetrics.getBounds().height() / windowMetrics.getDensity();
40  * </pre>
41  * Also, the density in DPI can be obtained by:
42  * <pre class="prettyprint">
43  * float densityDp = DisplayMetrics.DENSITY_DEFAULT * windowMetrics.getDensity();
44  * </pre>
45  * </p>
46  *
47  * @see WindowInsets#getInsets(int)
48  * @see WindowManager#getCurrentWindowMetrics()
49  * @see WindowManager#getMaximumWindowMetrics()
50  */
51 public final class WindowMetrics {
52     @NonNull
53     private final Rect mBounds;
54 
55     private WindowInsets mWindowInsets;
56     private Supplier<WindowInsets> mWindowInsetsSupplier;
57 
58     /** @see android.util.DisplayMetrics#density */
59     private final float mDensity;
60 
61     /** @deprecated use {@link #WindowMetrics(Rect, WindowInsets, float)} instead. */
62     @Deprecated
WindowMetrics(@onNull Rect bounds, @NonNull WindowInsets windowInsets)63     public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets) {
64         this(bounds, windowInsets, 1.0f);
65     }
66 
67     /**
68      * The constructor to create a {@link WindowMetrics} instance.
69      * <p>
70      * Note that in most cases {@link WindowMetrics} is obtained from
71      * {@link WindowManager#getCurrentWindowMetrics()} or
72      * {@link WindowManager#getMaximumWindowMetrics()}.
73      * </p>
74      *
75      * @param bounds The window bounds
76      * @param windowInsets The {@link WindowInsets} of the window
77      * @param density The window density
78      */
WindowMetrics(@onNull Rect bounds, @NonNull WindowInsets windowInsets, float density)79     public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets, float density) {
80         mBounds = bounds;
81         mWindowInsets = windowInsets;
82         mDensity = density;
83     }
84 
85     /**
86      * Similar to {@link #WindowMetrics(Rect, WindowInsets, float)} but the window insets are
87      * computed when {@link #getWindowInsets()} is first time called. This reduces unnecessary
88      * calculation and the overhead of obtaining insets state from server side because most
89      * callers are usually only interested in {@link #getBounds()}.
90      *
91      * @hide
92      */
WindowMetrics(@onNull Rect bounds, @NonNull Supplier<WindowInsets> windowInsetsSupplier, float density)93     public WindowMetrics(@NonNull Rect bounds, @NonNull Supplier<WindowInsets> windowInsetsSupplier,
94             float density) {
95         mBounds = bounds;
96         mWindowInsetsSupplier = windowInsetsSupplier;
97         mDensity = density;
98     }
99 
100     /**
101      * Returns the bounds of the area associated with this window or {@code UiContext}.
102      * <p>
103      * <b>Note that the size of the reported bounds can have different size than
104      * {@link Display#getSize(Point)} based on your target API level and calling context.</b>
105      * This method reports the window size including all system
106      * bar areas, while {@link Display#getSize(Point)} can report the area excluding navigation bars
107      * and display cutout areas depending on the calling context and target SDK level. Please refer
108      * to {@link Display#getSize(Point)} for details.
109      * <p>
110      * The value reported by {@link Display#getSize(Point)} excluding system decoration areas can be
111      * obtained by using:
112      * <pre class="prettyprint">
113      * final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
114      * // Gets all excluding insets
115      * final WindowInsets windowInsets = metrics.getWindowInsets();
116      * Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
117      *         | WindowInsets.Type.displayCutout());
118      *
119      * int insetsWidth = insets.right + insets.left;
120      * int insetsHeight = insets.top + insets.bottom;
121      *
122      * // Legacy size that Display#getSize reports
123      * final Rect bounds = metrics.getBounds();
124      * final Size legacySize = new Size(bounds.width() - insetsWidth,
125      *         bounds.height() - insetsHeight);
126      * </pre>
127      * </p>
128      *
129      * @return window bounds in pixels.
130      */
131     @NonNull
getBounds()132     public Rect getBounds() {
133         return mBounds;
134     }
135 
136     /**
137      * Returns the {@link WindowInsets} of the area associated with this window or
138      * {@code UiContext}.
139      *
140      * @return the {@link WindowInsets} of the visual area.
141      */
142     @NonNull
getWindowInsets()143     public WindowInsets getWindowInsets() {
144         if (mWindowInsets != null) {
145             return mWindowInsets;
146         }
147         return mWindowInsets = mWindowInsetsSupplier.get();
148     }
149 
150     /**
151      * Returns the density of the area associated with this window or {@code UiContext},
152      * which uses the same units as {@link android.util.DisplayMetrics#density}.
153      *
154      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
155      * @see android.util.DisplayMetrics#density
156      */
getDensity()157     public float getDensity() {
158         return mDensity;
159     }
160 
161     @Override
toString()162     public String toString() {
163         return WindowMetrics.class.getSimpleName() + ":{"
164                 + "bounds=" + mBounds
165                 + ", windowInsets=" + mWindowInsets
166                 + ", density=" + mDensity
167                 + "}";
168     }
169 }
170