(三十八)Android P Preview Digests

前言:从Android官网上过了一遍Android P preview的相关功能、行为变迁,写个博客记录一下自己感兴趣的修改,我比较感兴趣的是framework和app方面的。


参考/复制:https://developer.android.com/preview/features?hl=zh-cn


1.行为变更

Android P 对 Android 系统进行了多项变更。 其中大部分变更会影响所有应用,而不论应用针对的是何种版本的 Android。 不过,有几项变更仅影响针对 Android P 的应用。 为清楚起见,本页面分为两个部分:针对所有 API 级别的应用和针对 Android P 的应用。

1.1 在 Android P 上运行的所有应用

当应用运行在 Android P 平台上时,这些行为变更将影响所有应用,无论这些应用是针对哪个 API 级别构建。 所有开发者都应查看这些变更,并修改其应用以正确支持这些变更(如果适用)。

1.1.1 后台应用中的输入和数据隐私

Android P 通过限制后台应用访问用户输入和传感器数据的能力增强了隐私性。 如果您的应用在运行 Android P 的设备上在后台运行,系统将对您的应用施加以下限制:

  • 您的应用不能访问麦克风或摄像头。
  • 使用连续报告模式的传感器(例如加速度计和陀螺仪)不会接收事件。
  • 使用发送变化时或一次性报告模式的传感器不会接收事件。

如果您的应用需要在运行 Android P 的设备上检测传感器事件,请使用前台服务。
注:对 SensorManager 的某个实例调用 flush() 的应用不会受此变更影响。


1.1.2 对于非 SDK 接口的限制

Android P 引入了针对非 SDK 接口的使用限制,无论是直接使用还是通过反射或 JNI 间接使用。 无论应用是引用非 SDK 接口还是尝试使用反射或 JNI 获取其句柄,均适用这些限制。 有关此决定的详细信息,请参阅通过减少使用非 SDK 接口提升稳定性。

一般来说,应用应当仅使用 SDK 中正式记录的类。 特别是,这意味着,在您通过反射之类的语义来操作某个类时,不应打算访问 SDK 中未列出的函数或字段。

使用此类函数或字段很可能会破坏您的应用。



1.1.3 屏幕旋转变更

Android O 中的用户可以使用 Quicksettings 图块或 Display 设置在自动屏幕旋转和纵向旋转模式之间切换。 Android P 对纵向旋转模式做出了重大变更。 纵向模式已重命名为旋转锁定,它会在自动屏幕旋转关闭时启用。 自动屏幕旋转模式没有任何变更。

当设备处于旋转锁定模式时,用户可将其屏幕锁定到顶层可见 Activity 所支持的任何旋转。 Activity 不应假定它将始终以纵向呈现。 如果顶层 Activity 可在自动屏幕旋转模式下以多种旋转呈现,则应在旋转锁定模式下提供相同的选项,根据 Activity 的 screenOrientation 设置,允许存在一些例外情况(见下表)。

请求特定屏幕方向(例如,screenOrientation=landscape)的 Activity 会忽略用户锁定首选项,并且行为与 Android O 中的行为相同。

可在 Android 清单中,或以编程方式通过 setRequestedOrientation(),在 Activity 一级设置屏幕方向首选项。

旋转锁定模式通过设置 WindowManager 在处理 Activity 旋转时使用的用户旋转首选项来发挥作用。 用户旋转首选项可能在下列情况下发生变更。 请注意,恢复纵向模式存在偏差:

  • 当用户接受旋转建议时,旋转首选项变为建议方向。
  • 当用户切换到强制纵向应用(包括锁定屏幕或启动器)时,旋转首选项变为纵向。
下表总结了常见屏幕方向的旋转行为:


1.2 针对 Android P 的应用

这些行为变更仅应用于针对 P 平台或更高版本的应用。 针对 Android P 或更高版本进行编译,或将 targetSdkVersion 设为 Android P 或更高版本的应用开发者必须修改其应用以正确支持这些行为(如果适用)。

1.2.1 前台服务

针对 Android P 或更高版本并使用前台服务的应用必须请求 FOREGROUND_SERVICE 权限。 这是普通权限,因此,系统会自动为请求权限的应用授予此权限。

如果针对 Android P 的应用尝试创建一个前台服务且未请求 FOREGROUND_SERVICE,则系统会引发 SecurityException。

