RFC-0177:适用于父视图的 Focus Observer

RFC-0177:针对父视图的焦点观察器
状态已接受
领域
  • 查看系统
  • HCI
说明

用于父视图的 API,用于了解焦点在其视图树中如何移动

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2022-06-06
审核日期(年-月-日)2022-07-07

摘要

此 RFC 提出了一种可安全使用的视图焦点 API 设计 通过普通的界面客户端跳出树,并阐明了 与焦点可观测性相关的限制。重点在于 信息公开和优雅的开发者体验。

设计初衷

为了通过多种多语言模型来打造用户体验(图形、输入等), 组件,这是界面客户端委托 将内容制作传递给其他界面客户端,方法是设置一个视图树,其中 父视图可管理一个或多个子视图。Ermine 系统 shell 就是这样一个例子。Google 的智能显示屏则是另一种选择。一把钥匙 父视图的职责是监控视图焦点状态:

  1. 为了确定何时父视图可以通过编程方式将视图焦点移动到 子视图。
  2. 如果视图焦点移至某个子视图,则用于确定当前具有哪个子视图 视图焦点。
    • 例如,如果用户通过轻触将焦点移至某个视图,则其父项 视图可能希望使用焦点边界来装饰该子视图,并且 需要知道发生时间以及子视图的身份。

焦点可能会在没有父视图干预的情况下发生变化(用户触摸、分离视图、 等)。父视图必须了解视图焦点如何移动,但 并遵守由 Google 设置的信息限制, 全局视图树

此 RFC 提出了一个“焦点观察器”设计时,(1) 允许父视图 正确响应视图焦点更改;(2) 可在树外安全使用;(3) 改善了 Fuchsia View 系统的安全状况, 信息泄露。

利益相关方

教员

审核者:sanjayc@google.com(工作站)、quiche@google.com (HCI)、 neelsa@google.com (HCI)、akbiggs@google.com (Flutter)

已咨询:shiveshganju@google.com, fmil@google.com, emircan@google.com, jsankey@google.com

社交化

此 RFC 与受影响团队的负责人进行了社交互动。

要求

  • 尽量减少焦点可观测性的信息泄露
  • 用于获取观察信道的明确安全机制
  • SDK 添加到“合作伙伴”中级别或更高
  • 简化开发者体验

设计

此焦点观察器的核心提案是以下 FIDL 协议。

library fuchsia.ui.observation.focus;
using zx;

protocol ScopedProvider {
  Watch() -> (ScopedResponse);
};

type ScopedResponse = table {
  1: observation_end zx.time;
  2: focused zx.koid;
};

“限定范围”表示协议提供了焦点信息 范围限定在 focus.ScopedProvider 客户端的视图中或位于该客户端的视图中 树。shortcuts.ScopedProvider 客户端的视图是此可观察视图的根 树。

observation_end 时间表示观看期的结束,以便客户端 知道返回的焦点何时准确。例如,它允许客户端 如果一组 在单个 Watch 中发生了焦点更改,以返回到上一个焦点 。

focused KOID 是观看引用 KOID,或者 特殊标记值 ZX_KOID_INVALID,用于表示查看 焦点位于 focus.ScopedProvider 客户端的视图树之外。可能出现的 值和语义的详细信息将在下文中更详细地讨论。

视图拓扑示例

请考虑以下视图拓扑,其中每个圆圈代表一个视图, 视图“U”是 focus.ScopedProvider 的客户端。

L1 视图拓扑示例。
  L2 节点 U、V、W、X、Y。
  V 和 W 的 L3 U 父级。
  X 和 Y 的 L4 V 父级。
  L5 U 在标记为“视图树的其余部分”的较大三角形中未指定父级。

将公开范围范围限定为视图树

shortcuts.ScopedProvider 的客户端对全局视图的可见性有限 (如需了解详情,请参阅“安全注意事项”)。它可以知道视图焦点 在其视图树中(位于 focus.ScopedProvider 客户端的视图中)或 在其视图树之外,但我们会刻意省略详细信息。

当焦点位于 focus.ScopedProvider 客户端的视图树之外时,该客户端 用户仅能了解一般事实,使用ZX_KOID_INVALID哨兵 值。客户端不会获知新视图焦点的身份。

Wen 焦点位于焦点内。ScopedProvider 客户端的视图树,客户端 仅获知以下信息:

  • 如果焦点位于 focus.ScopedProvider 客户端的视图本身,则 KOID 客户视角
  • 如果焦点位于客户视图的直接子视图上,则 KOID 直接儿童视角。
  • 如果焦点位于客户视图的间接子视图上,则 KOID 直接子视图,即该间接子视图的祖先。

父视图需要知道何时能够在其自身之间移动焦点。 子女。当视图焦点位于其视图树中时,它具有此权限。否则, 调用 fuchsia.ui.views.Focuser.RequestFocus() 将始终失败。

