33import android .annotation .TargetApi ;
44import android .app .Activity ;
55import android .content .Context ;
6+ import android .content .res .Configuration ;
67import android .graphics .Insets ;
78import android .graphics .Rect ;
89import android .os .Build ;
910import android .util .DisplayMetrics ;
1011import android .view .Display ;
12+ import android .view .DisplayCutout ;
13+ import android .view .View ;
14+ import android .view .Window ;
1115import android .view .WindowInsets ;
1216import android .view .WindowManager ;
1317import android .view .WindowMetrics ;
1418import androidx .annotation .NonNull ;
1519
1620class UtilsDevice {
21+
22+ static DisplayCutout cutout = null ;
23+
1724 private UtilsDevice () {
1825 }
1926
@@ -25,7 +32,7 @@ static DisplayMetrics getDisplayMetrics(@NonNull final Context context) {
2532 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
2633 applyWindowMetrics (context , wm , metrics );
2734 } else {
28- applyLegacyMetrics (wm , metrics );
35+ applyLegacyMetrics (context , wm , metrics );
2936 }
3037 return metrics ;
3138 }
@@ -84,11 +91,63 @@ private static void applyWindowMetrics(@NonNull Context context,
8491 }
8592 }
8693
94+ /**
95+ * Tries to extract cutout information from the activity for api level 28-29
96+ *
97+ * @param activity Activity to extract cutout from
98+ */
99+ static void getCutout (@ NonNull Activity activity ) {
100+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .P && Build .VERSION .SDK_INT < Build .VERSION_CODES .R ) {
101+ Window window = activity .getWindow ();
102+ if (window == null ) return ;
103+
104+ View decorView = window .getDecorView ();
105+ if (decorView == null ) return ;
106+
107+ decorView .addOnAttachStateChangeListener (new View .OnAttachStateChangeListener () {
108+ @ Override
109+ public void onViewAttachedToWindow (View v ) {
110+ WindowInsets insets = v .getRootWindowInsets ();
111+ if (insets != null ) {
112+ DisplayCutout cutout1 = insets .getDisplayCutout ();
113+ if (cutout1 != null && !cutout1 .getBoundingRects ().isEmpty ()) {
114+ cutout = cutout1 ;
115+ }
116+ }
117+ v .removeOnAttachStateChangeListener (this );
118+ }
119+
120+ @ Override
121+ public void onViewDetachedFromWindow (View v ) {
122+ }
123+ });
124+ }
125+ }
126+
87127 @ SuppressWarnings ("deprecation" )
88- private static void applyLegacyMetrics (@ NonNull WindowManager wm ,
128+ private static void applyLegacyMetrics (@ NonNull Context context ,
129+ @ NonNull WindowManager wm ,
89130 @ NonNull DisplayMetrics outMetrics ) {
90131 final Display display = wm .getDefaultDisplay ();
91132 display .getRealMetrics (outMetrics );
92- //getMetrics gives us size minus navigation bar
133+
134+ if (context instanceof Activity ) {
135+ getCutout ((Activity ) context );
136+ }
137+
138+ boolean isLandscape = context .getResources ().getConfiguration ().orientation
139+ == Configuration .ORIENTATION_LANDSCAPE ;
140+
141+ if (cutout != null && Build .VERSION .SDK_INT >= Build .VERSION_CODES .P ) {
142+ if (isLandscape ) {
143+ // In landscape, top/bottom insets become width, left/right become height
144+ outMetrics .widthPixels -= (cutout .getSafeInsetTop () + cutout .getSafeInsetBottom ());
145+ outMetrics .heightPixels -= (cutout .getSafeInsetLeft () + cutout .getSafeInsetRight ());
146+ } else {
147+ // Portrait
148+ outMetrics .heightPixels -= (cutout .getSafeInsetTop () + cutout .getSafeInsetBottom ());
149+ outMetrics .widthPixels -= (cutout .getSafeInsetLeft () + cutout .getSafeInsetRight ());
150+ }
151+ }
93152 }
94153}
0 commit comments