1 /*
2  * Copyright (C) 2021 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 package com.android.launcher3.util;
17 
18 import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
19 import static com.android.launcher3.Utilities.dpiFromPx;
20 
21 import android.annotation.TargetApi;
22 import android.content.Context;
23 import android.content.res.Configuration;
24 import android.graphics.Insets;
25 import android.graphics.Rect;
26 import android.os.Build;
27 import android.util.ArraySet;
28 import android.view.WindowInsets;
29 import android.view.WindowInsets.Type;
30 import android.view.WindowManager;
31 import android.view.WindowMetrics;
32 
33 import com.android.launcher3.R;
34 import com.android.launcher3.ResourceUtils;
35 import com.android.launcher3.Utilities;
36 import com.android.launcher3.util.DisplayController.PortraitSize;
37 
38 import java.util.Collections;
39 import java.util.Set;
40 
41 /**
42  * Utility class to estimate window manager values
43  */
44 @TargetApi(Build.VERSION_CODES.S)
45 public class WindowManagerCompat {
46 
47     public static final int MIN_TABLET_WIDTH = 600;
48 
49     /**
50      * Returns a set of supported render sizes for a internal display.
51      * This is a temporary workaround which assumes only nav-bar insets change across displays, and
52      * is only used until we eventually get the real values
53      * @param consumeTaskBar if true, it assumes that task bar is part of the app window
54      *                       and ignores any insets because of task bar.
55      */
estimateDisplayProfiles( Context windowContext, PortraitSize size, int densityDpi, boolean consumeTaskBar)56     public static Set<WindowBounds> estimateDisplayProfiles(
57             Context windowContext, PortraitSize size, int densityDpi, boolean consumeTaskBar) {
58         if (!Utilities.ATLEAST_S) {
59             return Collections.emptySet();
60         }
61         WindowInsets defaultInsets = windowContext.getSystemService(WindowManager.class)
62                 .getMaximumWindowMetrics().getWindowInsets();
63         boolean isGesturalMode = ResourceUtils.getIntegerByName(
64                 "config_navBarInteractionMode",
65                 windowContext.getResources(),
66                 INVALID_RESOURCE_HANDLE) == 2;
67 
68         WindowInsets.Builder insetsBuilder = new WindowInsets.Builder(defaultInsets);
69         Set<WindowBounds> result = new ArraySet<>();
70         int swDP = (int) dpiFromPx(size.width, densityDpi);
71         boolean isTablet = swDP >= MIN_TABLET_WIDTH;
72 
73         final Insets portraitNav, landscapeNav;
74         if (isTablet && !consumeTaskBar) {
75             portraitNav = landscapeNav = Insets.of(0, 0, 0, windowContext.getResources()
76                     .getDimensionPixelSize(R.dimen.taskbar_size));
77         } else if (!isGesturalMode) {
78             portraitNav = Insets.of(0, 0, 0,
79                     getSystemResource(windowContext, "navigation_bar_height", swDP));
80             landscapeNav = isTablet
81                     ? Insets.of(0, 0, 0, getSystemResource(windowContext,
82                             "navigation_bar_height_landscape", swDP))
83                     : Insets.of(0, 0, getSystemResource(windowContext,
84                             "navigation_bar_width", swDP), 0);
85         } else {
86             portraitNav = landscapeNav = Insets.of(0, 0, 0, 0);
87         }
88 
89         result.add(WindowBounds.fromWindowMetrics(new WindowMetrics(
90                 new Rect(0, 0, size.width, size.height),
91                 insetsBuilder.setInsets(Type.navigationBars(), portraitNav).build())));
92         result.add(WindowBounds.fromWindowMetrics(new WindowMetrics(
93                 new Rect(0, 0, size.height, size.width),
94                 insetsBuilder.setInsets(Type.navigationBars(), landscapeNav).build())));
95         return result;
96     }
97 
getSystemResource(Context context, String key, int swDp)98     private static int getSystemResource(Context context, String key, int swDp) {
99         int resourceId = context.getResources().getIdentifier(key, "dimen", "android");
100         if (resourceId > 0) {
101             Configuration conf = new Configuration();
102             conf.smallestScreenWidthDp = swDp;
103             return context.createConfigurationContext(conf)
104                     .getResources().getDimensionPixelSize(resourceId);
105         }
106         return 0;
107     }
108 }
109