Android 9 增加了對在設備上實現不同類型的顯示切口的支持。顯示屏切口可讓您創建身臨其境的邊緣到邊緣體驗,同時仍為設備正面的重要傳感器留出空間。
圖 1.頂部中央顯示屏切口
Android 9 支持以下類型的摳圖:
- 頂部中心:頂部邊緣中心的切口
- 頂部不居中:切口可能位於角落或略微偏離中心
- 底部:底部鏤空
- 雙:頂部一個切口,底部一個切口
示例和來源
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 | 定義快速設置面板的上邊距。時鐘和電池顯示在面板上方的空間中。 在 values-land 中,設置為 |
quick_qs_total_height | 展開通知欄時快速設置面板(折疊的快速設置面板)的總高度,包括包含時鐘的面板上方的空間。 由於快速設置的佈局方式,快速快速設置面板的總高度(包括偏移量)必須是靜態已知的,因此該值必須通過相同的 delta |
status_bar_height_portrait | 從框架的角度來看狀態欄的默認高度。 在大多數設備中,這默認為 24dp。當有切口時,將此值設置為切口的高度。如果需要,可以選擇高於切口。 |
status_bar_height_landscape | 橫向狀態欄的高度。切口僅在設備的短邊上受支持,因此這將始終是未更改的狀態欄高度。 在沒有切口的設備中,這相當於 |
config_mainBuiltInDisplayCutout | 定義切口形狀的路徑。這是一個可由 |
config_fillMainBuiltinDisplayCutout | 一個布爾值,用於確定是否在軟件中繪製剪切路徑(如上定義)。可用於模擬切口,或填充物理切口以實現抗鋸齒。 如果為 true, |
有關默認定義,請參閱這些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>
驗證
要驗證您的顯示切口的實現,請在tests/framework/base/windowmanager/src/android/server/wm運行 CTS 測試。
,Android 9 增加了對在設備上實現不同類型的顯示切口的支持。顯示屏切口可讓您創建身臨其境的邊緣到邊緣體驗,同時仍為設備正面的重要傳感器留出空間。
圖 1.頂部中央顯示屏切口
Android 9 支持以下類型的摳圖:
- 頂部中心:頂部邊緣中心的切口
- 頂部不居中:切口可能位於角落或略微偏離中心
- 底部:底部鏤空
- 雙:頂部一個切口,底部一個切口
示例和來源
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 | 定義快速設置面板的上邊距。時鐘和電池顯示在面板上方的空間中。 在 values-land 中,設置為 |
quick_qs_total_height | 展開通知欄時快速設置面板(折疊的快速設置面板)的總高度,包括包含時鐘的面板上方的空間。 由於快速設置的佈局方式,快速快速設置面板的總高度(包括偏移量)必須是靜態已知的,因此該值必須通過相同的 delta |
status_bar_height_portrait | 從框架的角度來看狀態欄的默認高度。 在大多數設備中,這默認為 24dp。當有切口時,將此值設置為切口的高度。如果需要,可以選擇高於切口。 |
status_bar_height_landscape | 橫向狀態欄的高度。切口僅在設備的短邊上受支持,因此這將始終是未更改的狀態欄高度。 在沒有切口的設備中,這相當於 |
config_mainBuiltInDisplayCutout | 定義切口形狀的路徑。這是一個可由 |
config_fillMainBuiltinDisplayCutout | 一個布爾值,用於確定是否在軟件中繪製剪切路徑(如上定義)。可用於模擬切口,或填充物理切口以實現抗鋸齒。 如果為 true, |
有關默認定義,請參閱這些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>
驗證
要驗證您的顯示切口的實現,請在tests/framework/base/windowmanager/src/android/server/wm運行 CTS 測試。