1.2.2 设备串行访问限制

Build.SERIAL 字段在 Android 8.0(API 级别 26)中已被弃用。 在 Android P 中,Build.SERIAL 始终设置为 "UNKNOWN"。 此变更旨在保护用户的隐私。

如果您的应用需要访问设备的硬件序列号,您应请求 READ_PHONE_STATE 权限,然后调用 getSerial()。


2 功能和api

Android P 为用户和开发者引入众多新特性和新功能。

2.1 利用 Wi-Fi RTT 进行室内定位

全新 RTT API 支持在应用中进行室内定位。
Android P 添加了对 IEEE 802.11mc Wi-Fi 协议(也称为 Wi-Fi Round-Trip-Time (RTT))的平台支持,从而让您的应用可以利用室内定位功能。

在提供硬件支持的 Android P 设备上,应用可以使用全新的 RTT API 来测量与附近支持 RTT 的 Wi-Fi 接入点 (AP) 的距离。 设备必须已启用定位并开启了 Wi-Fi 扫描(在 Settings > Location 下),同时您的应用必须具有 ACCESS_FINE_LOCATION 权限。 设备不需要连接至 AP 即可使用 RTT。 为保证隐私性,只有手机可以确定与 AP 的距离;AP 不具备该信息。

如果您的设备测量与 3 个或更多 AP 的距离,您可以使用一个多点定位算法来预估与这些测量值最相符的设备位置。 结果通常精准至 1 至 2 米。

通过这种精确性,您可以打造新的体验,例如楼内导航、基于精细位置的服务,如无歧义语音控制(例如,“打开这盏灯”),以及基于位置的信息(如 “此产品是否有特别优惠?”)。


2.2 屏幕缺口支持

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

全新的窗口布局属性 layoutInDisplayCutoutMode 让您的应用可以为设备凹口屏幕周围的内容进行布局。 您可以将此属性设为下列值之一:

  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
  • LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER

您可以按如下方法在任何运行 Android P 的设备或模拟器上模拟屏幕缺口:

  1. 启用开发者选项。
  2. 在 Developer options 屏幕中,向下滚动至 Drawing 部分并选择 Simulate a display with a cutout。
  3. 选择凹口屏幕的大小。

注:我们建议您通过使用运行 Android P 的设备或模拟器测试凹口屏幕周围的内容显示。


2.3 通知

Android P 引入了多个通知增强功能,可供以 Android P 及更高版本作为目标平台的开发者使用。

提升短信体验
从 Android 7.0(API 级别 24)开始,您可以添加一个操作以回复短信或直接从通知中输入其他文本。 Android P 通过下列增强提升了该功能:

  • 支持图像:现在,Android P 可在手机的“短信通知”中显示图像。 您可以使用短信中的 setData() 来显示图像。
  • 简化了针对对话参与者的支持:全新的 Notification.Person 类可用于识别参与对话的人员,包括他们的头像和 URI。 现在,许多其他 API(如 addMessage())均可利用 Person 类,而不是 CharSequence。
  • 将回复另存为草稿:当用户无意中关闭一个短信通知时,您的应用可以检索系统发送的 EXTRA_REMOTE_INPUT_DRAFT。 您可以使用此 extra 预填充应用中的文本字段,以便用户可以完成他们的回复。
  • 确定对话是否为群组对话。您可以使用 setGroupConversation() 以明确确定对话是否为群组对话。
  • 为 Intent 设置语义操作:setSemanticAction() 函数允许您为操作提供语义含义,如标记为已读、删除、回复等。
  • SmartReply:Android P 支持您的短信应用中提供的建议回复。 使用 RemoteInput.setChoices() 为用户提供一组标准回复。


渠道设置、广播和请勿打扰

Android O 引入了通知渠道,从而允许您为要显示的每种通知类型创建可由用户自定义的渠道。

