小米开发平台刘海屏、水滴屏 Android O 适配

小米开发平台刘海屏、水滴屏 Android O 适配

1. 背景

1.1. 目前已上市的小米 Notch 设备(俗称刘海屏手机)如下,其宽度、高度和形状均略有差异

机型modeldevice分辨率Notch高度Notch宽度DPI
小米8MI 8dipper1080*224889560440
小米8 SEMI 8 SEsirius1080*224485540440
小米8 透明探索版MI 8 Explorer Editionursa1080*224889560440
小米屏幕指纹版MI 8 UDequuleus1080*224889560440
小米青春版MI8Liteplatina1080*228082296440
小米POCO F1POCO F1beryllium1080*224686588440
红米6 ProRedmi 6 Prosakura1080*228089352440

注:以上设备,由于MIUI调整了DPI值,因此DP值与像素值的转换关系是 1dp = 2.75 px 。

1.2. 含 Notch 往往都是全面屏手机,即屏幕比例可能是18:9、18.7:9 等不同的值

全面屏设备的适配建议详见:https://dev.mi.com/console/doc/detail?pId=1160

1.3. Android P 提供了 刘海屏的标准适配接口

MIUI 也将在 Android P 上采用标准接口,因此,下文提及的接口仅用于 Android O 上。关于 Android P 的接口说明,详见https://dev.mi.com/console/doc/detail?pId=1341

1.4. 如下图,为便于说明,我们将顶部区域定义为 Notch 和耳朵区

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

2. 系统级适配规则

Notch 机型在界面上会带来两个问题:

  • 顶部内容会被 Notch 遮挡
  • 如何处理耳朵区的显示区域

为了保证绝大部分应用都能正常显示,同时尽可能利用屏幕的显示区域。MIUI System UI 制定了以下全局规则

  • status bar 略高于 Notch 高度,对于应用来说,相当于一个更高的 status bar。
  • 当应用显示 status bar 时(如微信首页),允许应用使用耳朵区(背后的逻辑是:因为 status bar 区域本身不可交互,且会显示信号、电池等信息,因此我们假定应用不会在该区域放置重要的内容和可交互的控件)。
  • 当应用不显示 status bar 时(如全屏游戏),不允许应用使用耳朵区,系统默认填黑。
  • 横屏时,默认均不允许使用耳朵区,系统默认填黑。
  • 不允许应用180度倒转显示。

注:上述规则的模拟效果对比图,可以参见文末的附录“Notch 屏系统默认规则介绍”。

3. 开发者适配

系统规则只能解决最基础的可用性问题,在系统规则下,开发者仍需要检查以下内容:

  • 检查系统默认规则是否有可用性问题,考虑是否做针对性优化。
  • 检查 status bar 的显示策略。重新考虑是否隐藏 status bar
  • 尽量避免某些页面显示 status bar,某些页面又隐藏,否则会出现页面跳变的情况(应用的可用高度变了)。
  • 检查横屏的情况,确定是否需要利用横屏的Notch,若使用,需兼顾 Notch 出现在左边/右边的情况。
  • 检查是否写死了状态栏的高度值。Notch机器状态栏的值是变化的,建议改为读取系统的值(后有相关方法说明)。
  • 检查开启「隐藏屏幕刘海」后,应用是否显示异常(详见后文)。
  • 检查普通屏幕的显示,保证应用在普通屏幕和 Notch 屏幕下都能正常显示 。

4. 系统接口说明

若开发者对系统规则下的效果不满意,可以调用以下接口,做针对性的优化。

4.1. 如何判断设备为 Notch 机型

系统增加了 property ro.miui.notch,值为1时则是 Notch 屏手机。

SystemProperties.getInt("ro.miui.notch", 0) == 1;

4.2. 如何获取 Notch / 凹口 / 刘海 的高度和宽度(截至2018.6.26)

MIUI 10 新增了获取刘海宽和高的方法,需升级至8.6.26开发版及以上版本。

以下是获取当前设备刘海高度的方法:

int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}

以下是获取当前设备刘海宽度的方法:


int
resourceId = context.getResources().getIdentifier("notch_width", "dimen", "android"); if (resourceId > 0) { result = context.getResources().getDimensionPixelSize(resourceId); }

4.3. Application 级别的控制接口

如果开发者认为应用的所有页面统一处理就行,可以使用该接口。在 Application 下增加一个 meta-data,用以声明该应用是否使用耳朵区。示例如下:

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

其中,value 的取值可以是以下4种:

"none" 横竖屏都不绘制耳朵区

"portrait" 竖屏绘制到耳朵区

"landscape" 横屏绘制到耳朵区

"portrait|landscape" 横竖屏都绘制到耳朵区

注:一旦开发者声明了meta-data,系统就会优先遵从开发者的声明。

4.4. Window 级别的控制接口

如果开发者希望对特定 Window 作处理,可以使用该接口。 在 WindowManager.LayoutParams 增加 extraFlags 成员变量,用以声明该 window 是否使用耳朵区。

其中,extraFlags 有以下变量:

0x00000100 开启配置
0x00000200 竖屏配置
0x00000400 横屏配置

组合后表示 Window 的配置,如:

0x00000100 | 0x00000200 竖屏绘制到耳朵区
0x00000100 | 0x00000400 横屏绘制到耳朵区
0x00000100 | 0x00000200 | 0x00000400 横竖屏都绘制到耳朵区

控制 extraFlags 时注意只控制这几位,不要影响其他位。可以用 Window 的 addExtraFlags 和 clearExtraFlags 来修改, 这两个方法是 MIUI 增加的方法,需要反射调用。

