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
|
||||
abstract fun bindsFeatureFlagDebug(impl: FeatureFlagsDebug): FeatureFlags
|
||||
|
||||
@Binds
|
||||
abstract fun bindsRestarter(debugRestarter: FeatureFlagsDebugRestarter): Restarter
|
||||
|
||||
@Module
|
||||
companion object {
|
||||
@JvmStatic
|
||||
|
||||
@@ -27,4 +27,7 @@ import dagger.Module
|
||||
abstract class FlagsModule {
|
||||
@Binds
|
||||
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");
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "Restarting Android");
|
||||
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
|
||||
|
||||
import com.android.internal.statusbar.IStatusBarService
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import javax.inject.Named
|
||||
@@ -32,15 +31,5 @@ interface FlagsCommonModule {
|
||||
fun providesAllFlags(): Map<Int, Flag<*>> {
|
||||
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