在无屏眼镜上,系统会根据用户感知(而非视觉显示焦点)来路由物理输入(例如触控板手势或按键)。 由于用户看不到界面,系统会将物理输入路由到用户正在感知或主动与之互动的任何应用体验的投射 activity。
系统如何确定用户是否知晓
系统通过监控以下哪些数据流处于活跃状态来确定用户感知:
- 音频输出流:语音读出、音频提示或媒体播放。
- 麦克风录制流:持续的语音指令或从用户周围环境捕获的音频。
- 相机拍摄视频流:视频或照片流。
有些数据流是瞬时的,只会短时间引起用户注意。例如,在导航路线时,通过音频读出用户应采取的下一个转弯。其他数据流则没有时间限制,只要数据流持续,用户就会一直保持感知。例如,使用无尽的随机播放列表播放媒体。当瞬态数据流中断无限期数据流时,它会暂时获得用户感知。
并发和输入焦点
用户经常在无屏眼镜上同时运行多个应用体验。例如,用户可能会在遵循精细导航的同时听音乐。 在这些情况下,系统会分配并发状态,并通过执行以下操作来转移输入焦点以匹配音频焦点:
- 恢复或停止应用的投影 activity。
- 将物理输入路由到前台投影 activity。
这种方法有助于保持一致的用户体验。
让系统重新启动投影的 activity
当您的应用获得用户感知时,尤其是当其投影 activity 位于后台时,系统必须能够恢复该 activity 并将物理输入路由到该 activity。
为确保系统可以重新启动您的 activity,请执行以下操作:
创建待处理 intent:构建一个指向目标投影 activity 的显式
Intent。将 intent 封装在PendingIntent中,并设置FLAG_UPDATE_CURRENT或FLAG_IMMUTABLE,以保持安全且可预测的启动行为:// Build an explicit Intent pointing to this projected activity and wrap it in a // PendingIntent so the system can relaunch it and route physical input to it. private val pendingIntent: PendingIntent by lazy { val intent = Intent(this, ProjectedInputFocusActivity::class.java) PendingIntent.getActivity( this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) }
注册输入接收器:获取
ProjectedActivityCompat的实例,并通过将PendingIntent传递到setActivityAsInputReceiver中,将其注册为指定的输入接收器。override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { // Create or obtain the ProjectedActivityCompat instance val projectedActivity = ProjectedActivityCompat.create(this@ProjectedInputFocusActivity) // Register the PendingIntent as the designated input receiver projectedActivity.setActivityAsInputReceiver(pendingIntent) }
在清理时清除输入接收器:当 activity 被销毁或不再需要接收物理输入时,请清除输入接收器,以防止过时的
PendingIntent分派并避免内存泄漏。override fun onDestroy() { super.onDestroy() lifecycleScope.launch { val projectedActivity = ProjectedActivityCompat.create(this@ProjectedInputFocusActivity) projectedActivity.clearActivityAsInputReceiver() } }
了解输入焦点如何在并发状态之间切换
为了确定哪个应用获得输入焦点,系统会评估活跃的数据流,并根据以下并发状态路由输入:
| 并发状态 | 环境背景 | 系统行为和输入焦点 | 示例 |
|---|---|---|---|
非并发 |
独立的投射活动处于活跃状态;没有后台媒体会话在运行。 |
输入焦点会完全路由到投影的 activity,即使在读出之间的静默期也是如此。 |
用户运行锻炼跟踪应用。即使在静默时刻,触控板输入也会直接路由到健身应用。 |
半并发 |
投射的 activity 处于活跃状态,但后台媒体会话处于暂停状态。 |
在应用的主动朗读之间的静音期间,输入焦点默认位于已暂停的媒体控件上。 |
用户在音乐暂停时运行锻炼跟踪应用。在健身教练更新之间,轻击触控板会恢复音乐,而不是触发锻炼功能。 |
并发 |
双重播放处于活跃状态(例如,应用的语音播报中断或降低了背景音乐的音量)。 |
音频焦点等同于输入焦点。 在朗读期间,输入焦点会路由到投影的 activity,并在音频串流结束时恢复为媒体控件。 |
用户正在听音乐,此时导航应用发出指令读出。在朗读期间,导航应用会获得输入焦点。读出完成后,输入焦点会移回媒体控件。 |
系统计时保护措施
系统提供以下保护措施,以帮助防止用户意外输入或出现意外行为:
- 新启动的投影活动的宽限期:为了适应冷启动资源加载或网络延迟,新启动的投影活动会获得一个短暂的宽限期,以便在系统停止投影活动并将其移至后台之前建立数据流并获得用户感知。
- 焦点会根据用户感知进行路由:如果用户感知因新的活跃数据流(例如音频读数)而发生变化,系统会立即恢复投影的 activity 并将输入焦点路由到该 activity。
- 媒体播放期间的过渡缓冲区:在后台媒体播放期间,当瞬时读出完成时,输入焦点会暂时保留在投射的 activity 上。缓冲期有助于防止意外输入,例如用户尝试将朗读内容静音,却跳过了音乐曲目。在过渡缓冲区之后,系统会停止应用的投影 activity,并将输入焦点路由到媒体控件。
- 空闲的投射 activity 会停止或暂停:系统会在几分钟后停止所有没有活跃数据流的空闲投射 activity(或者在暂停时立即停止正在进行的媒体输出)。
输入焦点转换实践
为了解输入焦点如何在并发状态之间转换,请考虑以下示例场景,其中导航应用提供精细导航:
场景 A:非并发(非活跃媒体)
在这种情况下,系统会将输入路由到导航应用,该应用在整个行程中都具有用户感知能力。
- 用户在没有播放背景音乐的情况下启动导航。
- 导航应用在无屏眼镜上启动其投影 activity。
- 由于没有媒体会话处于活跃状态,因此导航应用会在整个行程中保持触控板输入焦点。
- 用户操作:在语音播报期间点按屏幕可能会使导航静音。 在静音期间点按可能会重复上一条指令。
场景 B:半并发(暂停媒体)
在这种情况下,只要导航应用不具备用户感知能力,系统就会将输入路由到系统媒体控件。
- 用户在背景音乐暂停时启动导航。
- 在朗读之间的静音期间,输入焦点默认为媒体控件。
- 当导航应用说出“500 英尺后左转”时,它会获得输入焦点。
- 用户操作:在朗读期间点按可能会将导航语音静音。在静音期间点按可继续播放音乐。
场景 C:并发(活跃媒体)
对于这种情况,只要导航应用没有用户感知,系统就会将输入路由到系统媒体控件,并且在导航应用每次读出内容时,正在播放的媒体音频都会降低音量。
- 用户在音乐正在播放时启动导航。
- 在播报指令期间,系统会降低背景音频的音量,并将输入焦点切换到导航应用。
- 用户操作:在朗读期间点按可能会将导航语音静音。在静音期间点按可控制媒体播放(暂停或继续)。