小米开发平台屏幕指纹设备适配说明

小米开发平台屏幕指纹设备适配说明

1. 什么是屏下指纹

小米 8 透明探索版中,我们引入屏下指纹这项新技术,即指纹传感器嵌入屏幕下。

由于是屏下指纹,所以需要出现指纹图标,提示用户指纹传感器的位置,但这样会和部分需要使用指纹验证的业务产生冲突。

2. 屏下指纹相关接口

由于各个开发者的指纹验证逻辑和 UI 样式非常不一样,所以系统不打算统一大家的样式,而是会提供相关接口,由各业务组做针对性地适配。

2.1. 是否为屏下指纹设备

// true means FOD project
PRODUCT_PROPERTY_OVERRIDES += ro.hardware.fp.fod=true

2.2. 指纹传感器的位置、大小(每次指纹验证都需要重新获取)

以下是 Android O 的接口:

//location of FOD sensor's top left corner in pixel, the top left corner of screen is (0,0)
//persist.sys.fp.fod.location.X_Y 表示sensor区域左上角的坐标,以pixel为单位,以物理屏幕左上角为(0,0)计算。
persist.sys.fp.fod.location.X_Y = 453,1640 //sensor的大小(单位也是pixel) persist.sys.fp.fod.size.width_height = 173,173

以下是 Android P 的接口(应谷歌要求,需要加入「vendor」字样)

//location of FOD sensor's top left corner in pixel, the top left corner of screen is (0,0)
// persist.vendor.sys.fp.fod.location.X_Y 表示sensor区域左上角的坐标,以pixel为单位,以物理屏幕左上角为(0,0)计算。
persist.vendor.sys.fp.fod.location.X_Y = 453,1640

//sensor的大小(单位也是pixel)
persist.vendor.sys.fp.fod.size.width_height = 173,173

因为同一款设备,市场上可能会同时存在 Android O 和 Android P 两个版本,所以开发者需要根据 Android 版本调用不同的接口,以获取正确的位置信息。

2.3. 控制指纹图标显示、消失

调用标准的指纹监听接口即可显示指纹图标。

2.4. 指定指纹图标的颜色(黑色或白色)

由于各个业务组的界面不尽相同,我们会提供一个接口,让业务方指定要用「黑色」还是「白色」的指纹图标。

复用原有 flag 中的「0」「1」标志(原flag标志没有使用),0表示黑色,1表示白色。

mFm.authenticate(null, mCancellationSignal, 0, callback, null); // 黑色指纹图标(默认)
mFm.authenticate(null, mCancellationSignal, 1, callback, null); // 白色指纹图标

3. 屏下指纹适配建议

3.1. UI 避开指纹传感器的位置

业务方可以通过上述接口获取指纹图标的位置和大小,建议控件、键盘等元素都避开那个区域。

3.2. 不建议同时支持密码验证和指纹验证

由于指纹图标会挡住键盘,所以不建议开发者同时支持指纹和密码验证,而是做成互斥的模式,类似微信支付。

3.3. 考虑是否需要调整正确、错误的反馈

如果第三方调用,系统不处理指纹验证正确或错误的反馈,交由开发者自行处理。开发者可以根据自身业务逻辑,考虑是否需要针对屏下指纹调整相关反馈。

4. FAQ

4.1. 有几款机型支持屏下指纹

小米机型中,目前支持屏下指纹的设备为「小米 8 透明探索版」和「小米8 屏幕指纹版」。

4.2. 如何测试

拿到设备后,建议同时测试以下两个版本的效果:

  • MIUI 9 稳定版,即出厂自带的版本,截至2018年底仍会是该机型用户的主要版本。
  • MIUI 10 开发版或稳定版,后续 MIUI 10 将成为 MIUI 系统的主流,又因为 System UI 的代码架构在MIUI 10有较多调整,所以建议同时覆盖测试。

顺便附上ROM下载链接如下:

小米开发平台 刘海屏、水滴屏、挖孔屏 Android P/Q 适配

小米开发平台 刘海屏、水滴屏、挖孔屏 Android P/Q 适配

1. 背景

  • 小米 8 等刘海设备上市时运行的是 Android O 设备,但由于 Android O 没有标准接口,所以当时适配的规则和接口仅在 MIUI 系统生效。关于小米 Android O 的规则,详见https://dev.mi.com/console/doc/detail?pId=1293
  • 后来 Android P 中新增了刘海屏适配的API,为了与行业标准一致,MIUI 也决定在运行 Android P 的设备上完全采用 Android P 的接口。
  • 但由于 Android P 的接口定义得比较晚,导致 MIUI 接口无法与其完全兼容,开发者需要针对 Android P 的小米设备重新适配。

