意图系统UI和应用示例

三个应用和一个通过意图通信的系统UI。

The Intents example with all applications running.

注意:如果您想在Linux机器上构建示例,请阅读此内容

简介

本示例展示了系统UI和应用程序如何发送和接收意图。与系统UI示例:“Hello World!”类似,为了专注于意图,窗口管理方面被降至最低:右侧的2x2网格将始终显示左上角的系统UI部分(灰色),而三个应用程序(红色、绿色和蓝色)将动态占据其他角落。您可以在左侧看到可用应用程序的名称和图标;点击它们各自的图标以启动和停止这些应用程序。

每个应用程序以及系统UI看起来都相似,并在UI中具有相同的功能:您可以在顶部的下拉框中选择一个可用的意图ID(标有“意图”),并可选地指定应处理所选请求的相应应用程序(标有“应用程序”)。点击“请求”/“广播”按钮将创建并发送相应的意图请求到应用程序管理器的IntentServer进行处理。

文件和文件夹结构

本示例包含一个系统UI和三个示例应用程序(“红色意图”、“绿色意图”和“蓝色意图”),总共四个单独的QML应用程序。系统UI最终也是一个QML应用程序,尽管它是一个特殊的应用程序。

每个应用程序都放在以下所描述的单独目录中。由于所有应用程序和系统UI都使用基于QtQuickControls 2的UI,因此其组件生活在共享目录中。

  • am-config.yaml
  • system-ui.qml
  • apps
    • intents.blue
      • icon.png
      • info.yaml
      • main.qml
    • intents.red
      • icon.png
      • info.yaml
      • main.qml
    • intents.green
      • icon.png
      • info.yaml
      • main.qml
  • shared
    • IntentsApplicationWindow.qml
    • IntentsUIPage.qml

如上图所示,每个应用程序除了主QML文件外,还有一个图标和一个info.yaml文件,该文件包含应用程序元数据,还包括该应用可以处理的目的定义。

运行示例

假设appman可执行文件在您的路径中,您可以按照以下方式运行系统UI

examples/applicationmanager/intents$ appman -c am-config.yaml

这是您应该看到的

有关am-config.yaml的内容和其他命令行选项的信息,您可以运行appman –help或查看配置文档。

应用程序实现

所有应用程序(红色、绿色和蓝色)都是相同的,它们的main.qml只是实例化了共享的IntentsApplicationWindow组件。

import "../../shared"

IntentsApplicationWindow { }

IntentsApplicationWindow组件实际上是一个顶级ApplicationManagerWindow,其UI内容是通过实例化共享的IntentsUIPage组件来定义的。这个UI组件没有任何特定于意图的代码,所以实际的发送是在连接到IntentsUIPage请求和广播信号的处理程序中完成的

onRequest: (intentId, applicationId, parameters) => {
    let request = IntentClient.sendIntentRequest(intentId, applicationId, parameters)
    request.onReplyReceived.connect(function() {
        intentPage.setResult(request.requestId, request.succeeded,
                             request.succeeded ? request.result : request.errorMessage)
    })
}

并且

onBroadcast: (intentId, parameters) => {
    IntentClient.broadcastIntentRequest(intentId, parameters)
}

在通过具有在UI中选择参数的IntentClient::sendIntentRequest调用后,示例代码将一个函数对象连接到请求的replyReceived信号。结果是放置在UI中的请求字段中。另一方面,广播不会生成回复。

此外,IntentsApplicationWindow定义了所有必要的IntentHandlers,例如

IntentHandler {
    intentIds: [ "rotate-window" ]
    onRequestReceived: (request) => {
        rotationAnimation.start()
        request.sendReply({ "done": true })
    }
}

这些intent处理程序并不复杂,每个只是触发一个在本文件中定义的基本动画,因此对于rotate-window意图来说,这将是这样

RotationAnimation on rotation {
    id: rotationAnimation
    running: false
    duration: 500; from: 0; to: 360
}

在QML中,仅实现IntentHandlers是不够的,因为应用程序管理器需要有关哪些应用程序支持哪些意图的信息。在应用程序运行之前,必须将这些信息提供给应用程序管理器,以实现基于意图请求的自动启动应用程序。对于应用程序管理器中的其他所有应用程序配置,都是通过应用程序的清单文件info.yaml来完成的

红色应用程序定义了三个可用的意图

