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

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

Merge "Add Open app in overflow menu" into tm-qpr-dev am: 2f927cff am: b6e02711

parents ebd915c9 b6e02711
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -189,9 +189,9 @@ open class ControlsProviderSelectorActivity @Inject constructor(
                    authorizedPanelsRepository.addAuthorizedPanels(
                            setOf(serviceInfo.componentName.packageName)
                    )
                    animateExitAndFinish()
                    val selected = SelectedItem.PanelItem(appName, componentName)
                    controlsController.setPreferredSelection(selected)
                    animateExitAndFinish()
                    openControlsOrigin()
                }
                dialog = null
+84 −30
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
@@ -38,6 +39,7 @@ import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.BaseAdapter
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
@@ -90,6 +92,7 @@ private data class ControlKey(val componentName: ComponentName, val controlId: S
class ControlsUiControllerImpl @Inject constructor (
        val controlsController: Lazy<ControlsController>,
        val context: Context,
        private val packageManager: PackageManager,
        @Main val uiExecutor: DelayableExecutor,
        @Background val bgExecutor: DelayableExecutor,
        val controlsListingController: Lazy<ControlsListingController>,
@@ -113,6 +116,11 @@ class ControlsUiControllerImpl @Inject constructor (
        private const val PREF_IS_PANEL = "controls_is_panel"

        private const val FADE_IN_MILLIS = 200L

        private const val OPEN_APP_ID = 0L
        private const val ADD_CONTROLS_ID = 1L
        private const val ADD_APP_ID = 2L
        private const val EDIT_CONTROLS_ID = 3L
    }

    private var selectedItem: SelectedItem = SelectedItem.EMPTY_SELECTION
@@ -140,6 +148,9 @@ class ControlsUiControllerImpl @Inject constructor (
        it.getTitle()
    }

    private var openAppIntent: Intent? = null
    private var overflowMenuAdapter: BaseAdapter? = null

    private val onSeedingComplete = Consumer<Boolean> {
        accepted ->
            if (accepted) {
@@ -216,6 +227,8 @@ class ControlsUiControllerImpl @Inject constructor (
        this.parent = parent
        this.onDismiss = onDismiss
        this.activityContext = activityContext
        this.openAppIntent = null
        this.overflowMenuAdapter = null
        hidden = false
        retainCache = false

@@ -306,6 +319,12 @@ class ControlsUiControllerImpl @Inject constructor (
        startTargetedActivity(si, ControlsEditingActivity::class.java)
    }

    private fun startDefaultActivity() {
        openAppIntent?.let {
            startActivity(it, animateExtra = false)
        }
    }

    private fun startTargetedActivity(si: StructureInfo, klazz: Class<*>) {
        val i = Intent(activityContext, klazz)
        putIntentExtras(i, si)
@@ -329,9 +348,11 @@ class ControlsUiControllerImpl @Inject constructor (
        startActivity(i)
    }

    private fun startActivity(intent: Intent) {
    private fun startActivity(intent: Intent, animateExtra: Boolean = true) {
        // Force animations when transitioning from a dialog to an activity
        if (animateExtra) {
            intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true)
        }

        if (keyguardStateController.isShowing()) {
            activityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */)
@@ -383,8 +404,31 @@ class ControlsUiControllerImpl @Inject constructor (
            Log.w(ControlsUiController.TAG, "Not TaskViewFactory to display panel $selectionItem")
        }

        bgExecutor.execute {
            val intent = Intent(Intent.ACTION_MAIN)
                    .addCategory(Intent.CATEGORY_LAUNCHER)
                    .setPackage(selectionItem.componentName.packageName)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or
                            Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
            val intents = packageManager
                    .queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(0L))
            intents.firstOrNull { it.activityInfo.exported }?.let { resolved ->
                intent.setPackage(null)
                intent.setComponent(resolved.activityInfo.componentName)
                openAppIntent = intent
                parent.post {
                    // This will call show on the PopupWindow in the same thread, so make sure this
                    // happens in the view thread.
                    overflowMenuAdapter?.notifyDataSetChanged()
                }
            }
        }
        createDropDown(panelsAndStructures, selectionItem)
        createMenu()

        val currentApps = panelsAndStructures.map { it.componentName }.toSet()
        val allApps = controlsListingController.get()
                .getCurrentServices().map { it.componentName }.toSet()
        createMenu(extraApps = (allApps - currentApps).isNotEmpty())
    }

    private fun createPanelView(componentName: ComponentName) {
@@ -423,28 +467,41 @@ class ControlsUiControllerImpl @Inject constructor (
        }
    }

    private fun createMenu() {
    private fun createMenu(extraApps: Boolean) {
        val isPanel = selectedItem is SelectedItem.PanelItem
        val selectedStructure = (selectedItem as? SelectedItem.StructureItem)?.structure
                ?: EMPTY_STRUCTURE
        val newFlows = featureFlags.isEnabled(Flags.CONTROLS_MANAGEMENT_NEW_FLOWS)
        val addControlsId = if (newFlows || isPanel) {
            R.string.controls_menu_add_another_app

        val items = buildList {
            add(OverflowMenuAdapter.MenuItem(
                    context.getText(R.string.controls_open_app),
                    OPEN_APP_ID
            ))
            if (newFlows || isPanel) {
                if (extraApps) {
                    add(OverflowMenuAdapter.MenuItem(
                            context.getText(R.string.controls_menu_add_another_app),
                            ADD_APP_ID
                    ))
                }
            } else {
            R.string.controls_menu_add
                add(OverflowMenuAdapter.MenuItem(
                        context.getText(R.string.controls_menu_add),
                        ADD_CONTROLS_ID
                ))
            }
            if (!isPanel) {
                add(OverflowMenuAdapter.MenuItem(
                        context.getText(R.string.controls_menu_edit),
                        EDIT_CONTROLS_ID
                ))
            }
        }

        val items = if (isPanel) {
            arrayOf(
                    context.resources.getString(addControlsId),
            )
        } else {
            arrayOf(
                    context.resources.getString(addControlsId),
                    context.resources.getString(R.string.controls_menu_edit)
            )
        val adapter = OverflowMenuAdapter(context, R.layout.controls_more_item, items) { position ->
                getItemId(position) != OPEN_APP_ID || openAppIntent != null
        }
        var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items)

        val anchor = parent.requireViewById<ImageView>(R.id.controls_more)
        anchor.setOnClickListener(object : View.OnClickListener {
@@ -462,25 +519,21 @@ class ControlsUiControllerImpl @Inject constructor (
                            pos: Int,
                            id: Long
                        ) {
                            when (pos) {
                                // 0: Add Control
                                0 -> {
                                    if (isPanel || newFlows) {
                                        startProviderSelectorActivity()
                                    } else {
                                        startFavoritingActivity(selectedStructure)
                                    }
                                }
                                // 1: Edit controls
                                1 -> startEditingActivity(selectedStructure)
                            when (id) {
                                OPEN_APP_ID -> startDefaultActivity()
                                ADD_APP_ID -> startProviderSelectorActivity()
                                ADD_CONTROLS_ID -> startFavoritingActivity(selectedStructure)
                                EDIT_CONTROLS_ID -> startEditingActivity(selectedStructure)
                            }
                            dismiss()
                        }
                    })
                    show()
                    listView?.post { listView?.requestAccessibilityFocus() }
                }
            }
        })
        overflowMenuAdapter = adapter
    }

    private fun createDropDown(items: List<SelectionItem>, selected: SelectionItem) {
@@ -542,6 +595,7 @@ class ControlsUiControllerImpl @Inject constructor (
                        }
                    })
                    show()
                    listView?.post { listView?.requestAccessibilityFocus() }
                }
            }
        })