值得注意的是,focus.ScopedProvider 的信息是 因此会在一个通道上传播,因此更改焦点的请求可能会与下一个 快照更新。例如,一个快照可能表示焦点位于 将焦点移至某个客户端的视图树的请求,以及将焦点更改为 如果祖先视图成功请求焦点,直接子项可能会被拒绝 更改到此视图树外部

在此序列图中,当焦点移至 U 时,U 会得到通知;当焦点移至 U 时, 焦点已经完全移出了 U 的视图树。

L1 Title: 聚焦观察器用法。
  L2 参与者 U。
  L3 参与者 ScopedProvider 为 S。
  L4 U ->S:注意
  L5 注意 U 形右侧:焦点已移到 U。
  L6 S ->U:response(U)。
  L7 U ->S:注意
  L8 U 形右侧备注:焦点移到了 U 形外面。
  L9 S ->U:response("invalid")。
  L10 U ->S:注意
  L11 U 形右侧注:正在等待更改焦点。

重点关注向客户报告的值

focused 是三个值类之一,其中包括 ZX_KOID_INVALID Sentinel 值。如果 focused 有效(即不是标记),则视图 能够在自身及其子视图之间任意移动焦点。

具体而言:

  • 如果 focusedZX_KOID_INVALID,则焦点已离开此视图树。这个 出现这种情况的原因有很多。例如,U 的视图树 可能与全局视图树相关联,但祖先视图可能有 将焦点移到了 U 的同级视图中。或者,U 可能已断开 ,这表示 U 不再有资格获得焦点。 或者,U 的祖先实体可能自身已断开连接,在这种情况下, 该祖先实体的后代无法获得焦点。请参阅 焦点政策
  • 如果是父视图引用 KOID,则父视图本身具有焦点。 此用法与 fuchsia.ui.views.ViewRefFocused 相同,后者 我们可以使用该协议
  • 如果 KOID 无效或父 ID 为 KOID,则它是直接子项的 查看参考 KOID。此字段中只提及直接子项,即使 聚焦视图是直接子级的后代。

在此示例中,焦点移到了 X,即 U 下 V 的子元素。焦点观察器 报告 U 的直接子项,也就是 V。

L1 Title: 聚焦观察器用法。
  L2 参与者 U。
  L3 参与者 ScopedProvider 为 S。
  L4 U ->S:注意
  L5 注意 U 右侧:焦点已移到 X。
  L6 S ->U:response(V)。
  L7 U ->S:注意
  L8 U 形右侧备注:正在等待更改焦点。

摘要语义

如果在过去的观察期内发生多次焦点变化,此 API 将 只返回最终焦点。客户通常不能根据过去的焦点采取行动 因此该 API 已简化为只返回“摘要”。

通常,如果挂起获取客户端通过 Watch 托管回调,则焦点会改变, 会使应用立即返回到客户端不过,有可能出现 这样,服务器就可能发现延迟停车, 多个焦点变化,以总结下次返回的结果。您同样可以 以便接收大量焦点变化,具体取决于线程或任务。 因此,在经过若干焦点之后 更改。

在这些示例中,无论使用哪个 Watch() 函数,U 都会收到相同的通知 调用时间。

L1 Title: 聚焦观察器用法。
  L2 参与者 U。
  L3 参与者 ScopedProvider 为 S。
  L4 U ->S:注意
  L5 注意 U 右侧:焦点已移到 X。
  L6 注意 U 形右侧:焦点已移到 Y。
  L7 注意 U 线右侧:焦点已移动到 W。
  L8 S ->U:response(W)。
  L9 U ->S:注意
  L10 U 形右侧注:正在等待更改焦点。

L1 Title: 聚焦观察器用法。
  L2 参与者 U。
  L3 参与者 ScopedProvider 为 S。
  L4 注意 U 线右侧:焦点已移动到 X。
  L5 注意 U 线右侧:焦点已移动到 Y。
  L6 注意 U 形右侧:焦点已移动到 W。
  L7 U ->S:注意
  L8 S ->U:response(W)。
  L9 U ->S:注意
  L10 U 形右侧注:正在等待更改焦点。

状态更改语义

Watch 调用由每个客户端的状态变化驱动。

  • 在建立连接后的第一次调用中,返回当前状态 。
  • 从一次 Watch 调用返回到下一次 Watch 调用开始之间, 如果发生了多次状态变化,则下一次 Watch 调用将返回 立即观察到最近一次观察到的变化。

使用级别更改时,服务器仅在更改发生时通知客户端 之后,它会在收到 Watch 调用之前忽略更改 手表通话。客户将错过该时间段的焦点变化摘要 这并不适合预期应用场景。

