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.
interface ICutout {
public boolean hasCutout();
public Rect[] getCutout();
}
Huawei display cutout
private static class HuaweiCutout implements ICutout {
private Context context;
public HuaweiCutout(@NonNull Context context) {
this.context = context;
}
@Override
public boolean hasCutout() {
try {
ClassLoader classLoader = context.getClassLoader();
Class class_HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method method_hasNotchInScreen = class_HwNotchSizeUtil.getMethod("hasNotchInScreen");
return (boolean) method_hasNotchInScreen.invoke(class_HwNotchSizeUtil);
} catch (Exception e) {
}
return false;
}
@Override
public Rect[] getCutout() {
try {
ClassLoader classLoader = context.getClassLoader();
Class class_HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method method_getNotchSize = class_HwNotchSizeUtil.getMethod("getNotchSize");
int[] size = (int[]) method_getNotchSize.invoke(class_HwNotchSizeUtil);
int notchWidth = size[0];
int notchHeight = size[1];
int screenWidth = DeviceUtil.getScreenWidth(context);
int x = (screenWidth - notchWidth) >> 1;
int y = 0;
Rect rect = new Rect(x, y, x + notchWidth, y + notchHeight);
return new Rect[] {rect};
} catch (Exception e) {
}
return new Rect[0];
}}
Oppo display cutout
private static class OppoCutout implements ICutout {
private Context context;
public OppoCutout(@NonNull Context context) {
this.context = context;
}
@Override
public boolean hasCutout() {
String CutoutFeature = "com.oppo.feature.screen.heteromorphism";
return context.getPackageManager().hasSystemFeature(CutoutFeature);
}
@Override
public Rect[] getCutout() {
String value = SystemProperties.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 = new Rect();
rect.left = values[0];
rect.top = values[1];
rect.right = values[2];
rect.bottom = values[3];
return new Rect[] {rect};
}
return new Rect[0];
}}
Vivo display cutout
private static class VivoCutout implements ICutout {
private Context context;
public VivoCutout(@NonNull Context context) {
this.context = context;
}
@Override
public boolean hasCutout() {
try {
ClassLoader clazz = context.getClassLoader();
Class ftFeature = clazz.loadClass("android.util.FtFeature");
Method[] methods = ftFeature.getDeclaredMethods();
for(Method method: methods) {
if (method.getName().equalsIgnoreCase("isFeatureSupport")) {
int NOTCH_IN_SCREEN = 0x00000020; // 表示是否有凹槽
int ROUNDED_IN_SCREEN = 0x00000008; // 表示是否有圆角
return (boolean) method.invoke(ftFeature, NOTCH_IN_SCREEN);
}
}
} catch (Exception e) {
}
return false;
}
@Override
public Rect[] getCutout() {
// throw new RuntimeException(); // not implemented yet.
return new Rect[0];
}}
Xiaomi display cutout of Android Oreo, of Android Pie
private static class XiaomiCutout implements ICutout {
private Context context;
public XiaomiCutout(@NonNull Context context) {
this.context = context;
}
@Override
public boolean hasCutout() {
// `getprop ro.miui.notch` output 1 if it's a notch screen.
String text = SystemProperties.getProperty("ro.miui.notch");
return text.equals("1");
}
@Override
public Rect[] getCutout() {
Resources res = context.getResources();
int widthResId = res.getIdentifier("notch_width", "dimen", "android");
int heightResId = res.getIdentifier("notch_height", "dimen", "android");
if(widthResId > 0 && heightResId > 0) {
int notchWidth = res.getDimensionPixelSize(widthResId);
int notchHeight = res.getDimensionPixelSize(heightResId);
// one notch in screen top
int screenWidth = DeviceUtil.getScreenSize(context).getWidth();
int left = (screenWidth - notchWidth) >> 1;
int right = left + notchWidth;
int top = 0;
int bottom = notchHeight;
Rect rect = new Rect(left, top, right, bottom);
return new Rect[] {rect};
}
return new Rect[0];
}}
For SystemProperties class, you can read this thread, actually it calls adb shell getprop <property_name>
.
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.
public static int getStatusBarHeight(Context context) {
int statusBarHeight = 0;
Resources res = context.getResources();
int resourceId = 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.
DisplayCutout displayCutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();