Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8660296a authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Automerger Merge Worker
Browse files

Merge changes from topics "265180342", "265979516_cts" into tm-qpr-dev am:...

Merge changes from topics "265180342", "265979516_cts" into tm-qpr-dev am: a9680091 am: e48ab2d2

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21023544



Change-Id: I906e0453a68b967e549c1c8938c900212fea6f05
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 8b074349 e48ab2d2
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -2342,6 +2342,14 @@
    <!-- Removed control in management screen [CHAR LIMIT=20] -->
    <!-- Removed control in management screen [CHAR LIMIT=20] -->
    <string name="controls_removed">Removed</string>
    <string name="controls_removed">Removed</string>


    <!-- Title for the dialog presented to the user to authorize this app to display a Device
         controls panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=30] -->
    <string name="controls_panel_authorization_title">Add <xliff:g id="appName" example="My app">%s</xliff:g>?</string>

    <!-- Shows in a dialog presented to the user to authorize this app to display a Device controls
         panel (embedded activity) instead of controls rendered by SystemUI [CHAR LIMIT=NONE] -->
    <string name="controls_panel_authorization">When you add <xliff:g id="appName" example="My app">%s</xliff:g>, it can add controls and content to this panel. In some apps, you can choose which controls show up here.</string>

    <!-- a11y state description for a control that is currently favorited [CHAR LIMIT=NONE] -->
    <!-- a11y state description for a control that is currently favorited [CHAR LIMIT=NONE] -->
    <string name="accessibility_control_favorite">Favorited</string>
    <string name="accessibility_control_favorite">Favorited</string>
    <!-- a11y state description for a control that is currently favorited with its position [CHAR LIMIT=NONE] -->
    <!-- a11y state description for a control that is currently favorited with its position [CHAR LIMIT=NONE] -->
@@ -2491,6 +2499,8 @@
    <string name="controls_menu_add">Add controls</string>
    <string name="controls_menu_add">Add controls</string>
    <!-- Controls menu, edit [CHAR_LIMIT=30] -->
    <!-- Controls menu, edit [CHAR_LIMIT=30] -->
    <string name="controls_menu_edit">Edit controls</string>
    <string name="controls_menu_edit">Edit controls</string>
    <!-- Controls menu, add another app [CHAR LIMIT=30] -->
    <string name="controls_menu_add_another_app">Add app</string>


    <!-- Title for the media output dialog with media related devices [CHAR LIMIT=50] -->
    <!-- Title for the media output dialog with media related devices [CHAR LIMIT=50] -->
    <string name="media_output_dialog_add_output">Add outputs</string>
    <string name="media_output_dialog_add_output">Add outputs</string>
