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

Commit b769860c authored by Zekan Qian's avatar Zekan Qian Committed by Android (Google) Code Review
Browse files

Merge "Add tests of BrowseActivity"

parents 3d9d4e5f 5387ee15
Loading
Loading
Loading
Loading
+77 −64
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.settingslib.spa.framework
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
@@ -37,6 +38,7 @@ import androidx.navigation.compose.rememberNavController
import com.android.settingslib.spa.R
import com.android.settingslib.spa.framework.common.LogCategory
import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.LocalNavController
@@ -74,48 +76,48 @@ open class BrowseActivity : ComponentActivity() {

        setContent {
            SettingsTheme {
                MainContent()
                val sppRepository by spaEnvironment.pageProviderRepository
                BrowseContent(
                    allProviders = sppRepository.getAllProviders(),
                    initialDestination = intent?.getStringExtra(KEY_DESTINATION)
                        ?: sppRepository.getDefaultStartPage(),
                    initialEntryId = intent?.getStringExtra(KEY_HIGHLIGHT_ENTRY)
                )
            }
        }
    }

    companion object {
        const val KEY_DESTINATION = "spaActivityDestination"
        const val KEY_HIGHLIGHT_ENTRY = "highlightEntry"
    }
}

@VisibleForTesting
@Composable
    private fun MainContent() {
        val sppRepository by spaEnvironment.pageProviderRepository
fun BrowseContent(
    allProviders: Collection<SettingsPageProvider>,
    initialDestination: String,
    initialEntryId: String?
) {
    val navController = rememberNavController()
        val nullPage = SettingsPage.createNull()
    CompositionLocalProvider(navController.localNavController()) {
            NavHost(
                navController = navController,
                startDestination = nullPage.sppName,
            ) {
                composable(nullPage.sppName) {}
                for (spp in sppRepository.getAllProviders()) {
                    composable(
                        route = spp.name + spp.parameter.navRoute(),
                        arguments = spp.parameter,
                    ) { navBackStackEntry ->
                        PageLogger(remember(navBackStackEntry.arguments) {
                            spp.createSettingsPage(arguments = navBackStackEntry.arguments)
                        })

                        spp.Page(navBackStackEntry.arguments)
                    }
                }
            }
            InitialDestinationNavigator()
        val controller = LocalNavController.current as NavControllerWrapperImpl
        controller.NavContent(allProviders)
        controller.InitialDestination(initialDestination, initialEntryId)
    }
}

@Composable
    private fun PageLogger(settingsPage: SettingsPage) {
private fun SettingsPageProvider.PageEvents(arguments: Bundle? = null) {
    val page = remember(arguments) { createSettingsPage(arguments) }
    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner) {
        val observer = LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_START) {
                    settingsPage.enterPage()
                page.enterPage()
            } else if (event == Lifecycle.Event.ON_STOP) {
                    settingsPage.leavePage()
                page.leavePage()
            }
        }

@@ -130,19 +132,37 @@ open class BrowseActivity : ComponentActivity() {
}

@Composable
    private fun InitialDestinationNavigator() {
        val sppRepository by spaEnvironment.pageProviderRepository
private fun NavControllerWrapperImpl.NavContent(allProvider: Collection<SettingsPageProvider>) {
    val nullPage = SettingsPage.createNull()
    NavHost(
        navController = navController,
        startDestination = nullPage.sppName,
    ) {
        composable(nullPage.sppName) {}
        for (spp in allProvider) {
            composable(
                route = spp.name + spp.parameter.navRoute(),
                arguments = spp.parameter,
            ) { navBackStackEntry ->
                spp.PageEvents(navBackStackEntry.arguments)
                spp.Page(navBackStackEntry.arguments)
            }
        }
    }
}

@Composable
private fun NavControllerWrapperImpl.InitialDestination(
    destination: String,
    highlightEntryId: String?
) {
    val destinationNavigated = rememberSaveable { mutableStateOf(false) }
    if (destinationNavigated.value) return
    destinationNavigated.value = true
        val controller = LocalNavController.current as NavControllerWrapperImpl

    if (destination.isEmpty()) return
    LaunchedEffect(Unit) {
            val destination =
                intent?.getStringExtra(KEY_DESTINATION) ?: sppRepository.getDefaultStartPage()
            val highlightEntryId = intent?.getStringExtra(KEY_HIGHLIGHT_ENTRY)
            if (destination.isNotEmpty()) {
                controller.highlightId = highlightEntryId
                val navController = controller.navController
        highlightId = highlightEntryId
        navController.navigate(destination) {
            popUpTo(navController.graph.findStartDestination().id) {
                inclusive = true
@@ -150,10 +170,3 @@ open class BrowseActivity : ComponentActivity() {
        }
    }
}
    }

    companion object {
        const val KEY_DESTINATION = "spaActivityDestination"
        const val KEY_HIGHLIGHT_ENTRY = "highlightEntry"
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -156,6 +156,15 @@ data class SettingsPage(
    }
}

fun SettingsPageProvider.createSettingsPage(arguments: Bundle? = null): SettingsPage {
    return SettingsPage.create(
        name = name,
        displayName = displayName,
        parameter = parameter,
        arguments = arguments
    )
}

fun String.toHashId(): String {
    return this.hashCode().toUInt().toString(36)
}
+0 −9
Original line number Diff line number Diff line
@@ -51,12 +51,3 @@ interface SettingsPageProvider {
        }
    }
}

fun SettingsPageProvider.createSettingsPage(arguments: Bundle? = null): SettingsPage {
    return SettingsPage.create(
        name = name,
        displayName = displayName,
        parameter = parameter,
        arguments = arguments
    )
}
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.settingslib.spa.framework

import android.content.Context
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.framework.common.LogCategory
import com.android.settingslib.spa.framework.common.LogEvent
import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
import com.android.settingslib.spa.tests.testutils.SpaLoggerForTest
import com.android.settingslib.spa.testutils.waitUntil
import com.google.common.truth.Truth
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

const val WAIT_UNTIL_TIMEOUT = 1000L

@RunWith(AndroidJUnit4::class)
class BrowseActivityTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    private val context: Context = ApplicationProvider.getApplicationContext()
    private val spaLogger = SpaLoggerForTest()
    private val spaEnvironment = SpaEnvironmentForTest(context, logger = spaLogger)

    @Test
    fun testBrowsePage() {
        spaLogger.reset()
        SpaEnvironmentFactory.reset(spaEnvironment)

        val sppRepository by spaEnvironment.pageProviderRepository
        val sppHome = sppRepository.getProviderOrNull("SppHome")!!
        val pageHome = sppHome.createSettingsPage()
        val sppLayer1 = sppRepository.getProviderOrNull("SppLayer1")!!
        val pageLayer1 = sppLayer1.createSettingsPage()

        composeTestRule.setContent {
            BrowseContent(
                allProviders = listOf(sppHome, sppLayer1),
                initialDestination = pageHome.buildRoute(),
                initialEntryId = null
            )
        }

        composeTestRule.onNodeWithText(sppHome.getTitle(null)).assertIsDisplayed()
        spaLogger.verifyPageEvent(pageHome.id, 1, 0)
        spaLogger.verifyPageEvent(pageLayer1.id, 0, 0)

        // click to layer1 page
        composeTestRule.onNodeWithText("SppHome to Layer1").assertIsDisplayed().performClick()
        waitUntil(WAIT_UNTIL_TIMEOUT) {
            composeTestRule.onAllNodesWithText(sppLayer1.getTitle(null))
                .fetchSemanticsNodes().size == 1
        }
        spaLogger.verifyPageEvent(pageHome.id, 1, 1)
        spaLogger.verifyPageEvent(pageLayer1.id, 1, 0)
    }
}

private fun SpaLoggerForTest.verifyPageEvent(id: String, entryCount: Int, leaveCount: Int) {
    Truth.assertThat(getEventCount(id, LogEvent.PAGE_ENTER, LogCategory.FRAMEWORK))
        .isEqualTo(entryCount)
    Truth.assertThat(getEventCount(id, LogEvent.PAGE_LEAVE, LogCategory.FRAMEWORK))
        .isEqualTo(leaveCount)
}
+7 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import com.android.settingslib.spa.framework.common.SettingsPageProviderReposito
import com.android.settingslib.spa.framework.common.SpaEnvironment
import com.android.settingslib.spa.framework.common.SpaLogger
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.widget.preference.SimplePreferenceMacro

class SpaLoggerForTest : SpaLogger {
    data class MsgCountKey(val msg: String, val category: LogCategory)
@@ -98,6 +99,12 @@ object SppLayer1 : SettingsPageProvider {

    fun buildInject(): SettingsEntryBuilder {
        return SettingsEntryBuilder.createInject(this.createSettingsPage())
            .setMacro {
                SimplePreferenceMacro(
                    title = "SppHome to Layer1",
                    clickRoute = name
                )
            }
    }

    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {