查看原文
其他

行为变更 | Android 12 中不受信任的触摸事件

Android Android 开发者 2021-10-20
我们在 Android 12 中进行了一些变更,来提升应用和平台的安全性,进而使我们的用户能够拥有更安全的使用体验。回顾关于隐私和安全的文章,请参阅: 政策更新 | 开发者如何处理软件包可见性

触摸控制是 Android 系统中同应用进行交互的主要方式。Android 12 中采取了额外的措施,来确保触摸事件被正确地传递给了应该响应此事件的应用,以此确保触摸交互的直观和安全性。具体地说,就是在 Android 12 中,如果触摸事件是从一个不同的应用窗口传递的,那么此事件会被屏蔽。这一改变将影响所有在 Android 12 中运行的应用,且与应用的 "targetSdkVersion" 无关。这有助于帮助用户更直观地确认他们正在进行交互的应用。继续阅读本文来看看您的应用是否会受到此变更的影响,以及了解如何针对此变更测试您的应用。



尽可能使用特殊用途 (Special-Purpose) 的 API



在检查您的应用是否会受此影响之前,最好先评估一下您应用的某些场景是否可以使用以下 Android API。这些 API 部分由系统控制,可以被信任,因此您不需要担心使用这些 API 会受到限制。它们是:

  • Bubbles: Bubbles 是像气泡一样浮动在其他应用内容的上层,并且会跟随用户所处的位置,还可以展开以显示应用功能和信息。

  • Picture-in-Picture (PIP): PIP 功能允许应用在一个小窗口中显示内容,用户可以通过固定到屏幕一角的小窗口观看视频,同时在应用之间进行导航或浏览主屏幕上的内容。用户还可以拖动 PIP 窗口,并可以点击它来展开或进行关闭。

  • Notifications: 通知是指 Android 在您应用的界面之外显示的消息,旨在向用户提供提醒、来自他人的通信信息或您应用中的其他适时弹出的信息。用户可以点按通知来打开应用,或直接在通知中执行操作。

  • SnackbarsToasts: 如果您需要在应用中显示一条简短的信息,可以使用 Snackbars。如果您需要应用在后台的情况下显示信息,可以看看 Toasts 是否符合您的需求。


  • Bubbles
    https://developer.android.google.cn/guide/topics/ui/bubbles
  • Picture-in-Picture
    https://developer.android.google.cn/guide/topics/ui/picture-in-picture
  • Notifications
    https://developer.android.google.cn/guide/topics/ui/notifiers/notifications
  • Snackbars
    https://developer.android.google.cn/reference/com/google/android/material/snackbar/Snackbar
  • Toasts
    https://developer.android.google.cn/guide/topics/ui/notifiers/toasts

如果您应用的使用场景匹配了上述某个 API 的使用场景,那么强烈建议您使用这些 API。不仅仅是因为这些 API 简单易用,它们还更加安全,而且用户已经对它们中的大多数很熟悉了。



我会受到影响吗?



如果您的应用不能使用上述 API,而是让触摸事件直接通过其窗口传递,那么在 Android 12 中它们可能无法按预期传递到下层。这方面的例子包括但不仅限于以下示例:
  • 使用 FLAG_NOT_TOUCHABLE 标志的 TYPE_APPLICATION_OVERLAY 窗口。
  • 使用 FLAG_NOT_TOUCHABLE 标志的 Activity 窗口。

  • FLAG_NOT_TOUCHABLE
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams#FLAG_NOT_TOUCHABLE

  • TYPE_APPLICATION_OVERLAY
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams?hl=zh-TW#TYPE_APPLICATION_OVERLAY


如果您正在使用 FLAG_NOT_TOUCHABLE,那么您的应用可能会被影响,除非您的应用符合以下某个豁免条件:
  • 应用中的交互。只有当用户与您的应用进行互动时才会显示叠加层。

  • 可信窗口。这些窗口包括但不仅限于: 无障碍窗口输入法 (IME) 窗口Google 助理窗口

  • 不可见窗口。窗口根视图是 GONEINVISIBLE

  • 全透明窗口。窗口的 alpha 属性值为 0.0。

  • 足够半透明的系统警报窗口。该窗口是 TYPE_APPLICATION_OVERLAY 类型的,并且其 alpha 值等于或小于 InputManager.getMaximumObscuringOpacityForTouch() 的值。这个值目前在开发者预览 3 的版本中是 0.8,但在最终版发布之前可能会改变。如果有多个这种类型的重叠窗口,则会使用它们各自的 opacity 值合并计算出一个值作为最终的结果。


  • 无障碍窗口
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams?hl=zh-TW#TYPE_ACCESSIBILITY_OVERLAY
  • 输入法 (IME) 窗口
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams?hl=zh-TW#TYPE_INPUT_METHOD
  • Google 助理窗口
    https://developer.android.google.cn/reference/android/service/voice/VoiceInteractionSession
  • GONE
    https://developer.android.google.cn/reference/android/view/View#GONE
  • INVISIBLE
    https://developer.android.google.cn/reference/android/view/View#INVISIBLE
  • alpha
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams#alpha
  • InputManager.getMaximumObscuringOpacityForTouch()
    https://developer.android.google.cn/reference/android/hardware/input/InputManager#getMaximumObscuringOpacityForTouch()
  • 合并计算出一个值
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams#combined-obscuring-opacity

如果您的使用场景并不包含于上述列表内,那么触摸事件将会被屏蔽。否则的话,如果您想阻止触摸事件传递,可以考虑删除 FLAG_NOT_TOUCHABLE 标志,而如果想让触摸事件穿透下去,可以调整您的代码来符合上述的几种情况之一。接下来我们会介绍必须要改变的一些常见模式的例子。



有着透明背景且无 UI 元素的窗口



在有着透明背景的窗口中展示某些 UI 的应用,可以在适当的时候在视图层面隐藏它们的 UI,同时添加 FLAG_NOT_TOUCHABLE 标志,这样用户就可以与下层的内容进行交互了。

如果像上图一样,应用仅仅是隐藏了 UI,要么是通过删除子视图的方法隐藏,或是改变它们的可见性 (visibility) 并添加 FLAG_NOT_TOUCHABLE 标志来允许用户与下层的视图进行交互,因为对下层其他应用的触摸事件会被屏蔽,所以这样的方法在 Android 12 上就不再起作用了 (注意与前面提到的豁免条件的区别,在这里我们改变的是内部视图,而不是窗口)。在这种情况下想解决此类问题,您可以:
  • 使用 WindowManager.removeView() 来移除窗口,并传递给根视图。

  • 通过在根视图上调用 View.setVisibility(),使用 View.GONEView.INVISIBLE 让窗口不可见。

  • 通过 LayoutParams.alpha 让窗口的 opacity 值为 0.0。


  • WindowManager.removeView()
    https://developer.android.google.cn/reference/android/view/ViewManager#removeView(android.view.View)

  • View.setVisibility()
    https://developer.android.google.cn/reference/android/view/View#setVisibility(int)

  • View.GONE
    https://developer.android.google.cn/reference/android/view/View#GONE

  • View.INVISIBLE
    https://developer.android.google.cn/reference/android/view/View#INVISIBLE

  • LayoutParams.alpha
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams#alpha


每当您需要再次显示那个界面时,您只需要把上面的动作反过来设置即可。



不必要的大窗口



有时应用会想要显示一些小的 UI 界面,并同时允许用户同窗口下层的内容进行交互。在之前,应用可以通过简单地使用一个全屏窗口,并将其标记为 FLAG_NOT_TOUCHABLE 来实现,如图 1 所示:

请注意,在以前的操作系统版本中,通过实际的 UI 元素进行的触摸事件,在这种情况下会传递到下层的窗口中。在这种情况下,首先请查看一下 Toast API 是否能满足需求,不行的话,解决方案也很简单——在右侧的图片有说明: 您只需要将窗口的边界缩小到实际的 UI 大小,并使用 FLAG_NOT_TOUCH_MODAL,有时您也可能需要删除 FLAG_NOT_TOUCHABLE


  • Toast
    https://developer.android.google.cn/guide/topics/ui/notifiers/toasts

  • FLAG_NOT_TOUCH_MODAL
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams#FLAG_NOT_TOUCH_MODAL


这样,在您的 UI 外的触摸事件,将直接穿透到下层的窗口,不再被屏蔽。



半透明窗口



如果您使用了一个 TYPE_APPLICATION_OVERLAY 窗口,并需要在显示内容时允许触摸事件穿透下去,那您就必须降低窗口的不透明度,让用户能够合理地看到他们在窗口后所触摸的 UI 元素。

您必须在窗口级别上降低不透明度,仅仅改变视图的不透明度是不行的。您可以使用 LayoutParams.alpha 来降低不透明度,使其低于或者等于
InputManager.getMaximumObscuringOpacityForTouch() 的值,如右边的图片所示。这个值目前是 0.8,但是在 Android 12 最终版本发布前可能会改变。

现在,只要您应用内的多个窗口没有相互重叠,触摸事件就会穿透到下层的窗口。关于重叠窗口的更多细节,请查阅 FLAG_NOT_TOUCHABLE 文档。


  • LayoutParams.alpha
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams#alpha

  • InputManager.getMaximumObscuringOpacityForTouch()
    https://developer.android.google.cn/reference/android/hardware/input/InputManager#getMaximumObscuringOpacityForTouch()

  • FLAG_NOT_TOUCHABLE
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams#FLAG_NOT_TOUCHABLE



无障碍服务



当使用 AccessibilityService (无障碍服务) 时,它可以创建 TYPE_ACCESSIBILITY_OVERLAY 类型的窗口,这些窗口是可信任的,因此可以免于前面所描述的一些限制。您只需要结合 AccessibilityService 的上下文,通过 getSystemService() 方法获得一个 WindowManager 来创建上述窗口。


  • TYPE_ACCESSIBILITY_OVERLAY
    https://developer.android.google.cn/reference/android/view/WindowManager.LayoutParams#TYPE_ACCESSIBILITY_OVERLAY

  • AccessibilityService
    https://developer.android.google.cn/reference/android/accessibilityservice/AccessibilityService

  • WindowManager
    https://developer.android.google.cn/reference/android/view/WindowManager



如何测试您的应用是否受到影响



如果系统屏蔽了触摸操作,Logcat 会输出以下信息:

Untrusted touch due to occlusion by PACKAGE_NAME.


  • Logcat
    https://developer.android.google.cn/studio/command-line/logcat?hl=zh-TW



接下来



如果您想了解到更多关于不受信任的触摸事件以及它们的例外情况,请查阅相关文档:


  • 不受信任的触摸事件

    https://developer.android.google.cn/about/versions/12/behavior-changes-all?hl=zh-TW#untrusted-touch-events

  • 例外情况
    https://developer.android.google.cn/about/versions/12/behavior-changes-all?hl=zh-TW#untrusted-touch-events-exceptions



 点击屏末 | 阅读原文 | 查看 Android 12 上运行的所有应用都会受到影响的行为变更


推荐阅读

如页面未加载,请刷新重试


视频 小程序 ,轻点两下取消赞 在看 ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存