咱们在 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 在您利用的界面之外显示的音讯,旨在向用户提供揭示、来自别人的通信信息或您利用中的其余适时弹出的信息。用户能够点按告诉来关上利用,或间接在告诉中执行操作。
- Snackbars 和 Toasts: 如果您须要在利用中显示一条简短的信息,能够应用 Snackbars。如果您须要利用在后盾的状况下显示信息,能够看看 Toasts 是否合乎您的需要。
如果您利用的应用场景匹配了上述某个 API 的应用场景,那么强烈建议您应用这些 API。不仅仅是因为这些 API 简略易用,它们还更加平安,而且用户曾经对它们中的大多数很相熟了。
我会受到影响吗?
如果您的利用不能应用上述 API,而是让触摸事件间接通过其窗口传递,那么在 Android 12 中它们可能无奈按预期传递到上层。这方面的例子包含但不仅限于以下示例:
- 应用 FLAG_NOT_TOUCHABLE 标记的 TYPE_APPLICATION_OVERLAY 窗口。
- 应用 FLAG_NOT_TOUCHABLE 标记的 Activity 窗口。
如果您正在应用 FLAG_NOT_TOUCHABLE,那么您的利用可能会被影响,除非您的利用合乎以下某个豁免条件:
- 利用中的交互 。只有当用户与您的利用进行互动时才会显示叠加层。
- 可信窗口 。这些窗口包含但不仅限于: 无障碍窗口、输入法 (IME) 窗口 和 Google 助理窗口。
- 不可见窗口 。窗口根视图是 GONE 或 INVISIBLE。
- 全透明窗口 。窗口的 alpha 属性值为 0.0。
- 足够半透明的零碎警报窗口 。该窗口是 TYPE_APPLICATION_OVERLAY 类型的,并且其 alpha 值等于或小于 InputManager.getMaximumObscuringOpacityForTouch()) 的值。这个值目前在开发者预览 3 的版本中是 0.8,但在最终版公布之前可能会扭转。如果有多个这种类型的重叠窗口,则会应用它们各自的 opacity 值 合并计算出一个值 作为最终的后果。
如果您的应用场景并不蕴含于上述列表内,那么触摸事件将会被屏蔽。否则的话,如果您想阻止触摸事件传递,能够思考删除 FLAG_NOT_TOUCHABLE 标记,而如果想让触摸事件穿透上来,能够调整您的代码来合乎上述的几种状况之一。接下来咱们会介绍必须要扭转的一些常见模式的例子。
有着通明背景且无 UI 元素的窗口
在有着通明背景的窗口中展现某些 UI 的利用,能够在适当的时候在视图层面暗藏它们的 UI,同时增加 FLAG_NOT_TOUCHABLE 标记,这样用户就能够与上层的内容进行交互了。
如果像上图一样,利用仅仅是暗藏了 UI,要么是通过删除子视图的办法暗藏,或是扭转它们的可见性 (visibility) 并增加 FLAG_NOT_TOUCHABLE 标记来容许用户与上层的视图进行交互,因为对上层其余利用的触摸事件会被屏蔽,所以这样的办法在 Android 12 上就不再起作用了 (留神与后面提到的豁免条件的区别,在这里咱们扭转的是外部视图,而不是窗口)。在这种状况下想解决此类问题,您能够:
- 应用 WindowManager.removeView()) 来移除窗口,并传递给根视图。
- 通过在根视图上调用 View.setVisibility()),应用 View.GONE 或 View.INVISIBLE 让窗口不可见。
- 通过 LayoutParams.alpha 让窗口的 opacity 值为 0.0。
每当您须要再次显示那个界面时,您只须要把下面的动作反过来设置即可。
不必要的大窗口
有时利用会想要显示一些小的 UI 界面,并同时容许用户同窗口上层的内容进行交互。在之前,利用能够通过简略地应用一个全屏窗口,并将其标记为 FLAG_NOT_TOUCHABLE 来实现,如图 1 所示:
请留神,在以前的操作系统版本中,通过理论的 UI 元素进行的触摸事件,在这种状况下会传递到上层的窗口中。在这种状况下,首先请查看一下 Toast API 是否能满足需要,不行的话,解决方案也很简略——在右侧的图片有阐明: 您只须要将窗口的边界放大到理论的 UI 大小,并应用 FLAG_NOT_TOUCH_MODAL,有时您也可能须要删除 FLAG_NOT_TOUCHABLE
。
这样,在您的 UI 外的触摸事件,将间接穿透到上层的窗口,不再被屏蔽。
半透明窗口
如果您应用了一个 TYPE_APPLICATION_OVERLAY
窗口,并须要在显示内容时容许触摸事件穿透上来,那您就必须升高窗口的不透明度,让用户可能正当地看到他们在窗口后所触摸的 UI 元素。
您必须在 窗口级别 上升高不透明度,仅仅扭转视图的不透明度是不行的。您能够应用 LayoutParams.alpha 来升高不透明度,使其低于或者等于
InputManager.getMaximumObscuringOpacityForTouch()) 的值,如左边的图片所示。这个值目前是 0.8,然而在 Android 12 最终版本公布前可能会扭转。
当初,只有您利用内的多个窗口没有互相重叠,触摸事件就会穿透到上层的窗口。对于重叠窗口的更多细节,请查阅 FLAG_NOT_TOUCHABLE 文档。
无障碍服务
当应用 AccessibilityService (无障碍服务) 时,它能够创立 TYPE_ACCESSIBILITY_OVERLAY 类型的窗口,这些窗口是可信赖的,因而能够免于后面所形容的一些限度。您只须要联合 AccessibilityService 的上下文,通过 getSystemService() 办法取得一个 WindowManager 来创立上述窗口。
如何测试您的利用是否受到影响
如果零碎屏蔽了触摸操作,Logcat 会输入以下信息:
Untrusted touch due to occlusion by PACKAGE_NAME.
接下来
如果您想理解到更多对于不受信赖的触摸事件以及它们的例外情况,请查阅相干文档:
- 不受信赖的触摸事件
- 例外情况