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  * @see android.annotation.UiContext
51  */
52 public final class WindowMetrics {
53     @NonNull
54     private final Rect mBounds;
55 
56     private WindowInsets mWindowInsets;
57     private Supplier<WindowInsets> mWindowInsetsSupplier;
58 
59     /** @see android.util.DisplayMetrics#density */
60     private final float mDensity;
61 
62     /** @deprecated use {@link #WindowMetrics(Rect, WindowInsets, float)} instead. */
63     @Deprecated
WindowMetrics(@onNull Rect bounds, @NonNull WindowInsets windowInsets)64     public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets) {
65         this(bounds, windowInsets, 1.0f);
66     }
67 
68     /**
69      * The constructor to create a {@link WindowMetrics} instance.
70      * <p>
71      * Note that in most cases {@link WindowMetrics} is obtained from
72      * {@link WindowManager#getCurrentWindowMetrics()} or
73      * {@link WindowManager#getMaximumWindowMetrics()}.
74      * </p>
75      *
76      * @param bounds The window bounds
77      * @param windowInsets The {@link WindowInsets} of the window
78      * @param density The window density
79      */
WindowMetrics(@onNull Rect bounds, @NonNull WindowInsets windowInsets, float density)80     public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets, float density) {
81         mBounds = bounds;
82         mWindowInsets = windowInsets;
83         mDensity = density;
84     }
85 
86     /**
87      * Similar to {@link #WindowMetrics(Rect, WindowInsets, float)} but the window insets are
88      * computed when {@link #getWindowInsets()} is first time called. This reduces unnecessary
89      * calculation and the overhead of obtaining insets state from server side because most
90      * callers are usually only interested in {@link #getBounds()}.
91      *
92      * @hide
93      */
WindowMetrics(@onNull Rect bounds, @NonNull Supplier<WindowInsets> windowInsetsSupplier, float density)94     public WindowMetrics(@NonNull Rect bounds, @NonNull Supplier<WindowInsets> windowInsetsSupplier,
95             float density) {
96         mBounds = bounds;
97         mWindowInsetsSupplier = windowInsetsSupplier;
98         mDensity = density;
99     }
100 
101     /**
102      * Returns the bounds of the area associated with this window or
103      * {@link android.annotation.UiContext}.
104      * <p>
105      * <b>Note that the size of the reported bounds can have different size than
106      * {@link Display#getSize(Point)}.</b> This method reports the window size including all system
107      * bar areas, while {@link Display#getSize(Point)} reports the area excluding navigation bars
108      * and display cutout areas. The value reported by {@link Display#getSize(Point)} can be
109      * obtained by using:
110      * <pre class="prettyprint">
111      * final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
112      * // Gets all excluding insets
113      * final WindowInsets windowInsets = metrics.getWindowInsets();
114      * Insets insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.navigationBars()
115      *         | WindowInsets.Type.displayCutout());
116      *
117      * int insetsWidth = insets.right + insets.left;
118      * int insetsHeight = insets.top + insets.bottom;
119      *
120      * // Legacy size that Display#getSize reports
121      * final Rect bounds = metrics.getBounds();
122      * final Size legacySize = new Size(bounds.width() - insetsWidth,
123      *         bounds.height() - insetsHeight);
124      * </pre>
125      * </p>
126      *
127      * @return window bounds in pixels.
128      */
129     @NonNull
getBounds()130     public Rect getBounds() {
131         return mBounds;
132     }
133 
134     /**
135      * Returns the {@link WindowInsets} of the area associated with this window or
136      * {@link android.annotation.UiContext}.
137      *
138      * @return the {@link WindowInsets} of the visual area.
139      */
140     @NonNull
getWindowInsets()141     public WindowInsets getWindowInsets() {
142         if (mWindowInsets != null) {
143             return mWindowInsets;
144         }
145         return mWindowInsets = mWindowInsetsSupplier.get();
146     }
147 
148     /**
149      * Returns the density of the area associated with this window or
150      * {@link android.annotation.UiContext}, which uses the same units as
151      * {@link android.util.DisplayMetrics#density}.
152      *
153      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
154      * @see android.util.DisplayMetrics#density
155      */
getDensity()156     public float getDensity() {
157         return mDensity;
158     }
159 
160     @Override
toString()161     public String toString() {
162         return WindowMetrics.class.getSimpleName() + ":{"
163                 + "bounds=" + mBounds
164                 + ", windowInsets=" + mWindowInsets
165                 + ", density=" + mDensity
166                 + "}";
167     }
168 }
169