int flag = 0x00000100 | 0x00000200 | 0x00000400;
try {
    Method method = Window.class.getMethod("addExtraFlags",
            int.class);
    method.invoke(getWindow(), flag);
} catch (Exception e) {
    Log.i(TAG, "addExtraFlags not found.");
}

4.5. 状态栏高度获取方法

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

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

int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}

4.6. 如何测试和联系我们

使用 小米 8 等任意有刘海的小米设备,升级到  MIUI 10 最新开发版即可(若开发版为Android P,请参见 Android P 的刘海适配文档),支持的机型和下载链接如下(找到对应机型的最新开发版):

4.7. 如何联系我们

可以邮件给我们的项目组 miuishell@xiaomi.com,会有同事解答相关疑问。

5. “隐藏屏幕刘海”适配

MIUI 针对 Notch 设备,有一个“隐藏屏幕刘海”的设置项(设置-全面屏-隐藏屏幕刘海),具体表现是:系统会强制盖黑状态栏(无视应用的Notch使用声明),视觉上达到隐藏刘海的效果。但会给某些应用带来适配问题(控件/内容遮挡或过于靠边等)。

因此开发者在适配时,还需要检查开启“隐藏屏幕刘海”后,应用的页面是否显示正常。针对有问题的页面,我们建议:

  • 通过以下方法获取系统状态栏高度,然后据此调整布局,而不是写死布局:
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
	result = context.getResources().getDimensionPixelSize(resourceId);
}
  • 如有需要,可以通过查询以下 Global settings 来确定「隐藏屏幕刘海」是否开启了,然后再作针对性优化。
Settings.Global.getInt(mContext.getContentResolver(), "force_black", 0) == 1

6. 关于 Android P 的适配

由于 Android P 已针对异形屏幕提供了标准的接口,因此 MIUI 在后续升级到 Android P 时,将会完全复用 Android P 的接口和逻辑。不过仍有几点值得注意:

  • 由于 MIUI Android O 的接口能力与 Android P 有差异,无法二者完全兼容。所以上述提到的接口,在升级到 Android P 后将不再生效,开发者需要针对 Android P 重新适配,望各位开发者谅解。
  • 同时,由于运行 MIUI Android O 的刘海屏设备还会存在好几年,开发者在代码上,仍需要保留对 MIUI Android O 的适配逻辑。

由于 Android P 的接口公布得较晚,我们没法做到和 Android P 完全兼容。给各位开发者造成不便,再次表示歉意。小米刘海屏 Android P 的适配文档详见 https://dev.mi.com/console/doc/detail?pId=1341。 

7. 附录 – 系统默认规则的说明

如果开发者未做任何声明,系统也会有一套默认的显示规则,下图说的就是这套规则,增加示意图方便大家理解。

小米开发平台 刘海屏、水滴屏、挖孔屏 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 可以分别配置横竖屏对耳朵区的使用策略。 

小米开发平台亮度适配说明

小米开发平台亮度适配说明

1.  前言

为了使亮度调节更加细腻, MIUI对原生亮度级别进行了扩展, 由原有的255级调整根据不同屏幕分别支持255/1023/2047/4095级。开发者在进行亮度调整时需要先去确认机型亮度的最大值和最小值,然后进行比例调整。

2.  机型最大和最小亮度确认方法

基于Android P以上的MIUI亮度级别支持超过255, 可通过如下方式确认最大值和最小值:

        public int getMaximumScreenBrightnessSetting() {

            return mContext.getResources().getInteger(mContext.getResources()

                    .getIdentifier(“config_screenBrightnessSettingMaximum”, “integer”, “android”));

        }

        public int getMinimumScreenBrightnessSetting() {

            return mContext.getResources().getInteger(mContext.getResources()

                    .getIdentifier(“config_screenBrightnessSettingMinimum”, “integer”, “android”));

        }

小米开发平台大字体适配说明

小米开发平台大字体适配说明

1.背景

目前MIUI中可调节字体大小的有两处:字体大小 、显示大小。

1.1.字体大小

位置:设置-显示-字体大小。

原理:修改FontScale,仅修改字体大小,当字体档位偏大时,可能会造成布局错乱、重叠等问题。

1.2.显示大小

位置:设置-更多设置-无障碍-显示大小。

原理:修改屏幕显示密度DPI,修改DPI后可整体调整显示比例,包括字体大小和图片大小。

2.现存问题

  • 无论是系统App、还是第三方App,对于大字体的适配效果均可以优化以满足特殊人群对大字体的需求;
  • 部分第三方App不随MIUI系统字体大小的变化而变化(或变化后效果欠佳),且部分App自身有大字体调节设置,未做关联融合,用户体验不佳。

3.三方应用适配MIUI大字体优化方案

3.1.字体大小调整说明

字体大小调整FontScale,并且应用对应的UIMode。FontScale和相应的UIMode档位详情如下:

3.1.1.字体大小适配步骤

如果需要特殊适配相应的UIMode,需要添加对应的资源文件夹,详见以下步骤:

  • Step1: 把需要随字体模式改变而变大小的文字大小用sp单位描述;
  • Step2: 把需要随字体模式改变的资源放在XXX-[YYYui]-ZZZ的目录下,例如drawable-largeui-hdpi,YYY的可选集合为{ smallui, mediumui, largeui, hugeui, godzillaui };
  • Step3:如果需要在代码中根据字体模式执行不同的代码,可通过MiuiConfiguration.getScaleMode()获取,并与MiuiConfiguration.UI_MODE_TYPE_SCALE_LARGE等比较即可。