Android P 通过下列变更简化通知渠道设置:

  • 屏蔽渠道组:现在,用户可以针对某个应用在通知设置中屏蔽整个渠道组。 您可以使用 isBlocked() 函数确定何时屏蔽一个渠道组,从而不会向该组中的渠道发送任何通知。此外,您的应用可以使用全新的 getNotificationChannelGroup() 函数查询当前渠道组设置。
  • 全新的广播 Intent 类型:现在,当通知渠道和渠道组的屏蔽状态发生变更时,Android 系统将发送广播 Intent。 拥有已屏蔽的渠道或渠道组的应用可以侦听这些 Intent 并做出相应的回应。 有关这些 Intent 操作和 extra 的更多信息,请参阅 NotificationManager 参考中更新的常量列表。 有关响应广播 Intent 的信息,请参阅广播。
  • 新的“请勿打扰”优先级类别: NotificationManager.Policy 具有两个新的策略常量:PRIORITY_CATEGORY_ALARMS(确定闹铃优先级)和 PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER(确定媒体、系统和游戏声音优先级)。


2.4 JobScheduler 中的数据成本敏感度

Android P 中对 JobScheduler 进行了改进,使其可以更好地为用户处理网络相关的作业,从而与运营商独立提供的网络状态信号相协调。

现在,作业可以声明其预估的数据大小、信号预提取,并指定具体的网络要求,而运营商可以报告网络拥塞或无限流量。 然后,JobScheduler 根据网络状态管理工作。 例如,当网络拥塞时,JobScheduler 可能会延迟较大的网络请求。 如果使用的是无限流量网络,则 JobScheduler 可运行预提取作业以提升用户体验(例如预提取标题)。

添加作业时,确保使用 setEstimatedNetworkBytes()、setIsPrefetch() 和 setRequiredNetwork()(如果适用),以帮助 JobScheduler 正确处理工作。 在执行作业时,请确保使用 JobParameters.getNetwork() 返回的 Network 对象。 否则,您将隐式使用设备的默认网络,其可能不符合您的要求,从而导致意外的流量消耗


2.5 统一的指纹身份验证对话框

在 Android P 中,系统代表应用提供指纹身份验证对话框。 此功能会创建标准化的对话框外观、风格和位置,让用户可以更放心地确信,他们是在根据可信的指纹凭据检查程序验证身份。

如果您的应用使用 FingerprintManager 向用户显示指纹身份验证对话框,请迁移应用的逻辑以改用 FingerprintDialog,后者依赖系统来显示该对话框。 注:在应用中使用 FingerprintDialog 之前,应该先使用 hasSystemFeature() 函数以确保设备支持 FEATURE_FINGERPRINT。

如果设备不支持指纹身份验证,可以回退为使用 createConfirmDeviceCredentialIntent() 函数验证用户的 PIN 码、图案或密码。


2.6 高可信度用户确认

发布时安装有 Android P 的受支持设备赋予您使用 Protected Confirmation API 的能力。 借助这个新增的 API,应用可以利用 ConfirmationDialog 的实例向用户显示提示,请他们批准一个简短的声明。 应用可以通过这个声明再次确认,用户确实想完成一项敏感事务,例如付款。

如果用户接受该声明,应用会收到由密钥哈希消息身份验证代码 (HMAC) 保护的加密签名。 该签名由可信执行环境 (TEE) 生成,该环境会对显示的确认对话框以及用户输入进行保护。 该签名具有很高的可信度,它表示用户已看过声明并同意其内容。


注意:Protected Confirmation API 不会为用户提供安全信息通道。 应用无法承担 Android 平台所提供机密性保证之外的任何其他保证。 具体地讲,请勿使用该 API 显示您通常不会显示在用户设备上的敏感信息。

用户确认消息后,其完整性将得到保证,但应用必须仍使用传输中数据加密来确保已签署消息的机密性。


