Merge "Restart after flag changes on screen off." into tm-qpr-dev
This commit is contained in:
@@ -34,6 +34,9 @@ abstract class FlagsModule {
|
|||||||
@Binds
|
@Binds
|
||||||
abstract fun bindsFeatureFlagDebug(impl: FeatureFlagsDebug): FeatureFlags
|
abstract fun bindsFeatureFlagDebug(impl: FeatureFlagsDebug): FeatureFlags
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindsRestarter(debugRestarter: FeatureFlagsDebugRestarter): Restarter
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
@@ -27,4 +27,7 @@ import dagger.Module
|
|||||||
abstract class FlagsModule {
|
abstract class FlagsModule {
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags
|
abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindsRestarter(debugRestarter: FeatureFlagsReleaseRestarter): Restarter
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,7 +336,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
|
|||||||
Log.i(TAG, "Android Restart Suppressed");
|
Log.i(TAG, "Android Restart Suppressed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.i(TAG, "Restarting Android");
|
|
||||||
mRestarter.restart();
|
mRestarter.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.flags
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/** Restarts SystemUI when the screen is locked. */
|
||||||
|
class FeatureFlagsDebugRestarter
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val wakefulnessLifecycle: WakefulnessLifecycle,
|
||||||
|
private val systemExitRestarter: SystemExitRestarter,
|
||||||
|
) : Restarter {
|
||||||
|
|
||||||
|
val observer =
|
||||||
|
object : WakefulnessLifecycle.Observer {
|
||||||
|
override fun onFinishedGoingToSleep() {
|
||||||
|
Log.d(FeatureFlagsDebug.TAG, "Restarting due to systemui flag change")
|
||||||
|
restartNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun restart() {
|
||||||
|
Log.d(FeatureFlagsDebug.TAG, "Restart requested. Restarting on next screen off.")
|
||||||
|
if (wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_ASLEEP) {
|
||||||
|
restartNow()
|
||||||
|
} else {
|
||||||
|
wakefulnessLifecycle.addObserver(observer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun restartNow() {
|
||||||
|
systemExitRestarter.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.flags
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.android.systemui.dagger.qualifiers.Background
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP
|
||||||
|
import com.android.systemui.statusbar.policy.BatteryController
|
||||||
|
import com.android.systemui.util.concurrency.DelayableExecutor
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/** Restarts SystemUI when the device appears idle. */
|
||||||
|
class FeatureFlagsReleaseRestarter
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val wakefulnessLifecycle: WakefulnessLifecycle,
|
||||||
|
private val batteryController: BatteryController,
|
||||||
|
@Background private val bgExecutor: DelayableExecutor,
|
||||||
|
private val systemExitRestarter: SystemExitRestarter
|
||||||
|
) : Restarter {
|
||||||
|
var shouldRestart = false
|
||||||
|
var pendingRestart: Runnable? = null
|
||||||
|
|
||||||
|
val observer =
|
||||||
|
object : WakefulnessLifecycle.Observer {
|
||||||
|
override fun onFinishedGoingToSleep() {
|
||||||
|
maybeScheduleRestart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val batteryCallback =
|
||||||
|
object : BatteryController.BatteryStateChangeCallback {
|
||||||
|
override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) {
|
||||||
|
maybeScheduleRestart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun restart() {
|
||||||
|
Log.d(FeatureFlagsDebug.TAG, "Restart requested. Restarting when plugged in and idle.")
|
||||||
|
if (!shouldRestart) {
|
||||||
|
// Don't bother scheduling twice.
|
||||||
|
shouldRestart = true
|
||||||
|
wakefulnessLifecycle.addObserver(observer)
|
||||||
|
batteryController.addCallback(batteryCallback)
|
||||||
|
maybeScheduleRestart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun maybeScheduleRestart() {
|
||||||
|
if (
|
||||||
|
wakefulnessLifecycle.wakefulness == WAKEFULNESS_ASLEEP && batteryController.isPluggedIn
|
||||||
|
) {
|
||||||
|
if (pendingRestart == null) {
|
||||||
|
pendingRestart = bgExecutor.executeDelayed(this::restartNow, 30L, TimeUnit.SECONDS)
|
||||||
|
}
|
||||||
|
} else if (pendingRestart != null) {
|
||||||
|
pendingRestart?.run()
|
||||||
|
pendingRestart = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun restartNow() {
|
||||||
|
Log.d(FeatureFlagsRelease.TAG, "Restarting due to systemui flag change")
|
||||||
|
systemExitRestarter.restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.systemui.flags
|
package com.android.systemui.flags
|
||||||
|
|
||||||
import com.android.internal.statusbar.IStatusBarService
|
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
@@ -32,15 +31,5 @@ interface FlagsCommonModule {
|
|||||||
fun providesAllFlags(): Map<Int, Flag<*>> {
|
fun providesAllFlags(): Map<Int, Flag<*>> {
|
||||||
return FlagsFactory.knownFlags.map { it.value.id to it.value }.toMap()
|
return FlagsFactory.knownFlags.map { it.value.id to it.value }.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
@Provides
|
|
||||||
fun providesRestarter(barService: IStatusBarService): Restarter {
|
|
||||||
return object : Restarter {
|
|
||||||
override fun restart() {
|
|
||||||
barService.restart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.systemui.flags
|
||||||
|
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SystemExitRestarter @Inject constructor() : Restarter {
|
||||||
|
override fun restart() {
|
||||||
|
System.exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.flags
|
||||||
|
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
class FeatureFlagsDebugRestarterTest : SysuiTestCase() {
|
||||||
|
private lateinit var restarter: FeatureFlagsDebugRestarter
|
||||||
|
|
||||||
|
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
|
||||||
|
@Mock private lateinit var systemExitRestarter: SystemExitRestarter
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
restarter = FeatureFlagsDebugRestarter(wakefulnessLifecycle, systemExitRestarter)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRestart_ImmediateWhenAsleep() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
|
||||||
|
restarter.restart()
|
||||||
|
verify(systemExitRestarter).restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRestart_WaitsForSceenOff() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE)
|
||||||
|
|
||||||
|
restarter.restart()
|
||||||
|
verify(systemExitRestarter, never()).restart()
|
||||||
|
|
||||||
|
val captor = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java)
|
||||||
|
verify(wakefulnessLifecycle).addObserver(captor.capture())
|
||||||
|
|
||||||
|
captor.value.onFinishedGoingToSleep()
|
||||||
|
|
||||||
|
verify(systemExitRestarter).restart()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.flags
|
||||||
|
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP
|
||||||
|
import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE
|
||||||
|
import com.android.systemui.statusbar.policy.BatteryController
|
||||||
|
import com.android.systemui.util.concurrency.FakeExecutor
|
||||||
|
import com.android.systemui.util.time.FakeSystemClock
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito.never
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Be careful with the {FeatureFlagsReleaseRestarter} in this test. It has a call to System.exit()!
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
class FeatureFlagsReleaseRestarterTest : SysuiTestCase() {
|
||||||
|
private lateinit var restarter: FeatureFlagsReleaseRestarter
|
||||||
|
|
||||||
|
@Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
|
||||||
|
@Mock private lateinit var batteryController: BatteryController
|
||||||
|
@Mock private lateinit var systemExitRestarter: SystemExitRestarter
|
||||||
|
private val executor = FakeExecutor(FakeSystemClock())
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
restarter =
|
||||||
|
FeatureFlagsReleaseRestarter(
|
||||||
|
wakefulnessLifecycle,
|
||||||
|
batteryController,
|
||||||
|
executor,
|
||||||
|
systemExitRestarter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRestart_ScheduledWhenReady() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
|
||||||
|
whenever(batteryController.isPluggedIn).thenReturn(true)
|
||||||
|
|
||||||
|
assertThat(executor.numPending()).isEqualTo(0)
|
||||||
|
restarter.restart()
|
||||||
|
assertThat(executor.numPending()).isEqualTo(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRestart_RestartsWhenIdle() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
|
||||||
|
whenever(batteryController.isPluggedIn).thenReturn(true)
|
||||||
|
|
||||||
|
restarter.restart()
|
||||||
|
verify(systemExitRestarter, never()).restart()
|
||||||
|
executor.advanceClockToLast()
|
||||||
|
executor.runAllReady()
|
||||||
|
verify(systemExitRestarter).restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRestart_NotScheduledWhenAwake() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE)
|
||||||
|
whenever(batteryController.isPluggedIn).thenReturn(true)
|
||||||
|
|
||||||
|
assertThat(executor.numPending()).isEqualTo(0)
|
||||||
|
restarter.restart()
|
||||||
|
assertThat(executor.numPending()).isEqualTo(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRestart_NotScheduledWhenNotPluggedIn() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
|
||||||
|
whenever(batteryController.isPluggedIn).thenReturn(false)
|
||||||
|
|
||||||
|
assertThat(executor.numPending()).isEqualTo(0)
|
||||||
|
restarter.restart()
|
||||||
|
assertThat(executor.numPending()).isEqualTo(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRestart_NotDoubleSheduled() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
|
||||||
|
whenever(batteryController.isPluggedIn).thenReturn(true)
|
||||||
|
|
||||||
|
assertThat(executor.numPending()).isEqualTo(0)
|
||||||
|
restarter.restart()
|
||||||
|
restarter.restart()
|
||||||
|
assertThat(executor.numPending()).isEqualTo(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testWakefulnessLifecycle_CanRestart() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_AWAKE)
|
||||||
|
whenever(batteryController.isPluggedIn).thenReturn(true)
|
||||||
|
assertThat(executor.numPending()).isEqualTo(0)
|
||||||
|
restarter.restart()
|
||||||
|
|
||||||
|
val captor = ArgumentCaptor.forClass(WakefulnessLifecycle.Observer::class.java)
|
||||||
|
verify(wakefulnessLifecycle).addObserver(captor.capture())
|
||||||
|
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
|
||||||
|
|
||||||
|
captor.value.onFinishedGoingToSleep()
|
||||||
|
assertThat(executor.numPending()).isEqualTo(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testBatteryController_CanRestart() {
|
||||||
|
whenever(wakefulnessLifecycle.wakefulness).thenReturn(WAKEFULNESS_ASLEEP)
|
||||||
|
whenever(batteryController.isPluggedIn).thenReturn(false)
|
||||||
|
assertThat(executor.numPending()).isEqualTo(0)
|
||||||
|
restarter.restart()
|
||||||
|
|
||||||
|
val captor =
|
||||||
|
ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback::class.java)
|
||||||
|
verify(batteryController).addCallback(captor.capture())
|
||||||
|
|
||||||
|
whenever(batteryController.isPluggedIn).thenReturn(true)
|
||||||
|
|
||||||
|
captor.value.onBatteryLevelChanged(0, true, true)
|
||||||
|
assertThat(executor.numPending()).isEqualTo(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user