根据状态变化进行处理会给服务器带来更大的负担 实现,因为它需要跟踪每个观察者最近一次发出的状态 。不过,这样可为开发者带来更直观的体验, 更改对客户端的 Watch 调用和任何 聚焦变化。例如,在服务器上停放 Watch 通话后, 在处理回调之前可能会临时发生焦点更改, 具体取决于服务器的线程处理情况和实现细节。

实现

视图焦点与视图拓扑的视图生命周期和维护紧密相关。 “景观”是视图管理器组件,因此,要实现此协议, 属于“风景”区。

性能

焦点可以频繁更改,但实际上是按照“人工规模”移动的。因此 FIDL 调用频率不被视为问题。FIDL 载荷 而且流控制模式可以避免信道填充。

工效学设计

此 API 力求比其前身改进 DX。简化错误处理 有损摘要语义,缺少容器数据类型应该意味着 更容易采用。

进化

此 API 旨在用于 OOT 代码库,并且服务器 都位于一个平台组件中,也就是风景。此 API 将不断改进, 安全地运行,并保持向后兼容性。 当所有使用已弃用方法的代码库都更新为较新的 方法,可将已弃用的方法标记为“已删除”。

安全注意事项

此 API 连接到 fuchsia.ui.composition.Flatland.ViewBoundProtocols 表,此表将此 API 的服务器端点与特定的 创建视图时与父视图关联的 ViewRef。

L1 Title: 聚焦观察器连接。
  L2 参与者界面客户端,格式为 U。
  L3 参与者 Flatland 作为 S.
  L4 参与者焦点提供程序,如 F.
  L5 U 右侧备注:“U”:视图 U 的视图引用。
  L6 U ->S:Flatland.CreateView2(U, server_end:f.u.o.focus.ScopedProvider)。
  L7 U ->S:Flatland.Present()。
  L8 U ->F:F:f.u.o.focus.ScopedProvider.Watch()。
  L9 U 形右侧注:正在等待更改焦点。

API 客户端无法请求在自己的视图中提供更详细的信息 或者位于其视图树之外收到的视图参考 KOID 信息限定了范围 从而改善 View 的安全状况。

专注窃取

在更为宽松的系统中,恶意视图可能会“窃取”从任何其他来源 就能尽情观看Fuchsia View 系统的 焦点政策通过定义 焦点移动的情况和范围:视图只有在满足以下条件时才能移动焦点: 焦点已由祖先视图授予,并且只能在其视图中移动焦点 而不是在子树之外

这种焦点观察器设计遵循此焦点政策的限定范围方法, 将可观测性限制为被观察视图及其直接子视图。

KOID 不是功能

另一个小改进是焦点观察器协议提供了 子视图引用的 KOID,而不是视图引用本身的副本。部分界面 所以返回 KOID 可降低 滥用行为。例如,如果 Ermine 的 focus.ScopedProvider 频道端点为 委托给另一个组件“C”,则这是安全的委托,因为“C”不能 以 Ermine 或 Ermine 的任何子视图假冒 键盘 Listener 协议。

典型用法是确定获得焦点的视图,以及 视图引用 KOID 就已足够。请注意,请求焦点需要 视图引用,而不仅仅是视图引用的 KOID。客户应以自己的方式 子视图引用(即通过 Flatland 协议获取)的列表,以及这些 视图引用可用于请求焦点。

隐私注意事项

FocusChainListener 协议可让您全面了解 一直到根视图此焦点观察器协议是有意为之 用于限制可见性范围,可见视图树位于 客户端视图本身

ViewRefFocused 的作用域已限定为客户端视图。重点 观察器协议将客户端的可见性扩展到客户端视图的直接 子视图。

得益于这些缓解措施,我们预计隐私受到的影响微乎其微。

测试

实现将具有单元测试和平台端集成测试。 此外,与任何其他 SDK 可见的 FIDL 一样,它会进行 CTF 测试。

文档

fuchsia.dev 中提供了一份使用文档指南。

缺点、替代方案和未知问题

此 API 并不适用于所有已知的焦点观察用法。不过,之前的 社会化举措的努力强化了为 Google Cloud 和 Google Cloud 的 需求。后续的 RFC 将处理其他“焦点观察器”API。

先验技术和参考资料

旧版 FocusChainListener 的问题

目前,观察视图树中视图焦点移动的唯一选项是 fuchsia.ui.focus.FocusChainListener 协议。时间是 停用,原因如下:

  • 可让客户端对视图焦点移动的位置进行全局可见性, 泄露平台实现详情。例如, 根场景在此焦点链中公开,这样,客户端就可以断言 因此可以防止平台内部 实施更改。
  • 它会提供 fuchsia.ui.views.ViewRef 令牌(由 Zircon 事件对对象),这些对象可让使用较弱协议的客户端 视为另一种视图