Android P刘海屏系统配置

前言

Android 8.0开始,各大手机厂商就开始提出刘海屏的概念,在2018 google开发者大会上公布的Android P版本,google官方支持了刘海屏,并提供官方API给开发者调用。那么系统开发者如何在自己的Aosp工程中实现刘海屏功能呢?本文将带领各位一同了解一下。

刘海屏

Android 9 新增了对在设备上实现不同类型刘海屏的支持。通过刘海屏,您可以打造沉浸式全面屏体验,同时继续在设备前端为重要传感器留出空间。


顶部中间刘海屏

Android 9 支持以下类型的刘海屏:

  • 顶部中间刘海屏:刘海屏位于顶部边缘的中间位置
  • 顶部非中间刘海屏:刘海屏位于边角处或稍微偏离中心的位置
  • 底部刘海屏:刘海屏位于底部
  • 双刘海屏:一个刘海屏位于顶部,一个位于底部

代码实现

以下窗口管理器代码 (PhoneWindowManager.java )显示了如何在未设置 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS的情况下将显示屏框架嵌入安全区域。

// Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
// the cutout safe zone.
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
    final Rect displayCutoutSafeExceptMaybeBars = mTmpDisplayCutoutSafeExceptMaybeBarsRect;
    displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
    if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
            && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
        // At the top we have the status bar, so apps that are
        // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
        // already expect that there's an inset there and we don't need to exclude
        // the window from that area.
        displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
    }
    if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
            && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
        // Same for the navigation bar.
        switch (mNavigationBarPosition) {
            case NAV_BAR_BOTTOM:
                displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
                break;
            case NAV_BAR_RIGHT:
                displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
                break;
            case NAV_BAR_LEFT:
                displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
                break;
        }
    }
    if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
        // The IME can always extend under the bottom cutout if the navbar is there.
        displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
    }
    // Windows that are attached to a parent and laid out in said parent already avoid
    // the cutout according to that parent and don't need to be further constrained.
    // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
    // They will later be cropped or shifted using the displayFrame in WindowState,
    // which prevents overlap with the DisplayCutout.
    if (!attachedInParent && !floatingInScreenWindow) {
        mTmpRect.set(pf);
        pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
        parentFrameWasClippedByDisplayCutout |= !mTmpRect.equals(pf);
    }
    // Make sure that NO_LIMITS windows clipped to the display don't extend under the
    // cutout.
    df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
}

SystemUI 在刘海屏区域呈现,且需要确定可以绘制的位置。 PhoneStatusBarView.java提供了一个视图示例,它确定了刘海屏的位置、刘海屏大小,以及从导航栏嵌入是否可以避开刘海屏区域。
通过方法 onApplyWindowInsets(),视图可以确定刘海屏的位置,并相应地更新其布局。

@Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        if (updateOrientationAndCutout(mLastOrientation)) {
            updateLayoutForCutout();
            requestLayout();
        }
        return super.onApplyWindowInsets(insets);
    }

这些方法概述了各种类型的刘海屏(即顶部中间刘海屏、顶部非中间刘海屏、底部刘海屏和双刘海屏)在状态栏中的处理方式。

官方要求

要确保刘海屏不会对应用造成负面影响,您必须确保:

  • 在竖屏模式下,状态栏的高度至少与刘海屏的高度持平
  • 在全屏模式和横屏模式下,刘海屏区域必须显示遮幅式黑边

您的设备最多可以在每个短边处(顶部和底部)各设一个刘海屏。

实现

要在设备上实现刘海屏,您必须为系统界面配置以下值。

说明
quick_qs_offset_height 定义“快捷设置”面板的上外边距。时钟和电池图标显示在该面板上方的空间。在 values-land 中,将此值设置为 status_bar_height_landscape,在纵屏模式下,将此值设置为默认值 48dp 或刘海屏高度(以较大者为准)。可以根据需要选择高于刘海屏的高度。
quick_qs_total_height 展开通知栏时,“超快设置”面板(收起的“快捷设置”面板)的总高度(其中包括包含时钟图标的面板上方的空间)。受“快捷设置”面板的布局方式限制,“超快设置”面板(包括偏移量)的总高度必须是静态已知的,因此必须由同一增量 quick_qs_offset_height 调整此值。在 Values-land 中,此值默认为 152dp,在纵屏模式下,此值默认为 176dp。
status_bar_height_portrait 从框架的角度而言,状态栏的默认高度。在大多数设备上,此值默认为 24dp。如果设备上有刘海屏,则将此值设置为刘海屏的高度。可以根据需要选择高于刘海屏的高度。
status_bar_height_landscape 状态栏在横屏模式下的高度。由于仅支持在设备的短边上显示刘海屏,因此此值始终是未经更改的状态栏高度。在没有刘海屏的设备上,此值等同于 status_bar_height_portrait。如果设备上有刘海屏,则将此值保留为默认的状态栏高度。
config_mainBuiltInDisplayCutout 用于定义刘海屏形状的路径。这是一个可由 android.util.PathParser 解析的字符串,并且是向系统定义刘海屏大小和形状的方式。可在路径中指定 @dp 以便模拟针对不同设备的形状。由于实际的刘海屏具有精确的像素尺寸,因此在定义硬件刘海屏的路径时,请勿使用 @dp 指定符。
config_fillMainBuiltinDisplayCutout 一个确定是否在软件中绘制刘海屏路径(在上文中进行了定义)的布尔值。可用于模拟刘海屏,或填充实际刘海屏,以实现抗锯齿。如果为 true,则系统会以黑色填充 config_mainBuiltInDisplayCutout。

有关默认定义,请参阅以下 dimens 文件:

  • core/res/res/values-land/dimens.xml
  • core/res/res/values/dimens.xml
    模拟刘海屏的示例叠加层:


    
    
        M 0,0
        L -48, 0
        L -44.3940446283, 36.0595537175
        C -43.5582133885, 44.4178661152 -39.6, 48.0 -31.2, 48.0
        L 31.2, 48.0
        C 39.6, 48.0 43.5582133885, 44.4178661152 44.3940446283, 36.0595537175
        L 48, 0
        Z
        @dp
    

    
    true

    
    48dp
    28dp
    
    48dp
    
    176dp


验证

要验证刘海屏的实现,请在以下位置运行 CTS 测试:tests/framework/base/windowmanager/src/android/server/wm

参考文章

https://source.android.com/devices/tech/display/display-cutouts

本文已独家授权公众号ApeClub使用,更多好文章,请关注ApeClub。

你可能感兴趣的:(Android P刘海屏系统配置)