/* * Copyright (C) 2019 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.systemui.controls.management import android.content.ComponentName import android.content.res.Resources import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView import com.android.systemui.R import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.util.icuMessageFormat import java.text.Collator import java.util.concurrent.Executor /** * Adapter for binding [ControlsServiceInfo] related to [ControlsProviderService]. * * This class handles subscribing and keeping track of the list of valid applications for * displaying. * * @param uiExecutor an executor on the view thread of the containing [RecyclerView] * @param lifecycle the lifecycle of the containing [LifecycleOwner] to control listening status * @param controlsListingController the controller to keep track of valid applications * @param layoutInflater an inflater for the views in the containing [RecyclerView] * @param onAppSelected a callback to indicate that an app has been selected in the list. */ class AppAdapter( backgroundExecutor: Executor, uiExecutor: Executor, lifecycle: Lifecycle, controlsListingController: ControlsListingController, private val layoutInflater: LayoutInflater, private val onAppSelected: (ControlsServiceInfo) -> Unit = {}, private val favoritesRenderer: FavoritesRenderer, private val resources: Resources, private val authorizedPanels: Set = emptySet(), ) : RecyclerView.Adapter() { private var listOfServices = emptyList() private val callback = object : ControlsListingController.ControlsListingCallback { override fun onServicesUpdated(serviceInfos: List) { backgroundExecutor.execute { val collator = Collator.getInstance(resources.configuration.locales[0]) val localeComparator = compareBy(collator) { it.loadLabel() ?: "" } // No panel or the panel is not authorized listOfServices = serviceInfos.filter { it.panelActivity == null || it.panelActivity?.packageName !in authorizedPanels }.sortedWith(localeComparator) uiExecutor.execute(::notifyDataSetChanged) } } } init { controlsListingController.observe(lifecycle, callback) } override fun onCreateViewHolder(parent: ViewGroup, i: Int): Holder { return Holder( layoutInflater.inflate(R.layout.controls_app_item, parent, false), favoritesRenderer ) } override fun getItemCount() = listOfServices.size override fun onBindViewHolder(holder: Holder, index: Int) { holder.bindData(listOfServices[index]) holder.view.setOnClickListener { onAppSelected(listOfServices[index]) } } /** * Holder for binding views in the [RecyclerView]- */ class Holder(view: View, val favRenderer: FavoritesRenderer) : RecyclerView.ViewHolder(view) { val view: View = itemView private val icon: ImageView = itemView.requireViewById(com.android.internal.R.id.icon) private val title: TextView = itemView.requireViewById(com.android.internal.R.id.title) private val favorites: TextView = itemView.requireViewById(R.id.favorites) /** * Bind data to the view * @param data Information about the [ControlsProviderService] to bind to the data */ fun bindData(data: ControlsServiceInfo) { icon.setImageDrawable(data.loadIcon()) title.text = data.loadLabel() val text = if (data.panelActivity == null) { favRenderer.renderFavoritesForComponent(data.componentName) } else { null } favorites.text = text favorites.visibility = if (text == null) View.GONE else View.VISIBLE } } } class FavoritesRenderer( private val resources: Resources, private val favoriteFunction: (ComponentName) -> Int ) { fun renderFavoritesForComponent(component: ComponentName): String? { val qty = favoriteFunction(component) return if (qty != 0) { icuMessageFormat(resources, R.string.controls_number_of_favorites, qty) } else { null } } }