该文档将结合小米的情况给大家简要介绍 Android P 的刘海屏适配规则及 API,更详细的内容可以直接查看官方文档 https://developer.android.com/guide/topics/display-cutout/

2. 部分小米水滴屏/刘海屏/挖孔屏设备信息如下

机型modeldevice分辨率Notch高度Notch宽度DPI
小米8MI 8dipper1080*224889560440
小米8 SEMI 8 SEsirius1080*224485540440
小米8 透明探索版MI 8 Explorer Editionursa1080*224889560440
小米8 屏幕指纹版MI 8 UDequuleus1080*224889560440
小米8 青春版MI8Liteplatina1080*228082296440
小米POCO F1POCO F1beryllium1080*224686588440
红米6 ProRedmi 6 Prosakura1080*228089352440
红米Note 7Redmi Note 7lavender1080*234079116440
小米CC9 ProMi CC9 Protucana1080*2340​71146​​440
Redmi K30​​Redmi K30​phoenix​1080*2400​92179​440

注意事项:

  • 以上设备,由于MIUI调整了 DPI 值,因此DP值与像素值的转换关系是 1dp = 2.75 px ;
  • 用原生api DisplayCutout就可以直接获取​设备屏幕尺寸和异形的位置大小等信息,以上仅做参考,之后新机将不再罗列。​

3. 概念说明

为了方便讨论,我们明确下以下概念:

上述两种屏幕都可以统称为刘海屏,不过对于右侧较小的刘海,业界一般称为水滴屏或美人尖。为便于说明,后文提到的「刘海屏」「刘海区」都同时指代上图两种屏幕。

4. Android P/Q 刘海屏水滴屏挖孔屏的适配规则 

Android P 提供了 3 种显示模式供开发者选择,分别是:

  • 默认模式(LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT)
  • 刘海区绘制模式( LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)
  • 刘海区不绘制模式(LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER)

如果开发者未作任何声明,则会按默认模式处理。以下将具体介绍这三种模式的表现。

4.1. 默认模式(LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT)

为了在不影响操作的情况下,尽可能利用刘海屏的显示区域,有以下表现:

非全屏(normal mode)全屏(fullscreen mode)
竖屏(portrait mode)使用耳朵区禁用耳朵区
横屏(landscape mode)禁用耳朵区禁用耳朵区

注:所谓全屏(fullscreen mode),是指隐藏状态栏(status bar),即通过 SYSTEM_UI_FLAG_FULLSCREEN 实现的效果。

默认模式的截图效果如下:

4.2. 刘海区绘制模式(LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)

如上所述,默认模式下某些场景会禁用耳朵区,那是因为这些场景下,系统无法判断开发者是否会把控件放置在耳朵区,所以只好默认禁用。如果开发者想要在那些场景下使用耳朵区,需要主动声明,即使用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 来主动声明。

由于各个厂商的刘海或者凹口形状、位置不一, 开发者可以通过 WindowInsets.getDisplayCutout()  来获得 DisplayCutout object,里面包含了几个有用的方法:

开发者根据业务内容,自行判断是否需要根据不同的刘海形状做不同的布局调整。以小米8(刘海高度89px)为例,当开发者选用 SHORT_EDGES 模式时,以上接口会返回以下值:

竖屏横屏(刘海在左边)
getBoundingRects()(201, 0 – 879, 90)(0, 201 – 90, 879)
getSafeInsetLeft() 090
getSafeInsetTop()900
getSafeInsetRight() 00
getSafeInsetBottom()00

上述接口的返回值代表:

  • 小米8有一个刘海,竖屏时,这个刘海所在的矩形区域的左上角、右下角的坐标分别为 (201, 0) 和 (879, 90) —— 左上角为 (0, 0) 原点;横屏时,这个刘海所在的矩形区域的左上角、右下角的坐标分别为 (0, 201) 和 (90, 879) —— 左上角为 (0, 0) 原点。
  • 对于小米8,如果开发者需要将内容避开刘海区域,竖屏时就需要从顶部向下偏移 90 px,左、右和下无需要偏移。

又以红米Note 7(水滴屏设备) 为例,当开发者选用 SHORT_EDGES 模式时,以上接口会返回以下值:

竖屏横屏(水滴在左边)
getBoundingRects()(450, 0 – 630, 80)(0, 450 – 80, 630)
getSafeInsetLeft() 080
getSafeInsetTop()800
getSafeInsetRight() 00
getSafeInsetBottom()00