intents:
- id: rotate-window
  name:
    en: Rotate Red
- id: scale-window
  name:
    en: Scale Red
- id: broadcast/blink-window
  name:
    en: Blink Red

此外,红色应用程序获得了call-blue功能,这是蓝色应用程序中某些意图所必需的。

capabilities: 'call-blue'

绿色应用程序只定义了两个可用的意图。请注意,即使这个应用程序通过共享的IntentsApplicationWindow组件对scale-window意图有IntentHandler,但这个处理程序永远不会被调用,因为这个意图ID没有通过info.yaml清单注册到系统中

intents:
- id: rotate-window
  name:
    en: Rotate Green
- id: broadcast/blink-window
  name:
    en: Blink Green
  handleOnlyWhenRunning: yes

除此之外,broadcast/blink-window意图被标记为handleOnlyWhenRunning: yes,这阻止了在特定意图的广播上自动启动绿色应用程序。

蓝色应用程序有最复杂的意图定义。除了处理和红色应用程序相同的三个意图外,它还注册了一个具有属性visibility: privateblue-window-private意图。私有意图只能由注册它们的同一应用程序请求,所以在这个例子中,只有蓝色能够成功请求blue-window-private意图。此外,rotate-window意图只能由具有call-blue能力的应用程序请求:在这里,红色应用程序带有所需的功能,而绿色则不具备。

intents:
- id: rotate-window
  name:
    en: Rotate Blue
  requiredCapabilities: [ 'call-blue' ]
- id: scale-window
  name:
    en: Scale Blue
- id: broadcast/blink-window
  name:
    en: Blink Blue
- id: blue-window-private
  name:
    en: Blue Private Intent
  visibility: private

系统UI实现

除了处理应用程序启动和停止的左侧栏之外,System UI还具有两个特殊功能,用于处理意图机制

  • 在系统UI中处理意图
  • 意图请求去歧义
在系统UI中处理意图

意图不仅可以在应用程序中处理,也可以在系统UI中处理。由于系统UI始终运行,我们不需要依赖 info.yaml 清单文件来定义支持的任务,而是可以直接将所需元数据的声明直接作为 IntentServerHandler 组件的属性。实际的 IntentServerHandlerIntentHandler 继承而来,因此与它的应用程序端对应部分工作方式相同:它只添加了所需的属性来定义所有元数据(例如 namesicon 等)。

IntentServerHandler {
    intentIds: [ "rotate-window" ]
    names: { "en": "Rotate System UI" }
    visibility: IntentObject.Public

    onRequestReceived: (request) => {
        rotationAnimation.start()
        request.sendReply({ "wasRequestedBy": request.requestingApplicationId })
    }
}

处理器的回调几乎与在应用程序中的一样。唯一值得注意的是,我们可以访问 requestingApplicationId 来识别请求的来源;出于安全原因,此数据对于应用程序中的意图处理器不可用。

意图请求去歧义

此示例实现了一个UI,允许用户选择如何去歧义传入的意图请求。在这里注册对IntentServer去歧义请求的登记。

Connections {
    target: IntentServer
    function onDisambiguationRequest(requestId, potentialIntents) {
        disambiguationDialog.add(requestId, potentialIntents)
    }
}

由于我们希望对系统中并行意图请求的数量保持灵活性,我们只需将传入的请求添加到队列(allRequests)。消耗该队列的 Dialog 是一个相当标准的 QtQuickControls 2 对话框,它为您提供了一个显示来自 IntentServer::disambiguationRequested() 信号的可能应用程序选择的优美UI。在按 确定取消 后,对话框将通知 IntentServer 用户的决定。

onAccepted: {
    IntentServer.acknowledgeDisambiguationRequest(currentRequest.requestId,
                                                  currentRequest.intents[handlingApplications.currentIndex]);
    showNext()
}
onRejected: {
    IntentServer.rejectDisambiguationRequest(currentRequest.requestId)
    showNext()
}

示例项目 @ code.qt.io

© 2024 Qt公司有限公司。本文件中包含的文档贡献是各自所有者的版权。本文件提供的文档根据自由软件基金会发布的 GNU自由文档许可证版本1.3 的条款提供许可。Qt及其标志是芬兰以及/或其他国家/地区的 Qt公司有限公司的商标 。所有其他商标均为其各自所有者的财产。