3.1.2.附加说明

  • 不同UIMode下的资源, 是并列关系, 不存在类似 xxhdpi -> xhdpi 的兜底,意思是在xxhdpi没找到资源并不会再去xhdpi中找;
  • 对于不需要特殊适配 “巨无霸” 模式的app, 只要复制 “超大号” 适配的资源到 “巨无霸” 下即可完成适配。

3.2.显示大小调整说明

显示大小调整修改屏幕显示密度DPI,在系统默认DPI的基础上进行放大和缩小,修改显示大小是通过修改设备configuration中的display density 实现的,具体档位说明如下:

用户修改了显示大小,那就是修改了屏幕显示密度DPI参数,此时应用加载的资源目录可能会发生变化,比如由xxhdpi变为xxxhdpi,具体加载哪个目录的资源由当前显示密度决定。

3.3.三方应用监听字体大小档位变化的方法

  • 监听字体大小变化的方法
IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);registerReceiver(mIntentReceiver, filter);
  • 获取当前字体大小档位的方法,通过获取UIMode来获取
static int getCurrentUIModeType() { Configuration config = Resources.getSystem().getConfiguration(); return config.uiMode & Configuration.UI_MODE_TYPE_MASK;}

其中字体大小的小号,标准,中号,大号,超大,巨无霸对应的UIMode值分别是12,1,13 ,14 ,15 ,11

  • 获取当前屏幕显示密度的方法可参考:
static float getCurrentDensityDpi(Context context) {DisplayMetrics metrics = new DisplayMetrics();WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);wm.getDefaultDisplay().getMetrics(metrics);return metrics.densityDpi;}

4.需三方应用支持的具体内容

MIUI大字体的适配,能够照顾到视力有障碍以及老年用户,能够让用户感受到App的用心,提升用户体验;将用户放在首位,建立良好的口碑,让App能够在更广泛的人群中传播,因此在适配过程中,需要三方应用支持下述内容:

  • MIUI修改字体大小的时候修改了FontScale,FontScale的变化针对屏幕上用像素为单位的文本是不起作用的,需要适配的话文本需要使用sp为单位,同时字体变大可能导致布局变化,需要特殊注意;
  • MIUI修改字体大小的同时还修改显示模式(UIMode),需要特殊适配需要添加对应的资源文件夹,具体的UIMode详情和适配步骤详见:3.1字体大小调整说明;
  • MIUI修改了显示大小时是修改了屏幕的DPI值,此时应用加载资源的目录可能会发生变化,具体加载哪个目录由当前的DPI值决定,同时DPI变化会直接导致布局的变化,需要进行一个自查,若出现文字折行、文字和icon重叠等情况,需进行调整适配,有利于用户体验的提升。

5.FAQ

5.1.常见的修改字体大小引起的问题和解决方法

  • 文本内容显示不全, 需要调整布局, 或者调整不同显示密度对应的文本dp和sp值。
  • 图片割裂或显示不全, 原因一般是图片资源和显示密度不匹配, 需要在监听到字体变化后重新加载图片。

5.2.平板应用不需要修改,保持原来的设计

小米开放平台屏幕圆角适配说明

小米开放平台屏幕圆角适配说明

1.背景

目前大部分小米手机的屏幕都是圆角,如下示意图所示。四个黑色角表示屏幕缺失部分。

2.参数说明

MIUI提供以下两个值分别表示屏幕上下方圆角的半径:

  • rounded_corner_radius_top 
  • rounded_corner_radius_bottom

3.使用方法

例如需要取得rounded_corner_radius_top的值,可以参考如下代码:

