三星远程开发测试平台

反馈 注册 登录

三星钻孔屏适配指导

1.  前言

 

钻孔屏(Punch Hole),即屏幕内相机开孔技术(Hole In Display),官方称其为“黑瞳全视屏”,相比刘海屏,可以带来保留窄边框的全面屏体验。三星此次突破手机屏幕工艺,将钻孔屏作为Galaxy A8s上“首次采用”的技术,而Galaxy A8s也成为首个采用钻孔屏的机型。

 

在钻孔的区域,要避免布局重要的控件、文本或其他内容,对于安卓P OS,谷歌提供了统一的适配方案(Cutout API);然而由于Galaxy A8s上线版本为安卓O OS,O OS在市场中仍会存在很长一段时间,因此强烈建议并感谢第三方合作伙伴按照下文方式适配三星O OS方案。

 


 

2.  分辨率信息

 

型号

分辨率

屏幕纵横比

Dpi

Galaxy A8s(SM-G8870)

1080*2340

19.5:9

403

 

3.  三星钻孔屏手机安卓O OS适配方法

 

3.1如何识别钻孔屏

 

资源 "config_mainBuiltInDisplayCutout" 中若包含一个有内容的cutout spec,可识别该型号为钻孔屏。

 

try {

    final Resources res = context.getResources();

    final int resId = res.getIdentifier("config_mainBuiltInDisplayCutout", "string", "android");

    final String spec = resId > 0 ? res.getString(resId): null;

    mHasDisplayCutout = spec != null && !TextUtils.isEmpty(spec);

    } catch (Exception e) {

    Log.w(mLogTag, "Can not update hasDisplayCutout. " +

    e.toString());

}

 

3.2如何获取钻孔屏区域

 

DisplayCutout  API

 

List

返回Rects的列表,每个Rects都是屏幕上非功能区域的边界矩形。

int getSafeInsetBottom()

返回安全区域距离屏幕底部的距离,单位是px

int getSafeInsetLeft ()

返回安全区域距离屏幕左边的距离,单位是px

int getSafeInsetRight ()

返回安全区域距离屏幕右边的距离,单位是px

int getSafeInsetTop ()

返回安全区域距离屏幕顶部的距离,单位是px

 

Anroid8.1可以通过代码反射调用DisplayCutout的主要API

1)通过WindowInsets 的 getDisplayCutout 反射调用获得DisplayCutout的实例。

 

(Sample) Reflection 1

Method method = WindowInsets.class.getDeclaredMethod("getDisplayCutout");

Object displayCutoutInstance = method.invoke(windowInsets);

 

2)通过实例做getSafeInsetTop, getSafeInsetBottom, getSafeInsetLeft,getSafeInsetRight, getBoundingRects方法的反射

 

(Sample) Reflection 1

Rect safeInsets = new Rect();

List

Class cls = displayCutoutInstance.getClass();

int top = (int)cls.getDeclaredMethod("getSafeInsetTop").invoke

(displayCutoutInstance);

int bottom = (int)cls.getDeclaredMethod("getSafeInsetBottom").invoke

(displayCutoutInstance);

int left = (int)cls.getDeclaredMethod("getSafeInsetLeft").invoke

(displayCutoutInstance);

int right = (int)cls.getDeclaredMethod("getSafeInsetRight").invoke

(displayCutoutInstance);

safeInsets.set(left, top, right, bottom);

boundingRects.addAll((List

invoke(displayCutoutInstance));

 

以上DisplayCutout是谷歌提供的P OS(Android9.0)对缺口屏的集成解决方案,对P OS以下版本并未提供。 为了便于有更多需求的应用适配,三星将DisplayCutout方案应用到Android 8.1。详细资料可通过5.适配支持提供的联系方式获取。

 

3.3如何获取系统状态栏高度

 

钻孔屏手机中,系统Status Bar完全包含了钻孔区域,因此,可以直接获取状态栏的高度作为非安全区域的高度,在进行页面设计和布局时,确保重要内容(按键、菜单、文本等)不要显示在非安全区域。

 

 

 

3.3.1获取系统状态栏高度接口

 

public int getStatusBarHeight() {
int result = 0;
int resourceId = mApplicationContext.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
  result = mApplicationContext.getResources().getDimensionPixelSize(resourceId);
}
TLog.d(TAG, "statusBarHeight : " + result);
return result;

}

 