@@ -631,7 +685,7 @@ class ControlsUiControllerImpl @Inject constructor (
                .putString(PREF_COMPONENT, selectedItem.componentName.flattenToString())
                .putString(PREF_STRUCTURE_OR_APP_NAME, selectedItem.name.toString())
                .putBoolean(PREF_IS_PANEL, selectedItem is SelectedItem.PanelItem)
                .commit()
                .apply()
    }

    private fun maybeUpdateSelectedItem(item: SelectionItem): Boolean {
+42 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.ui

import android.content.Context
import android.widget.ArrayAdapter
import androidx.annotation.LayoutRes

open class OverflowMenuAdapter(
    context: Context,
    @LayoutRes layoutId: Int,
    itemsWithIds: List<MenuItem>,
    private val isEnabledInternal: OverflowMenuAdapter.(Int) -> Boolean
) : ArrayAdapter<CharSequence>(context, layoutId, itemsWithIds.map(MenuItem::text)) {

    private val ids = itemsWithIds.map(MenuItem::id)

    override fun getItemId(position: Int): Long {
        return ids[position]
    }

    override fun isEnabled(position: Int): Boolean {
        return isEnabledInternal(position)
    }

    data class MenuItem(val text: CharSequence, val id: Long)
}
+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.pm.ServiceInfo
import android.os.UserHandle
import android.service.controls.ControlsProviderService
@@ -95,6 +96,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
    @Mock lateinit var dumpManager: DumpManager
    @Mock lateinit var authorizedPanelsRepository: AuthorizedPanelsRepository
    @Mock lateinit var featureFlags: FeatureFlags
    @Mock lateinit var packageManager: PackageManager
    val sharedPreferences = FakeSharedPreferences()
    lateinit var controlsSettingsRepository: FakeControlsSettingsRepository

@@ -124,6 +126,7 @@ class ControlsUiControllerImplTest : SysuiTestCase() {
            ControlsUiControllerImpl(
                Lazy { controlsController },
                context,
                packageManager,
                uiExecutor,
                bgExecutor,
                Lazy { controlsListingController },
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.ui

import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidTestingRunner::class)
class OverflowMenuAdapterTest : SysuiTestCase() {

    @Test
    fun testGetItemId() {
        val ids = listOf(27L, 73L)
        val labels = listOf("first", "second")
        val adapter =
            OverflowMenuAdapter(
                context,
                layoutId = 0,
                labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
            ) { true }

        ids.forEachIndexed { index, id -> assertThat(adapter.getItemId(index)).isEqualTo(id) }
    }

    @Test
    fun testCheckEnabled() {
        val ids = listOf(27L, 73L)
        val labels = listOf("first", "second")
        val adapter =
            OverflowMenuAdapter(
                context,
                layoutId = 0,
                labels.zip(ids).map { OverflowMenuAdapter.MenuItem(it.first, it.second) }
            ) { position -> position == 0 }

        assertThat(adapter.isEnabled(0)).isTrue()
        assertThat(adapter.isEnabled(1)).isFalse()
    }
}