Merge "[Catalyst] Support SET api for int value" into main
diff --git a/android-sdk-flags/OWNERS b/android-sdk-flags/OWNERS
new file mode 100644
index 0000000..01f45dd
--- /dev/null
+++ b/android-sdk-flags/OWNERS
@@ -0,0 +1 @@
+include /SDK_OWNERS
diff --git a/android-sdk-flags/flags.aconfig b/android-sdk-flags/flags.aconfig
index cfe298e..19c7bf6 100644
--- a/android-sdk-flags/flags.aconfig
+++ b/android-sdk-flags/flags.aconfig
@@ -6,6 +6,7 @@
namespace: "android_sdk"
description: "Use the new SDK major.minor versioning scheme (e.g. Android 40.1) which replaces the old single-integer scheme (e.g. Android 15)."
bug: "350458259"
+ is_exported: true
# Use is_fixed_read_only because DeviceConfig may not be available when Build.VERSION_CODES is first accessed
is_fixed_read_only: true
diff --git a/core/java/android/content/res/TEST_MAPPING b/core/java/android/content/res/TEST_MAPPING
index c2febae..e8893e4 100644
--- a/core/java/android/content/res/TEST_MAPPING
+++ b/core/java/android/content/res/TEST_MAPPING
@@ -5,6 +5,9 @@
},
{
"path": "frameworks/base/core/tests/coretests/src/com/android/internal/content/res"
+ },
+ {
+ "path": "platform_testing/libraries/screenshot"
}
],
"presubmit": [
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 7877352..acbd95bf 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -212,8 +212,7 @@
&& mInitiallyVisible == that.mInitiallyVisible
&& mSurfacePosition.equals(that.mSurfacePosition)
&& mInsetsHint.equals(that.mInsetsHint)
- && mSkipAnimationOnce == that.mSkipAnimationOnce
- && Objects.equals(mImeStatsToken, that.mImeStatsToken);
+ && mSkipAnimationOnce == that.mSkipAnimationOnce;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 5f0eed9..14f8cc7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1632,6 +1632,7 @@
if (!isShowingAsBubbleBar()) {
callback = b -> {
if (mStackView != null) {
+ b.setSuppressFlyout(true);
mStackView.addBubble(b);
mStackView.setSelectedBubble(b);
} else {
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 5c5edb1..b0bd5b7 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1708,3 +1708,9 @@
bug: "365064144"
}
+flag {
+ name: "touchpad_three_finger_tap_customization"
+ namespace: "systemui"
+ description: "Customize touchpad three finger tap"
+ bug: "365063048"
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index 6fc51e4..66a0908 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -53,6 +53,7 @@
import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace
import com.android.systemui.res.R
import com.android.systemui.shade.LargeScreenHeaderHelper
+import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.AlwaysOnDisplayNotificationIconViewStore
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.StatusBarIconViewBindingFailureTracker
@@ -84,7 +85,7 @@
stackScrollLayout: NotificationStackScrollLayout,
sharedNotificationContainerBinder: SharedNotificationContainerBinder,
private val keyguardRootViewModel: KeyguardRootViewModel,
- private val configurationState: ConfigurationState,
+ @ShadeDisplayAware private val configurationState: ConfigurationState,
private val iconBindingFailureTracker: StatusBarIconViewBindingFailureTracker,
private val nicAodViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/OnTeardownRuleTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/OnTeardownRuleTest.kt
new file mode 100644
index 0000000..8635bb0
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/OnTeardownRuleTest.kt
@@ -0,0 +1,124 @@
+/*
+ * 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
+
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.JUnitCore
+
+@Suppress("JUnitMalformedDeclaration")
+@SmallTest
+class OnTeardownRuleTest : SysuiTestCase() {
+ // None of these inner classes should be run except as part of this utilities-testing test
+ class HasTeardown {
+ @get:Rule val teardownRule = OnTeardownRule()
+
+ @Before
+ fun setUp() {
+ teardownWasRun = false
+ teardownRule.onTeardown { teardownWasRun = true }
+ }
+
+ @Test fun doTest() {}
+
+ companion object {
+ var teardownWasRun = false
+ }
+ }
+
+ @Test
+ fun teardownRuns() {
+ val result = JUnitCore().run(HasTeardown::class.java)
+ assertThat(result.failures).isEmpty()
+ assertThat(HasTeardown.teardownWasRun).isTrue()
+ }
+
+ class FirstTeardownFails {
+ @get:Rule val teardownRule = OnTeardownRule()
+
+ @Before
+ fun setUp() {
+ teardownWasRun = false
+ teardownRule.onTeardown { fail("One fails") }
+ teardownRule.onTeardown { teardownWasRun = true }
+ }
+
+ @Test fun doTest() {}
+
+ companion object {
+ var teardownWasRun = false
+ }
+ }
+
+ @Test
+ fun allTeardownsRun() {
+ val result = JUnitCore().run(FirstTeardownFails::class.java)
+ assertThat(result.failures.map { it.message }).isEqualTo(listOf("One fails"))
+ assertThat(FirstTeardownFails.teardownWasRun).isTrue()
+ }
+
+ class ThreeTeardowns {
+ @get:Rule val teardownRule = OnTeardownRule()
+
+ @Before
+ fun setUp() {
+ messages.clear()
+ }
+
+ @Test
+ fun doTest() {
+ teardownRule.onTeardown { messages.add("A") }
+ teardownRule.onTeardown { messages.add("B") }
+ teardownRule.onTeardown { messages.add("C") }
+ }
+
+ companion object {
+ val messages = mutableListOf<String>()
+ }
+ }
+
+ @Test
+ fun reverseOrder() {
+ val result = JUnitCore().run(ThreeTeardowns::class.java)
+ assertThat(result.failures).isEmpty()
+ assertThat(ThreeTeardowns.messages).isEqualTo(listOf("C", "B", "A"))
+ }
+
+ class TryToDoABadThing {
+ @get:Rule val teardownRule = OnTeardownRule()
+
+ @Test
+ fun doTest() {
+ teardownRule.onTeardown {
+ teardownRule.onTeardown {
+ // do nothing
+ }
+ }
+ }
+ }
+
+ @Test
+ fun prohibitTeardownDuringTeardown() {
+ val result = JUnitCore().run(TryToDoABadThing::class.java)
+ assertThat(result.failures.map { it.message })
+ .isEqualTo(listOf("Cannot add new teardown routines after test complete."))
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
index 2905a73..646722b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/navigationbar/views/NavigationBarTest.java
@@ -116,6 +116,7 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.data.repository.LightBarControllerStore;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -208,7 +209,7 @@
@Mock
private LightBarController mLightBarController;
@Mock
- private LightBarController.Factory mLightBarcontrollerFactory;
+ private LightBarControllerStore mLightBarControllerStore;
@Mock
private AutoHideController mAutoHideController;
@Mock
@@ -257,7 +258,7 @@
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
- when(mLightBarcontrollerFactory.create(any(Context.class))).thenReturn(mLightBarController);
+ when(mLightBarControllerStore.forDisplay(anyInt())).thenReturn(mLightBarController);
when(mAutoHideControllerFactory.create(any(Context.class))).thenReturn(mAutoHideController);
when(mNavigationBarView.getHomeButton()).thenReturn(mHomeButton);
when(mNavigationBarView.getRecentsButton()).thenReturn(mRecentsButton);
@@ -649,8 +650,7 @@
mFakeExecutor,
mUiEventLogger,
mNavBarHelper,
- mLightBarController,
- mLightBarcontrollerFactory,
+ mLightBarControllerStore,
mAutoHideController,
mAutoHideControllerFactory,
Optional.of(mTelecomManager),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
new file mode 100644
index 0000000..18eef33
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.statusbar.data.repository
+
+import android.view.Display.DEFAULT_DISPLAY
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LightBarControllerStoreImplTest : SysuiTestCase() {
+ private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+ private val testScope = kosmos.testScope
+ private val fakeDisplayRepository = kosmos.displayRepository
+
+ private val underTest = kosmos.lightBarControllerStoreImpl
+
+ @Before
+ fun start() {
+ underTest.start()
+ }
+
+ @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
+
+ @Test
+ fun forDisplay_startsInstance() =
+ testScope.runTest {
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+ verify(instance).start()
+ }
+
+ @Test
+ fun beforeDisplayRemoved_doesNotStopInstances() =
+ testScope.runTest {
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+ verify(instance, never()).stop()
+ }
+
+ @Test
+ fun displayRemoved_stopsInstance() =
+ testScope.runTest {
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+ fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+
+ verify(instance).stop()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index 88ec18d..12f6825 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -48,12 +48,10 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.statusbar.data.model.StatusBarAppearance;
import com.android.systemui.statusbar.data.model.StatusBarMode;
-import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModePerDisplayRepository;
import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.util.kotlin.JavaAdapter;
import kotlinx.coroutines.test.TestScope;
@@ -81,8 +79,8 @@
private SysuiDarkIconDispatcher mStatusBarIconController;
private LightBarController mLightBarController;
private final TestScope mTestScope = TestScopeProvider.getTestScope();
- private final FakeStatusBarModeRepository mStatusBarModeRepository =
- new FakeStatusBarModeRepository();
+ private final FakeStatusBarModePerDisplayRepository mStatusBarModeRepository =
+ new FakeStatusBarModePerDisplayRepository();
@Before
public void setup() {
@@ -92,15 +90,15 @@
mLightBarTransitionsController = mock(LightBarTransitionsController.class);
when(mStatusBarIconController.getTransitionsController()).thenReturn(
mLightBarTransitionsController);
- mLightBarController = new LightBarController(
- mContext,
- new JavaAdapter(mTestScope),
+ mLightBarController = new LightBarControllerImpl(
+ mContext.getDisplayId(),
+ mTestScope,
mStatusBarIconController,
mock(BatteryController.class),
mock(NavigationModeController.class),
mStatusBarModeRepository,
mock(DumpManager.class),
- new FakeDisplayTracker(mContext));
+ mTestScope.getCoroutineContext());
mLightBarController.start();
}
@@ -121,7 +119,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, secondBounds)
);
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -142,7 +140,7 @@
new AppearanceRegion(0 /* appearance */, secondBounds)
);
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -165,7 +163,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, secondBounds)
);
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -190,7 +188,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, thirdBounds)
);
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -214,7 +212,7 @@
new AppearanceRegion(0 /* appearance */, secondBounds)
);
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -231,7 +229,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect(0, 0, 1, 1))
);
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -249,7 +247,7 @@
new AppearanceRegion(0, new Rect(0, 0, 1, 1))
);
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -266,7 +264,7 @@
new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect(0, 0, 1, 1))
);
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -276,7 +274,7 @@
reset(mStatusBarIconController);
// WHEN the same appearance regions but different status bar mode is sent
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.LIGHTS_OUT_TRANSPARENT,
STATUS_BAR_BOUNDS,
@@ -298,7 +296,7 @@
/* start= */ new Rect(0, 0, 10, 10),
/* end= */ new Rect(0, 0, 20, 20));
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
startingBounds,
@@ -311,7 +309,7 @@
BoundsPair newBounds = new BoundsPair(
/* start= */ new Rect(0, 0, 30, 30),
/* end= */ new Rect(0, 0, 40, 40));
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
+ mStatusBarModeRepository.getStatusBarAppearance().setValue(
new StatusBarAppearance(
StatusBarMode.TRANSPARENT,
newBounds,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
index e0d9fac..110dec6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
@@ -36,7 +36,6 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testScope
import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
@@ -58,7 +57,6 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
-import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -144,6 +142,7 @@
controller.start()
controller.addCallback(mockOngoingCallListener)
controller.setChipView(chipView)
+ onTeardown { controller.tearDownChipView() }
val collectionListenerCaptor = ArgumentCaptor.forClass(NotifCollectionListener::class.java)
verify(notificationCollection).addCollectionListener(collectionListenerCaptor.capture())
@@ -153,11 +152,6 @@
.thenReturn(PROC_STATE_INVISIBLE)
}
- @After
- fun tearDown() {
- controller.tearDownChipView()
- }
-
@Test
fun onEntryUpdated_isOngoingCallNotif_listenerAndRepoNotified() {
val notification = NotificationEntryBuilder(createOngoingCallNotifEntry())
@@ -224,7 +218,7 @@
notifCollectionListener.onEntryUpdated(notification.build())
chipView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
)
assertThat(chipView.findViewById<View>(R.id.ongoing_activity_chip_time)?.measuredWidth)
@@ -241,7 +235,7 @@
notifCollectionListener.onEntryUpdated(notification.build())
chipView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
)
assertThat(chipView.findViewById<View>(R.id.ongoing_activity_chip_time)?.measuredWidth)
@@ -257,7 +251,7 @@
notifCollectionListener.onEntryUpdated(notification.build())
chipView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
)
assertThat(chipView.findViewById<View>(R.id.ongoing_activity_chip_time)?.measuredWidth)
@@ -668,7 +662,7 @@
private fun createCallNotifEntry(
callStyle: Notification.CallStyle,
- nullContentIntent: Boolean = false
+ nullContentIntent: Boolean = false,
): NotificationEntry {
val notificationEntryBuilder = NotificationEntryBuilder()
notificationEntryBuilder.modifyNotification(context).style = callStyle
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
index fc1ea22..19d5a16 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcherTest.kt
@@ -66,6 +66,7 @@
logBuffer = FakeLogBuffer.Factory.create(),
verboseLogBuffer = FakeLogBuffer.Factory.create(),
systemClock,
+ context.resources,
)
private val demoDataSource =
mock<DemoDeviceBasedSatelliteDataSource>().also {
@@ -80,7 +81,11 @@
)
}
private val demoImpl =
- DemoDeviceBasedSatelliteRepository(demoDataSource, testScope.backgroundScope)
+ DemoDeviceBasedSatelliteRepository(
+ demoDataSource,
+ testScope.backgroundScope,
+ context.resources,
+ )
private val underTest =
DeviceBasedSatelliteRepositorySwitcher(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
index 8769389..a70881a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepositoryTest.kt
@@ -58,7 +58,12 @@
whenever(it.satelliteEvents).thenReturn(fakeSatelliteEvents)
}
- underTest = DemoDeviceBasedSatelliteRepository(dataSource, testScope.backgroundScope)
+ underTest =
+ DemoDeviceBasedSatelliteRepository(
+ dataSource,
+ testScope.backgroundScope,
+ context.resources,
+ )
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
index 55460bd..41fa9e7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/FakeDeviceBasedSatelliteRepository.kt
@@ -28,4 +28,6 @@
override val signalStrength = MutableStateFlow(0)
override val isSatelliteAllowedForCurrentLocation = MutableStateFlow(false)
+
+ override var isOpportunisticSatelliteIconEnabled: Boolean = true
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
index e7e4969..509aa7a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt
@@ -172,6 +172,26 @@
}
@Test
+ fun icon_null_allOosAndConfigIsFalse() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.icon)
+
+ // GIVEN config for opportunistic icon is false
+ repo.isOpportunisticSatelliteIconEnabled = false
+
+ // GIVEN all icons are OOS
+ val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1)
+ i1.isInService.value = false
+ i1.isEmergencyOnly.value = false
+
+ // GIVEN apm is disabled
+ airplaneModeRepository.setIsAirplaneMode(false)
+
+ // THEN icon is null because it is not allowed
+ assertThat(latest).isNull()
+ }
+
+ @Test
fun icon_null_isEmergencyOnly() =
testScope.runTest {
val latest by collectLastValue(underTest.icon)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 53e033e..e7ca1dd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -51,6 +51,8 @@
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
@@ -561,6 +563,113 @@
}
@Test
+ @EnableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI)
+ public void onWallpaperColorsChanged_homeWallpaper_shouldUpdateTheme() {
+ // Should ask for a new theme when the colors of the last applied wallpaper change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+
+ String jsonString =
+ "{\"android.theme.customization.color_source\":\"home_wallpaper\","
+ + "\"android.theme.customization.system_palette\":\"A16B00\","
+ + "\"android.theme.customization.accent_color\":\"A16B00\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(1);
+ // Set LOCK wallpaper as the last applied one to verify that theme is no longer based on
+ // latest wallpaper
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(2);
+
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
+
+ ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
+ verify(mSecureSettings).putStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture(),
+ anyInt());
+
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
+ }
+
+
+
+ @Test
+ @EnableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI)
+ public void onWallpaperColorsChanged_homeWallpaperWithSameColor_shouldKeepThemeAndReapply() {
+ // Shouldn't ask for a new theme when the colors of the last applied wallpaper change
+ // with the same specified system palette one.
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(0xffa16b00), null);
+
+ String jsonString =
+ "{\"android.theme.customization.color_source\":\"home_wallpaper\","
+ + "\"android.theme.customization.system_palette\":\"A16B00\","
+ + "\"android.theme.customization.accent_color\":\"A16B00\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(1);
+ // Set LOCK wallpaper as the last applied one to verify that theme is no longer based on
+ // latest wallpaper
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(2);
+
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
+
+ ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
+ verify(mSecureSettings, never()).putString(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
+
+ // Apply overlay by existing theme from secure setting
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
+ }
+
+ @Test
+ @EnableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI)
+ public void onWallpaperColorsChanged_lockWallpaper_shouldKeepTheme() {
+ // Should ask for a new theme when the colors of the last applied wallpaper change
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
+ Color.valueOf(Color.BLUE), null);
+
+ String jsonString =
+ "{\"android.theme.customization.color_source\":\"home_wallpaper\","
+ + "\"android.theme.customization.system_palette\":\"A16B00\","
+ + "\"android.theme.customization.accent_color\":\"A16B00\","
+ + "\"android.theme.customization.color_index\":\"2\"}";
+
+ when(mSecureSettings.getStringForUser(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
+ .thenReturn(jsonString);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(1);
+ // Set LOCK wallpaper as the last applied one to verify that theme is no longer based on
+ // latest wallpaper
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(2);
+
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK,
+ USER_SYSTEM);
+
+ ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
+ verify(mSecureSettings, never()).putString(
+ eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
+
+ verify(mThemeOverlayApplier, never())
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
+ }
+
+ @Test
+ @DisableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI)
public void onWallpaperColorsChanged_resetThemeWhenFromLatestWallpaper() {
// Should ask for a new theme when the colors of the last applied wallpaper change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
@@ -594,6 +703,7 @@
}
@Test
+ @DisableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI)
public void onWallpaperColorsChanged_keepThemeWhenFromLatestWallpaperAndSpecifiedColor() {
// Shouldn't ask for a new theme when the colors of the last applied wallpaper change
// with the same specified system palette one.
@@ -627,6 +737,7 @@
}
@Test
+ @DisableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI)
public void onWallpaperColorsChanged_keepThemeIfNotLatestWallpaper() {
// Shouldn't ask for a new theme when the colors of the wallpaper that is not the last
// applied one change
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d4a52c3..c8ef093 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -383,6 +383,10 @@
<!-- Whether to show activity indicators in the status bar -->
<bool name="config_showActivity">false</bool>
+ <!-- Whether to show the opportunistic satellite icon. When true, an icon will show to indicate
+ satellite capabilities when all other connections are out of service. -->
+ <bool name="config_showOpportunisticSatelliteIcon">true</bool>
+
<!-- Whether or not to show the notification shelf that houses the icons of notifications that
have been scrolled off-screen. -->
<bool name="config_showNotificationShelf">true</bool>
diff --git a/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
index d1c728c..b0f5e5e 100644
--- a/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
@@ -26,11 +26,6 @@
@Module
abstract class CommonDataLayerModule {
@Binds
- abstract fun bindConfigurationRepository(
- impl: ConfigurationRepositoryImpl
- ): ConfigurationRepository
-
- @Binds
abstract fun bindPackageChangeRepository(
impl: PackageChangeRepositoryImpl
): PackageChangeRepository
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt
index b36da3b..e0756fc 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt
@@ -17,6 +17,7 @@
package com.android.systemui.common.ui
import android.content.Context
+import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryModule
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -28,7 +29,7 @@
/**
* Annotates elements that provide information from the global configuration.
*
- * The global configuration is the one associted with the main display. Secondary displays will
+ * The global configuration is the one associated with the main display. Secondary displays will
* apply override to the global configuration. Elements annotated with this shouldn't be used for
* secondary displays.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
index 2052c70..31a7fa4 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -23,13 +23,17 @@
import androidx.annotation.DimenRes
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.common.ui.GlobalConfig
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.wrapper.DisplayUtilsWrapper
import dagger.Binds
import dagger.Module
-import javax.inject.Inject
+import dagger.Provides
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
@@ -57,66 +61,62 @@
fun getDimensionPixelSize(id: Int): Int
}
-@SysUISingleton
class ConfigurationRepositoryImpl
-@Inject
+@AssistedInject
constructor(
- private val configurationController: ConfigurationController,
- private val context: Context,
+ @Assisted private val configurationController: ConfigurationController,
+ @Assisted private val context: Context,
@Application private val scope: CoroutineScope,
private val displayUtils: DisplayUtilsWrapper,
) : ConfigurationRepository {
private val displayInfo = MutableStateFlow(DisplayInfo())
- override val onAnyConfigurationChange: Flow<Unit> =
- conflatedCallbackFlow {
- val callback =
- object : ConfigurationController.ConfigurationListener {
- override fun onUiModeChanged() {
- sendUpdate("ConfigurationRepository#onUiModeChanged")
- }
-
- override fun onThemeChanged() {
- sendUpdate("ConfigurationRepository#onThemeChanged")
- }
-
- override fun onConfigChanged(newConfig: Configuration) {
- sendUpdate("ConfigurationRepository#onConfigChanged")
- }
-
- fun sendUpdate(reason: String) {
- trySendWithFailureLogging(Unit, reason)
- }
+ override val onAnyConfigurationChange: Flow<Unit> = conflatedCallbackFlow {
+ val callback =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onUiModeChanged() {
+ sendUpdate("ConfigurationRepository#onUiModeChanged")
}
- configurationController.addCallback(callback)
- awaitClose { configurationController.removeCallback(callback) }
- }
- override val onConfigurationChange: Flow<Unit> =
- conflatedCallbackFlow {
- val callback =
- object : ConfigurationController.ConfigurationListener {
- override fun onConfigChanged(newConfig: Configuration) {
- trySendWithFailureLogging(Unit, "ConfigurationRepository#onConfigChanged")
- }
+ override fun onThemeChanged() {
+ sendUpdate("ConfigurationRepository#onThemeChanged")
}
- configurationController.addCallback(callback)
- awaitClose { configurationController.removeCallback(callback) }
- }
- override val configurationValues: Flow<Configuration> =
- conflatedCallbackFlow {
- val callback =
- object : ConfigurationController.ConfigurationListener {
- override fun onConfigChanged(newConfig: Configuration) {
- trySend(newConfig)
- }
- }
+ override fun onConfigChanged(newConfig: Configuration) {
+ sendUpdate("ConfigurationRepository#onConfigChanged")
+ }
- trySend(context.resources.configuration)
- configurationController.addCallback(callback)
- awaitClose { configurationController.removeCallback(callback) }
+ fun sendUpdate(reason: String) {
+ trySendWithFailureLogging(Unit, reason)
+ }
}
+ configurationController.addCallback(callback)
+ awaitClose { configurationController.removeCallback(callback) }
+ }
+
+ override val onConfigurationChange: Flow<Unit> = conflatedCallbackFlow {
+ val callback =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration) {
+ trySendWithFailureLogging(Unit, "ConfigurationRepository#onConfigChanged")
+ }
+ }
+ configurationController.addCallback(callback)
+ awaitClose { configurationController.removeCallback(callback) }
+ }
+
+ override val configurationValues: Flow<Configuration> = conflatedCallbackFlow {
+ val callback =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration) {
+ trySend(newConfig)
+ }
+ }
+
+ trySend(context.resources.configuration)
+ configurationController.addCallback(callback)
+ awaitClose { configurationController.removeCallback(callback) }
+ }
override val scaleForResolution: StateFlow<Float> =
onConfigurationChange
@@ -134,8 +134,7 @@
maxDisplayMode.physicalWidth,
maxDisplayMode.physicalHeight,
displayInfo.value.naturalWidth,
- displayInfo.value.naturalHeight
- )
+ displayInfo.value.naturalHeight)
return if (scaleFactor == Float.POSITIVE_INFINITY) 1f else scaleFactor
}
return 1f
@@ -144,9 +143,40 @@
override fun getDimensionPixelSize(@DimenRes id: Int): Int {
return context.resources.getDimensionPixelSize(id)
}
+
+ @AssistedFactory
+ interface Factory {
+ fun create(
+ context: Context,
+ configurationController: ConfigurationController
+ ): ConfigurationRepositoryImpl
+ }
}
@Module
-interface ConfigurationRepositoryModule {
- @Binds fun bindImpl(impl: ConfigurationRepositoryImpl): ConfigurationRepository
+abstract class ConfigurationRepositoryModule {
+
+ /**
+ * For compatibility reasons. Ideally, only the an annotated [ConfigurationRepository] should be
+ * injected.
+ */
+ @Binds
+ @Deprecated("Use the ConfigurationRepository annotated with @GlobalConfig instead.")
+ @SysUISingleton
+ abstract fun provideDefaultConfigRepository(
+ @GlobalConfig configurationRepository: ConfigurationRepository
+ ): ConfigurationRepository
+
+ companion object {
+ @Provides
+ @GlobalConfig
+ @SysUISingleton
+ fun provideGlobalConfigRepository(
+ context: Context,
+ @GlobalConfig configurationController: ConfigurationController,
+ factory: ConfigurationRepositoryImpl.Factory
+ ): ConfigurationRepository {
+ return factory.create(context, configurationController)
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt b/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt
index adb1ee2..eb423d6 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/domain/interactor/ConfigurationInteractor.kt
@@ -32,6 +32,7 @@
import kotlinx.coroutines.flow.onStart
/** Business logic related to configuration changes. */
+// TODO: b/374267505 - Create a @ShadeDisplayWindow annotated version of this.
@SysUISingleton
class ConfigurationInteractor @Inject constructor(private val repository: ConfigurationRepository) {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index cb649f2..9138243 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -49,6 +49,7 @@
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule;
import com.android.systemui.common.data.CommonDataLayerModule;
import com.android.systemui.common.ui.ConfigurationStateModule;
+import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryModule;
import com.android.systemui.common.usagestats.data.CommonUsageStatsDataLayerModule;
import com.android.systemui.communal.dagger.CommunalModule;
import com.android.systemui.complication.dagger.ComplicationComponent;
@@ -212,6 +213,7 @@
CommunalModule.class,
CommonDataLayerModule.class,
ConfigurationStateModule.class,
+ ConfigurationRepositoryModule.class,
CommonUsageStatsDataLayerModule.class,
ConfigurationControllerModule.class,
ConnectivityModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
index 96c0cac..40613c0 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
@@ -149,6 +149,7 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.data.repository.LightBarControllerStore;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -258,8 +259,7 @@
private boolean mTransientShownFromGestureOnSystemBar;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private LightBarController mLightBarController;
- private final LightBarController mMainLightBarController;
- private final LightBarController.Factory mLightBarControllerFactory;
+ private final LightBarControllerStore mLightBarControllerStore;
private AutoHideController mAutoHideController;
private final AutoHideController mMainAutoHideController;
private final AutoHideController.Factory mAutoHideControllerFactory;
@@ -580,8 +580,7 @@
@Background Executor bgExecutor,
UiEventLogger uiEventLogger,
NavBarHelper navBarHelper,
- LightBarController mainLightBarController,
- LightBarController.Factory lightBarControllerFactory,
+ LightBarControllerStore lightBarControllerStore,
AutoHideController mainAutoHideController,
AutoHideController.Factory autoHideControllerFactory,
Optional<TelecomManager> telecomManagerOptional,
@@ -628,8 +627,7 @@
mUiEventLogger = uiEventLogger;
mNavBarHelper = navBarHelper;
mNotificationShadeDepthController = notificationShadeDepthController;
- mMainLightBarController = mainLightBarController;
- mLightBarControllerFactory = lightBarControllerFactory;
+ mLightBarControllerStore = lightBarControllerStore;
mMainAutoHideController = mainAutoHideController;
mAutoHideControllerFactory = autoHideControllerFactory;
mTelecomManagerOptional = telecomManagerOptional;
@@ -842,8 +840,7 @@
// Unfortunately, we still need it because status bar needs LightBarController
// before notifications creation. We cannot directly use getLightBarController()
// from NavigationBarFragment directly.
- LightBarController lightBarController = mIsOnDefaultDisplay
- ? mMainLightBarController : mLightBarControllerFactory.create(mContext);
+ LightBarController lightBarController = mLightBarControllerStore.forDisplay(mDisplayId);
setLightBarController(lightBarController);
// TODO(b/118592525): to support multi-display, we start to add something which is
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 0e82bf8..c15c8f9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2053,6 +2053,9 @@
}
if (mQsController.getExpanded()) {
mQsController.flingQs(0, FLING_COLLAPSE);
+ } else if (mBarState == KEYGUARD) {
+ mLockscreenShadeTransitionController.goToLockedShade(
+ /* expandedView= */null, /* needsQSAnimation= */false);
} else {
expand(true /* animate */);
}
@@ -3109,7 +3112,7 @@
if (isTracking()) {
onTrackingStopped(true);
}
- if (isExpanded() && !mQsController.getExpanded()) {
+ if (isExpanded() && mBarState != KEYGUARD && !mQsController.getExpanded()) {
mShadeLog.d("Status Bar was long pressed. Expanding to QS.");
expandToQs();
} else {
@@ -5091,13 +5094,6 @@
}
boolean handled = mHeadsUpTouchHelper.onTouchEvent(event);
- if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch(
- event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) {
- if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
- mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
- }
- return true;
- }
// This touch session has already resulted in shade expansion. Ignore everything else.
if (ShadeExpandsOnStatusBarLongPress.isEnabled()
&& event.getActionMasked() != MotionEvent.ACTION_DOWN
@@ -5105,6 +5101,13 @@
mShadeLog.d("Touch has same down time as Status Bar long press. Ignoring.");
return false;
}
+ if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch(
+ event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) {
+ if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
+ mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
+ }
+ return true;
+ }
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
mMetricsLogger.count(COUNTER_PANEL_OPEN, 1);
handled = true;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index a8026cd..32255c6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -20,7 +20,11 @@
import android.content.res.Resources
import android.view.LayoutInflater
import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.common.ui.ConfigurationStateImpl
import com.android.systemui.common.ui.GlobalConfig
+import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImpl
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.res.R
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
@@ -97,4 +101,36 @@
ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
return shadeConfigurationController
}
+
+ @SysUISingleton
+ @Provides
+ @ShadeDisplayAware
+ fun provideShadeDisplayAwareConfigurationState(
+ factory: ConfigurationStateImpl.Factory,
+ @ShadeDisplayAware configurationController: ConfigurationController,
+ @ShadeDisplayAware context: Context,
+ @GlobalConfig configurationState: ConfigurationState,
+ ): ConfigurationState {
+ return if (ShadeWindowGoesAround.isEnabled) {
+ factory.create(context, configurationController)
+ } else {
+ configurationState
+ }
+ }
+
+ @SysUISingleton
+ @Provides
+ @ShadeDisplayAware
+ fun provideShadeDisplayAwareConfigurationRepository(
+ factory: ConfigurationRepositoryImpl.Factory,
+ @ShadeDisplayAware configurationController: ConfigurationController,
+ @ShadeDisplayAware context: Context,
+ @GlobalConfig globalConfigurationRepository: ConfigurationRepository
+ ): ConfigurationRepository {
+ return if (ShadeWindowGoesAround.isEnabled) {
+ factory.create(context, configurationController)
+ } else {
+ globalConfigurationRepository
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LongPressGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/shade/LongPressGestureDetector.kt
rename to packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt
index 6fb3ca5..ae36e81 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LongPressGestureDetector.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt
@@ -25,7 +25,7 @@
/** Accepts touch events, detects long press, and calls ShadeViewController#onStatusBarLongPress. */
@SysUISingleton
-class LongPressGestureDetector
+class StatusBarLongPressGestureDetector
@Inject
constructor(context: Context, val shadeViewController: ShadeViewController) {
val gestureDetector =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
index e5d08a0..a8d616c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
@@ -51,7 +51,7 @@
@Application private val applicationScope: CoroutineScope,
@ShadeDisplayAware private val context: Context,
@ShadeTouchLog private val touchLog: LogBuffer,
- private val configurationRepository: ConfigurationRepository,
+ @ShadeDisplayAware private val configurationRepository: ConfigurationRepository,
private val shadeRepository: ShadeRepository,
private val splitShadeStateController: SplitShadeStateController,
private val scrimShadeTransitionController: ScrimShadeTransitionController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index f65ae67..4341200 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -26,6 +26,7 @@
import com.android.systemui.log.LogBufferFactory
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.data.StatusBarDataLayerModule
+import com.android.systemui.statusbar.data.repository.LightBarControllerStore
import com.android.systemui.statusbar.phone.LightBarController
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProviderImpl
@@ -55,26 +56,26 @@
* [com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule], etc.).
*/
@Module(includes = [StatusBarDataLayerModule::class, SystemBarUtilsProxyImpl.Module::class])
-abstract class StatusBarModule {
+interface StatusBarModule {
@Binds
@IntoMap
@ClassKey(OngoingCallController::class)
- abstract fun bindOngoingCallController(impl: OngoingCallController): CoreStartable
+ fun bindOngoingCallController(impl: OngoingCallController): CoreStartable
@Binds
@IntoMap
@ClassKey(LightBarController::class)
- abstract fun bindLightBarController(impl: LightBarController): CoreStartable
+ fun lightBarControllerAsCoreStartable(controller: LightBarController): CoreStartable
@Binds
@IntoMap
@ClassKey(StatusBarSignalPolicy::class)
- abstract fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable
+ fun bindStatusBarSignalPolicy(impl: StatusBarSignalPolicy): CoreStartable
@Binds
@SysUISingleton
- abstract fun statusBarWindowControllerFactory(
+ fun statusBarWindowControllerFactory(
implFactory: StatusBarWindowControllerImpl.Factory
): StatusBarWindowController.Factory
@@ -82,6 +83,12 @@
@Provides
@SysUISingleton
+ fun lightBarController(store: LightBarControllerStore): LightBarController {
+ return store.defaultDisplay
+ }
+
+ @Provides
+ @SysUISingleton
fun windowControllerStore(
multiDisplayImplLazy: Lazy<MultiDisplayStatusBarWindowControllerStore>,
singleDisplayImplLazy: Lazy<SingleDisplayStatusBarWindowControllerStore>,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
index f2d926f..39de28e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.data
import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryModule
+import com.android.systemui.statusbar.data.repository.LightBarControllerStoreModule
import com.android.systemui.statusbar.data.repository.RemoteInputRepositoryModule
import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerModule
import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStoreModule
@@ -28,6 +29,7 @@
includes =
[
KeyguardStatusBarRepositoryModule::class,
+ LightBarControllerStoreModule::class,
RemoteInputRepositoryModule::class,
StatusBarConfigurationControllerModule::class,
StatusBarContentInsetsProviderStoreModule::class,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
new file mode 100644
index 0000000..ff50e31
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.statusbar.data.repository
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.DisplayScopeRepository
+import com.android.systemui.display.data.repository.PerDisplayStore
+import com.android.systemui.display.data.repository.PerDisplayStoreImpl
+import com.android.systemui.statusbar.phone.LightBarController
+import com.android.systemui.statusbar.phone.LightBarControllerImpl
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+
+/** Provides per display instances of [LightBarController]. */
+interface LightBarControllerStore : PerDisplayStore<LightBarController>
+
+@SysUISingleton
+class LightBarControllerStoreImpl
+@Inject
+constructor(
+ @Background backgroundApplicationScope: CoroutineScope,
+ displayRepository: DisplayRepository,
+ private val factory: LightBarControllerImpl.Factory,
+ private val displayScopeRepository: DisplayScopeRepository,
+ private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
+) :
+ LightBarControllerStore,
+ PerDisplayStoreImpl<LightBarController>(backgroundApplicationScope, displayRepository) {
+
+ override fun createInstanceForDisplay(displayId: Int): LightBarController {
+ return factory
+ .create(
+ displayId,
+ displayScopeRepository.scopeForDisplay(displayId),
+ statusBarModeRepositoryStore.forDisplay(displayId),
+ )
+ .also { it.start() }
+ }
+
+ override suspend fun onDisplayRemovalAction(instance: LightBarController) {
+ instance.stop()
+ }
+
+ override val instanceClass = LightBarController::class.java
+}
+
+@Module
+interface LightBarControllerStoreModule {
+
+ @Binds fun store(impl: LightBarControllerStoreImpl): LightBarControllerStore
+
+ @Binds
+ @IntoMap
+ @ClassKey(LightBarControllerStore::class)
+ fun storeAsCoreStartable(impl: LightBarControllerStoreImpl): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 99efba4..dceee22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -171,12 +171,14 @@
import com.android.systemui.shade.NotificationShadeWindowViewController;
import com.android.systemui.shade.QuickSettingsController;
import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress;
import com.android.systemui.shade.ShadeExpansionChangeEvent;
import com.android.systemui.shade.ShadeExpansionListener;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeLogger;
import com.android.systemui.shade.ShadeSurface;
import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.StatusBarLongPressGestureDetector;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -366,6 +368,7 @@
private PhoneStatusBarViewController mPhoneStatusBarViewController;
private PhoneStatusBarTransitions mStatusBarTransitions;
+ private final Provider<StatusBarLongPressGestureDetector> mStatusBarLongPressGestureDetector;
private final AuthRippleController mAuthRippleController;
@WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
private final NotificationShadeWindowController mNotificationShadeWindowController;
@@ -671,6 +674,7 @@
ShadeController shadeController,
WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ Provider<StatusBarLongPressGestureDetector> statusBarLongPressGestureDetector,
ViewMediatorCallback viewMediatorCallback,
InitController initController,
@Named(TIME_TICK_HANDLER_NAME) Handler timeTickHandler,
@@ -778,6 +782,7 @@
mShadeController = shadeController;
mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector;
mKeyguardViewMediatorCallback = viewMediatorCallback;
mInitController = initController;
mPluginDependencyProvider = pluginDependencyProvider;
@@ -1527,6 +1532,11 @@
// to touch outside the customizer to close it, such as on the status or nav bar.
mShadeController.onStatusBarTouch(event);
}
+ if (ShadeExpandsOnStatusBarLongPress.isEnabled()
+ && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+ mStatusBarLongPressGestureDetector.get().handleTouch(event);
+ }
+
return getNotificationShadeWindowView().onTouchEvent(event);
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt
new file mode 100644
index 0000000..b5b3162
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.statusbar.phone
+
+import android.view.WindowInsetsController
+import com.android.internal.colorextraction.ColorExtractor
+import com.android.internal.view.AppearanceRegion
+import com.android.systemui.CoreStartable
+
+/** Controls how light status bar flag applies to the icons. */
+interface LightBarController : CoreStartable {
+
+ fun stop()
+
+ fun setNavigationBar(navigationBar: LightBarTransitionsController)
+
+ fun setBiometricUnlockController(biometricUnlockController: BiometricUnlockController)
+
+ fun onNavigationBarAppearanceChanged(
+ @WindowInsetsController.Appearance appearance: Int,
+ nbModeChanged: Boolean,
+ navigationBarMode: Int,
+ navbarColorManagedByIme: Boolean,
+ )
+
+ fun onNavigationBarModeChanged(newBarMode: Int)
+
+ fun setQsCustomizing(customizing: Boolean)
+
+ /** Set if Quick Settings is fully expanded, which affects notification scrim visibility. */
+ fun setQsExpanded(expanded: Boolean)
+
+ /** Set if Global Actions dialog is visible, which requires dark mode (light buttons). */
+ fun setGlobalActionsVisible(visible: Boolean)
+
+ /**
+ * Controls the light status bar temporarily for back navigation.
+ *
+ * @param appearance the customized appearance.
+ */
+ fun customizeStatusBarAppearance(appearance: AppearanceRegion)
+
+ /**
+ * Sets whether the direct-reply is in use or not.
+ *
+ * @param directReplying `true` when the direct-reply is in-use.
+ */
+ fun setDirectReplying(directReplying: Boolean)
+
+ fun setScrimState(
+ scrimState: ScrimState,
+ scrimBehindAlpha: Float,
+ scrimInFrontColor: ColorExtractor.GradientColors,
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
similarity index 82%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
index a33996b..6ff9f4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.systemui.statusbar.phone;
@@ -22,9 +22,9 @@
import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
-import android.content.Context;
import android.graphics.Rect;
import android.util.Log;
+import android.view.Display;
import android.view.InsetsFlags;
import android.view.ViewDebug;
import android.view.WindowInsetsController.Appearance;
@@ -34,30 +34,32 @@
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.view.AppearanceRegion;
-import com.android.systemui.CoreStartable;
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.statusbar.data.model.StatusBarAppearance;
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
+import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.util.Compile;
-import com.android.systemui.util.kotlin.JavaAdapter;
+import com.android.systemui.util.kotlin.JavaAdapterKt;
+
+import dagger.assisted.Assisted;
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
+import kotlin.coroutines.CoroutineContext;
+
+import kotlinx.coroutines.CoroutineScope;
import java.io.PrintWriter;
import java.util.ArrayList;
-import javax.inject.Inject;
-
/**
* Controls how light status bar flag applies to the icons.
*/
-@SysUISingleton
-public class LightBarController implements
- BatteryController.BatteryStateChangeCallback, Dumpable, CoreStartable {
+public class LightBarControllerImpl implements
+ BatteryController.BatteryStateChangeCallback, LightBarController {
private static final String TAG = "LightBarController";
private static final boolean DEBUG_NAVBAR = Compile.IS_DEBUG;
@@ -65,10 +67,13 @@
private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
- private final JavaAdapter mJavaAdapter;
+ private final CoroutineScope mCoroutineScope;
private final SysuiDarkIconDispatcher mStatusBarIconController;
private final BatteryController mBatteryController;
- private final StatusBarModeRepositoryStore mStatusBarModeRepository;
+ private final NavigationModeController mNavModeController;
+ private final DumpManager mDumpManager;
+ private final StatusBarModePerDisplayRepository mStatusBarModeRepository;
+ private final CoroutineContext mMainContext;
private BiometricUnlockController mBiometricUnlockController;
private LightBarTransitionsController mNavigationBarController;
@@ -119,42 +124,59 @@
private String mLastNavigationBarAppearanceChangedLog;
private StringBuilder mLogStringBuilder = null;
- @Inject
- public LightBarController(
- Context ctx,
- JavaAdapter javaAdapter,
+ private final String mDumpableName;
+
+ private final NavigationModeController.ModeChangedListener mNavigationModeListener =
+ (mode) -> mNavigationMode = mode;
+
+ @AssistedInject
+ public LightBarControllerImpl(
+ @Assisted int displayId,
+ @Assisted CoroutineScope coroutineScope,
DarkIconDispatcher darkIconDispatcher,
BatteryController batteryController,
NavigationModeController navModeController,
- StatusBarModeRepositoryStore statusBarModeRepository,
+ @Assisted StatusBarModePerDisplayRepository statusBarModeRepository,
DumpManager dumpManager,
- DisplayTracker displayTracker) {
- mJavaAdapter = javaAdapter;
+ @Main CoroutineContext mainContext) {
+ mCoroutineScope = coroutineScope;
mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
mBatteryController = batteryController;
- mBatteryController.addCallback(this);
+ mNavModeController = navModeController;
+ mDumpManager = dumpManager;
mStatusBarModeRepository = statusBarModeRepository;
- mNavigationMode = navModeController.addListener((mode) -> {
- mNavigationMode = mode;
- });
-
- if (ctx.getDisplayId() == displayTracker.getDefaultDisplayId()) {
- dumpManager.registerDumpable(getClass().getSimpleName(), this);
- }
+ mMainContext = mainContext;
+ String dumpableNameSuffix =
+ displayId == Display.DEFAULT_DISPLAY ? "" : String.valueOf(displayId);
+ mDumpableName = getClass().getSimpleName() + dumpableNameSuffix;
}
@Override
public void start() {
- mJavaAdapter.alwaysCollectFlow(
- mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance(),
+ mDumpManager.registerCriticalDumpable(mDumpableName, this);
+ mBatteryController.addCallback(this);
+ mNavigationMode = mNavModeController.addListener(mNavigationModeListener);
+ JavaAdapterKt.collectFlow(
+ mCoroutineScope,
+ mMainContext,
+ mStatusBarModeRepository.getStatusBarAppearance(),
this::onStatusBarAppearanceChanged);
}
+ @Override
+ public void stop() {
+ mDumpManager.unregisterDumpable(mDumpableName);
+ mBatteryController.removeCallback(this);
+ mNavModeController.removeListener(mNavigationModeListener);
+ }
+
+ @Override
public void setNavigationBar(LightBarTransitionsController navigationBar) {
mNavigationBarController = navigationBar;
updateNavigation();
}
+ @Override
public void setBiometricUnlockController(
BiometricUnlockController biometricUnlockController) {
mBiometricUnlockController = biometricUnlockController;
@@ -202,6 +224,7 @@
mNavbarColorManagedByIme = navbarColorManagedByIme;
}
+ @Override
public void onNavigationBarAppearanceChanged(@Appearance int appearance, boolean nbModeChanged,
int navigationBarMode, boolean navbarColorManagedByIme) {
int diff = appearance ^ mAppearance;
@@ -244,6 +267,7 @@
mNavbarColorManagedByIme = navbarColorManagedByIme;
}
+ @Override
public void onNavigationBarModeChanged(int newBarMode) {
mHasLightNavigationBar = isLight(mAppearance, newBarMode, APPEARANCE_LIGHT_NAVIGATION_BARS);
}
@@ -258,30 +282,28 @@
mNavigationBarMode, mNavbarColorManagedByIme);
}
+ @Override
public void setQsCustomizing(boolean customizing) {
if (mQsCustomizing == customizing) return;
mQsCustomizing = customizing;
reevaluate();
}
- /** Set if Quick Settings is fully expanded, which affects notification scrim visibility */
+ @Override
public void setQsExpanded(boolean expanded) {
if (mQsExpanded == expanded) return;
mQsExpanded = expanded;
reevaluate();
}
- /** Set if Global Actions dialog is visible, which requires dark mode (light buttons) */
+ @Override
public void setGlobalActionsVisible(boolean visible) {
if (mGlobalActionsVisible == visible) return;
mGlobalActionsVisible = visible;
reevaluate();
}
- /**
- * Controls the light status bar temporarily for back navigation.
- * @param appearance the custmoized appearance.
- */
+ @Override
public void customizeStatusBarAppearance(AppearanceRegion appearance) {
if (appearance != null) {
final ArrayList<AppearanceRegion> appearancesList = new ArrayList<>();
@@ -303,16 +325,14 @@
}
}
- /**
- * Sets whether the direct-reply is in use or not.
- * @param directReplying {@code true} when the direct-reply is in-use.
- */
+ @Override
public void setDirectReplying(boolean directReplying) {
if (mDirectReplying == directReplying) return;
mDirectReplying = directReplying;
reevaluate();
}
+ @Override
public void setScrimState(ScrimState scrimState, float scrimBehindAlpha,
GradientColors scrimInFrontColor) {
boolean bouncerVisibleLast = mBouncerVisible;
@@ -387,20 +407,17 @@
}
}
- // If no one is light, all icons become white.
if (lightBarBounds.isEmpty()) {
- mStatusBarIconController.getTransitionsController().setIconsDark(
- false, animateChange());
- }
-
- // If all stacks are light, all icons get dark.
- else if (lightBarBounds.size() == numStacks) {
+ // If no one is light, all icons become white.
+ mStatusBarIconController
+ .getTransitionsController()
+ .setIconsDark(false, animateChange());
+ } else if (lightBarBounds.size() == numStacks) {
+ // If all stacks are light, all icons get dark.
mStatusBarIconController.setIconsDarkArea(null);
mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
- }
-
- // Not the same for every stack, magic!
- else {
+ } else {
+ // Not the same for every stack, magic!
mStatusBarIconController.setIconsDarkArea(lightBarBounds);
mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
}
@@ -468,47 +485,15 @@
}
}
- /**
- * Injectable factory for creating a {@link LightBarController}.
- */
- public static class Factory {
- private final JavaAdapter mJavaAdapter;
- private final DarkIconDispatcher mDarkIconDispatcher;
- private final BatteryController mBatteryController;
- private final NavigationModeController mNavModeController;
- private final StatusBarModeRepositoryStore mStatusBarModeRepository;
- private final DumpManager mDumpManager;
- private final DisplayTracker mDisplayTracker;
+ /** Injectable factory for creating a {@link LightBarControllerImpl}. */
+ @AssistedFactory
+ @FunctionalInterface
+ public interface Factory {
- @Inject
- public Factory(
- JavaAdapter javaAdapter,
- DarkIconDispatcher darkIconDispatcher,
- BatteryController batteryController,
- NavigationModeController navModeController,
- StatusBarModeRepositoryStore statusBarModeRepository,
- DumpManager dumpManager,
- DisplayTracker displayTracker) {
- mJavaAdapter = javaAdapter;
- mDarkIconDispatcher = darkIconDispatcher;
- mBatteryController = batteryController;
- mNavModeController = navModeController;
- mStatusBarModeRepository = statusBarModeRepository;
- mDumpManager = dumpManager;
- mDisplayTracker = displayTracker;
- }
-
- /** Create an {@link LightBarController} */
- public LightBarController create(Context context) {
- return new LightBarController(
- context,
- mJavaAdapter,
- mDarkIconDispatcher,
- mBatteryController,
- mNavModeController,
- mStatusBarModeRepository,
- mDumpManager,
- mDisplayTracker);
- }
+ /** Creates a {@link LightBarControllerImpl}. */
+ LightBarControllerImpl create(
+ int displayId,
+ CoroutineScope coroutineScope,
+ StatusBarModePerDisplayRepository statusBarModePerDisplayRepository);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 91c43dd..176dd8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -39,8 +39,8 @@
import com.android.systemui.Flags;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.res.R;
-import com.android.systemui.shade.LongPressGestureDetector;
import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress;
+import com.android.systemui.shade.StatusBarLongPressGestureDetector;
import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
import com.android.systemui.user.ui.binder.StatusBarUserChipViewBinder;
@@ -69,7 +69,7 @@
private InsetsFetcher mInsetsFetcher;
private int mDensity;
private float mFontScale;
- private LongPressGestureDetector mLongPressGestureDetector;
+ private StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector;
/**
* Draw this many pixels into the left/right side of the cutout to optimally use the space
@@ -81,9 +81,10 @@
mStatusBarWindowControllerStore = Dependency.get(StatusBarWindowControllerStore.class);
}
- void setLongPressGestureDetector(LongPressGestureDetector longPressGestureDetector) {
+ void setLongPressGestureDetector(
+ StatusBarLongPressGestureDetector statusBarLongPressGestureDetector) {
if (ShadeExpandsOnStatusBarLongPress.isEnabled()) {
- mLongPressGestureDetector = longPressGestureDetector;
+ mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector;
}
}
@@ -207,8 +208,9 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (ShadeExpandsOnStatusBarLongPress.isEnabled() && mLongPressGestureDetector != null) {
- mLongPressGestureDetector.handleTouch(event);
+ if (ShadeExpandsOnStatusBarLongPress.isEnabled()
+ && mStatusBarLongPressGestureDetector != null) {
+ mStatusBarLongPressGestureDetector.handleTouch(event);
}
if (mTouchEventHandler == null) {
Log.w(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index c24f432..4245494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -33,11 +33,11 @@
import com.android.systemui.res.R
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.ui.view.WindowRootView
-import com.android.systemui.shade.LongPressGestureDetector
import com.android.systemui.shade.ShadeController
import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress
import com.android.systemui.shade.ShadeLogger
import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.shade.StatusBarLongPressGestureDetector
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore
@@ -68,7 +68,7 @@
private val shadeController: ShadeController,
private val shadeViewController: ShadeViewController,
private val panelExpansionInteractor: PanelExpansionInteractor,
- private val longPressGestureDetector: Provider<LongPressGestureDetector>,
+ private val statusBarLongPressGestureDetector: Provider<StatusBarLongPressGestureDetector>,
private val windowRootView: Provider<WindowRootView>,
private val shadeLogger: ShadeLogger,
private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
@@ -118,7 +118,7 @@
addCursorSupportToIconContainers()
if (ShadeExpandsOnStatusBarLongPress.isEnabled) {
- mView.setLongPressGestureDetector(longPressGestureDetector.get())
+ mView.setLongPressGestureDetector(statusBarLongPressGestureDetector.get())
}
progressProvider?.setReadyToHandleTransition(true)
@@ -335,7 +335,7 @@
private val shadeController: ShadeController,
private val shadeViewController: ShadeViewController,
private val panelExpansionInteractor: PanelExpansionInteractor,
- private val longPressGestureDetector: Provider<LongPressGestureDetector>,
+ private val statusBarLongPressGestureDetector: Provider<StatusBarLongPressGestureDetector>,
private val windowRootView: Provider<WindowRootView>,
private val shadeLogger: ShadeLogger,
private val viewUtil: ViewUtil,
@@ -360,7 +360,7 @@
shadeController,
shadeViewController,
panelExpansionInteractor,
- longPressGestureDetector,
+ statusBarLongPressGestureDetector,
windowRootView,
shadeLogger,
statusBarMoveFromCenterAnimationController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepository.kt
index 1d08f2b..98eed84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepository.kt
@@ -37,6 +37,9 @@
/** Clients must observe this property, as device-based satellite is location-dependent */
val isSatelliteAllowedForCurrentLocation: StateFlow<Boolean>
+
+ /** When enabled, a satellite icon will display when all other connections are OOS */
+ val isOpportunisticSatelliteIconEnabled: Boolean
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcher.kt
index 58c30e0..de42b92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/DeviceBasedSatelliteRepositorySwitcher.kt
@@ -97,6 +97,9 @@
}
.stateIn(scope, SharingStarted.WhileSubscribed(), realImpl)
+ override val isOpportunisticSatelliteIconEnabled: Boolean
+ get() = activeRepo.value.isOpportunisticSatelliteIconEnabled
+
override val isSatelliteProvisioned: StateFlow<Boolean> =
activeRepo
.flatMapLatest { it.isSatelliteProvisioned }
@@ -118,6 +121,6 @@
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
- realImpl.isSatelliteAllowedForCurrentLocation.value
+ realImpl.isSatelliteAllowedForCurrentLocation.value,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepository.kt
index d557bbf..755899f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/demo/DemoDeviceBasedSatelliteRepository.kt
@@ -16,15 +16,18 @@
package com.android.systemui.statusbar.pipeline.satellite.data.demo
+import android.content.res.Resources
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.res.R
import com.android.systemui.statusbar.pipeline.satellite.data.DeviceBasedSatelliteRepository
import com.android.systemui.statusbar.pipeline.satellite.shared.model.SatelliteConnectionState
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
-import com.android.app.tracing.coroutines.launchTraced as launch
/** A satellite repository that represents the latest satellite values sent via demo mode. */
@SysUISingleton
@@ -33,9 +36,13 @@
constructor(
private val dataSource: DemoDeviceBasedSatelliteDataSource,
@Application private val scope: CoroutineScope,
+ @Main resources: Resources,
) : DeviceBasedSatelliteRepository {
private var demoCommandJob: Job? = null
+ override val isOpportunisticSatelliteIconEnabled =
+ resources.getBoolean(R.bool.config_showOpportunisticSatelliteIcon)
+
override val isSatelliteProvisioned = MutableStateFlow(true)
override val connectionState = MutableStateFlow(SatelliteConnectionState.Unknown)
override val signalStrength = MutableStateFlow(0)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
index 7686338..a36ef56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.satellite.data.prod
+import android.content.res.Resources
import android.os.OutcomeReceiver
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
@@ -27,14 +28,17 @@
import android.telephony.satellite.SatelliteProvisionStateCallback
import android.telephony.satellite.SatelliteSupportedStateCallback
import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.core.MessageInitializer
import com.android.systemui.log.core.MessagePrinter
+import com.android.systemui.res.R
import com.android.systemui.statusbar.pipeline.dagger.DeviceBasedSatelliteInputLog
import com.android.systemui.statusbar.pipeline.dagger.VerboseDeviceBasedSatelliteInputLog
import com.android.systemui.statusbar.pipeline.satellite.data.RealDeviceBasedSatelliteRepository
@@ -66,7 +70,6 @@
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
@@ -146,10 +149,14 @@
@DeviceBasedSatelliteInputLog private val logBuffer: LogBuffer,
@VerboseDeviceBasedSatelliteInputLog private val verboseLogBuffer: LogBuffer,
private val systemClock: SystemClock,
+ @Main resources: Resources,
) : RealDeviceBasedSatelliteRepository {
private val satelliteManager: SatelliteManager?
+ override val isOpportunisticSatelliteIconEnabled: Boolean =
+ resources.getBoolean(R.bool.config_showOpportunisticSatelliteIcon)
+
// Some calls into satellite manager will throw exceptions if it is not supported.
// This is never expected to change after boot, but may need to be retried in some cases
@get:VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index f1a444f..08a98c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -53,6 +53,9 @@
@DeviceBasedSatelliteInputLog private val logBuffer: LogBuffer,
@DeviceBasedSatelliteTableLog private val tableLog: TableLogBuffer,
) {
+ /** Whether or not we should show the satellite icon when all connections are OOS */
+ val isOpportunisticSatelliteIconEnabled = repo.isOpportunisticSatelliteIconEnabled
+
/** Must be observed by any UI showing Satellite iconography */
val isSatelliteAllowed =
if (Flags.oemEnabledSatelliteFlag()) {
@@ -93,12 +96,7 @@
flowOf(0)
}
.distinctUntilChanged()
- .logDiffsForTable(
- tableLog,
- columnPrefix = "",
- columnName = COL_LEVEL,
- initialValue = 0,
- )
+ .logDiffsForTable(tableLog, columnPrefix = "", columnName = COL_LEVEL, initialValue = 0)
.stateIn(scope, SharingStarted.WhileSubscribed(), 0)
val isSatelliteProvisioned = repo.isSatelliteProvisioned
@@ -132,10 +130,9 @@
/** When all connections are considered OOS, satellite connectivity is potentially valid */
val areAllConnectionsOutOfService =
if (Flags.oemEnabledSatelliteFlag()) {
- combine(
- allConnectionsOos,
- iconsInteractor.isDeviceInEmergencyCallsOnlyMode,
- ) { connectionsOos, deviceEmergencyOnly ->
+ combine(allConnectionsOos, iconsInteractor.isDeviceInEmergencyCallsOnlyMode) {
+ connectionsOos,
+ deviceEmergencyOnly ->
logBuffer.log(
TAG,
LogLevel.INFO,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
index 37f2f19..13ac321 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt
@@ -77,35 +77,38 @@
// This adds a 10 seconds delay before showing the icon
private val shouldShowIconForOosAfterHysteresis: StateFlow<Boolean> =
- interactor.areAllConnectionsOutOfService
- .flatMapLatest { shouldShow ->
- if (shouldShow) {
- logBuffer.log(
- TAG,
- LogLevel.INFO,
- { long1 = DELAY_DURATION.inWholeSeconds },
- { "Waiting $long1 seconds before showing the satellite icon" }
+ if (interactor.isOpportunisticSatelliteIconEnabled) {
+ interactor.areAllConnectionsOutOfService
+ .flatMapLatest { shouldShow ->
+ if (shouldShow) {
+ logBuffer.log(
+ TAG,
+ LogLevel.INFO,
+ { long1 = DELAY_DURATION.inWholeSeconds },
+ { "Waiting $long1 seconds before showing the satellite icon" },
+ )
+ delay(DELAY_DURATION)
+ flowOf(true)
+ } else {
+ flowOf(false)
+ }
+ }
+ .distinctUntilChanged()
+ .logDiffsForTable(
+ tableLog,
+ columnPrefix = "vm",
+ columnName = COL_VISIBLE_FOR_OOS,
+ initialValue = false,
)
- delay(DELAY_DURATION)
- flowOf(true)
- } else {
- flowOf(false)
- }
+ } else {
+ flowOf(false)
}
- .distinctUntilChanged()
- .logDiffsForTable(
- tableLog,
- columnPrefix = "vm",
- columnName = COL_VISIBLE_FOR_OOS,
- initialValue = false,
- )
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
private val canShowIcon =
- combine(
- interactor.isSatelliteAllowed,
- interactor.isSatelliteProvisioned,
- ) { allowed, provisioned ->
+ combine(interactor.isSatelliteAllowed, interactor.isSatelliteProvisioned) {
+ allowed,
+ provisioned ->
allowed && provisioned
}
@@ -141,11 +144,10 @@
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val icon: StateFlow<Icon?> =
- combine(
- showIcon,
- interactor.connectionState,
- interactor.signalStrength,
- ) { shouldShow, state, signalStrength ->
+ combine(showIcon, interactor.connectionState, interactor.signalStrength) {
+ shouldShow,
+ state,
+ signalStrength ->
if (shouldShow) {
SatelliteIconModel.fromConnectionState(state, signalStrength)
} else {
@@ -155,10 +157,7 @@
.stateIn(scope, SharingStarted.WhileSubscribed(), null)
override val carrierText: StateFlow<String?> =
- combine(
- showIcon,
- interactor.connectionState,
- ) { shouldShow, connectionState ->
+ combine(showIcon, interactor.connectionState) { shouldShow, connectionState ->
logBuffer.log(
TAG,
LogLevel.INFO,
@@ -166,7 +165,7 @@
bool1 = shouldShow
str1 = connectionState.name
},
- { "Updating carrier text. shouldShow=$bool1 connectionState=$str1" }
+ { "Updating carrier text. shouldShow=$bool1 connectionState=$str1" },
)
if (shouldShow) {
when (connectionState) {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 9c8ef04..1c3fece 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -242,10 +242,16 @@
}
};
- private int getLatestWallpaperType(int userId) {
- return mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, userId)
- > mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, userId)
- ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM;
+ private int getDefaultWallpaperColorsSource(int userId) {
+ if (com.android.systemui.shared.Flags.newCustomizationPickerUi()) {
+ // The wallpaper colors source is always the home wallpaper.
+ return WallpaperManager.FLAG_SYSTEM;
+ } else {
+ // The wallpaper colors source is based on the last set wallpaper.
+ return mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, userId)
+ > mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, userId)
+ ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM;
+ }
}
private boolean isSeedColorSet(JSONObject jsonObject, WallpaperColors newWallpaperColors) {
@@ -279,9 +285,9 @@
private void handleWallpaperColors(WallpaperColors wallpaperColors, int flags, int userId) {
final int currentUser = mUserTracker.getUserId();
final boolean hadWallpaperColors = mCurrentColors.get(userId) != null;
- int latestWallpaperType = getLatestWallpaperType(userId);
- boolean eventForLatestWallpaper = (flags & latestWallpaperType) != 0;
- if (eventForLatestWallpaper) {
+ int wallpaperColorsSource = getDefaultWallpaperColorsSource(userId);
+ boolean wallpaperColorsNeedUpdate = (flags & wallpaperColorsSource) != 0;
+ if (wallpaperColorsNeedUpdate) {
mCurrentColors.put(userId, wallpaperColors);
if (DEBUG) Log.d(TAG, "got new colors: " + wallpaperColors + " where: " + flags);
}
@@ -328,7 +334,7 @@
boolean userChoseLockScreenColor = COLOR_SOURCE_LOCK.equals(wallpaperPickerColorSource);
boolean preserveLockScreenColor = isDestinationHomeOnly && userChoseLockScreenColor;
- if (!userChosePresetColor && !preserveLockScreenColor && eventForLatestWallpaper
+ if (!userChosePresetColor && !preserveLockScreenColor && wallpaperColorsNeedUpdate
&& !isSeedColorSet(jsonObject, wallpaperColors)) {
mSkipSettingChange = true;
if (jsonObject.has(OVERLAY_CATEGORY_ACCENT_COLOR) || jsonObject.has(
@@ -494,7 +500,7 @@
// Upon boot, make sure we have the most up to date colors
Runnable updateColors = () -> {
WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
- getLatestWallpaperType(mUserTracker.getUserId()));
+ getDefaultWallpaperColorsSource(mUserTracker.getUserId()));
Runnable applyColors = () -> {
if (DEBUG) Log.d(TAG, "Boot colors: " + systemColor);
mCurrentColors.put(mUserTracker.getUserId(), systemColor);
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
index 3159124..63a5b3f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt
@@ -20,6 +20,7 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.lifecycle.repeatWhenAttached
@@ -35,7 +36,7 @@
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
+import kotlinx.coroutines.plus
/** A class allowing Java classes to collect on Kotlin flows. */
@SysUISingleton
@@ -102,6 +103,22 @@
}
}
+/**
+ * Collect information for the given [flow], calling [consumer] for each emitted event on the
+ * specified [collectContext].
+ *
+ * Collection will continue until the given [scope] is cancelled.
+ */
+@JvmOverloads
+fun <T> collectFlow(
+ scope: CoroutineScope,
+ collectContext: CoroutineContext = scope.coroutineContext,
+ flow: Flow<T>,
+ consumer: Consumer<T>,
+): Job {
+ return scope.plus(collectContext).launch { flow.collect { consumer.accept(it) } }
+}
+
fun <A, B, R> combineFlows(flow1: Flow<A>, flow2: Flow<B>, bifunction: (A, B) -> R): Flow<R> {
return combine(flow1, flow2, bifunction)
}
diff --git a/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
index a95735e..82cfab6 100644
--- a/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ b/packages/SystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -56,7 +56,6 @@
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestCase {
-
private static final String TAG = "AAA++VerifyTest";
private static final Class[] BASE_CLS_TO_INCLUDE = {
@@ -149,6 +148,9 @@
*/
private boolean isTestClass(Class<?> loadedClass) {
try {
+ if (loadedClass.getAnnotation(SkipSysuiVerification.class) != null) {
+ return false;
+ }
if (Modifier.isAbstract(loadedClass.getModifiers())) {
logDebug(String.format("Skipping abstract class %s: not a test",
loadedClass.getName()));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index f472fd1..11b5603 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -155,6 +155,7 @@
import com.android.systemui.shade.ShadeControllerImpl;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.ShadeLogger;
+import com.android.systemui.shade.StatusBarLongPressGestureDetector;
import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.KeyboardShortcutListSearch;
@@ -174,7 +175,6 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
import com.android.systemui.statusbar.core.StatusBarInitializerImpl;
-import com.android.systemui.statusbar.core.StatusBarOrchestrator;
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -371,7 +371,7 @@
@Mock private EmergencyGestureIntentFactory mEmergencyGestureIntentFactory;
@Mock private NotificationSettingsInteractor mNotificationSettingsInteractor;
@Mock private ViewCaptureAwareWindowManager mViewCaptureAwareWindowManager;
- @Mock private StatusBarOrchestrator mStatusBarOrchestrator;
+ @Mock private StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector;
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeGlobalSettings mFakeGlobalSettings = new FakeGlobalSettings();
@@ -602,6 +602,7 @@
mShadeController,
mWindowRootViewVisibilityInteractor,
mStatusBarKeyguardViewManager,
+ () -> mStatusBarLongPressGestureDetector,
mViewMediatorCallback,
mInitController,
new Handler(TestableLooper.get(this).getLooper()),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 638f195..69efa87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -40,14 +40,13 @@
import com.android.systemui.plugins.fakeDarkIconDispatcher
import com.android.systemui.res.R
import com.android.systemui.scene.ui.view.WindowRootView
-import com.android.systemui.shade.LongPressGestureDetector
import com.android.systemui.shade.ShadeControllerImpl
import com.android.systemui.shade.ShadeLogger
import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.shade.StatusBarLongPressGestureDetector
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.data.repository.fakeStatusBarContentInsetsProviderStore
-import com.android.systemui.statusbar.data.repository.statusBarContentInsetsProviderStore
import com.android.systemui.statusbar.policy.Clock
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.window.StatusBarWindowStateController
@@ -98,7 +97,7 @@
@Mock private lateinit var windowRootView: Provider<WindowRootView>
@Mock private lateinit var shadeLogger: ShadeLogger
@Mock private lateinit var viewUtil: ViewUtil
- @Mock private lateinit var longPressGestureDetector: LongPressGestureDetector
+ @Mock private lateinit var mStatusBarLongPressGestureDetector: StatusBarLongPressGestureDetector
private lateinit var statusBarWindowStateController: StatusBarWindowStateController
private lateinit var view: PhoneStatusBarView
@@ -395,7 +394,7 @@
shadeControllerImpl,
shadeViewController,
panelExpansionInteractor,
- { longPressGestureDetector },
+ { mStatusBarLongPressGestureDetector },
windowRootView,
shadeLogger,
viewUtil,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
index 4d293b9..6326e73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
@@ -102,6 +102,7 @@
logBuffer = FakeLogBuffer.Factory.create(),
verboseLogBuffer = FakeLogBuffer.Factory.create(),
systemClock,
+ context.resources,
)
val connectionState by collectLastValue(underTest.connectionState)
@@ -267,11 +268,7 @@
fun satelliteProvisioned_notSupported_defaultFalse() =
testScope.runTest {
// GIVEN satellite is not supported
- setUpRepo(
- uptime = MIN_UPTIME,
- satMan = satelliteManager,
- satelliteSupported = false,
- )
+ setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = false)
assertThat(underTest.isSatelliteProvisioned.value).isFalse()
}
@@ -280,11 +277,7 @@
fun satelliteProvisioned_supported_defaultFalse() =
testScope.runTest {
// GIVEN satellite is supported
- setUpRepo(
- uptime = MIN_UPTIME,
- satMan = satelliteManager,
- satelliteSupported = true,
- )
+ setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = true)
// THEN default provisioned state is false
assertThat(underTest.isSatelliteProvisioned.value).isFalse()
@@ -323,6 +316,7 @@
logBuffer = FakeLogBuffer.Factory.create(),
verboseLogBuffer = FakeLogBuffer.Factory.create(),
systemClock,
+ context.resources,
)
// WHEN we try to check for provisioned status
@@ -361,6 +355,7 @@
logBuffer = FakeLogBuffer.Factory.create(),
verboseLogBuffer = FakeLogBuffer.Factory.create(),
systemClock,
+ context.resources,
)
// WHEN we try to check for provisioned status
@@ -445,11 +440,7 @@
fun satelliteProvisioned_supported_tracksCallback_reRegistersOnCrash() =
testScope.runTest {
// GIVEN satellite is supported
- setUpRepo(
- uptime = MIN_UPTIME,
- satMan = satelliteManager,
- satelliteSupported = true,
- )
+ setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = true)
val provisioned by collectLastValue(underTest.isSatelliteProvisioned)
@@ -487,11 +478,7 @@
fun satelliteNotSupported_listenersAreNotRegistered() =
testScope.runTest {
// GIVEN satellite is not supported
- setUpRepo(
- uptime = MIN_UPTIME,
- satMan = satelliteManager,
- satelliteSupported = false,
- )
+ setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = false)
// WHEN data is requested from the repo
val connectionState by collectLastValue(underTest.connectionState)
@@ -517,11 +504,7 @@
fun satelliteNotSupported_registersCallbackForStateChanges() =
testScope.runTest {
// GIVEN satellite is not supported
- setUpRepo(
- uptime = MIN_UPTIME,
- satMan = satelliteManager,
- satelliteSupported = false,
- )
+ setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = false)
runCurrent()
// THEN the repo registers for state changes of satellite support
@@ -577,11 +560,7 @@
fun satelliteNotSupported_supportShowsUp_registersListeners() =
testScope.runTest {
// GIVEN satellite is not supported
- setUpRepo(
- uptime = MIN_UPTIME,
- satMan = satelliteManager,
- satelliteSupported = false,
- )
+ setUpRepo(uptime = MIN_UPTIME, satMan = satelliteManager, satelliteSupported = false)
runCurrent()
val callback =
@@ -610,11 +589,7 @@
fun repoDoesNotCheckForSupportUntilMinUptime() =
testScope.runTest {
// GIVEN we init 100ms after sysui starts up
- setUpRepo(
- uptime = 100,
- satMan = satelliteManager,
- satelliteSupported = true,
- )
+ setUpRepo(uptime = 100, satMan = satelliteManager, satelliteSupported = true)
// WHEN data is requested
val connectionState by collectLastValue(underTest.connectionState)
@@ -726,6 +701,7 @@
logBuffer = FakeLogBuffer.Factory.create(),
verboseLogBuffer = FakeLogBuffer.Factory.create(),
systemClock,
+ context.resources,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/OnTeardownRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/OnTeardownRule.kt
new file mode 100644
index 0000000..778614b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/OnTeardownRule.kt
@@ -0,0 +1,75 @@
+/*
+ * 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
+
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+import org.junit.runners.model.MultipleFailureException
+
+/**
+ * Rule that allows teardown steps to be added right next to the places where it becomes clear they
+ * are needed. This can avoid the need for complicated or conditional logic in a single teardown
+ * method. Examples:
+ * ```
+ * @get:Rule teardownRule = OnTeardownRule()
+ *
+ * // setup and teardown right next to each other
+ * @Before
+ * fun setUp() {
+ * val oldTimeout = getGlobalTimeout()
+ * teardownRule.onTeardown { setGlobalTimeout(oldTimeout) }
+ * overrideGlobalTimeout(5000)
+ * }
+ *
+ * // add teardown logic for fixtures that aren't used in every test
+ * fun addCustomer() {
+ * val id = globalDatabase.addCustomer(TEST_NAME, TEST_ADDRESS, ...)
+ * teardownRule.onTeardown { globalDatabase.deleteCustomer(id) }
+ * }
+ * ```
+ */
+class OnTeardownRule : TestWatcher() {
+ private var canAdd = true
+ private val teardowns = mutableListOf<() -> Unit>()
+
+ fun onTeardown(teardownRunnable: () -> Unit) {
+ if (!canAdd) {
+ throw IllegalStateException("Cannot add new teardown routines after test complete.")
+ }
+ teardowns.add(teardownRunnable)
+ }
+
+ fun onTeardown(teardownRunnable: Runnable) {
+ if (!canAdd) {
+ throw IllegalStateException("Cannot add new teardown routines after test complete.")
+ }
+ teardowns.add { teardownRunnable.run() }
+ }
+
+ override fun finished(description: Description?) {
+ canAdd = false
+ val errors = mutableListOf<Throwable>()
+ teardowns.reversed().forEach {
+ try {
+ it()
+ } catch (e: Throwable) {
+ errors.add(e)
+ }
+ }
+ MultipleFailureException.assertEmpty(errors)
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 27a2cab..153a8be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -56,6 +56,8 @@
import java.io.FileInputStream;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
@@ -69,6 +71,17 @@
// background on Ravenwood is available at go/ravenwood-docs
@DisabledOnRavenwood
public abstract class SysuiTestCase {
+ /**
+ * Especially when self-testing test utilities, we may have classes that look like test
+ * classes, but we don't expect to ever actually run as a top-level test.
+ * For example, {@link com.android.systemui.TryToDoABadThing}.
+ * Verifying properties on these as a part of structural tests like
+ * AAAPlusPlusVerifySysuiRequiredTestPropertiesTest is a waste of our time, and makes things
+ * look more confusing, so this lets us skip when appropriate.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface SkipSysuiVerification {
+ }
private static final String TAG = "SysuiTestCase";
@@ -172,6 +185,15 @@
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
+ @Rule public final OnTeardownRule mTearDownRule = new OnTeardownRule();
+
+ /**
+ * Schedule a cleanup routine to happen when the test state is torn down.
+ */
+ protected void onTeardown(Runnable tearDownRunnable) {
+ mTearDownRule.onTeardown(tearDownRunnable);
+ }
+
// set the highest order so it's the innermost rule
@Rule(order = Integer.MAX_VALUE)
public TestWithLooperRule mlooperRule = new TestWithLooperRule();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreKosmos.kt
new file mode 100644
index 0000000..5f33732
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreKosmos.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.statusbar.data.repository
+
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.display.data.repository.displayScopeRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import org.mockito.kotlin.mock
+
+val Kosmos.lightBarControllerStoreImpl by
+ Kosmos.Fixture {
+ LightBarControllerStoreImpl(
+ backgroundApplicationScope = applicationCoroutineScope,
+ displayRepository = displayRepository,
+ factory = { _, _, _ -> mock() },
+ displayScopeRepository = displayScopeRepository,
+ statusBarModeRepositoryStore = statusBarModeRepository,
+ )
+ }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 985155d..0cf55bb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -493,7 +493,7 @@
private static final int MSG_INIT_ADI_DEVICE_STATES = 103;
private static final int MSG_INIT_INPUT_GAINS = 104;
- private static final int MSG_SET_INPUT_GAIN_INDEX = 105;
+ private static final int MSG_APPLY_INPUT_GAIN_INDEX = 105;
private static final int MSG_PERSIST_INPUT_GAIN_INDEX = 106;
// end of messages handled under wakelock
@@ -1626,7 +1626,6 @@
new InputDeviceVolumeHelper(
mSettings,
mContentResolver,
- mSettingsLock,
System.INPUT_GAIN_INDEX_SETTINGS);
}
@@ -5804,7 +5803,7 @@
// to persist).
sendMsg(
mAudioHandler,
- MSG_SET_INPUT_GAIN_INDEX,
+ MSG_APPLY_INPUT_GAIN_INDEX,
SENDMSG_QUEUE,
/*arg1*/ index,
/*arg2*/ 0,
@@ -5813,22 +5812,22 @@
}
}
- private void setInputGainIndexInt(@NonNull AudioDeviceAttributes ada, int index) {
+ private void onApplyInputGainIndex(@NonNull AudioDeviceAttributes ada, int index) {
// TODO(b/364923030): call AudioSystem to apply input gain in native layer.
// Post a persist input gain msg.
sendMsg(
mAudioHandler,
MSG_PERSIST_INPUT_GAIN_INDEX,
- SENDMSG_QUEUE,
- /*arg1*/ index,
+ SENDMSG_REPLACE,
+ /*arg1*/ 0,
/*arg2*/ 0,
/*obj*/ ada,
PERSIST_DELAY);
}
- private void persistInputGainIndex(@NonNull AudioDeviceAttributes ada, int index) {
- mInputDeviceVolumeHelper.persistInputGainIndex(ada, index);
+ private void onPersistInputGainIndex(@NonNull AudioDeviceAttributes ada) {
+ mInputDeviceVolumeHelper.persistInputGainIndex(ada);
}
/**
@@ -10213,12 +10212,12 @@
vgs.persistVolumeGroup(msg.arg1);
break;
- case MSG_SET_INPUT_GAIN_INDEX:
- setInputGainIndexInt((AudioDeviceAttributes) msg.obj, msg.arg1);
+ case MSG_APPLY_INPUT_GAIN_INDEX:
+ onApplyInputGainIndex((AudioDeviceAttributes) msg.obj, msg.arg1);
break;
case MSG_PERSIST_INPUT_GAIN_INDEX:
- persistInputGainIndex((AudioDeviceAttributes) msg.obj, msg.arg1);
+ onPersistInputGainIndex((AudioDeviceAttributes) msg.obj);
break;
case MSG_PERSIST_RINGER_MODE:
diff --git a/services/core/java/com/android/server/audio/InputDeviceVolumeHelper.java b/services/core/java/com/android/server/audio/InputDeviceVolumeHelper.java
index d83dca6..d094629 100644
--- a/services/core/java/com/android/server/audio/InputDeviceVolumeHelper.java
+++ b/services/core/java/com/android/server/audio/InputDeviceVolumeHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -43,7 +43,6 @@
private final SettingsAdapter mSettings;
private final ContentResolver mContentResolver;
- private final Object mSettingsLock;
private final String mInputGainIndexSettingsName;
// A map between device internal type (e.g. AudioSystem.DEVICE_IN_BUILTIN_MIC) to its input gain
@@ -54,11 +53,9 @@
InputDeviceVolumeHelper(
SettingsAdapter settings,
ContentResolver contentResolver,
- Object settingsLock,
String settingsName) {
mSettings = settings;
mContentResolver = contentResolver;
- mSettingsLock = settingsLock;
mInputGainIndexSettingsName = settingsName;
IntArray internalDeviceTypes = new IntArray();
@@ -82,34 +79,27 @@
readSettings();
}
- public void readSettings() {
+ private void readSettings() {
synchronized (InputDeviceVolumeHelper.class) {
for (int inputDeviceType : mSupportedDeviceTypes) {
// Retrieve current input gain for device. If no input gain stored for current
// device, use default input gain.
- int index;
- if (!hasValidSettingsName()) {
- index = INDEX_DEFAULT;
- } else {
- String name = getSettingNameForDevice(inputDeviceType);
- index =
- mSettings.getSystemIntForUser(
- mContentResolver, name, INDEX_DEFAULT, UserHandle.USER_CURRENT);
- }
+ String name = getSettingNameForDevice(inputDeviceType);
+ int index = name == null
+ ? INDEX_DEFAULT
+ : mSettings.getSystemIntForUser(
+ mContentResolver, name, INDEX_DEFAULT, UserHandle.USER_CURRENT);
mInputGainIndexMap.put(inputDeviceType, getValidIndex(index));
}
}
}
- public boolean hasValidSettingsName() {
- return mInputGainIndexSettingsName != null && !mInputGainIndexSettingsName.isEmpty();
- }
-
- public @Nullable String getSettingNameForDevice(int inputDeviceType) {
- if (!hasValidSettingsName()) {
+ private @Nullable String getSettingNameForDevice(int inputDeviceType) {
+ if (mInputGainIndexSettingsName == null || mInputGainIndexSettingsName.isEmpty()) {
return null;
}
+
final String suffix = AudioSystem.getInputDeviceName(inputDeviceType);
if (suffix.isEmpty()) {
return mInputGainIndexSettingsName;
@@ -158,29 +148,27 @@
ensureValidInputDeviceType(inputDeviceType);
int oldIndex;
- synchronized (mSettingsLock) {
- synchronized (InputDeviceVolumeHelper.class) {
- oldIndex = getInputGainIndex(ada);
- index = getValidIndex(index);
+ synchronized (InputDeviceVolumeHelper.class) {
+ oldIndex = getInputGainIndex(ada);
+ index = getValidIndex(index);
- if (oldIndex == index) {
- return false;
- }
-
- mInputGainIndexMap.put(inputDeviceType, index);
- return true;
+ if (oldIndex == index) {
+ return false;
}
+
+ mInputGainIndexMap.put(inputDeviceType, index);
+ return true;
}
}
- public void persistInputGainIndex(@NonNull AudioDeviceAttributes ada, int index) {
+ public void persistInputGainIndex(@NonNull AudioDeviceAttributes ada) {
int inputDeviceType = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice(ada.getType());
- ensureValidInputDeviceType(inputDeviceType);
-
- if (hasValidSettingsName()) {
+ String name = getSettingNameForDevice(inputDeviceType);
+ if (name != null) {
+ int index = getInputGainIndex(ada);
mSettings.putSystemIntForUser(
mContentResolver,
- getSettingNameForDevice(inputDeviceType),
+ name,
index,
UserHandle.USER_CURRENT);
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 8627a47..ee07d2e 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1735,9 +1735,9 @@
}
// Show IME over the keyguard if the target allows it.
- final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisible()
- && win.mIsImWindow && (imeTarget.canShowWhenLocked()
- || !imeTarget.canBeHiddenByKeyguard());
+ final boolean showImeOverKeyguard =
+ imeTarget != null && imeTarget.isOnScreen() && win.mIsImWindow && (
+ imeTarget.canShowWhenLocked() || !imeTarget.canBeHiddenByKeyguard());
if (showImeOverKeyguard) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index e9c6e93..71adb80 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -100,13 +100,13 @@
// isLeashReadyForDispatching (used to dispatch the leash of the control) is
// depending on mGivenInsetsReady. Therefore, triggering notifyControlChanged here
// again, so that the control with leash can be eventually dispatched
- if (!mGivenInsetsReady && mServerVisible && !givenInsetsPending) {
+ if (!mGivenInsetsReady && isServerVisible() && !givenInsetsPending) {
mGivenInsetsReady = true;
ImeTracker.forLogging().onProgress(mStatsToken,
ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
mStateController.notifyControlChanged(mControlTarget, this);
setImeShowing(true);
- } else if (wasServerVisible && mServerVisible && mGivenInsetsReady
+ } else if (wasServerVisible && isServerVisible() && mGivenInsetsReady
&& givenInsetsPending) {
// If the server visibility didn't change (still visible), and mGivenInsetsReady
// is set, we won't call into notifyControlChanged. Therefore, we can reset the
@@ -114,7 +114,7 @@
ImeTracker.forLogging().onCancelled(mStatsToken,
ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
mStatsToken = null;
- } else if (wasServerVisible && !mServerVisible) {
+ } else if (wasServerVisible && !isServerVisible()) {
setImeShowing(false);
}
}
@@ -134,11 +134,15 @@
@Override
protected boolean isLeashReadyForDispatching() {
if (android.view.inputmethod.Flags.refactorInsetsController()) {
+ // We should only dispatch the leash, if the following conditions are fulfilled:
+ // 1. parent isLeashReadyForDispatching, 2. mGivenInsetsReady (means there are no
+ // givenInsetsPending), 3. the IME surface is drawn, 4. either the IME is
+ // serverVisible (the unfrozen state)
final WindowState ws =
mWindowContainer != null ? mWindowContainer.asWindowState() : null;
final boolean isDrawn = ws != null && ws.isDrawn();
return super.isLeashReadyForDispatching()
- && mServerVisible && isDrawn && mGivenInsetsReady;
+ && isServerVisible() && isDrawn && mGivenInsetsReady;
} else {
return super.isLeashReadyForDispatching();
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 1d4d6eb..7276007 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -730,6 +730,10 @@
return mFakeControlTarget;
}
+ boolean isServerVisible() {
+ return mServerVisible;
+ }
+
boolean isClientVisible() {
return mClientVisible;
}