如何处理android API低于28的缺口(显示切口)?

bla*_*ade 12 android android-appcompat android-9.0-pie androidx

Android在API 28上增加了缺口支持,但如何在运行API 27的设备上处理它(荣誉10,华为P20等)?

我试图使用,DisplayCutoutCompat但我无法创建它的实例,因为文档没有真正指出如何创建一个.

如何创建构造函数参数值:Rect safeInsets,List<Rect> boundingRects

我也查看了构造函数的源代码,这对我来说有点混乱:

public DisplayCutoutCompat(Rect safeInsets, List<Rect> boundingRects) {
        this(SDK_INT >= 28 ? new DisplayCutout(safeInsets, boundingRects) : null);
    }
Run Code Online (Sandbox Code Playgroud)

这将始终在运行API <28的设备上返回null .先感谢您.

小智 13

Google在Android P. Devices中提供了与缺口相关的API,缺口和API版本低于P实现了自己的缺口API.您可以从设备指定的文档中查询API.

此外,我没有在官方文档中看到DisplayCutoutCompat实例的创建,但您可以创建DisplayCutout,如下所示:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            DisplayCutout displayCutout = getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
}
Run Code Online (Sandbox Code Playgroud)


KAl*_*lO2 5

所以你想在低于 28 的 android API 中处理缺口(显示切口)。这太可怕了,因为不同的制造商有不同的实现。尽管如此,都使用Java反射来获取缺口信息。这里应该使用工厂设计模式

interface ICutout {
    public boolean hasCutout();

    public Rect[] getCutout();
}
Run Code Online (Sandbox Code Playgroud)
  1. 华为显示屏开孔

    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];
    }}
    
    Run Code Online (Sandbox Code Playgroud)
  2. Oppo显示屏镂空

    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 = 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];
    }}
    
    Run Code Online (Sandbox Code Playgroud)
  3. Vivo显示屏镂空

    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];
    }}
    
    Run Code Online (Sandbox Code Playgroud)
  4. 小米显示切口的Android奥利奥的Android的馅饼的

    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 = 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];
    }}
    
    Run Code Online (Sandbox Code Playgroud)

如果某些制造商没有提供 getNotchHeight() 方法,您可以只使用状态栏的高度。Android 保证缺口高度最多为状态栏高度。

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;
}
Run Code Online (Sandbox Code Playgroud)

对于 Android Pie 及以上 ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.P),您可以使用系统的 API 来获取缺口信息。请注意,必须附加窗口,Activity#onAttachedToWindow否则您将获得空 DisplayCutout。

DisplayCutout displayCutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout();
Run Code Online (Sandbox Code Playgroud)