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

Commit 6568631f authored by Anton Potapov's avatar Anton Potapov
Browse files

Add test utilities to simplify writing tests for new tiles

Test: atest QsTileIntentUserInputHandlerTest
Flag: LEGACY QS_PIPELINE_NEW_TILES DISABLED
Bug: 299909368
Change-Id: I85ecbe35fb8784a0f7a2ef8feffa63818c5bb891
parent 7a17d789
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -29,12 +29,18 @@ import javax.inject.Inject
 * Provides a shortcut to start an activity from [QSTileUserActionInteractor]. It supports keyguard
 * dismissing and tile from-view animations.
 */
interface QSTileIntentUserInputHandler {

    fun handle(view: View?, intent: Intent)
    fun handle(view: View?, pendingIntent: PendingIntent)
}

@SysUISingleton
class QSTileIntentUserInputHandler
class QSTileIntentUserInputHandlerImpl
@Inject
constructor(private val activityStarter: ActivityStarter) {
constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler {

    fun handle(view: View?, intent: Intent) {
    override fun handle(view: View?, intent: Intent) {
        val animationController: ActivityLaunchAnimator.Controller? =
            view?.let {
                ActivityLaunchAnimator.Controller.fromView(
@@ -46,7 +52,7 @@ constructor(private val activityStarter: ActivityStarter) {
    }

    // TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939
    fun handle(view: View?, pendingIntent: PendingIntent) {
    override fun handle(view: View?, pendingIntent: PendingIntent) {
        if (!pendingIntent.isActivity) {
            return
        }
+7 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.qs.tiles.di

import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerImpl
import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider
@@ -45,4 +47,9 @@ interface QSTilesModule {
    @Multibinds fun tileViewModelMap(): Map<String, QSTileViewModel>

    @Binds fun bindQSTileConfigProvider(impl: QSTileConfigProviderImpl): QSTileConfigProvider

    @Binds
    fun bindQSTileIntentUserInputHandler(
        impl: QSTileIntentUserInputHandlerImpl
    ): QSTileIntentUserInputHandler
}
+1 −1
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ class QSTileIntentUserInputHandlerTest : SysuiTestCase() {
    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)
        underTest = QSTileIntentUserInputHandler(activityStarted)
        underTest = QSTileIntentUserInputHandlerImpl(activityStarted)
    }

    @Test
+52 −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.qs.tiles.base.actions

import android.app.PendingIntent
import android.content.Intent
import android.view.View

/**
 * Fake implementation of [QSTileIntentUserInputHandler] interface. Consider using this alongside
 * [QSTileIntentUserInputHandlerSubject].
 */
class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler {

    val handledInputs: List<Input>
        get() = mutableInputs

    private val mutableInputs = mutableListOf<Input>()

    override fun handle(view: View?, intent: Intent) {
        mutableInputs.add(Input.Intent(view, intent))
    }

    override fun handle(view: View?, pendingIntent: PendingIntent) {
        mutableInputs.add(Input.PendingIntent(view, pendingIntent))
    }

    sealed interface Input {
        data class Intent(val view: View?, val intent: android.content.Intent) : Input
        data class PendingIntent(val view: View?, val pendingIntent: android.app.PendingIntent) :
            Input
    }
}

val FakeQSTileIntentUserInputHandler.intentInputs
    get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.Intent }
val FakeQSTileIntentUserInputHandler.pendingIntentInputs
    get() = handledInputs.mapNotNull { it as? FakeQSTileIntentUserInputHandler.Input.PendingIntent }
+76 −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.qs.tiles.base.actions

import com.google.common.truth.FailureMetadata
import com.google.common.truth.Subject
import com.google.common.truth.Truth

/** [Truth] [Subject] to assert inputs handled by [FakeQSTileIntentUserInputHandler] */
class QSTileIntentUserInputHandlerSubject
private constructor(
    failureMetadata: FailureMetadata,
    private val subject: FakeQSTileIntentUserInputHandler
) : Subject(failureMetadata, subject) {

    fun handledOneIntentInput(
        intentAssertions: (FakeQSTileIntentUserInputHandler.Input.Intent) -> Unit = {},
    ) {
        // check that there are no other inputs
        check("handledInputs").that(subject.handledInputs).hasSize(1)
        // check there is an intent input
        check("intentInputs").that(subject.intentInputs).hasSize(1)

        intentAssertions(subject.intentInputs.first())
    }

    fun handledOnePendingIntentInput(
        intentAssertions: (FakeQSTileIntentUserInputHandler.Input.PendingIntent) -> Unit = {},
    ) {
        // check that there are no other inputs
        check("handledInputs").that(subject.handledInputs).hasSize(1)
        // check there is a pending intent input
        check("intentInputs").that(subject.pendingIntentInputs).hasSize(1)

        intentAssertions(subject.pendingIntentInputs.first())
    }

    fun handledNoInputs() {
        check("handledInputs").that(subject.handledInputs).isEmpty()
    }

    companion object {

        /**
         * [Truth.assertThat]-like factory to initialize the assertion. Example:
         * ```
         *  assertThat(inputHandler).handledOneIntentInput {
         *      assertThat(it.intent.action).isEqualTo("action.Test")
         *  }
         * ```
         */
        fun assertThat(
            handler: FakeQSTileIntentUserInputHandler
        ): QSTileIntentUserInputHandlerSubject =
            Truth.assertAbout {
                    failureMetadata: FailureMetadata,
                    subject: FakeQSTileIntentUserInputHandler ->
                    QSTileIntentUserInputHandlerSubject(failureMetadata, subject)
                }
                .that(handler)
    }
}
Loading