1 /* 2 * Copyright 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 17 package androidx.window.layout 18 19 import android.app.Activity 20 import android.content.Context 21 import android.inputmethodservice.InputMethodService 22 import android.os.Build 23 import android.util.DisplayMetrics 24 import android.view.Display 25 import android.view.WindowMetrics as AndroidWindowMetrics 26 import androidx.annotation.RequiresApi 27 import androidx.annotation.RestrictTo 28 import androidx.annotation.UiContext 29 import androidx.window.core.Bounds 30 import androidx.window.layout.util.WindowMetricsCompatHelper 31 32 /** An interface to calculate the [WindowMetrics] for an [Activity] or a [UiContext]. */ 33 interface WindowMetricsCalculator { 34 35 /** 36 * Computes the size and position of the area the window would occupy with 37 * [MATCH_PARENT][android.view.WindowManager.LayoutParams.MATCH_PARENT] width and height and any 38 * combination of flags that would allow the window to extend behind display cutouts. 39 * 40 * For example, [android.view.WindowManager.LayoutParams.layoutInDisplayCutoutMode] set to 41 * [android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS] or the 42 * [android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS] flag set. 43 * 44 * The value returned from this method may be different from platform API(s) used to determine 45 * the size and position of the visible area a given context occupies. For example: 46 * * [Display.getSize] can be used to determine the size of the visible area a window occupies, 47 * but may be subtracted to exclude certain system decorations that always appear on screen, 48 * notably the navigation bar. 49 * * The decor view's [android.view.View#getWidth] and [android.view.View@getHeight] can be used 50 * to determine the size of the top level view in the view hierarchy, but this size is 51 * determined through a combination of [android.view.WindowManager.LayoutParams] flags and may 52 * not represent the true window size. For example, a window that does not indicate it can be 53 * displayed behind a display cutout will have the size of the decor view offset to exclude 54 * this region unless this region overlaps with the status bar, while the value returned from 55 * this method will include this region. 56 * 57 * The value returned from this method is guaranteed to be correct on platforms 58 * [Q][Build.VERSION_CODES.Q] and above. For older platforms the value may be invalid if the 59 * activity is in multi-window mode or if the navigation bar offset can not be accounted for, 60 * though a best effort is made to ensure the returned value is as close as possible to the true 61 * value. See [.computeWindowBoundsP] and [.computeWindowBoundsN]. 62 * 63 * Note: The value of this is based on the last windowing state reported to the client. 64 * 65 * @see android.view.WindowManager.getCurrentWindowMetrics 66 * @see android.view.WindowMetrics.getBounds 67 */ computeCurrentWindowMetricsnull68 fun computeCurrentWindowMetrics(activity: Activity): WindowMetrics 69 70 /** 71 * Computes the size and position of the area the window would occupy with 72 * [MATCH_PARENT][android.view.WindowManager.LayoutParams.MATCH_PARENT] width and height and any 73 * combination of flags that would allow the window to extend behind display cutouts. 74 * 75 * On [Build.VERSION_CODES.Q] and older, a [UiContext] is either an [Activity] or an 76 * [InputMethodService]. On [Build.VERSION_CODES.R] and newer, a [UiContext] can also be one 77 * created via the [Context.createWindowContext] APIs. 78 * 79 * @throws NotImplementedError if not implemented. The default implementation from [getOrCreate] 80 * is guaranteed to implement this method. 81 * @see [computeCurrentWindowMetrics] 82 */ 83 fun computeCurrentWindowMetrics(@UiContext context: Context): WindowMetrics { 84 throw NotImplementedError( 85 "Must override computeCurrentWindowMetrics(context) and" + " provide an implementation." 86 ) 87 } 88 89 /** 90 * Computes the maximum size and position of the area the window can expect with 91 * [MATCH_PARENT][android.view.WindowManager.LayoutParams.MATCH_PARENT] width and height and any 92 * combination of flags that would allow the window to extend behind display cutouts. 93 * 94 * The value returned from this method will always match [Display.getRealSize] on 95 * [Android 10][Build.VERSION_CODES.Q] and below. 96 * 97 * @see android.view.WindowManager.getMaximumWindowMetrics 98 */ computeMaximumWindowMetricsnull99 fun computeMaximumWindowMetrics(activity: Activity): WindowMetrics 100 101 /** 102 * Computes the maximum size and position of the area the window can expect with 103 * [MATCH_PARENT][android.view.WindowManager.LayoutParams.MATCH_PARENT] width and height and any 104 * combination of flags that would allow the window to extend behind display cutouts. 105 * 106 * The value returned from this method will always match [Display.getRealSize] on 107 * [Android 10][Build.VERSION_CODES.Q] and below. 108 * 109 * On [Build.VERSION_CODES.Q] and older, a [UiContext] is either an [Activity] or an 110 * [InputMethodService]. On [Build.VERSION_CODES.R] and newer, a [UiContext] can also be one 111 * created via the [Context.createWindowContext] APIs. 112 * 113 * @throws NotImplementedError if not implemented. The default implementation from [getOrCreate] 114 * is guaranteed to implement this method. 115 * @see [computeMaximumWindowMetrics] 116 */ 117 fun computeMaximumWindowMetrics(@UiContext context: Context): WindowMetrics { 118 throw NotImplementedError( 119 "Must override computeMaximumWindowMetrics(context) and" + " provide an implementation." 120 ) 121 } 122 123 companion object { 124 <lambda>null125 private var decorator: (WindowMetricsCalculator) -> WindowMetricsCalculator = { it } 126 private val windowMetricsCalculatorCompat = WindowMetricsCalculatorCompat() 127 128 @JvmStatic getOrCreatenull129 fun getOrCreate(): WindowMetricsCalculator { 130 return decorator(windowMetricsCalculatorCompat) 131 } 132 133 @JvmStatic 134 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) overrideDecoratornull135 fun overrideDecorator(overridingDecorator: WindowMetricsCalculatorDecorator) { 136 decorator = overridingDecorator::decorate 137 } 138 139 @JvmStatic 140 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) resetnull141 fun reset() { 142 decorator = { it } 143 } 144 145 /** 146 * Converts [Android API WindowMetrics][AndroidWindowMetrics] to 147 * [Jetpack version WindowMetrics][WindowMetrics] 148 */ 149 @RequiresApi(Build.VERSION_CODES.R) translateWindowMetricsnull150 internal fun translateWindowMetrics( 151 windowMetrics: AndroidWindowMetrics, 152 density: Float 153 ): WindowMetrics { 154 return WindowMetricsCompatHelper.getInstance() 155 .translateWindowMetrics(windowMetrics, density) 156 } 157 fromDisplayMetricsnull158 internal fun fromDisplayMetrics(displayMetrics: DisplayMetrics): WindowMetrics { 159 return WindowMetrics( 160 Bounds(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels), 161 displayMetrics.density 162 ) 163 } 164 } 165 } 166 167 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 168 interface WindowMetricsCalculatorDecorator { 169 170 /** Returns an instance of [WindowMetricsCalculator] */ decoratenull171 fun decorate(calculator: WindowMetricsCalculator): WindowMetricsCalculator 172 } 173