输入法支持

我们对这些与屏幕相关的部分进行了更新,详情见下文:

对于在非默认屏幕上运行的应用,Android 10 支持使用软件键盘

在非默认屏幕上运行的应用

关于输入法 (IME) 的软件键盘显示在哪个屏幕上,有两种不同的模式。软件键盘显示在:

  • 目标应用所在的屏幕上。
  • 默认屏幕上(当目标应用在非默认屏幕上运行时)。

系统会根据目标应用所在屏幕的设置确定要使用的模式。如需了解详情,请参阅:

  • DisplayWindowSettings#shouldShowImeLocked()
  • DisplayWindowSettings#setShouldShowImeLocked()

图 1. 在辅助屏幕上显示 IME 软件键盘,包括目标应用

系统使用一个 IME,但可以在屏幕之间切换,以跟踪用户焦点。Android 10 默认所有第一方和第三方 IME 在创建时都会根据新屏幕的尺寸调整布局和大小。

如果屏幕 A 上有一个活动连接,并且屏幕 B 上的输入字段请求获得输入焦点,则会触发以下流程:

  1. 屏幕 B 上的输入字段发出一个新的输入连接。
  2. InputMethodManagerService 检查是否应该批准该连接。
  3. 系统为该 IME 选择一个屏幕。如果屏幕 B 支持且允许显示 IME,则使用屏幕 B。否则,将选择设备的主屏幕。
  4. 如果所选屏幕并非来自屏幕 A,则重新建立连接。系统会销毁 InputMethodService,然后重新创建它。

安全限制

系统不会在不属于自己的虚拟屏幕上显示 IME。这是出于安全方面的考虑,因为恶意应用可能会创建启用系统装饰支持的虚拟屏幕,并从界面读取用户敏感信息(例如输入预测和自定义背景)。

实现

在 Android 9(及更低版本)中,IME 只能在默认屏幕上使用,如屏幕输入法中所述。在 Android 10(及更高版本)中,用户可以通过切换焦点在不同屏幕上的不同输入文本字段之间切换,IME 窗口会移动到辅助屏幕上。

WindowManager 中的实现会跟踪输入法窗口(绘制软件键盘的 IME 窗口)和输入法目标窗口(IME 输入所在的窗口),以管理 IME 状态。

对于 InputMethodManagerService (IMMS),将焦点移至另一个屏幕时,没有其他内置机制可以将屏幕更改传递给 InputMethodService (IMS),并在运行时重新配置键盘布局。

为了实现在屏幕之间切换 IME 窗口,Android 10 实现了以下功能:

  • 现在,可以在 DisplayContent#mInputMethodWindowDisplayContent#mInputMethodTarget 中跟踪每个屏幕的 IME 和输入目标窗口,以便 WindowManager (WM) 可以单独管理每个屏幕的 IME 焦点状态。
  • 在 IMMS 端,当通过 ViewRootImpl#handleWindowFocusChanged -> InputMethodManager#onPostWindowFocus -> IMMS#startInputOrWindowGainedFocus 收到来自外部屏幕的应用客户端焦点请求时,它会先取消绑定当前的输入法服务,然后再重新绑定该服务,以在 onServiceConnected() 中重新附加针对该外部屏幕的新 IME 窗口令牌。
  • 在 IMS 端,收到 IMS#attachToken 后,将触发以下流程:
    • 调用 ContextImpl#updateDisplay,以在 InputMethodService#attachToken() 中更新服务上下文的屏幕。这会调用 ViewGroup#addView() 来调整键盘布局并适应检查当前上下文的目标屏幕。
    • 调用 DisplayContent#setInputMethodWindowLocked() 之后,该实现使用 WindowProcessController 将进程级屏幕配置更改发送给 IME 进程,以替换资源和屏幕指标。
    • 调用 onConfigurationChanged()ViewGroup#addView() 之后,InputMethodService 客户端将获得合适的配置(其中包含正确的屏幕指标)来重新初始化输入视图。

多会话输入法支持

具有多个屏幕的设备实现可供多个用户同时使用来提供合适的输入来源,这些实现可以配置为同时显示多个输入法 (IME),每个屏幕最多显示一个。下面的两个图显示了两个屏幕上的多会话 IME 示例:

图 2. 多会话 IME 示例

图 3. 多会话 IME 示例

支持每屏幕焦点是启用此功能的前提。如果不支持,则无法启用此功能。由于安全限制,每屏幕焦点限制规定只有一小部分设备支持此功能。

在 Android 10 中,对多会话 IME 的支持是通过不同的系统服务实现的,这些服务具有一组不同的 API 和简化的功能。多会话 IME 与现有 IME 不兼容。可以使用多会话服务,也可以使用单会话服务,但不能同时使用这两者。

无法使用基于 InputMethodService 类构建的现有 Android IME,这是因为一次只能有一个 IME 客户端作为目标客户端的假设是在 Android 1.5 中推出 Android IME API 之前提出的,因而 InputMethodService 中的许多公共 API 在很大程度上都是基于这种假设构建的。然而,通过更新 InputMethodService 类来支持多客户端情景也并非易事,这是因为:

  1. 这样做会极大地增加 InputMethodService 的复杂性,而该服务本就已经很难维护了。
  2. IME 开发者仍然需要更新其实现才能支持来自多个目标 IME 客户端的并行请求,这可能需要他们进行大范围的重新设计(例如输入解码器和输入历史数据库)。
  3. 多 IME 客户端的实际用例会快速演变,导致新协议不稳定,也无法作为公共 API 提供。

与单会话(常规)IME 一样,将使用 DisplayWindowSettings 控制 IME 在各个屏幕上的显示。

development/samples/MultiClientInputMethod 中提供了多会话 IME 示例。

如需测试多会话 IME,请执行以下操作:

  1. config_perDisplayFocusEnabled 设置为 true
  2. 运行以下命令:
    1. $ make -j MultiClientInputMethod
    2. $ adb install -r $OUT/system/priv-app/MultiClientInputMethod/MultiClientInputMethod.apk
    3. $ adb root
    4. $ adb shell setprop persist.debug.multi_client_ime \
      com.example.android.multiclientinputmethod/.MultiClientInputMethod
    5. $ adb reboot
  3. 尝试多个文本输入情景。

实现

如需了解实现详情,请参阅 MultiClientInputMethodManagerService