How To Handle Notch(display Cutout) In Android Api Lower Than 28?
Solution 1:
Google provided notch related APIs in Android P. Devices with notch and API version lower than P implemented their own notch APIs.You can consult the APIs from device specified documentation.
Also I did not see creation of DisplayCutoutCompat instance in official documentation, but you can create DisplayCutout as follow:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
DisplayCutoutdisplayCutout= getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
}
Solution 2:
So you want to handle notch(display cutout) in android API lower than 28. That's horrible because different manufactures has different implementations. Nevertheless, all use Java reflection to get notch information. Factory design pattern should be used here.
interfaceICutout {
public boolean hasCutout();
public Rect[] getCutout();
}
Huawei display cutout
privatestaticclassHuaweiCutoutimplementsICutout { private Context context; publicHuaweiCutout(@NonNull Context context) { this.context = context; } @OverridepublicbooleanhasCutout() { try { ClassLoaderclassLoader= context.getClassLoader(); Classclass_HwNotchSizeUtil= classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil"); Methodmethod_hasNotchInScreen= class_HwNotchSizeUtil.getMethod("hasNotchInScreen"); return (boolean) method_hasNotchInScreen.invoke(class_HwNotchSizeUtil); } catch (Exception e) { } returnfalse; } @Overridepublic Rect[] getCutout() { try { ClassLoaderclassLoader= context.getClassLoader(); Classclass_HwNotchSizeUtil= classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil"); Methodmethod_getNotchSize= class_HwNotchSizeUtil.getMethod("getNotchSize"); int[] size = (int[]) method_getNotchSize.invoke(class_HwNotchSizeUtil); intnotchWidth= size[0]; intnotchHeight= size[1]; intscreenWidth= DeviceUtil.getScreenWidth(context); intx= (screenWidth - notchWidth) >> 1; inty=0; Rectrect=newRect(x, y, x + notchWidth, y + notchHeight); returnnewRect[] {rect}; } catch (Exception e) { } returnnewRect[0]; }}
Oppo display cutout
privatestaticclassOppoCutoutimplements ICutout { privateContext context; publicOppoCutout(@NonNullContext context) { this.context = context; } @OverridepublicbooleanhasCutout() { StringCutoutFeature = "com.oppo.feature.screen.heteromorphism"; return context.getPackageManager().hasSystemFeature(CutoutFeature); } @OverridepublicRect[] getCutout() { String value = getProperty("ro.oppo.screen.heteromorphism"); String[] texts = value.split("[,:]"); int[] values = new int[texts.length]; try { for(int i = 0; i < texts.length; ++i) values[i] = Integer.parseInt(texts[i]); } catch(NumberFormatException e) { values = null; } if(values != null && values.length == 4) { Rect rect = newRect(); rect.left = values[0]; rect.top = values[1]; rect.right = values[2]; rect.bottom = values[3]; returnnewRect[] {rect}; } returnnewRect[0]; }}
Vivo display cutout
privatestaticclassVivoCutoutimplementsICutout { private Context context; publicVivoCutout(@NonNull Context context) { this.context = context; } @OverridepublicbooleanhasCutout() { try { ClassLoaderclazz= context.getClassLoader(); ClassftFeature= clazz.loadClass("android.util.FtFeature"); Method[] methods = ftFeature.getDeclaredMethods(); for(Method method: methods) { if (method.getName().equalsIgnoreCase("isFeatureSupport")) { intNOTCH_IN_SCREEN=0x00000020; // 表示是否有凹槽intROUNDED_IN_SCREEN=0x00000008; // 表示是否有圆角return (boolean) method.invoke(ftFeature, NOTCH_IN_SCREEN); } } } catch (Exception e) { } returnfalse; } @Overridepublic Rect[] getCutout() { // throw new RuntimeException(); // not implemented yet.returnnewRect[0]; }}
Xiaomi display cutout of Android Oreo, of Android Pie
privatestaticclassXiaomiCutoutimplementsICutout { private Context context; publicXiaomiCutout(@NonNull Context context) { this.context = context; } @OverridepublicbooleanhasCutout() { // `getprop ro.miui.notch` output 1 if it's a notch screen.Stringtext= getProperty("ro.miui.notch"); return text.equals("1"); } @Overridepublic Rect[] getCutout() { Resourcesres= context.getResources(); intwidthResId= res.getIdentifier("notch_width", "dimen", "android"); intheightResId= res.getIdentifier("notch_height", "dimen", "android"); if(widthResId > 0 && heightResId > 0) { intnotchWidth= res.getDimensionPixelSize(widthResId); intnotchHeight= res.getDimensionPixelSize(heightResId); // one notch in screen topintscreenWidth= DeviceUtil.getScreenSize(context).getWidth(); intleft= (screenWidth - notchWidth) >> 1; intright= left + notchWidth; inttop=0; intbottom= notchHeight; Rectrect=newRect(left, top, right, bottom); returnnewRect[] {rect}; } returnnewRect[0]; }}
In case some manufactures' not coming up with a getNotchHeight() method, you can just use the status bar's height. Android has guarantee that notch height is at most the status bar height.
publicstaticintgetStatusBarHeight(Context context) {
intstatusBarHeight=0;
Resourcesres= context.getResources();
intresourceId= res.getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusBarHeight = res.getDimensionPixelSize(resourceId);
}
return statusBarHeight;
}
For Android Pie and above (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
), you can use system's API to get notch information. Note the window must be attachedActivity#onAttachedToWindow
or you will get null DisplayCutout.
DisplayCutoutdisplayCutout= activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
Solution 3:
I had similar issue, and had to use reflection to access what I need. My problem was that I had some calculations depending on screen size and while not accessing the notch space, the calculations were wrong and code didn't work well.
publicstaticfinalStringCLASS_DISPLAY_CUTOUT="android.view.DisplayCutout";
publicstaticfinalStringMETHOD_GET_DISPLAY_CUTOUT="getDisplayCutout";
publicstaticfinalStringFIELD_GET_SAFE_INSET_TOP="getSafeInsetTop";
publicstaticfinalStringFIELD_GET_SAFE_INSET_LEFT="getSafeInsetLeft";
publicstaticfinalStringFIELD_GET_SAFE_INSET_RIGHT="getSafeInsetRight";
publicstaticfinalStringFIELD_GET_SAFE_INSET_BOTTOM="getSafeInsetBottom";
try {
WindowInsetswindowInsets= activity.getWindow().getDecorView().getRootWindowInsets();
if (windowInsets == null) {
return;
}
Methodmethod= WindowInsets.class.getMethod(METHOD_GET_DISPLAY_CUTOUT);
ObjectdisplayCutout= method.invoke(windowInsets);
if (displayCutout == null) {
return;
}
Classclz= Class.forName(CLASS_DISPLAY_CUTOUT);
inttop= (int) clz.getMethod(FIELD_GET_SAFE_INSET_TOP).invoke(displayCutout);
intleft= (int) clz.getMethod(FIELD_GET_SAFE_INSET_LEFT).invoke(displayCutout);
intright= (int) clz.getMethod(FIELD_GET_SAFE_INSET_RIGHT).invoke(displayCutout);
intbottom= (int) clz.getMethod(FIELD_GET_SAFE_INSET_BOTTOM).invoke(displayCutout);
Rectrect=newRect(left, top, right, bottom);
} catch (Exception e) {
Log.e(TAG, "Error when getting display cutout size");
}
Solution 4:
To handle API lower then 28 WindowInsetsCompat can be used. Kotlin example:
WindowInsetsCompat.toWindowInsetsCompat(window.decorView.rootWindowInsets).displayCutout
Post a Comment for "How To Handle Notch(display Cutout) In Android Api Lower Than 28?"