+2 −0
Original line number Original line Diff line number Diff line
@@ -188,6 +188,8 @@ interface ControlsController : UserAwareController {
    /** See [ControlsUiController.getPreferredSelectedItem]. */
    /** See [ControlsUiController.getPreferredSelectedItem]. */
    fun getPreferredSelection(): SelectedItem
    fun getPreferredSelection(): SelectedItem


    fun setPreferredSelection(selectedItem: SelectedItem)

    /**
    /**
     * Bind to a service that provides a Device Controls panel (embedded activity). This will allow
     * Bind to a service that provides a Device Controls panel (embedded activity). This will allow
     * the app to remain "warm", and reduce latency.
     * the app to remain "warm", and reduce latency.
+12 −0
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.systemui.backup.BackupHelper
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
@@ -63,6 +64,7 @@ class ControlsControllerImpl @Inject constructor (
    private val listingController: ControlsListingController,
    private val listingController: ControlsListingController,
    private val userFileManager: UserFileManager,
    private val userFileManager: UserFileManager,
    private val userTracker: UserTracker,
    private val userTracker: UserTracker,
    private val authorizedPanelsRepository: AuthorizedPanelsRepository,
    optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
    optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
    dumpManager: DumpManager,
    dumpManager: DumpManager,
) : Dumpable, ControlsController {
) : Dumpable, ControlsController {
@@ -251,6 +253,11 @@ class ControlsControllerImpl @Inject constructor (
    private fun resetFavorites() {
    private fun resetFavorites() {
        Favorites.clear()
        Favorites.clear()
        Favorites.load(persistenceWrapper.readFavorites())
        Favorites.load(persistenceWrapper.readFavorites())
        // After loading favorites, add the package names of any apps with favorites to the list
        // of authorized panels. That way, if the user has previously favorited controls for an app,
        // that panel will be authorized.
        authorizedPanelsRepository.addAuthorizedPanels(
                Favorites.getAllStructures().map { it.componentName.packageName }.toSet())
    }
    }


    private fun confirmAvailability(): Boolean {
    private fun confirmAvailability(): Boolean {
@@ -491,6 +498,7 @@ class ControlsControllerImpl @Inject constructor (
        if (!confirmAvailability()) return
        if (!confirmAvailability()) return
        executor.execute {
        executor.execute {
            if (Favorites.addFavorite(componentName, structureName, controlInfo)) {
            if (Favorites.addFavorite(componentName, structureName, controlInfo)) {
                authorizedPanelsRepository.addAuthorizedPanels(setOf(componentName.packageName))
                persistenceWrapper.storeFavorites(Favorites.getAllStructures())
                persistenceWrapper.storeFavorites(Favorites.getAllStructures())
            }
            }
        }
        }
@@ -557,6 +565,10 @@ class ControlsControllerImpl @Inject constructor (
        return uiController.getPreferredSelectedItem(getFavorites())
        return uiController.getPreferredSelectedItem(getFavorites())
    }
    }


    override fun setPreferredSelection(selectedItem: SelectedItem) {
        uiController.updatePreferences(selectedItem)
    }

    override fun dump(pw: PrintWriter, args: Array<out String>) {
    override fun dump(pw: PrintWriter, args: Array<out String>) {
        pw.println("ControlsController state:")
        pw.println("ControlsController state:")
        pw.println("  Changing users: $userChanging")
        pw.println("  Changing users: $userChanging")
+22 −13
Original line number Original line Diff line number Diff line
@@ -50,9 +50,10 @@ class AppAdapter(
        lifecycle: Lifecycle,
        lifecycle: Lifecycle,
        controlsListingController: ControlsListingController,
        controlsListingController: ControlsListingController,
        private val layoutInflater: LayoutInflater,
        private val layoutInflater: LayoutInflater,
    private val onAppSelected: (ComponentName?) -> Unit = {},
        private val onAppSelected: (ControlsServiceInfo) -> Unit = {},
        private val favoritesRenderer: FavoritesRenderer,
        private val favoritesRenderer: FavoritesRenderer,
    private val resources: Resources
        private val resources: Resources,
        private val authorizedPanels: Set<String> = emptySet(),
) : RecyclerView.Adapter<AppAdapter.Holder>() {
) : RecyclerView.Adapter<AppAdapter.Holder>() {


    private var listOfServices = emptyList<ControlsServiceInfo>()
    private var listOfServices = emptyList<ControlsServiceInfo>()
@@ -64,8 +65,10 @@ class AppAdapter(
                val localeComparator = compareBy<ControlsServiceInfo, CharSequence>(collator) {
                val localeComparator = compareBy<ControlsServiceInfo, CharSequence>(collator) {
                    it.loadLabel() ?: ""
                    it.loadLabel() ?: ""
                }
                }
                listOfServices = serviceInfos.filter { it.panelActivity == null }
                // No panel or the panel is not authorized
                        .sortedWith(localeComparator)
                listOfServices = serviceInfos.filter {
                    it.panelActivity == null || it.panelActivity?.packageName !in authorizedPanels
                }.sortedWith(localeComparator)
                uiExecutor.execute(::notifyDataSetChanged)
                uiExecutor.execute(::notifyDataSetChanged)
            }
            }
        }
        }
@@ -86,8 +89,8 @@ class AppAdapter(


    override fun onBindViewHolder(holder: Holder, index: Int) {
    override fun onBindViewHolder(holder: Holder, index: Int) {
        holder.bindData(listOfServices[index])
        holder.bindData(listOfServices[index])
        holder.itemView.setOnClickListener {
        holder.view.setOnClickListener {
            onAppSelected(ComponentName.unflattenFromString(listOfServices[index].key))
            onAppSelected(listOfServices[index])
        }
        }
    }
    }


@@ -95,6 +98,8 @@ class AppAdapter(
     * Holder for binding views in the [RecyclerView]-
     * Holder for binding views in the [RecyclerView]-
     */
     */
    class Holder(view: View, val favRenderer: FavoritesRenderer) : RecyclerView.ViewHolder(view) {
    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 icon: ImageView = itemView.requireViewById(com.android.internal.R.id.icon)
        private val title: TextView = itemView.requireViewById(com.android.internal.R.id.title)
        private val title: TextView = itemView.requireViewById(com.android.internal.R.id.title)
        private val favorites: TextView = itemView.requireViewById(R.id.favorites)
        private val favorites: TextView = itemView.requireViewById(R.id.favorites)
@@ -106,7 +111,11 @@ class AppAdapter(
        fun bindData(data: ControlsServiceInfo) {
        fun bindData(data: ControlsServiceInfo) {
            icon.setImageDrawable(data.loadIcon())
            icon.setImageDrawable(data.loadIcon())
            title.text = data.loadLabel()
            title.text = data.loadLabel()
            val text = favRenderer.renderFavoritesForComponent(data.componentName)
            val text = if (data.panelActivity == null) {
                favRenderer.renderFavoritesForComponent(data.componentName)
            } else {
                null
            }
            favorites.text = text
            favorites.text = text
            favorites.visibility = if (text == null) View.GONE else View.VISIBLE
            favorites.visibility = if (text == null) View.GONE else View.VISIBLE
        }
        }
+44 −6
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.controls.management
package com.android.systemui.controls.management


import android.app.ActivityOptions
import android.app.ActivityOptions
import android.app.Dialog
import android.content.ComponentName
import android.content.ComponentName
import android.content.Context
import android.content.Context
import android.content.Intent
import android.content.Intent
@@ -31,12 +32,15 @@ import android.widget.TextView
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedCallback
import android.window.OnBackInvokedDispatcher
import android.window.OnBackInvokedDispatcher
import androidx.activity.ComponentActivity
import androidx.activity.ComponentActivity
import androidx.annotation.VisibleForTesting
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.R
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.panels.AuthorizedPanelsRepository
import com.android.systemui.controls.ui.ControlsActivity
import com.android.systemui.controls.ui.ControlsActivity
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.controls.ui.SelectedItem
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.UserTracker
import com.android.systemui.settings.UserTracker
@@ -52,7 +56,8 @@ open class ControlsProviderSelectorActivity @Inject constructor(
    private val listingController: ControlsListingController,
    private val listingController: ControlsListingController,
    private val controlsController: ControlsController,
    private val controlsController: ControlsController,
    private val userTracker: UserTracker,
    private val userTracker: UserTracker,
    private val uiController: ControlsUiController
    private val authorizedPanelsRepository: AuthorizedPanelsRepository,
    private val panelConfirmationDialogFactory: PanelConfirmationDialogFactory
) : ComponentActivity() {
) : ComponentActivity() {


    companion object {
    companion object {
@@ -72,6 +77,7 @@ open class ControlsProviderSelectorActivity @Inject constructor(
            }
            }
        }
        }
    }
    }
    private var dialog: Dialog? = null


    private val mOnBackInvokedCallback = OnBackInvokedCallback {
    private val mOnBackInvokedCallback = OnBackInvokedCallback {
        if (DEBUG) {
        if (DEBUG) {
@@ -138,9 +144,11 @@ open class ControlsProviderSelectorActivity @Inject constructor(
                lifecycle,
                lifecycle,
                listingController,
                listingController,
                LayoutInflater.from(this),
                LayoutInflater.from(this),
                ::launchFavoritingActivity,
                ::onAppSelected,
                FavoritesRenderer(resources, controlsController::countFavoritesForComponent),
                FavoritesRenderer(resources, controlsController::countFavoritesForComponent),
                resources).apply {
                resources,
                authorizedPanelsRepository.getAuthorizedPanels()
        ).apply {
            registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
            registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
                var hasAnimated = false
                var hasAnimated = false
                override fun onChanged() {
                override fun onChanged() {
@@ -167,13 +175,35 @@ open class ControlsProviderSelectorActivity @Inject constructor(
            Log.d(TAG, "Unregistered onBackInvokedCallback")
            Log.d(TAG, "Unregistered onBackInvokedCallback")
        }
        }
        onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback)
        onBackInvokedDispatcher.unregisterOnBackInvokedCallback(mOnBackInvokedCallback)
        dialog?.cancel()
    }

    fun onAppSelected(serviceInfo: ControlsServiceInfo) {
        dialog?.cancel()
        if (serviceInfo.panelActivity == null) {
            launchFavoritingActivity(serviceInfo.componentName)
        } else {
            val appName = serviceInfo.loadLabel() ?: ""
            dialog = panelConfirmationDialogFactory.createConfirmationDialog(this, appName) { ok ->
                if (ok) {
                    authorizedPanelsRepository.addAuthorizedPanels(
                            setOf(serviceInfo.componentName.packageName)
                    )
                    animateExitAndFinish()
                    val selected = SelectedItem.PanelItem(appName, componentName)
                    controlsController.setPreferredSelection(selected)
                    openControlsOrigin()
                }
                dialog = null
            }.also { it.show() }
        }
    }
    }


    /**
    /**
     * Launch the [ControlsFavoritingActivity] for the specified component.
     * Launch the [ControlsFavoritingActivity] for the specified component.
     * @param component a component name for a [ControlsProviderService]
     * @param component a component name for a [ControlsProviderService]
     */
     */
    fun launchFavoritingActivity(component: ComponentName?) {
    private fun launchFavoritingActivity(component: ComponentName?) {
        executor.execute {
        executor.execute {
            component?.let {
            component?.let {
                val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java)
                val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java)
@@ -194,7 +224,15 @@ open class ControlsProviderSelectorActivity @Inject constructor(
        super.onDestroy()
        super.onDestroy()
    }
    }


    private fun animateExitAndFinish() {
    private fun openControlsOrigin() {
        startActivity(
                Intent(applicationContext, ControlsActivity::class.java),
                ActivityOptions.makeSceneTransitionAnimation(this).toBundle()
        )
    }

    @VisibleForTesting
    internal open fun animateExitAndFinish() {
        val rootView = requireViewById<ViewGroup>(R.id.controls_management_root)
        val rootView = requireViewById<ViewGroup>(R.id.controls_management_root)
        ControlsAnimations.exitAnimation(
        ControlsAnimations.exitAnimation(
                rootView,
                rootView,
Loading