/* * Copyright 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.appfunctions import android.app.appsearch.GenericDocument import androidx.annotation.Keep import com.android.settings.appfunctions.providers.DeviceStateExecutor import com.android.settings.appfunctions.providers.DeviceStateExecutorResult import com.google.android.appfunctions.schema.common.v1.devicestate.DeviceStateMetadataResponse import com.google.android.appfunctions.schema.common.v1.devicestate.DeviceStateResponse import com.google.android.appfunctions.schema.common.v1.devicestate.PerScreenDeviceStates import com.google.android.appfunctions.schema.common.v1.devicestate.PerScreenMetadata import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope /** * Orchestrates the collection and transformation of device state metadata information. * * This class executes from multiple [DeviceStateExecutor]s in parallel, aggregates the results to * produce the final [DeviceStateMetadataResponse]. * * @property executors The list of [DeviceStateExecutor]s to query for device state metadata. */ @Keep class DeviceStateMetadataProviderAggregator(private val executors: List) : DeviceStateAggregator(executors) { /** * Aggregates device state from all registered providers. * * This function performs the following steps: * 1. Calls all [DeviceStateExecutor]s concurrently to gather device state information. * 2. Combines the states and hint text from all provider results. * 3. Constructs and returns the final [DeviceStateResponse]. * * @param appFunctionType The device state app function to fetch, passed to each provider. * @param deviceLocale The current locale of the device, included in the final response. * @return A [DeviceStateResponse] containing the fully aggregated device state. */ override suspend fun aggregate( appFunctionType: DeviceStateAppFunctionType, params: GenericDocument, deviceLocale: String, ): DeviceStateMetadataResponse { val executorResults = coroutineScope { executors .map { executor -> async { executor.execute(appFunctionType) as DeviceStateMetadataProviderExecutorResult } } .map { it.await() } } val allStates = executorResults.flatMap { it.states } val allHintText = executorResults.mapNotNull { it.hintText }.joinToString(separator = "\n") return DeviceStateMetadataResponse( perScreenMetadata = allStates, deviceLocale = deviceLocale, ) } } /** * Represents the self-contained result from a single [DeviceStateExecutor]. This is an immutable * data class. * * @property states The list of [PerScreenDeviceStates] generated by the provider. * @property hintText An optional, non-parseable hint text contribution. Null if none. */ @Keep data class DeviceStateMetadataProviderExecutorResult( val states: List, val hintText: String? = null, ) : DeviceStateExecutorResult()