public static int getCornerRadiusTop(Context context) {
         int radius = 0;
         int resourceId = context.getResources().getIdentifier("rounded_corner_radius_top", "dimen", "android");
         if (resourceId > 0) {
              radius = context.getResources().getDimensionPixelSize(resourceId);
       
         return radius;
}

小米开发平台全面屏及虚拟键适配说明

小米开发平台全面屏及虚拟键适配说明

1. 前言

自2016年小米 Mix 全面屏手机推出时,得到了业界和用户的双重认可,小米也引领了“全面屏”手机的风潮。作为全面屏手机的引领者,小米将推出更多的全面屏手机,追求更大的屏幕比例,更高的屏占比。

这些变化也影响了手机软件的设计,最值得开发者关注的,是以下两点:

  • 更大的屏幕高宽比
  • 虚拟导航键

2. 更大的屏幕高宽比

大部分全面屏设备都是18:9,从下图可以看到,在 1080P 的分辨率下,比标准的 16:9 屏幕,足足多了240像素。开发者需要作一些优化,以充分利用更大的显示空间。

2.1. 声明 Maximum Aspect Ratio

Android 标准接口中,支持应用声明其支持的最大屏幕高宽比(maximum aspect ratio)。具体声明如下,其中的 ratio_float 被定义为是高除以宽,以 16:9 为例,ratio_float = 16/9 = 1.778 (18:9则为2.0)。

<application>
    <meta-data android:name="android.max_aspect" android:value="ratio_float" />
</application>

若开发者没有声明该属性,ratio_float 的默认值为1.86,小于2.0,因此这类应用在全面屏手机上,默认不会全屏显示,屏幕底部会留黑。考虑到将有更多 19.5:9 甚至更长的手机出现,建议开发者声明 Maximum Aspect Ratio ≥ 2.2 或更多。值得一提的是,如果应用的 android:resizeableActivity 已经设置为 true,就不必设置 Maximum Aspect Ratio 了。详见 Android 官方文档 Declaring maximum aspect ratio

2.2. 避免内容拉伸/变形

从16:9变成18:9甚至更长的比例,图片往往被会拉伸变形,此问题常见于应用开屏图。开发者应使用更灵活的布局,以适应不同的屏幕比例。

2.3. 充分利用屏幕空间

开发者应充分利用全面屏显示更多内容。如下图,王者荣耀已修改了 Maximum Aspect Ratio,在全面屏有更宽阔的游戏视野。

3. 虚拟导航键(Navigation bar)优化

3.1. 虚拟导航键样式

为了实现更高的屏占比,屏幕内的虚拟导航键就成了标准功能,如何让其应用界面在视觉上统一,同样需要开发者的积极适配。Android 已经有相关接口允许开发者自定义虚拟键的样式,以下是可供选择的样式。

关于使用哪种样式,我们有以下建议:

建议1:如果页面含有复杂背景/纹理,建议设置为透明,如下图中的桌面和通话界面。

建议2:含「底部Tab」的页面,建议将虚拟键设置为「底部Tab」的颜色,如 MIUI 的相机和小米商城。

建议3:不含「底部Tab」的页面,建议使用背景颜色,如多看阅读。

由于一个应用内含有多种不同的页面,我们希望开发者能当前页面的情况,来选择合适的虚拟键样式,以保证视觉的统一美观。

3.2. 如何修改虚拟键样式

Android 有标准的实现方式, 调用以下接口即可 window.setNavigationBarColor (int color)。在调用该接口时,还需要设置一些flag,详见该接口的注释说明(即下文):

/**
 * Sets the color of the navigation bar to {@param color}.
 *
 * For this to take effect,
 * the window must be drawing the system bar backgrounds with
 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION} must not be set.
 *
 * If {@param color} is not opaque, consider setting
 * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
 * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
 * <p>
 * The transitionName for the view background will be "android:navigation:background".
 * </p>
 */
public abstract void setNavigationBarColor(@ColorInt int color);​

4. FAQ

4.1. 这些改动是仅针对 MIUI 系统吗

不是。上述提及的均是 Android 标准接口,且早在几年前就已经存在。因此开发者的任何改动,可以在其余 Android 手机中直接生效。我们相信全面屏会是往后手机设计的趋势,做好相关的适配工作,对于开发者来说是非常值得的。

4.2. 如何测试

目前市面上的小米新机均为全面屏手机,测试方法如下:

  • 升级至 MIUI 9.5 及以上版本
  • 前往「设置 > 全面屏 > 应用全屏运行设置」,找到相关应用,然后打开开关,就可以在全面屏比例下运行应用,以观察应用的表现。

有任何问题可以邮件给我们的项目组 miuishell@xiaomi.com ,会有同事解答相关疑问。

小米开发平台剪切板隐私保护功能说明及读写剪切板权限调整说明

小米开发平台剪切板隐私保护功能说明及读写剪切板权限调整说明

1.应用口令规则告知

您的应用若存在通过读取剪切板内容识别并弹出口令的交互逻辑(例如:淘宝读取淘口令),请告知我们您的应用读取的口令规则。

您可将:

  • 开发者名称
  • 应用名称
  • 包名
  • 口令规则(正则patten字符)
  • 口令的使用说明

发送至邮箱miui-security-open@xiaomi.com

我们将在系统中维护您的应用口令,以帮助您的应用能够正确读取剪切板中的必要信息。(注意:我们仅接受在小米应用商店已上架的应用的相关申请)。

2.剪切板权限调整说明

  • 原读写剪切板权限拆分为“读取剪切板”和“写入剪切板”,给予用户更加灵活的隐私权限管控方式;
  • “读取剪切板”权限将默认设置为“智能允许”;“写入剪切板”权限将默认设置为“仅在使用中允许”;
  • 当应用读取剪切板时,若剪切板中的最新内容符合应用读取规则(例如:淘宝读取剪切板中的淘口令),将智能允许应用读取剪切板;智能允许时,将在屏幕顶部通过提示气泡的方式告知用户(用户可见内容为:已智能允许某某应用读取剪切板);
  • 当应用读取剪切板时,若剪切板中的最新内容不符合应用读取规则,且剪切板中的内容符合其他应用读取规则(例如:非淘宝应用读取剪切板中的淘口令),将智能拒绝应用读取剪切板,且用户无感知;
  • 当应用读取剪切板时,若该应用存在读取规则但剪切板最新内容不符合应用读取规则(例如:淘宝读取剪切板中的一段任意文字),将智能拒绝应用读取剪切板,且用户无感知;
  • 当应用读取剪切板时,若剪切板中的最新内容不符合任何应用读取规则且应用不存在读取规则(例如:某地图应用读取剪切板中的一段任意文字),将智能拒绝应用读取剪切板,并弹出通知、气泡告知用户,用户有权利关闭提示。

3.FAQ

3.1.此功能适配哪些Android版本

此功能适配Android的版本:Android 10、 Android 11。

3.2.开发者在哪个MIUI版本可以体验测试

三方开发者可安装MIUI 12开发版20.11.16之后的版本调试。

3.3.智能拒绝的逻辑是否会影响用户主动粘贴剪切板中的内容

不会,只要用户不手动将应用读取剪切板的权限状态手动调整为“拒绝”,用户都可正常手动长按粘贴。此次剪切板隐私保护的功能仅针对应用主动请求读取剪切板的情况。

3.4.读取剪切板权限是否可以使用权限弹窗引导用户授权

读取剪切板权限目前未支持权限询问弹窗,所有应用默认权限状态为“智能允许”。

后台发送本地通知权限管理说明

1.介绍 

安卓系统中,三方应用位于后台运行时会发送大量通知,意图召回用户,严重影响用户体验。该权限可以控制应用在后台运行时发送本地通知的能力。

2.原则

该权限默认拒绝,即应用位于后台时默认不允许发送本地通知。针对特殊应用会提供白名单,例如音乐播放、日程提醒等。白名单应用一旦使用本地通知发送普通消息,或是出现其他有损用户体验等行为时,将永久取消白名单。普通消息定义请参考:https://dev.mi.com/console/doc/detail?pId=2086

3.建议

开发者可以接入小米推送,使用push消息触达并服务用户,相关接入流程请参考:https://dev.mi.com/console/doc/detail?pId=230

小米开发平台后台弹出页面权限管理说明

小米开发平台后台弹出页面权限管理说明

1. 介绍 

安卓系统中,由于三方应用可以随意从后台弹出页面,严重影响用户体验,该权限可以控制应用是否可以在后台启动页面。

2. 原则

该权限默认为拒绝的,既为应用默认不允许在后台弹出页面,针对特殊应用会提供白名单,例如音乐(歌词显示)、运动、VOIP(来电)等;

白名单应用一旦出现推广等恶意行为,将永久取消白名单。

小米开发平台自启动权限管理说明

小米开发平台自启动权限管理说明

1. 介绍

自启动是指手机开机后,应用会未经用户允许自动启用。

在用户手机使用过程中,当自启动应用过多时,会造成手机耗电加快,内存占用过高等情况,造成用户使用体验下降。

2. 原则

为防止应用自启动数量过多,占用用户手机内存,造成用户手机耗电加快等现象发生,手机将默认应用不可自启动,且应用自启动功能需告知用户。如有需要,用户可以自行设置应用允许应用自启动。

小米手机锁屏显示权限管理说明

小米手机锁屏显示权限管理说明

1. 介绍 

安卓系统中,由于三方应用在锁屏上推广告,严重影响用户体验,该权限可以控制应用是否可以在锁屏上显示界面。

2. 原则

该权限默认为拒绝的,既为应用默认不允许在锁屏上显示界面,针对特殊应用会提供白名单,音乐(歌词显示)、运动、VOIP(来电), 白名单应用一旦出现推广等恶意行为,将永久取消白名单。

小米手机无障碍权限管理说明

小米手机无障碍权限管理说明

1. 介绍 

无障碍服务(Accessibility Service)又称为辅助功能服务,出发点是让应用通过该接口给残障人士提供便捷的服务。但近年来,辅助功能服务愈发有被滥用的趋势,部分应用利用这些服务和API创建各种“自动化机制”强化功能。

2017年11月,谷歌邮件已通知所有应用开发者:除非开发者能明确澄清App通过使用辅助功能服务是用来帮助残障人士更好的使用安卓设备和应用。否则将拒绝其使用该服务接口的请求,并将其应用程序从Play商店中移除。

2. 原则 

  • 无障碍服务仅用于帮助残障人士更好的使用手机、应用的便捷服务,禁止应用滥用无障碍服务服务接口、提供无障碍功能之外的其他功能及服务,包括但不限于自动安装、自动下载、批量操作等。
  • 对于引导或提供非正常使用无障碍服务的应用,按标准执行系统管控策略。包括但不限于:在系统内强提醒用户进行关闭处理、禁止应用获取相关服务或权限接口。
  • 对于引导或提供通过无障碍服务权限,对用户的数据、设备使用安全可能产生危害的应用,将严格执行:将该应用在小米应用商店进行下架处理、禁止应用获取相关服务接口 、禁止相关应用在无障碍服务列表中显示。

小米手机设备管理器权限管理说明

小米手机设备管理器权限管理说明

1. 介绍 

设备管理器权限是Android提供给(企业)设备管理类应用的设备保护功能,对手机设备进行管理和操作的接口权限。

权限接口涉及对用户数据、密码的操作,安全性风险极高。

部分应用滥用权限声明来进行防卸载保护,应用内并无相关功能,当用户开启后就无法卸载。

2. 原则 

  • 设备管理器是提供给设备管理类应用的系统权限接口,禁止应用滥用设备管理器权限提供非设备管理功能外的其他功能及服务,包括但不限于清除用户数据、防卸载等。
  • 对于引导或提供非正常使用设备管理器权限的应用,按标准执行系统管控策略。包括但不限于:在系统内强提醒用户进行关闭处理、禁止应用获取相关服务或权限接口。
  • 对于引导或提供通过设备管理器权限,对用户的数据、设备使用安全可能产生危害的应用,将严格执行:将该应用在小米应用商店进行下架处理、禁止应用获取相关服务接口 、禁止相关应用在设备管理器应用列表中显示。
  • 禁止一揽子权限授权原则,各APP只能在其核心业务功能需要特定权限,且用户不同意授予该权限时,才允许退出应用。否则,非核心功能的权限调用中,应用不得以用户不授权而强制退出应用,相关权限应当为设计时的默计关闭保护状态。

小米手机默认桌面应用管理说明

小米手机默认桌面应用管理说明

1. 介绍 

安卓系统中,由于第三方桌面类的应用不稳定,会带来手机系统卡顿、手机功耗大、偷偷下载应用、恶意扣费等问题,给用户带来了很大的使用困扰。

2. 原则

桌面作为系统常用、基础并承担着入口安全责任的重要应用,为保证系统的稳定、完整、一致性,小米方强制禁止三方应用设为默认桌面,只允许使用系统桌面。

小米关于调整“获取应用列表”权限&新增“调节媒体音量”权限的适配说明

小米关于调整“获取应用列表”权限&新增“调节媒体音量”权限的适配说明

1、获取应用列表权限简介

“获取应用列表”权限是在Android原生 QUERY_ALL_PACKAGES 权限基础上额外的权限管理。

影响 PackageManager#getInstalledPackages和PackageManager#getInstalledApplications 两个接口返回值。

应用没适配的情况下,默认添加权限状是“仅在使用中允许”(应用不声明也会添加),即应用在前台时可以正常获取。也可以按照下面方法适配动态申请。

1.1.适配方法

清单文件声明

<uses-permission android:name="com.android.permission.GET_INSTALLED_APPS"/>

判断MIUI 是否支持动态申请权限

try {
    PermissionInfo permissionInfo =  getApplicationContext().getPackageManager().getPermissionInfo("com.android.permission.GET_INSTALLED_APPS", 0);
    if (permissionInfo != null && permissionInfo.packageName.equals("com.lbe.security.miui")) {//MIUI 系统支持动态申请该权限
        if (ContextCompat.checkSelfPermission(getApplicationContext(), "com.android.permission.GET_INSTALLED_APPS") != PackageManager.PERMISSION_GRANTED) {
            //没有权限,需要申请
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{"com.android.permission.GET_INSTALLED_APPS"}, 999);
        }
    }
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

提示:如果系统侧不支持此权限,应用仍然会保持默认(仅在使用中允许)。

判断权限授予结果(与普通运行时权限没有区别)

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    // do something
}

