螢幕凹口

Android 9 額外支援實作多種不同的 不同類型的螢幕凹口類型螢幕凹口能讓你 無邊框沉浸式體驗,同時仍能保留重要空間 感應器。

上方中央螢幕凹口

圖 1. 上方中央螢幕凹口

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

這些方法會概述在所有情況下,狀態列中處理凹口的方式 (所有旋轉角度皆為正上方、上方未置中、底部和雙切)。

需求條件

為確保應用程式不會因剪接問題而受到負面影響,請務必確保 顯示:

  • 在直向模式下,狀態列至少會延伸至凹口高度
  • 在全螢幕模式和橫向模式下,凹口區域必須加上黑邊

裝置的每條短邊 (頂部和底部) 最多可以有一個凹口。

詳情請參閱 CDD

實作

如要在裝置上實作螢幕凹口,請設定下列項目 以及系統 UI 的值

說明
quick_qs_offset_height

定義快速設定面板的上邊界。時鐘與電池 會顯示在面板上方的空間

在值土地中,設為 status_bar_height_landscape,而在 直向設為 48dp 的預設值或凹口高度 以較大者為準您可以選擇大於凹口高度,前提是

quick_qs_total_height

快速設定面板的總高度 (已收合的快速設定) 面板), 包含時鐘的面板

由於快速設定的配置方式, 您必須以靜態方式得知快速快速設定面板 (包括偏移) 所以,您必須以相同的差異調整這個值 quick_qs_offset_height。「值界」預設為 152dp 直向則預設為 176dp

status_bar_height_portrait

從架構的角度來看,狀態列的預設高度。

在大多數裝置上,這個值預設為 24dp。如果有凹口,請設定這個 的值設為凹口高度。可以選擇高度大於凹口 可以視需要使用

status_bar_height_landscape

橫向狀態列的高度。只有以下瀏覽器支援去背功能: 裝置的短邊,因此狀態一律是未經變更的狀態 長條高度。

在沒有凹口的裝置上,這等同於 status_bar_height_portrait。如果有凹口,請保留 套用該值的預設狀態列高度

config_mainBuiltInDisplayCutout

定義凹口形狀的路徑。您可以將這個字串 android.util.PathParser,也是圖像大小和形狀的方式 中斷點向系統定義

可以在模擬指定形狀的路徑上指定 @dp 不同的裝置由於實體凹口有確切的像素大小,因此 定義 Pod 的路徑時,請勿使用 @dp 指定碼 硬體凹槽

config_fillMainBuiltinDisplayCutout

決定是否要繪製凹口路徑的布林值 (已定義) 。可模擬凹口或填入 以達到反鋸齒技術

如為 true,config_mainBuiltInDisplayCutout 已填入值 黑色。

如需預設定義,請參閱下列 dimens 檔案:

模擬凹口的重疊範例:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">

    <!-- The bounding path of the cutout region of the main built-in display.
         Must either be empty if there is no cutout region, or a string that is parsable by
         {@link android.util.PathParser}.

         The path is assumed to be specified in display coordinates with pixel units and in
         the display's native orientation, with the origin of the coordinate system at the
         center top of the display.

         To facilitate writing device-independent emulation overlays, the marker `@dp` can be
         appended after the path string to interpret coordinates in dp instead of px units.
         Note that a physical cutout should be configured in pixels for the best results.
         -->
    <string translatable="false" name="config_mainBuiltInDisplayCutout">
        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
    </string>

    <!-- Whether the display cutout region of the main built-in display should be forced to
         black in software (to avoid aliasing or emulate a cutout that is not physically existent).
     -->
    <bool name="config_fillMainBuiltInDisplayCutout">true</bool>

    <!-- Height of the status bar -->
    <dimen name="status_bar_height_portrait">48dp</dimen>
    <dimen name="status_bar_height_landscape">28dp</dimen>
    <!-- Height of area above QQS where battery/time go (equal to status bar height if > 48dp) -->
    <dimen name="quick_qs_offset_height">48dp</dimen>
    <!-- Total height of QQS (quick_qs_offset_height + 128) -->
    <dimen name="quick_qs_total_height">176dp</dimen>

</resources>

驗證

如要驗證螢幕凹口的實作方式,請在以下位置執行 CTS 測試: tests/framework/base/windowmanager/src/android/server/wm