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

Commit 97dfe306 authored by Liam Lee Pong Lam's avatar Liam Lee Pong Lam Committed by Android (Google) Code Review
Browse files

Merge changes I6ac13c51,Idec75be8 into main

* changes:
  [smartspace] Refactor WakefulnessLifecycle to PowerInteractor
  [aconfig] Refactor WakefulnessLifecyle to PowerInteractor
parents 5b97ebe5 a7e33d62
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -524,6 +524,13 @@ flag {
   bug: "326292691"
}

flag {
   name: "smartspace_lockscreen_viewmodel"
   namespace: "systemui"
   description: "Indicate Smartspace lockscreen viewmodel"
   bug: "331451011"
}

flag {
   name: "pin_input_field_styled_focus_state"
   namespace: "systemui"
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.smartspace

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.smartspace.ui.viewmodel.SmartspaceViewModel
import com.android.systemui.smartspace.viewmodel.smartspaceViewModelFactory
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.withTimeoutOrNull
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class SmartspaceViewModelTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope

    private val powerInteractor = kosmos.powerInteractor
    private val smartspaceViewModelFactory = kosmos.smartspaceViewModelFactory

    private lateinit var underTest: SmartspaceViewModel

    @Test
    fun dateVew_isAwakeTrue_true() =
        testScope.runTest {
            underTest = smartspaceViewModelFactory.create(SmartspaceViewModel.SURFACE_DATE_VIEW)

            powerInteractor.setAwakeForTest()
            val isAwake by collectLastValue(underTest.isAwake)

            assertThat(isAwake).isTrue()
        }

    @Test
    fun dateVew_isAwakeFalse_false() =
        testScope.runTest {
            underTest = smartspaceViewModelFactory.create(SmartspaceViewModel.SURFACE_DATE_VIEW)

            powerInteractor.setAsleepForTest()
            val isAwake by collectLastValue(underTest.isAwake)

            assertThat(isAwake).isFalse()
        }

    @Test
    fun dateVew_isAwakeMultipleTimes_correctResults() =
        testScope.runTest {
            underTest = smartspaceViewModelFactory.create(SmartspaceViewModel.SURFACE_DATE_VIEW)
            val isAwake by collectLastValue(underTest.isAwake)

            powerInteractor.setAsleepForTest()

            assertThat(isAwake).isFalse()

            powerInteractor.setAwakeForTest()

            assertThat(isAwake).isTrue()

            powerInteractor.setAsleepForTest()

            assertThat(isAwake).isFalse()

            powerInteractor.setAwakeForTest()

            assertThat(isAwake).isTrue()
        }

    @Test
    fun weatherView_isAwakeTrue_doesNotEmit() =
        testScope.runTest {
            underTest = smartspaceViewModelFactory.create(SmartspaceViewModel.SURFACE_WEATHER_VIEW)

            powerInteractor.setAwakeForTest()
            val isAwake = withTimeoutOrNull(100) { underTest.isAwake.firstOrNull() }

            assertThat(isAwake).isNull()
        }
}
+45 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.smartspace.ui.binder

import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
import com.android.systemui.smartspace.ui.viewmodel.SmartspaceViewModel
import kotlinx.coroutines.launch

/** Binds the view and view-model for the smartspace. */
object SmartspaceViewBinder {

    /** Binds the view and view-model for the smartspace. */
    fun bind(
        smartspaceView: SmartspaceView,
        viewModel: SmartspaceViewModel,
    ) {
        val view = smartspaceView as View
        view.repeatWhenAttached {
            repeatOnLifecycle(Lifecycle.State.CREATED) {
                launch {
                    // Observe screen on/off changes
                    viewModel.isAwake.collect { isAwake -> smartspaceView.setScreenOn(isAwake) }
                }
            }
        }
    }
}
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.smartspace.ui.viewmodel

import com.android.systemui.power.domain.interactor.PowerInteractor
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter

class SmartspaceViewModel
@AssistedInject
constructor(
    powerInteractor: PowerInteractor,
    @Assisted val surfaceName: String,
) {

    /** Screen on/off state */
    val isAwake: Flow<Boolean> =
        powerInteractor.isAwake.filter { surfaceName != SURFACE_WEATHER_VIEW }

    @AssistedFactory
    interface Factory {
        fun create(surfaceName: String): SmartspaceViewModel
    }

    companion object {
        const val SURFACE_DATE_VIEW = "date_view"
        const val SURFACE_WEATHER_VIEW = "weather_view"
        const val SURFACE_GENERAL_VIEW = "general_view"
    }
}
+41 −8
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.settingslib.Utils
import com.android.systemui.Dumpable
import com.android.systemui.Flags.smartspaceLockscreenViewmodel
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -60,6 +61,8 @@ import com.android.systemui.settings.UserTracker
import com.android.systemui.shared.regionsampling.RegionSampler
import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DATE_SMARTSPACE_DATA_PLUGIN
import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.WEATHER_SMARTSPACE_DATA_PLUGIN
import com.android.systemui.smartspace.ui.binder.SmartspaceViewBinder
import com.android.systemui.smartspace.ui.viewmodel.SmartspaceViewModel
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -98,6 +101,7 @@ constructor(
        private val bypassController: KeyguardBypassController,
        private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
        private val wakefulnessLifecycle: WakefulnessLifecycle,
        private val smartspaceViewModelFactory: SmartspaceViewModel.Factory,
        private val dumpManager: DumpManager,
        private val execution: Execution,
        @Main private val uiExecutor: Executor,
@@ -333,7 +337,12 @@ constructor(
            throw RuntimeException("Cannot build date view when not decoupled")
        }

        val view = buildView(parent, datePlugin)
        val view =
            buildView(
                surfaceName = SmartspaceViewModel.SURFACE_DATE_VIEW,
                parent = parent,
                plugin = datePlugin
            )
        connectSession()

        return view
@@ -352,7 +361,12 @@ constructor(
            throw RuntimeException("Cannot build weather view when not decoupled")
        }

        val view = buildView(parent, weatherPlugin)
        val view =
            buildView(
                surfaceName = SmartspaceViewModel.SURFACE_WEATHER_VIEW,
                parent = parent,
                plugin = weatherPlugin
            )
        connectSession()

        return view
@@ -368,13 +382,20 @@ constructor(
            throw RuntimeException("Cannot build view when not enabled")
        }

        val view = buildView(parent, plugin, configPlugin)
        val view =
            buildView(
                surfaceName = SmartspaceViewModel.SURFACE_GENERAL_VIEW,
                parent = parent,
                plugin = plugin,
                configPlugin = configPlugin
            )
        connectSession()

        return view
    }

    private fun buildView(
        surfaceName: String,
        parent: ViewGroup,
        plugin: BcSmartspaceDataPlugin?,
        configPlugin: BcSmartspaceConfigPlugin? = null
@@ -424,6 +445,14 @@ constructor(
        return (ssView as View).apply {
            setTag(R.id.tag_smartspace_view, Any())
            addOnAttachStateChangeListener(stateChangeListener)

            if (smartspaceLockscreenViewmodel()) {
                val viewModel = smartspaceViewModelFactory.create(surfaceName)
                SmartspaceViewBinder.bind(
                    smartspaceView = ssView,
                    viewModel = viewModel,
                )
            }
        }
    }

@@ -466,7 +495,9 @@ constructor(
        configurationController.addCallback(configChangeListener)
        statusBarStateController.addCallback(statusBarStateListener)
        bypassController.registerOnBypassStateChangedListener(bypassStateChangedListener)
        if (!smartspaceLockscreenViewmodel()) {
            wakefulnessLifecycle.addObserver(wakefulnessLifecycleObserver)
        }

        datePlugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
        weatherPlugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
@@ -509,7 +540,9 @@ constructor(
        configurationController.removeCallback(configChangeListener)
        statusBarStateController.removeCallback(statusBarStateListener)
        bypassController.unregisterOnBypassStateChangedListener(bypassStateChangedListener)
        if (!smartspaceLockscreenViewmodel()) {
            wakefulnessLifecycle.removeObserver(wakefulnessLifecycleObserver)
        }
        session = null

        datePlugin?.registerSmartspaceEventNotifier(null)
Loading