1.2.特殊说明:

如果不需要系统添加获取应用列表的权限,可以通过下面代码实现(同时,清单文件中不能申请更改权限)

<meta-data
     android:name="do_not_need_get_installed_apps"
     android:value="true"/>

注意:如果声明此meta-data,等于“获取应用列表”权限关闭!

1.3.MIUI生效版本:

MIUI 13

2、调节媒体音量权限说明

为减少部分应用擅自修改媒体音量,而不主动告知用户或获得用户许可的行为,同时尽可能避免对用户带来相应的困扰。现在单独设立“调节媒体音量”的权限,并将默认状态设置为“仅在使用中允许”。同时,“应用行为记录”功能中将会对应用修改媒体音量的行为进行记录,用户可主动调整相关的权限。您的应用如有调节媒体音量的需求,可能受到影响,建议您自行调整相关的产品策略。

MIUI 11及以下版本将不受该调整的影响。

小米开发平台隐身模式三方应用适配文档

小米开发平台隐身模式三方应用适配文档

说明:若不涉及到使用录音、相机、麦克风权限,则可忽略此项适配

1.MIUI「隐身模式」功能

功能效果:

  • 用户开启该模式后,应用将无法使用ACCESS_FINE_LOCATION、CAMERA、RECORD_AUDIO三项权限
  • 应用请求对应权限时,系统会弹出通知告知用户“隐身模式已开启,应用无法xx”,但为避免频繁打扰用户,该通知有弹出策略,所以并不会每次应用使用权限时都弹出,如下图:

2.需适配的场景:

若三方应用在隐私模式开启状态下,因无法使用定位、相机、麦克风而无任何提示,且用户忽略了系统弹出push,可能使用户产生疑惑,认为应用出现问题,影响用户体验

适配方案:

MIUI提供两项属性值以供业务查询当前隐私模式的开启状态,便于在用户开启隐身模式时弹出“因开启隐身模式故无法使用麦克风相机获取定位”解释文案的弹窗

判断隐身模式为开启状态的属性值:

1. public static final String KEY_INVISIBLE_MODE_STATE = “key_invisible_mode_state”;

Settings.Secure.getInt(getContentResolver(), PermTipsUtils.KEY_INVISIBLE_MODE_STATE, 0) == 1;

2. public static final String KEY_INVISIBLE_MODE_PROP = “persist.sys.invisible_mode”;

SystemPropertiesUtils.get(PermTipsUtils.KEY_INVISIBLE_MODE_PROP) 是 “1”

3.功能体验说明:

若想体验该功能,机型和版本要求如下:

机型:小米10、小米9、红米Redmi K40游戏增强版、红米Redmi K30至尊纪念版、红米Redmi 9、MIX FOLD

MIUI版本:21.6.5之后的开发版rom 

小米开放平台MIUI进程管理适配说明

小米开放平台MIUI进程管理适配说明

1. 介绍

应用进程的存活与否常常受到三方开发者的关注。与原生系统不同,MIUI在Android系统的基础之上,开发了一套进程管理模块,便于系统管理运行中的进程。

此文档将会提供进程相关信息,方便开发者适配MIUI进程管理机制、初步自查应用被杀原因、更精确的向我们的三方团队同事反馈应用异常被杀问题

2. 进程管理功能

MIUI的进程管理功能大致分为两类:用户主动触发、用户被动触发

用户主动触发的功能包含:

 名称 触发入口Reason 
 一键清理 最近任务/悬浮球 OneKeyClean
 强力清理 负一屏 ForceClean
 垃圾清理 安全中心  GarbageClean
  锁屏清理 安全中心LockScreenClean
 游戏清理 安全中心 GameClean
 优化清理 安全中心 OptimizationClean
上滑清理 最近任务SwipeUpClean 

如果发现应用因为以上原因被杀死,那么意味着是用户在触发入口主动杀死这些应用