3.3.2主要适配问题举例

 

1. 状态栏高度写死问题

 

没有从系统读取状态栏的高度值,而是直接使用固定值来显示高度,造成页面显示异常。

 

 

2.    沉浸式布局遮挡问题

 

页面不显示状态栏,导致重要内容被钻孔遮挡

两种方法:

1)判断是否是钻孔屏,若是,将window更改为非全屏显示界面,即显示状态栏。

2)使用getStatusBarHeight()直接获取状态栏的高度,重要的元素布局在非安全区域外。

 

4.   三星钻孔屏手机安卓P OS适配方法

 

谷歌开放者网站称P OS版本为摄像头和扬声器预留的空间为屏幕缺口或凹口,上文提到的钻孔屏也属于缺口屏的一种,本节统一用缺口描述。以下内容整理自谷歌开发者网站,详情请参看:https://developer.android.com/guide/topics/display-cutout/:

 

1.    一个类

-      Android9支持最新的全面屏,其中包含为摄像头和扬声器预留空间的屏幕缺口(或凹口)。通过DisplayCutout类可确定非功能区域的位置和形状,这些区域不应显示内容。要确定这些屏幕缺口区域是否存在及其位置,请使用getDisplayCutout()函数。

 

2.    三种布局模式

-      全新的窗口布局属性layoutInDisplayCutoutMode,让您的应用可以为设备屏幕缺口周围的内容进行布局。有三种模式可选,您可以将此属性设为下列值之一:

1)     LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT

2)     LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES

3)     LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER

对应的解释为:

1)   仅仅当系统提供的bar完全包含了缺口区时才允许window延伸到缺口区,否则window不会和屏幕缺口区重叠。

//在实际使用中,这意味着如果窗口没有设置FLAG_FULLSCREEN或View.SYSTEM_UI_FLAG_FULLSCREEN(或View.SYSTEM_UI_FLAG_HIDE_NAVIGATION),如果缺口在屏幕顶部(或底部),它可以延伸到竖屏的缺口区域。否则(即全屏或横屏)它不会和缺口区域重叠。

也就是说此模式在全屏下不允许使用缺口区域

2)   允许window延伸到短边的缺口区。

//窗口必须确保没有重要元素和缺口区域重叠。另外,在这种模式下,无论窗口是否隐藏了状态栏,在竖屏和横屏下都可以延伸到缺口区域。

 

 

3)   不允许window延伸到缺口区。

 

3.    新增主要接口介绍

 

3.1 如果有缺口区域返回位置

class WindowInsets  {DisplayCutout getDisplayCutout();}

 

public DisplayCutout getDisplayCutout ()

返回

DisplayCutout

如果有缺口区域返回位置

 

3.2 缺口位置接口

class DisplayCutout {int getSafeInsetLeft();int getSafeInsetTop();int getSafeInsetRight();int getSafeInsetBottom();Region getBounds();}

 

public final class DisplayCutout

方法

List

返回Rects的列表,每个Rects都是屏幕上非功能区域的边界矩形。

int getSafeInsetBottom()

返回安全区域距离屏幕底部的距离,单位是px

int getSafeInsetLeft ()

返回安全区域距离屏幕左边的距离,单位是px

int getSafeInsetRight ()

返回安全区域距离屏幕右边的距离,单位是px

int getSafeInsetTop ()

返回安全区域距离屏幕顶部的距离,单位是px

 

4.    提示

l  内容如果非放在危险区不可,尽量使用SafeInsets

l  如需动态切换fullscreen模式,就用SHORT_EDGES或NEVER模式

l  如果APP没有特别使用P的API:

- Status bar高度 >= 缺口区域高度

- Fullscreen 或 横屏时,必须letterbox

l  避免Status Bar硬代码:


image.png

image.png


l  Windows v.s. Screen 坐标

-当进入letterbox状态时:

(0,0)的screen坐标 != (0,0)的window坐标

     - MotionEvent.getRawX/Y()返回screen坐标

     - 使用getLocationOnScreen()转换到视图的坐标空间

 

5.   适配支持

 

如果您在适配过程中遇到任何技术问题,

可以发邮件至:

huan.ding@samsung.com

jingjing.z@samsung.com

yanyan.he@samsung.com

邮件主题:三星钻孔屏适配+APP名