summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt3
-rw-r--r--packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt51
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt82
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt145
9 files changed, 378 insertions, 12 deletions
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
index 7b216017df7d..8323d0971ad7 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
@@ -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
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
index aef887667527..87beff76290d 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
@@ -27,4 +27,7 @@ import dagger.Module
abstract class FlagsModule {
@Binds
abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags
+
+ @Binds
+ abstract fun bindsRestarter(debugRestarter: FeatureFlagsReleaseRestarter): Restarter
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index ec3fdecb919a..5dae0a21d588 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -336,7 +336,6 @@ public class FeatureFlagsDebug implements FeatureFlags {
Log.i(TAG, "Android Restart Suppressed");
return;
}
- Log.i(TAG, "Restarting Android");
mRestarter.restart();
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt
new file mode 100644
index 000000000000..3d9f62768a37
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugRestarter.kt
@@ -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()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt
new file mode 100644
index 000000000000..a3f0f665c056
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseRestarter.kt
@@ -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()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
index 18d7bcf9b3fc..8442230fc5b1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagsCommonModule.kt
@@ -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()
- }
- }
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt b/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt
new file mode 100644
index 000000000000..f1b1be47a84f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/SystemExitRestarter.kt
@@ -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)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt
new file mode 100644
index 000000000000..1e7b1f26ba8c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugRestarterTest.kt
@@ -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()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt
new file mode 100644
index 000000000000..68ca48dd327d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseRestarterTest.kt
@@ -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)
+ }
+}