用户被动触发的功能包含:

 名称 被动触发场景 Reason
 Power异常查杀 应用过度耗电 AutoPowerKill
 Thermal异常查杀 应用使手机发热 AutoThermalKill

如果发现应用因为以上原因被杀死,那么意味着应用出现异常,会影响到系统正常运作,系统将应用清理掉了

3. FAQ

3.1. 我的应用在原生上运行时正常,但在MIUI上频繁被杀,该怎么定位原因

可以在shell中输入命令:

adb logcat -b events | grep am_kill

查看被杀应用的日志,例如:

1494  2963 I am_kill : [0,5253,com.eg.android.AlipayGphone,500,LockScreenClean]

最后一列信息即为被杀的Reason,和上面的表格进行一下对比,即可定位被杀的原因

3.2. 我的应用频繁的被AutoPowerKill/AutoThermalKill杀死,该怎么解决这个问题

当出现应用频繁被被动原因杀时的情况时,开发者首先应该自己检查下自身应用有没有过度耗电、发热的行为

如果确认自身应用质量没有问题,可以打个bugreport并联系我们的三方团队的同事进行反馈,我们内部的对应开发会进行深度分析

3.3. 我的应用被用户主动杀死后,怎么样可以让应用进程自动重新启动呢

开发者可以在用户使用应用时,引导用户在安全中心中打开自启动开关

小米耳返功能SDK适配说明

1、耳返功能sdk简介

小米手机目前高通平台机型上提供K歌低延时耳返功能 ,用户可以在小米手机上体验震撼的K歌效果,诚邀应用开发者适配,感谢支持!

支持耳返功能的设备

itgsa接口小米12S, 小米12S Pro,小米12S Ultra和其他出厂系统为Android 13版本的高通平台机型
小米接口其他高通平台机型

2、sdk接入方法

2.1 权限说明

需要应用权限配置:

android.permission.MODIFY_AUDIO_SETTINGS

android.permission.RECORD_AUDIO

2.2 API使用说明

1)小米12S, 小米12S Pro,小米12S Ultra和其他出厂系统为Android 13版本的高通平台机型获取MediaClient单例,其他高通平台机型获取KaraokeMediaHelper单例

2)isSupported判断应用是否支持KTV功能使用,小米平台通过应用白名单控制是否支持app使用KTV功能。 若app申请支持KTV功能,请联系我们(gengping@xiaomi.com

3)演唱开始,先打开KTV系统,openKTVDevice

4)设置相关配置:

setMixerSoundType 混响音效类型

setEqualizerType EQ音效类型

setPlayFeedbackParam 耳返开关

setMicVolParam 耳返音量大小

5)再开启播放,最后开启录音 【小米仅支持deep buffer播放方式的KTV效果】

6)演唱结束,先关闭播放、录音

7)再closeKTVDevice 关闭KTV系统

2.3 接口函数列表

  • itgsa结构机型

小米12S、小米12S Pro、小米12S Ultra和其他出厂系统为Android 13版本的高通平台机型

详情请参考 DEMO

接入实例参考 com.example.mediademo

函数名称功能简介
initialize初始化并获取KTV MediaClient单例。
getVersion获取KTV SDK库版本号。
isDeviceSupportKaraoke判断当前机器设备能否支持KTV。
isAppSupportKaraoke应用是否支持KTV。【oppo、vivo返回默认值true,小米手机检测】补充说明:小米平台通过应用白名单控制是否支持app使用KTV功能。 若app申请支持KTV功能,请联系我们(gengping@xiaomi.com),邮件说明应用包名和应用功能简介。
isSupported应用是否支持KTV功能使用,注意此为前三个接口组合判断结果,通常来说三方只使用该接口判断是否支持。
getKaraokeSupportParameters应用获取当前机器支持KTV的JSON参数信息,比如应用设置何种参数(AudioTrack的采样率、flag等,AudioRecord的source等),判断是否可以正常使用KTV功能。
openKTVDevice打开KTV设备,此动作必须是刚发生在播放伴奏前。
closeKTVDevice关闭KTV设备。
setPlayFeedbackParam控制耳返开启/关闭接口,系统默认打开,建议无论怎么app调用都打开调用一次,排除其他app不正确调用的干扰。
getPlayFeedbackParam获取当前耳返开关状态。
setMicVolParam设置人声音量大小。
getMicVolParam获取当前人声音量值。
setMixerSoundType设置混响效果。 ( 0:无、1:KTV、2:剧场、3:音乐厅、4:录音棚 )
setEqualizerType设置EQ均衡器音效。 (0:无、1:标准、2:浑厚、3:清脆、4:明亮)
getExtMixerSoundType扩展混响音效。
getExtEqualizerType扩展EQ均衡器音效。
  • 小米结构机型

详情请参考:KaraokeMediaHelper

接入实例参考 com.miui.media.KaraokeMediaHelper

函数名称功能简介
KaraokeMediaHelper初始化KTV工具类
isDeviceSupportKaraoke判断当前机器设备能否支持KTV。
getKaraokeSupportParameters应用获取当前机器支持KTV的JSON参数信息,比如应用设置何种参数(AudioTrack的采样率、flag等,AudioRecord的source等),判断是否可以正常使用KTV功能
isDeviceSupportMixerSound判断当前机器设备能否支持KTV。
openKTVDevice打开KTV设备,此动作必须是刚发生在播放伴奏前 。
closeKTVDevice关闭KTV设备。
isAppSupportKaraoke应用是否支持KTV。【小米手机检测】补充说明:小米平台通过应用白名单控制是否支持app使用KTV功能。 若app申请支持KTV功能,请联系我们(gengping@xiaomi.com),邮件说明应用包名和 0:无、1:KTV、2:剧场应用功能简介。
setMixerSoundType设置混响效果。( 0:无、1:KTV、2:剧场、3:音乐厅)
setPlayFeedbackParam控制耳返开启/关闭接口,系统默认打开,建议无论怎么app调用都打开调用一次,排除其他app不正确调用的干扰。
setMicVolParam设置人声音量大小。
getPlayFeedbackParam获取当前耳返开关状态。
getMicVolParam获取当前人声音量值。
setEqualizerType设置EQ均衡器音效。(0:无、1:标准、2:浑厚)
getExtMixerSoundType扩展混响音效。
getExtEqualizerType扩展EQ均衡器音效。