上述接口的返回值代表:红米Note 7 有一个刘海(水滴),竖屏时,这个刘海所在的矩形区域的左上角、右下角的坐标分别为 (450, 0) 和 (630, 80) ;横屏时,这个刘海所在的矩形区域的左上角、右下角的坐标分别为 (0, 450) 和 (80, 630) 。

又以Redmi K30 (挖孔屏设备)为例子,当开发者选用 SHORT_EDGES 模式时,以上接口会返回以下值:

 竖屏横屏(摄像头在左边)
getBoundingRects()(844, 0 – 1080, 95)](0, 0 – 95, 236)
getSafeInsetLeft()095
getSafeInsetTop()950
getSafeInsetRight()00
getSafeInsetBottom()00

上述接口的返回值代表:

Redmi K30有刘海/水滴/挖孔,竖屏是,这个刘海在手机的左上角,右下角的坐标分别为 (844,0)和 (1080, 95);左上角为(0,0);横屏时,这个刘海对应的值为(0,0)和(95,236)。对于Redmi K30,如果开发者需要将内容避开挖孔区域,竖屏就需要从顶部向下偏移95px,左、右和下无需偏移。

4.3. 刘海区不绘制模式(LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER )

开发者选用这个模式后,意味着不绘制内容到耳朵区。如非必需,我们不建议采用这种模式,因为那样会浪费不少屏幕空间,用户体验不佳。

当开发者选用 NEVER 模式时, DisplayCutout object 的以下方法都会返回空值,因为 Google 认为既然开发者不使用耳朵区,就不需要关心刘海的大小了。

竖屏横屏(刘海在左边)
getBoundingRects()nullnull
getSafeInsetLeft() null null
 getSafeInsetTop()nullnull
getSafeInsetRight() nullnull
getSafeInsetBottom()nullnull

5. 其他注意事项

5.1. 避免写死状态栏的值

由于 Notch 设备的状态栏高度与正常机器不一样,因此在需要使用状态栏高度时,不建议写死一个值,而应该改为读取系统的值。

以下是获取当前设备状态栏高度的方法:

int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");

if (resourceId > 0) {

result = context.getResources().getDimensionPixelSize(resourceId);

}

5.2. 处理好同一页面,进入与退出全屏模式(fullscreen mode)的过渡

因为在默认模式 / LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 下,系统针对全屏与非全屏的页面,耳朵区的显示逻辑不一样。如果开发者没有处理好,容易出现页面可用区域跳变的问题。针对这种页面,我们建议开发者主动声明是否使用耳朵区,以避免跳变。

6. 常见问题

6.1. 如何测试

有两种方法:

  • 使用小米设备测试,如小米8系列(含标准版、探索版、屏幕指纹版),然后升级至 Android P 的 MIUI 版本,下载地址为:https://www.miui.com/download-345.html
  • 使用运行原生 Android 9 的设备,然后前往「开发者选项 – 模拟“刘海屏”」,选择任一刘海选项。 

若适配中遇到问题,可以发邮件给相关工程师张定昌 zhangdingchang@xiaomi.com、喻伟 yuwei@xiaomi.com 或工程组 miuishell@xiaomi.com。

6.2. 适配过小米 Android O 的刘海屏接口,在小米的 Android P 设备上是否需要重新适配

需要。如文章开头所说,Android P 的接口今年6月才公布,我们在接口设计上和他们有一些出入,所以没法兼容。开发者仍然需要再针对 Android P 做适配,但好消息是,各大手机厂商都支持 Android P 的接口,所以大家只要适配一次就可以了。

6.3. MIUI Android O 的老接口在 Android P/Q设备上是否生效?

P和Q大部份用的是原生Andoid的API,MIUI的接口保留了O里面的Application级别的控制接口

<meta-data
 android:name="notch.config"
 android:value="portrait|landscape"/>

app如果用这个meta-data声明了横竖屏都绘制到耳朵区,相当于每个页面都设成了LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES模式。这就需要app确认自己的所有页面会不会被遮挡,特别是横屏和全屏页面。如果想单独修改某个页面,可以单独修改该页面Window的layoutInDisplayCutoutMode属性

6.4. 原生 Android P 的规则和 MIUI Android O 的规则有什么区别

双方在默认模式下的表现是完全一致的,区别主要体现在:

  • Android P 能通过 DisplayCutout object 获取刘海 / Notch / Cutout 的具体信息,但 MIUI Android O 只能获取刘海的高宽信息。
  • Android P 不能控制仅竖屏(或横屏)使用耳朵区,但 MIUI Android O 可以分别配置横竖屏对耳朵区的使用策略。