How to handle notch(display cutout) in android API lower than 28?

前端 未结 4 1242
你的背包
你的背包 2020-12-16 14:12

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<

4条回答
  •  臣服心动
    2020-12-16 14:48

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

    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();
    

提交回复
热议问题