小米APP相册安全分享适配文档

一、 功能介绍

开启小米相册的安全分享功能后,从相册分享图片会自动抹除位置、手机型号、拍摄参数等信息。

安全分享开关: 相册->右上角菜单->设置->安全分享

二、分享图片路径变化

小米相册中打开安全分享中任意一个开关(默认抹除照片位置、默认抹除照片拍摄信息)后,从相册分享时会将抹除相关信息的照片保存到相册的私有目录,然后通过FileProvider的方式生成content://Uri分享给应用

开启安全分享后分享的照片路径:

storage/emulated/0/Android/data/com.miui.gallery/cache/SecurityShare/XXX.jpg

未开启安全分享功能分享的照片路径:

storage/emulated/0/DCIM/Screenshots/XXX.jpg

三、应用不可以直接访问私有目录

由于从Android11开始,应用的私有目录不能被外部访问,即使获取了“所有文件管理”权限也不行。具体参见https://developer.android.google.cn/about/versions/11/privacy/storage。因此如果在用户打开安全分享的情况下,应用接收到相册传递给应用的URL,获取到绝对路径,再直接通过访问绝对路径的方式来读取照片,会发生读取异常。

例如以下错误

BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.miui.gallery/cache/SecurityShare/1655174005823.jpg: open failed: ENOENT (No such file or directory)

四、适配方式推荐FileProvider

针对开启安全分享的情况下,分享照片到应用,建议应用使用fileprovider(https://developer.android.com/reference/androidx/core/content/FileProvider)的方式访问照片,参考代码如下:

Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();

if (Intent.ACTION_SEND.equals(action) && type != null) {
     if (type.startsWith("image/")) {
         Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
         InputStream is = null;
        try {
            is = getContentResolver().openInputStream(imageUri);
            Bitmap bmp = BitmapFactory.decodeStream(is);
            imageView.setImageBitmap(bmp);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
     }
    } 

小米跑步机传感器数据集成到计步器数据库说明

1.小米跑步机传感器简介

当手机放置在跑步机上时,收集手机中传感器的数据,判断是否在跑步机上运动,若运动一步则跑步机传感器上报一次数据1,不运动则不报。

2.将跑步机数据集成到计步器数据库

2.1.通知系统服务

在注册或者解除注册跑步机传感器的时候通过Binder告知系统服务。 这步骤为必须操作,否则跑步机计步器数据无法同步至系统计步数据库。

代码示例:

public class MainActivity extends AppCompatActivity {

    private SensorManager mSensorManager;
    private Sensor mTreadmillSensor;
    private TreadmillListener mTreadmillListener;
    private static final int TREADMILL_SENSOR = 33171041;
    private static final String SERVICE_NAME = "miui_step_counter_service";
    private Binder mBinder;

    @RequiresApi(api = Build.VERSION_CODES.Q)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mTreadmillSensor = mSensorManager.getDefaultSensor(TREADMILL_SENSOR,true);
        mTreadmillListener = new TreadmillListener();
        //监听跑步机Sensor
        mSensorManager.registerListener(mTreadmillListener,mTreadmillSensor,mSensorManager.SENSOR_DELAY_NORMAL);
        //通知系统服务,注册的时候发送true
        sendMessage(true);
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    public void sendMessage(boolean is){
        //获取系统服务,ServiceManager报错底下有解决方案
        IBinder binder = ServiceManager.getService(SERVICE_NAME);        
        if (mBinder == null) {
            mBinder = new Binder();
        }
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken("miui_step_counter_service");
        data.writeBoolean(is);
        //传过去一个全局Binder(为了感知本类是否被销毁)
        data.writeStrongBinder(mBinder);
        try {
            binder.transact(0,data,reply,0);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private class TreadmillListener implements SensorEventListener{

        @Override
        public void onSensorChanged(SensorEvent sensorEvent) {

        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int i) {

        }
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //解注册的时候,通知系统服务,发送false
        mSensorManager.unregisterListener(mTreadmillListener,mTreadmillSensor);
        sendMessage(false);
    }
}

2.2.ServiceManager拿不到解决方案

在代码中创建一个包名为android.os,类名为ServiceManager的类。

代码示例:

package android.os;

public class ServiceManager {
    private ServiceManager(){}

    public static IBinder getService(String name){
        return null;
    }
}

2.3.说明

目前跑步机计步传感器支持小米12、小米12 Pro、小米12S Pro、小米12S Ultra四款机型,如果您的应用在注册下面这个特定传感器type时返回的sensor对象为空,说明当前机型不支持跑步机计步传感器,应用可通过此sensor对象的返回值来判定该功能是否生效。

  mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mTreadmillSensor = mSensorManager.getDefaultSensor(TREADMILL_SENSOR,true);
        //根据mTreadmillListener是否为空来判定当前手机是否支持跑步机计步的功能
        mTreadmillListener = new TreadmillListener();