要在应用中提供高可信度用户确认,请完成以下步骤:

  1. 使用 KeyGenParameterSpec.Builder 类生成一个非对称签名密钥。 创建该密钥时,将 true 传入 setUserConfirmationRequired()。 此外,调用 setAttestationChallenge() 以传递由依赖方提供的合适私钥保护值。
  2. 向相应的依赖方登记新生成的密钥和密钥的认证证书。
  3. 将事务详情发送至服务器,并让其生成并返回一个额外数据 blob。 例如,一项金融事务的额外数据可能包括金额、来源帐户和目标帐户。 该 blob 应包含加密随机数以防范重播攻击 {: .external-link},并且该 blob 还可包含应用特有数据。 服务器应将该 blob 和事务详情存储在本地。
  4. 设置 ConfirmationCallback 对象,让它在用户已接受确认对话框中显示的提示时通知应用:
    class MyConfirmationCallback :ConfirmationCallback() {
        override fun onConfirmedByUser(dataThatWasConfirmed:ByteArray?) {
            super.onConfirmedByUser(dataThatWasConfirmed)
            // Sign dataThatWasConfirmed using your generated signing key.
            // By completing this process, you generate a "signed statement".
        }
    
        override fun onDismissedByUser() {
            super.onDismissedByUser()
            // Handle case where user declined the prompt in the
            // confirmation dialog.
        }
    
        override fun onDismissedByApplication() {
            super.onDismissedByApplication()
            // Handle case where your app closed the dialog before the user
            // could respond to the prompt.
        }
    
        override fun onError(e:Exception?) {
            super.onError(e)
            // Handle the exception that the callback captured.
        }
    }
    如果用户批准该对话框,则会调用 onConfirmedByUser() 回调。 dataThatWasConfirmed blob 是一个 CBOR 数据结构, {: .external-link} 其中包含用户看到的提示文本以及您传入 ConfirmationDialog 构建器的额外数据,还包含其他详细信息。 应用应使用之前创建的密钥签署 dataThatWasConfirmed blob。 然后您应该将该 blob 连同签名和事务详情回传给依赖方。

    注:由于密钥是使用 setUserConfirmationRequired() 创建的,因此只能用于签署以 dataThatWasConfirmed 参数形式返回的数据。

    签署任何其他种类数据的尝试不会获得成功。 收到签名后,您的服务器应对其进行检查。 如果签名有效,您即可从 dataThatWasConfirmed 中提取 extraData 和 promptText,并验证 extraData 与之前存储的内容是否匹配。作为最后一项检查,服务器应检查 promptText 是否与出现在额外数据中的事务详情一致。如果此步骤成功,则服务器可以执行该事务,因为它已获得高可信度的确认,用户已看到并批准了 promptText 中的消息。
  5. 添加与以下代码段所示内容类似的逻辑以显示对话框本身:
    // This data structure varies by app type. This is just an example.
    data class ConfirmationPromptData(val sender:String,
            val receiver:String, val amount:String)
    
    val myExtraData:ByteArray = byteArrayOf()
    val myDialogData = ConfirmationPromptData("Ashlyn", "Jordan", "$500")
    val threadReceivingCallback = Executor { runnable -> runnable.run() }
    val callback = MyConfirmationCallback()
    
    val dialog = ConfirmationDialog.Builder()
            .setPromptText("${myDialogData.sender}, send
                            ${myDialogData.amount} to
                            ${myDialogData.receiver}?")
            .setExtraData(myExtraData)
            .build(context)
    dialog.presentPrompt(threadReceivingCallback, callback)
    注:包含全屏对话框的确认提示界面无法进行自定义。 但框架会为您处理按钮文本的本地化。


2.7  apn/time 配置

配置 APN
设备所有者可以使用 DevicePolicyManager 类的下列新函数在设备上配置 APN:

  • addOverrideApn()
  • updateOverrideApn()
  • removeOverrideApn()
  • getOverrideApns()
  • setOverrideApnEnabled()
  • isOverrideApnEnabled()

配置时间和时区
设备所有者可以使用 DevicePolicyManager 类中的下列新函数在设备上设置时间和时区:

  • setTime()
  • setTimeZone()

对重要设置强制执行用户限制
描述文件所有者和设备所有者可以通过 DevicePolicyManager.addUserRestriction(),使用下列新增的 UserManager 字段阻止或停用重要设置:

  • DISALLOW_AIRPLANE_MODE
  • DISALLOW_AMBIENT_DISPLAY
  • DISALLOW_CONFIG_BRIGHTNESS
  • DISALLOW_CONFIG_DATE_TIME
  • DISALLOW_CONFIG_LOCATION
  • DISALLOW_CONFIG_SCREEN_TIMEOUT
  • DISALLOW_PRINTING

如果在设备上强制执行了 DISALLOW_CONFIG_BRIGHTNESS 和 DISALLOW_CONFIG_SCREEN_TIMEOUT,设备所有者仍然可以利用新增的 API DevicePolicyManager.setSystemSetting() 在设备上设置屏幕亮度、屏幕亮度模式和屏幕超时 设置。


猜你喜欢

转载自blog.csdn.net/sinat_20059415/article/details/80465241