Skip to content Skip to sidebar Skip to footer

How To Handle Notch(display Cutout) In Android Api Lower Than 28?

Android added notch support on API 28, but how to handle it on devices running API 27 (Honor 10, Huawei P20, etc.) ? I was trying to use DisplayCutoutCompat but I was not able to

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();
}
  1. 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];
    }}
    
  2. 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];
    }}
    
  3. 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];
    }}
    
  4. 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?"