Merge changes from topic "stl-move-offset-effect" into main
* changes:
Move OffsetOverscrollEffect and others to PlatformComposeCore (1/2)
Extract internal GestureEffect out of ContentOverscrollEffect
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 34c88e9..8da630c 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -28,6 +28,7 @@
import static com.android.hardware.input.Flags.mouseScrollingAcceleration;
import static com.android.hardware.input.Flags.mouseReverseVerticalScrolling;
import static com.android.hardware.input.Flags.mouseSwapPrimaryButton;
+import static com.android.hardware.input.Flags.pointerAcceleration;
import static com.android.hardware.input.Flags.touchpadSystemGestureDisable;
import static com.android.hardware.input.Flags.touchpadThreeFingerTapShortcut;
import static com.android.hardware.input.Flags.touchpadVisualizer;
@@ -418,6 +419,15 @@
}
/**
+ * Returns true if the feature flag for the pointer acceleration toggle is
+ * enabled.
+ * @hide
+ */
+ public static boolean isPointerAccelerationFeatureFlagEnabled() {
+ return pointerAcceleration();
+ }
+
+ /**
* Returns true if the touchpad visualizer is allowed to appear.
*
* @param context The application context.
@@ -720,6 +730,47 @@
}
/**
+ * Whether cursor acceleration is enabled or not for connected mice.
+ *
+ * @param context The application context.
+ *
+ * @hide
+ */
+ public static boolean isMousePointerAccelerationEnabled(@NonNull Context context) {
+ if (!isPointerAccelerationFeatureFlagEnabled()) {
+ return false;
+ }
+
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.System.MOUSE_POINTER_ACCELERATION_ENABLED, 1, UserHandle.USER_CURRENT)
+ == 1;
+ }
+
+ /**
+ * Sets whether mouse acceleration is enabled.
+ *
+ * When enabled, the mouse cursor moves farther when it is moved faster.
+ * When disabled, the mouse cursor speed becomes directly proportional to
+ * the speed at which the mouse is moved.
+ *
+ * @param context The application context.
+ * @param enabled Will enable mouse acceleration if true, disable it if
+ * false.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setMouseAccelerationEnabled(@NonNull Context context,
+ boolean enabled) {
+ if (!isPointerAccelerationFeatureFlagEnabled()) {
+ return;
+ }
+ Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.System.MOUSE_POINTER_ACCELERATION_ENABLED, enabled ? 1 : 0,
+ UserHandle.USER_CURRENT);
+ }
+
+
+ /**
* Whether Accessibility bounce keys feature is enabled.
*
* <p>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2ad6669..6e58780 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6362,6 +6362,16 @@
public static final String MOUSE_SCROLLING_ACCELERATION = "mouse_scrolling_acceleration";
/**
+ * Whether mouse acceleration is enabled.
+ *
+ * When enabled, the mouse cursor will accelerate as the mouse moves faster.
+ *
+ * @hide
+ */
+ public static final String MOUSE_POINTER_ACCELERATION_ENABLED =
+ "mouse_pointer_acceleration_enabled";
+
+ /**
* Pointer fill style, specified by
* {@link android.view.PointerIcon.PointerIconVectorStyleFill} constants.
*
@@ -6610,6 +6620,7 @@
PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE);
PRIVATE_SETTINGS.add(MOUSE_REVERSE_VERTICAL_SCROLLING);
PRIVATE_SETTINGS.add(MOUSE_SWAP_PRIMARY_BUTTON);
+ PRIVATE_SETTINGS.add(MOUSE_POINTER_ACCELERATION_ENABLED);
PRIVATE_SETTINGS.add(PREFERRED_REGION);
PRIVATE_SETTINGS.add(MOUSE_SCROLLING_ACCELERATION);
}
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index dd9bfa5..0d99200 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -228,6 +228,7 @@
optional SettingProto reverse_vertical_scrolling = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto swap_primary_button = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto scrolling_acceleration = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto pointer_acceleration_enabled = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Mouse mouse = 38;
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index 7e87462..166b388 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -276,16 +276,19 @@
/**
* Sets preferred default picture profile.
*
- * @param id the ID of the default profile. {@code null} to unset the default profile.
+ * @param pictureProfileId the ID of the default profile. {@code null} to unset the default
+ * profile.
* @return {@code true} if it's set successfully; {@code false} otherwise.
*
+ * @see PictureProfile#getProfileId()
+ *
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
- public boolean setDefaultPictureProfile(@Nullable String id) {
+ public boolean setDefaultPictureProfile(@Nullable String pictureProfileId) {
try {
- return mService.setDefaultPictureProfile(id, mUserHandle);
+ return mService.setDefaultPictureProfile(pictureProfileId, mUserHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -467,16 +470,19 @@
/**
* Sets preferred default sound profile.
*
- * @param id the ID of the default profile. {@code null} to unset the default profile.
+ * @param soundProfileId the ID of the default profile. {@code null} to unset the default
+ * profile.
* @return {@code true} if it's set successfully; {@code false} otherwise.
*
+ * @see SoundProfile#getProfileId()
+ *
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
- public boolean setDefaultSoundProfile(@Nullable String id) {
+ public boolean setDefaultSoundProfile(@Nullable String soundProfileId) {
try {
- return mService.setDefaultSoundProfile(id, mUserHandle);
+ return mService.setDefaultSoundProfile(soundProfileId, mUserHandle);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index f1bbfc6..5b4ee8b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -110,6 +110,7 @@
Settings.System.MOUSE_REVERSE_VERTICAL_SCROLLING,
Settings.System.MOUSE_SCROLLING_ACCELERATION,
Settings.System.MOUSE_SWAP_PRIMARY_BUTTON,
+ Settings.System.MOUSE_POINTER_ACCELERATION_ENABLED,
Settings.System.TOUCHPAD_POINTER_SPEED,
Settings.System.TOUCHPAD_NATURAL_SCROLLING,
Settings.System.TOUCHPAD_TAP_TO_CLICK,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 6abd9b7..0432eea 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -226,6 +226,7 @@
VALIDATORS.put(System.MOUSE_REVERSE_VERTICAL_SCROLLING, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.MOUSE_SWAP_PRIMARY_BUTTON, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.MOUSE_SCROLLING_ACCELERATION, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(System.MOUSE_POINTER_ACCELERATION_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.TOUCHPAD_POINTER_SPEED, new InclusiveIntegerRangeValidator(-7, 7));
VALIDATORS.put(System.TOUCHPAD_NATURAL_SCROLLING, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.TOUCHPAD_TAP_TO_CLICK, BOOLEAN_VALIDATOR);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt
index f68a1b5..eae5728 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepositoryImplTest.kt
@@ -16,7 +16,7 @@
package com.android.systemui.display.data.repository
-import android.content.testableContext
+import android.content.Context
import android.platform.test.annotations.EnableFlags
import android.view.Display
import android.view.layoutInflater
@@ -24,6 +24,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.SysuiTestableContext
import com.android.systemui.display.shared.model.DisplayWindowProperties
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testScope
@@ -36,8 +37,12 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.doAnswer
+import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
@RunWith(AndroidJUnit4::class)
@@ -48,7 +53,8 @@
private val fakeDisplayRepository = kosmos.displayRepository
private val testScope = kosmos.testScope
- private val applicationContext = kosmos.testableContext
+ private val applicationContext = spy(context)
+
private val applicationWindowManager = kosmos.mockWindowManager
private val applicationLayoutInflater = kosmos.layoutInflater
@@ -64,6 +70,22 @@
}
@Before
+ fun setUpContext() {
+ doAnswer { createContextForDisplay(it.arguments[0] as Display) }
+ .whenever(applicationContext)
+ .createWindowContext(any(), any(), any())
+ }
+
+ private fun createContextForDisplay(display: Display): Context {
+ if (display.displayId == BEING_REMOVED_DISPLAY_ID) {
+ // Simulate what happens when a display is being removed.
+ // Return a context with the same display id as the original context.
+ return mContext
+ }
+ return SysuiTestableContext(mContext).also { it.display = display }
+ }
+
+ @Before
fun start() {
repo.start()
}
@@ -72,6 +94,7 @@
fun addDisplays() = runBlocking {
fakeDisplayRepository.addDisplay(createDisplay(DEFAULT_DISPLAY_ID))
fakeDisplayRepository.addDisplay(createDisplay(NON_DEFAULT_DISPLAY_ID))
+ fakeDisplayRepository.addDisplay(createDisplay(BEING_REMOVED_DISPLAY_ID))
}
@Test
@@ -94,7 +117,7 @@
@Test
fun get_nonDefaultDisplayId_returnsNewStatusBarContext() =
testScope.runTest {
- val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+ val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)!!
assertThat(displayContext.context).isNotSameInstanceAs(applicationContext)
}
@@ -102,7 +125,7 @@
@Test
fun get_nonDefaultDisplayId_returnsNewWindowManager() =
testScope.runTest {
- val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+ val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)!!
assertThat(displayContext.windowManager).isNotSameInstanceAs(applicationWindowManager)
}
@@ -110,7 +133,7 @@
@Test
fun get_nonDefaultDisplayId_returnsNewLayoutInflater() =
testScope.runTest {
- val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)
+ val displayContext = repo.get(NON_DEFAULT_DISPLAY_ID, WINDOW_TYPE_FOO)!!
assertThat(displayContext.layoutInflater).isNotSameInstanceAs(applicationLayoutInflater)
}
@@ -154,17 +177,26 @@
.isNotSameInstanceAs(displayContext)
}
- @Test(expected = IllegalArgumentException::class)
- fun get_nonExistingDisplayId_throws() =
- testScope.runTest { repo.get(NON_EXISTING_DISPLAY_ID, WINDOW_TYPE_FOO) }
+ @Test
+ fun get_nonExistingDisplayId_returnsNull() =
+ testScope.runTest {
+ assertThat(repo.get(NON_EXISTING_DISPLAY_ID, WINDOW_TYPE_FOO)).isNull()
+ }
+
+ @Test
+ fun get_displayBeingRemoved_returnsNull() =
+ testScope.runTest {
+ assertThat(repo.get(BEING_REMOVED_DISPLAY_ID, WINDOW_TYPE_FOO)).isNull()
+ }
private fun createDisplay(displayId: Int) =
- mock<Display> { on { getDisplayId() } doReturn displayId }
+ mock<Display> { on { getDisplayId() } doReturn (displayId) }
companion object {
private const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
private const val NON_DEFAULT_DISPLAY_ID = DEFAULT_DISPLAY_ID + 1
private const val NON_EXISTING_DISPLAY_ID = DEFAULT_DISPLAY_ID + 2
+ private const val BEING_REMOVED_DISPLAY_ID = DEFAULT_DISPLAY_ID + 4
private const val WINDOW_TYPE_FOO = 123
private const val WINDOW_TYPE_BAR = 321
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
index 6a0781b..73957eb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayStoreImplTest.kt
@@ -80,9 +80,9 @@
assertThat(store.forDisplay(NON_DEFAULT_DISPLAY_ID)).isNotSameInstanceAs(instance)
}
- @Test(expected = IllegalArgumentException::class)
- fun forDisplay_nonExistingDisplayId_throws() =
- testScope.runTest { store.forDisplay(NON_EXISTING_DISPLAY_ID) }
+ @Test
+ fun forDisplay_nonExistingDisplayId_returnsNull() =
+ testScope.runTest { assertThat(store.forDisplay(NON_EXISTING_DISPLAY_ID)).isNull() }
@Test
fun forDisplay_afterDisplayRemoved_onDisplayRemovalActionInvoked() =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
index 009b33b..3515c56 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
@@ -26,10 +26,12 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.fragments.FragmentHostManager
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.plugins.fakeDarkIconDispatcher
import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent
import com.android.systemui.statusbar.pipeline.shared.ui.composable.StatusBarRootFactory
+import com.android.systemui.statusbar.policy.statusBarConfigurationController
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
import com.android.systemui.testKosmos
@@ -77,6 +79,8 @@
componentFactory = mock(HomeStatusBarComponent.Factory::class.java),
creationListeners = setOf(),
statusBarModePerDisplayRepository = statusBarModePerDisplayRepository,
+ darkIconDispatcher = kosmos.fakeDarkIconDispatcher,
+ statusBarConfigurationController = kosmos.statusBarConfigurationController,
)
@Test
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
index 18eef33..884c35c 100644
--- 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
@@ -51,7 +51,7 @@
@Test
fun forDisplay_startsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance).start()
}
@@ -59,7 +59,7 @@
@Test
fun beforeDisplayRemoved_doesNotStopInstances() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance, never()).stop()
}
@@ -67,7 +67,7 @@
@Test
fun displayRemoved_stopsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
index a2c3c66..f37648a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
@@ -56,7 +56,7 @@
@Test
fun beforeDisplayRemoved_doesNotStopInstances() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance, never()).stop()
}
@@ -64,7 +64,7 @@
@Test
fun displayRemoved_stopsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
index 4a26fdf..e0a1f27 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
@@ -51,7 +51,7 @@
@Test
fun forDisplay_startsInstances() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance).start()
}
@@ -59,7 +59,7 @@
@Test
fun beforeDisplayRemoved_doesNotStopInstances() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance, never()).stop()
}
@@ -67,7 +67,7 @@
@Test
fun displayRemoved_stopsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
index a9920ec5..11fd902 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
@@ -53,7 +53,7 @@
@Test
fun forDisplay_startsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance).start()
}
@@ -61,7 +61,7 @@
@Test
fun displayRemoved_stopsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
index e65c04c..3cc592c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
@@ -56,7 +56,7 @@
@Test
fun beforeDisplayRemoved_doesNotStopInstances() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance, never()).stop()
}
@@ -64,7 +64,7 @@
@Test
fun displayRemoved_stopsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index be20bc1..d86c6ef 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -225,7 +225,7 @@
val displayId = 123
darkIconRepository.darkState(displayId).value =
SysuiDarkIconDispatcher.DarkChange(emptyList(), 0f, 0xAABBCC)
- val iconColors by collectLastValue(underTest.iconColors(displayId))
+ val iconColors by collectLastValue(underTest.iconColors(displayId)!!)
assertThat(iconColors).isNotNull()
assertThat(iconColors!!.tint).isEqualTo(0xAABBCC)
@@ -241,7 +241,7 @@
val displayId = 321
darkIconRepository.darkState(displayId).value =
SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC)
- val iconColors by collectLastValue(underTest.iconColors(displayId))
+ val iconColors by collectLastValue(underTest.iconColors(displayId)!!)
val staticDrawableColor = iconColors?.staticDrawableColor(Rect(6, 6, 7, 7))
assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
}
@@ -252,7 +252,7 @@
val displayId = 987
darkIconRepository.darkState(displayId).value =
SysuiDarkIconDispatcher.DarkChange(listOf(Rect(0, 0, 5, 5)), 0f, 0xAABBCC)
- val iconColors by collectLastValue(underTest.iconColors(displayId))
+ val iconColors by collectLastValue(underTest.iconColors(displayId)!!)
assertThat(iconColors!!.staticDrawableColor(Rect(6, 6, 7, 7)))
.isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
index 90506a1..d163726 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
@@ -56,7 +56,7 @@
@Test
fun beforeDisplayRemoved_doesNotStopInstances() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance, never()).stop()
}
@@ -64,7 +64,7 @@
@Test
fun displayRemoved_stopsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
index 2d9880a..659d91a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
@@ -39,7 +39,7 @@
fun isLowProfile_lightsOutStatusBarMode_false() = runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.LIGHTS_OUT
- val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+ val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID)!!)
assertThat(actual).isTrue()
}
@@ -49,7 +49,7 @@
statusBarModeRepository.defaultDisplay.statusBarMode.value =
StatusBarMode.LIGHTS_OUT_TRANSPARENT
- val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+ val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID)!!)
assertThat(actual).isTrue()
}
@@ -58,7 +58,7 @@
fun isLowProfile_transparentStatusBarMode_false() = runTest {
statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
- val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+ val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID)!!)
assertThat(actual).isFalse()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
index 7a9d017..769f012 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
@@ -53,7 +53,7 @@
@Test
fun beforeDisplayRemoved_doesNotStopInstances() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
verify(instance, never()).stop()
}
@@ -61,7 +61,7 @@
@Test
fun displayRemoved_stopsInstance() =
testScope.runTest {
- val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+ val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerGestureRecognizerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerGestureRecognizerTest.kt
index 8972f3e..8b526bb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerGestureRecognizerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/touchpad/tutorial/ui/gesture/ThreeFingerGestureRecognizerTest.kt
@@ -30,12 +30,14 @@
import com.android.systemui.touchpad.ui.gesture.FakeVelocityTracker
import com.google.common.truth.Truth.assertThat
import org.junit.Before
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
@SmallTest
+@Ignore("b/386412866")
@RunWith(ParameterizedAndroidJunit4::class)
class ThreeFingerGestureRecognizerTest(
private val recognizer: GestureRecognizer,
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
index f310b30..3390640 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayWindowPropertiesRepository.kt
@@ -18,6 +18,8 @@
import android.annotation.SuppressLint
import android.content.Context
+import android.os.Bundle
+import android.util.Log
import android.view.Display
import android.view.LayoutInflater
import android.view.WindowManager
@@ -39,14 +41,13 @@
interface DisplayWindowPropertiesRepository {
/**
- * Returns a [DisplayWindowProperties] instance for a given display id and window type.
- *
- * @throws IllegalArgumentException if no display with the given display id exists.
+ * Returns a [DisplayWindowProperties] instance for a given display id and window type, or null
+ * if no display with the given display id exists.
*/
fun get(
displayId: Int,
@WindowManager.LayoutParams.WindowType windowType: Int,
- ): DisplayWindowProperties
+ ): DisplayWindowProperties?
}
@SysUISingleton
@@ -72,12 +73,10 @@
override fun get(
displayId: Int,
@WindowManager.LayoutParams.WindowType windowType: Int,
- ): DisplayWindowProperties {
- val display =
- displayRepository.getDisplay(displayId)
- ?: throw IllegalArgumentException("Display with id $displayId doesn't exist")
+ ): DisplayWindowProperties? {
+ val display = displayRepository.getDisplay(displayId) ?: return null
return properties.get(displayId, windowType)
- ?: create(display, windowType).also { properties.put(displayId, windowType, it) }
+ ?: create(display, windowType)?.also { properties.put(displayId, windowType, it) }
}
override fun start() {
@@ -88,7 +87,7 @@
}
}
- private fun create(display: Display, windowType: Int): DisplayWindowProperties {
+ private fun create(display: Display, windowType: Int): DisplayWindowProperties? {
val displayId = display.displayId
return if (displayId == Display.DEFAULT_DISPLAY) {
// For the default display, we can just reuse the global/application properties.
@@ -102,6 +101,14 @@
)
} else {
val context = createWindowContext(display, windowType)
+ if (context.displayId != display.displayId) {
+ Log.e(
+ TAG,
+ "Returning null because the new context doesn't have the desired display id " +
+ "${display.displayId}. Display was already removed.",
+ )
+ return null
+ }
@SuppressLint("NonInjectedService") // Need to manually get the service
val windowManager = context.getSystemService(WindowManager::class.java) as WindowManager
val layoutInflater = LayoutInflater.from(context)
@@ -110,11 +117,15 @@
}
private fun createWindowContext(display: Display, windowType: Int): Context =
- globalContext.createWindowContext(display, windowType, /* options= */ null).also {
+ globalContext.createWindowContext(display, windowType, /* options= */ Bundle.EMPTY).also {
it.setTheme(R.style.Theme_SystemUI)
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.write("perDisplayContexts: $properties")
}
+
+ private companion object {
+ const val TAG = "DisplayWindowPropsRepo"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
index 711534f..564588c 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
@@ -16,6 +16,7 @@
package com.android.systemui.display.data.repository
+import android.util.Log
import android.view.Display
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.systemui.CoreStartable
@@ -36,12 +37,10 @@
val defaultDisplay: T
/**
- * Returns an instance for a specific display id.
- *
- * @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
- * displays.
+ * Returns an instance for a specific display id, or null if [displayId] doesn't match the id of
+ * any existing displays.
*/
- fun forDisplay(displayId: Int): T
+ fun forDisplay(displayId: Int): T?
}
abstract class PerDisplayStoreImpl<T>(
@@ -58,7 +57,7 @@
* Note that the id of the default display is [Display.DEFAULT_DISPLAY].
*/
override val defaultDisplay: T
- get() = forDisplay(Display.DEFAULT_DISPLAY)
+ get() = forDisplay(Display.DEFAULT_DISPLAY)!!
/**
* Returns an instance for a specific display id.
@@ -66,16 +65,30 @@
* @throws IllegalArgumentException if [displayId] doesn't match the id of any existing
* displays.
*/
- override fun forDisplay(displayId: Int): T {
+ override fun forDisplay(displayId: Int): T? {
if (displayRepository.getDisplay(displayId) == null) {
- throw IllegalArgumentException("Display with id $displayId doesn't exist.")
+ Log.e(TAG, "<${instanceClass.simpleName}>: Display with id $displayId doesn't exist.")
+ return null
}
- return perDisplayInstances.computeIfAbsent(displayId) {
- createInstanceForDisplay(displayId)
+ synchronized(perDisplayInstances) {
+ val existingInstance = perDisplayInstances[displayId]
+ if (existingInstance != null) {
+ return existingInstance
+ }
+ val newInstance = createInstanceForDisplay(displayId)
+ if (newInstance == null) {
+ Log.e(
+ TAG,
+ "<${instanceClass.simpleName}> returning null because createInstanceForDisplay($displayId) returned null.",
+ )
+ } else {
+ perDisplayInstances[displayId] = newInstance
+ }
+ return newInstance
}
}
- protected abstract fun createInstanceForDisplay(displayId: Int): T
+ protected abstract fun createInstanceForDisplay(displayId: Int): T?
override fun start() {
val instanceType = instanceClass.simpleName
@@ -98,6 +111,10 @@
override fun dump(pw: PrintWriter, args: Array<out String>) {
pw.println(perDisplayInstances)
}
+
+ private companion object {
+ const val TAG = "PerDisplayStore"
+ }
}
class SingleDisplayStore<T>(defaultInstance: T) : PerDisplayStore<T> {
diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt
index 22e467b..99c9ca9 100644
--- a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/DisplayWindowPropertiesInteractor.kt
@@ -33,7 +33,7 @@
*
* @throws IllegalArgumentException if no display with the given display id exists.
*/
- fun getForStatusBar(displayId: Int): DisplayWindowProperties
+ fun getForStatusBar(displayId: Int): DisplayWindowProperties?
}
@SysUISingleton
@@ -42,7 +42,7 @@
constructor(private val repo: DisplayWindowPropertiesRepository) :
DisplayWindowPropertiesInteractor {
- override fun getForStatusBar(displayId: Int): DisplayWindowProperties {
+ override fun getForStatusBar(displayId: Int): DisplayWindowProperties? {
return repo.get(displayId, TYPE_STATUS_BAR)
}
}
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 c895732..f9df676 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
@@ -720,9 +720,24 @@
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mView);
- mViewCaptureAwareWindowManager.addView(mFrame,
- getBarLayoutParams(mContext.getResources().getConfiguration().windowConfiguration
- .getRotation()));
+ try {
+ mViewCaptureAwareWindowManager.addView(
+ mFrame,
+ getBarLayoutParams(
+ mContext.getResources()
+ .getConfiguration()
+ .windowConfiguration
+ .getRotation()));
+ } catch (WindowManager.InvalidDisplayException e) {
+ // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+ // after being added, and initialization hasn't finished yet.
+ Log.e(
+ TAG,
+ "Unable to add view to WindowManager. Display with id "
+ + mDisplayId
+ + " does not exist anymore",
+ e);
+ }
mDisplayId = mContext.getDisplayId();
mIsOnDefaultDisplay = mDisplayId == mDisplayTracker.getDefaultDisplayId();
@@ -764,6 +779,15 @@
Trace.beginSection("NavigationBar#removeViewImmediate");
try {
mViewCaptureAwareWindowManager.removeViewImmediate(mView.getRootView());
+ } catch (IllegalArgumentException e) {
+ // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+ // after being added, and initialization hasn't finished yet.
+ // When that happens, adding the View to WindowManager fails, and therefore removing
+ // it here will fail too, since it wasn't added in the first place.
+ Log.e(
+ TAG,
+ "Failed to removed view from WindowManager. The View wasn't attached.",
+ e);
} finally {
Trace.endSection();
}
@@ -859,7 +883,15 @@
if (mOrientationHandle != null) {
resetSecondaryHandle();
getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
- mViewCaptureAwareWindowManager.removeView(mOrientationHandle);
+ try {
+ mViewCaptureAwareWindowManager.removeView(mOrientationHandle);
+ } catch (IllegalArgumentException e) {
+ // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+ // after being added, and initialization hasn't finished yet.
+ // When that happens, adding the View to WindowManager fails, and therefore removing
+ // it here will fail too, since it wasn't added in the first place.
+ Log.e(TAG, "Trying to remove a View that is not attached", e);
+ }
mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener(
mOrientationHandleGlobalLayoutListener);
}
@@ -930,7 +962,18 @@
mOrientationParams.setTitle("SecondaryHomeHandle" + mContext.getDisplayId());
mOrientationParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION
| WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
- mViewCaptureAwareWindowManager.addView(mOrientationHandle, mOrientationParams);
+ try {
+ mViewCaptureAwareWindowManager.addView(mOrientationHandle, mOrientationParams);
+ } catch (WindowManager.InvalidDisplayException e) {
+ // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+ // after being added, and initialization hasn't finished yet.
+ Log.e(
+ TAG,
+ "Unable to add view to WindowManager. Display with id "
+ + mDisplayId
+ + " does not exist anymore",
+ e);
+ }
mOrientationHandle.setVisibility(View.GONE);
logNavbarOrientation("initSecondaryHomeHandleForRotation");
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
index 201dc03..4edba27 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
@@ -77,7 +77,17 @@
private fun getContextOrDefault(displayId: Int): Context {
return try {
traceSection({ "Getting dialog context for displayId=$displayId" }) {
- displayWindowPropertyRepository.get().get(displayId, DIALOG_WINDOW_TYPE).context
+ val displayWindowProperties =
+ displayWindowPropertyRepository.get().get(displayId, DIALOG_WINDOW_TYPE)
+ if (displayWindowProperties == null) {
+ Log.e(
+ TAG,
+ "DisplayWindowPropertiesRepository returned null for display $displayId. Returning default one",
+ )
+ defaultContext
+ } else {
+ displayWindowProperties.context
+ }
}
} catch (e: Exception) {
// This can happen if the display was disconnected in the meantime.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
index d24edda..d25ca28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
@@ -72,7 +72,7 @@
private fun initializeStatusBarForDisplay(displayId: Int, result: RegisterStatusBarResult) {
if ((result.mTransientBarTypes and WindowInsets.Type.statusBars()) != 0) {
- statusBarModeRepository.forDisplay(displayId).showTransient()
+ statusBarModeRepository.forDisplay(displayId)?.showTransient()
}
val commandQueueCallbacks = commandQueueCallbacksLazy.get()
commandQueueCallbacks.onSystemBarAttributesChanged(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
index 9e9a38e..b057fb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
@@ -89,21 +89,26 @@
}
private fun createAndStartOrchestratorForDisplay(displayId: Int) {
+ val statusBarModeRepository = statusBarModeRepositoryStore.forDisplay(displayId) ?: return
+ val statusBarInitializer = initializerStore.forDisplay(displayId) ?: return
+ val statusBarWindowController =
+ statusBarWindowControllerStore.forDisplay(displayId) ?: return
+ val autoHideController = autoHideControllerStore.forDisplay(displayId) ?: return
statusBarOrchestratorFactory
.create(
displayId,
displayScopeRepository.scopeForDisplay(displayId),
statusBarWindowStateRepositoryStore.forDisplay(displayId),
- statusBarModeRepositoryStore.forDisplay(displayId),
- initializerStore.forDisplay(displayId),
- statusBarWindowControllerStore.forDisplay(displayId),
- autoHideControllerStore.forDisplay(displayId),
+ statusBarModeRepository,
+ statusBarInitializer,
+ statusBarWindowController,
+ autoHideController,
)
.start()
}
private fun createAndStartInitializerForDisplay(displayId: Int) {
- statusBarInitializerStore.forDisplay(displayId).start()
+ statusBarInitializerStore.forDisplay(displayId)?.start()
}
private fun startPrivacyDotForDisplay(displayId: Int) {
@@ -111,6 +116,6 @@
// For the default display, privacy dot is started via ScreenDecorations
return
}
- privacyDotWindowControllerStore.forDisplay(displayId).start()
+ privacyDotWindowControllerStore.forDisplay(displayId)?.start()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
index 4c54fc4..1e127ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
@@ -20,9 +20,11 @@
import androidx.annotation.VisibleForTesting
import com.android.systemui.CoreStartable
import com.android.systemui.fragments.FragmentHostManager
+import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.res.R
import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewUpdatedListener
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController
import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository
import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions
import com.android.systemui.statusbar.phone.PhoneStatusBarView
@@ -34,7 +36,6 @@
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-import java.lang.IllegalStateException
import javax.inject.Provider
/**
@@ -75,6 +76,8 @@
fun create(
statusBarWindowController: StatusBarWindowController,
statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+ statusBarConfigurationController: StatusBarConfigurationController,
+ darkIconDispatcher: DarkIconDispatcher,
): StatusBarInitializer
}
}
@@ -84,6 +87,8 @@
constructor(
@Assisted private val statusBarWindowController: StatusBarWindowController,
@Assisted private val statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+ @Assisted private val statusBarConfigurationController: StatusBarConfigurationController,
+ @Assisted private val darkIconDispatcher: DarkIconDispatcher,
private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
private val statusBarRootFactory: StatusBarRootFactory,
private val componentFactory: HomeStatusBarComponent.Factory,
@@ -131,23 +136,32 @@
->
val phoneStatusBarView = cv.findViewById<PhoneStatusBarView>(R.id.status_bar)
component =
- componentFactory.create(phoneStatusBarView).also { component ->
- // CollapsedStatusBarFragment used to be responsible initializing
- component.init()
-
- statusBarViewUpdatedListener?.onStatusBarViewUpdated(
- component.phoneStatusBarViewController,
- component.phoneStatusBarTransitions,
+ componentFactory
+ .create(
+ phoneStatusBarView,
+ statusBarConfigurationController,
+ statusBarWindowController,
+ darkIconDispatcher,
)
+ .also { component ->
+ // CollapsedStatusBarFragment used to be responsible initializing
+ component.init()
- if (StatusBarConnectedDisplays.isEnabled) {
- statusBarModePerDisplayRepository.onStatusBarViewInitialized(component)
- } else {
- creationListeners.forEach { listener ->
- listener.onStatusBarViewInitialized(component)
+ statusBarViewUpdatedListener?.onStatusBarViewUpdated(
+ component.phoneStatusBarViewController,
+ component.phoneStatusBarTransitions,
+ )
+
+ if (StatusBarConnectedDisplays.isEnabled) {
+ statusBarModePerDisplayRepository.onStatusBarViewInitialized(
+ component
+ )
+ } else {
+ creationListeners.forEach { listener ->
+ listener.onStatusBarViewInitialized(component)
+ }
}
}
- }
}
// Add the new compose view to the hierarchy because we don't use fragment transactions
@@ -163,9 +177,11 @@
CollapsedStatusBarFragment.TAG,
object : FragmentHostManager.FragmentListener {
override fun onFragmentViewCreated(tag: String, fragment: Fragment) {
- component =
- (fragment as CollapsedStatusBarFragment).homeStatusBarComponent
- ?: throw IllegalStateException()
+ val statusBarFragment = fragment as CollapsedStatusBarFragment
+ if (statusBarFragment.homeStatusBarComponent == null) {
+ return
+ }
+ component = fragment.homeStatusBarComponent
statusBarViewUpdatedListener?.onStatusBarViewUpdated(
component!!.phoneStatusBarViewController,
component!!.phoneStatusBarTransitions,
@@ -195,6 +211,8 @@
override fun create(
statusBarWindowController: StatusBarWindowController,
statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+ statusBarConfigurationController: StatusBarConfigurationController,
+ darkIconDispatcher: DarkIconDispatcher,
): StatusBarInitializerImpl
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
index 4f815c1..de6cd07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
@@ -22,6 +22,8 @@
import com.android.systemui.display.data.repository.PerDisplayStore
import com.android.systemui.display.data.repository.PerDisplayStoreImpl
import com.android.systemui.display.data.repository.SingleDisplayStore
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore
import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
import javax.inject.Inject
@@ -39,6 +41,8 @@
private val factory: StatusBarInitializer.Factory,
private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
+ private val statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore,
+ private val darkIconDispatcherStore: DarkIconDispatcherStore,
) :
StatusBarInitializerStore,
PerDisplayStoreImpl<StatusBarInitializer>(backgroundApplicationScope, displayRepository) {
@@ -47,10 +51,19 @@
StatusBarConnectedDisplays.assertInNewMode()
}
- override fun createInstanceForDisplay(displayId: Int): StatusBarInitializer {
+ override fun createInstanceForDisplay(displayId: Int): StatusBarInitializer? {
+ val statusBarWindowController =
+ statusBarWindowControllerStore.forDisplay(displayId) ?: return null
+ val statusBarModePerDisplayRepository =
+ statusBarModeRepositoryStore.forDisplay(displayId) ?: return null
+ val statusBarConfigurationController =
+ statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
+ val darkIconDispatcher = darkIconDispatcherStore.forDisplay(displayId) ?: return null
return factory.create(
- statusBarWindowController = statusBarWindowControllerStore.forDisplay(displayId),
- statusBarModePerDisplayRepository = statusBarModeRepositoryStore.forDisplay(displayId),
+ statusBarWindowController,
+ statusBarModePerDisplayRepository,
+ statusBarConfigurationController,
+ darkIconDispatcher,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
index 8183a48..041f3c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
@@ -65,8 +65,9 @@
StatusBarConnectedDisplays.assertInNewMode()
}
- override fun createInstanceForDisplay(displayId: Int): SysuiDarkIconDispatcher {
- val properties = displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR)
+ override fun createInstanceForDisplay(displayId: Int): SysuiDarkIconDispatcher? {
+ val properties =
+ displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
return factory.create(displayId, properties.context)
}
@@ -103,7 +104,7 @@
override val defaultDisplay: DarkIconDispatcher
get() = store.defaultDisplay
- override fun forDisplay(displayId: Int): DarkIconDispatcher = store.forDisplay(displayId)
+ override fun forDisplay(displayId: Int): DarkIconDispatcher? = store.forDisplay(displayId)
}
@Module
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
index e498755..c629d10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
@@ -49,13 +49,16 @@
LightBarControllerStore,
PerDisplayStoreImpl<LightBarController>(backgroundApplicationScope, displayRepository) {
- override fun createInstanceForDisplay(displayId: Int): LightBarController {
+ override fun createInstanceForDisplay(displayId: Int): LightBarController? {
+ val darkIconDispatcher = darkIconDispatcherStore.forDisplay(displayId) ?: return null
+ val statusBarModePerDisplayRepository =
+ statusBarModeRepositoryStore.forDisplay(displayId) ?: return null
return factory
.create(
displayId,
displayScopeRepository.scopeForDisplay(displayId),
- darkIconDispatcherStore.forDisplay(displayId),
- statusBarModeRepositoryStore.forDisplay(displayId),
+ darkIconDispatcher,
+ statusBarModePerDisplayRepository,
)
.also { it.start() }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
index bd61c44..d48c94b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
@@ -52,11 +52,14 @@
PrivacyDotViewControllerStore,
PerDisplayStoreImpl<PrivacyDotViewController>(backgroundApplicationScope, displayRepository) {
- override fun createInstanceForDisplay(displayId: Int): PrivacyDotViewController {
+ override fun createInstanceForDisplay(displayId: Int): PrivacyDotViewController? {
+ val configurationController =
+ statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
+ val contentInsetsProvider = contentInsetsProviderStore.forDisplay(displayId) ?: return null
return factory.create(
displayScopeRepository.scopeForDisplay(displayId),
- statusBarConfigurationControllerStore.forDisplay(displayId),
- contentInsetsProviderStore.forDisplay(displayId),
+ configurationController,
+ contentInsetsProvider,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
index a1f5655..086cc99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
@@ -58,15 +58,18 @@
StatusBarConnectedDisplays.assertInNewMode()
}
- override fun createInstanceForDisplay(displayId: Int): PrivacyDotWindowController {
+ override fun createInstanceForDisplay(displayId: Int): PrivacyDotWindowController? {
if (displayId == Display.DEFAULT_DISPLAY) {
throw IllegalArgumentException("This class should only be used for connected displays")
}
val displayWindowProperties =
displayWindowPropertiesRepository.get(displayId, TYPE_NAVIGATION_BAR_PANEL)
+ ?: return null
+ val privacyDotViewController =
+ privacyDotViewControllerStore.forDisplay(displayId) ?: return null
return windowControllerFactory.create(
displayId = displayId,
- privacyDotViewController = privacyDotViewControllerStore.forDisplay(displayId),
+ privacyDotViewController = privacyDotViewController,
viewCaptureAwareWindowManager =
viewCaptureAwareWindowManagerFactory.create(displayWindowProperties.windowManager),
inflater = displayWindowProperties.layoutInflater,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
index 6cf2c73..38cea83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
@@ -62,9 +62,9 @@
StatusBarConnectedDisplays.assertInNewMode()
}
- override fun createInstanceForDisplay(displayId: Int): StatusBarConfigurationController {
+ override fun createInstanceForDisplay(displayId: Int): StatusBarConfigurationController? {
val displayWindowProperties =
- displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR)
+ displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
return configurationControllerFactory.create(displayWindowProperties.context)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
index e471b12..554c46f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
@@ -59,13 +59,17 @@
displayRepository,
) {
- override fun createInstanceForDisplay(displayId: Int): StatusBarContentInsetsProvider {
- val context = displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR).context
+ override fun createInstanceForDisplay(displayId: Int): StatusBarContentInsetsProvider? {
+ val displayWindowProperties =
+ displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
+ val context = displayWindowProperties.context
+ val configurationController =
+ statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
val cameraProtectionLoader = cameraProtectionLoaderFactory.create(context)
return factory
.create(
context,
- statusBarConfigurationControllerStore.forDisplay(displayId),
+ configurationController,
sysUICutoutProviderFactory.create(context, cameraProtectionLoader),
)
.also { it.start() }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
index 7760f58..ffc1255 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
@@ -62,11 +62,17 @@
StatusBarConnectedDisplays.assertInNewMode()
}
- override fun createInstanceForDisplay(displayId: Int): SystemEventChipAnimationController {
+ override fun createInstanceForDisplay(displayId: Int): SystemEventChipAnimationController? {
+ val displayWindowProperties =
+ displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
+ val statusBarWindowController =
+ statusBarWindowControllerStore.forDisplay(displayId) ?: return null
+ val contentInsetsProvider =
+ statusBarContentInsetsProviderStore.forDisplay(displayId) ?: return null
return factory.create(
- displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR).context,
- statusBarWindowControllerStore.forDisplay(displayId),
- statusBarContentInsetsProviderStore.forDisplay(displayId),
+ displayWindowProperties.context,
+ statusBarWindowController,
+ contentInsetsProvider,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
index f2bb7b1..4b9721e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
@@ -72,5 +72,5 @@
}
private fun controllersForAllDisplays() =
- displayRepository.displays.value.map { controllerStore.forDisplay(it.displayId) }
+ displayRepository.displays.value.mapNotNull { controllerStore.forDisplay(it.displayId) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt
index 9928ac6..f7799bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotWindowController.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.events
+import android.util.Log
import android.view.Display
import android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM
import android.view.DisplayCutout.BOUNDS_POSITION_LEFT
@@ -23,6 +24,7 @@
import android.view.DisplayCutout.BOUNDS_POSITION_TOP
import android.view.LayoutInflater
import android.view.View
+import android.view.WindowManager.InvalidDisplayException
import android.view.WindowManager.LayoutParams.WRAP_CONTENT
import android.widget.FrameLayout
import com.android.app.viewcapture.ViewCaptureAwareWindowManager
@@ -97,7 +99,17 @@
// PrivacyDotViewController expects the dot view to have a FrameLayout parent.
val rootView = FrameLayout(context)
rootView.addView(this)
- viewCaptureAwareWindowManager.addView(rootView, params)
+ try {
+ // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+ // after being added, and initialization hasn't finished yet.
+ viewCaptureAwareWindowManager.addView(rootView, params)
+ } catch (e: InvalidDisplayException) {
+ Log.e(
+ TAG,
+ "Unable to add view to WM. Display with id $displayId does not exist anymore",
+ e,
+ )
+ }
}
@AssistedFactory
@@ -109,4 +121,8 @@
inflater: LayoutInflater,
): PrivacyDotWindowController
}
+
+ private companion object {
+ const val TAG = "PrivacyDotWindowController"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ConnectedDisplaysStatusBarNotificationIconViewStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ConnectedDisplaysStatusBarNotificationIconViewStore.kt
index 227a1fe..eb55856 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ConnectedDisplaysStatusBarNotificationIconViewStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/ConnectedDisplaysStatusBarNotificationIconViewStore.kt
@@ -62,8 +62,10 @@
override fun iconView(key: String): StatusBarIconView? {
val entry = notifCollection.getEntry(key) ?: return null
+ val displayWindowProperties =
+ displayWindowPropertiesInteractor.getForStatusBar(displayId) ?: return null
return cachedIcons.computeIfAbsent(key) {
- val context = displayWindowPropertiesInteractor.getForStatusBar(displayId).context
+ val context = displayWindowProperties.context
iconManager.createSbIconView(context, entry)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
index 2ba28a6..e103282 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -68,13 +68,14 @@
.distinctUntilChanged()
/** The colors with which to display the notification icons. */
- fun iconColors(displayId: Int): Flow<NotificationIconColors> =
- darkIconInteractor
+ fun iconColors(displayId: Int): Flow<NotificationIconColors> {
+ return darkIconInteractor
.darkState(displayId)
.map { (areas: Collection<Rect>, tint: Int) -> IconColorsImpl(tint, areas) }
.flowOn(bgContext)
.conflate()
.distinctUntilChanged()
+ }
/** [NotificationIconsViewData] indicating which icons to display in the view. */
val icons: Flow<NotificationIconsViewData> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
index 744f969..2ae38dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
@@ -47,9 +47,9 @@
StatusBarConnectedDisplays.assertInNewMode()
}
- override fun createInstanceForDisplay(displayId: Int): AutoHideController {
+ override fun createInstanceForDisplay(displayId: Int): AutoHideController? {
val displayWindowProperties =
- displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR)
+ displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
return autoHideControllerFactory.create(displayWindowProperties.context)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
index ea67f1c..ca0c1ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
@@ -499,9 +499,9 @@
/** Creates a {@link LightBarControllerImpl}. */
LightBarControllerImpl create(
int displayId,
- CoroutineScope coroutineScope,
- DarkIconDispatcher darkIconDispatcher,
- StatusBarModePerDisplayRepository statusBarModePerDisplayRepository);
+ @NonNull CoroutineScope coroutineScope,
+ @NonNull DarkIconDispatcher darkIconDispatcher,
+ @NonNull StatusBarModePerDisplayRepository statusBarModePerDisplayRepository);
}
public static class LegacyFactory implements LightBarController.Factory {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
index 394502b..031754d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusOverlayHoverListener.kt
@@ -33,6 +33,7 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.res.R
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController
import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore
import com.android.systemui.statusbar.data.repository.SysuiDarkIconDispatcherStore
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
@@ -54,7 +55,7 @@
) {
/** Creates listener always using the same light color for overlay */
- fun createListener(view: View) =
+ fun createListener(view: View): StatusOverlayHoverListener =
StatusOverlayHoverListener(
view,
configurationController,
@@ -65,8 +66,10 @@
/**
* Creates listener using [DarkIconDispatcher] to determine light or dark color of the overlay
*/
- fun createDarkAwareListener(view: View) =
- createDarkAwareListener(view, view.darkIconDispatcher.darkChangeFlow())
+ fun createDarkAwareListener(view: View): StatusOverlayHoverListener? {
+ val darkIconDispatcher = view.darkIconDispatcher ?: return null
+ return createDarkAwareListener(view, darkIconDispatcher.darkChangeFlow())
+ }
/**
* Creates listener using [DarkIconDispatcher] to determine light or dark color of the overlay
@@ -78,27 +81,34 @@
rightHoverMargin: Int = 0,
topHoverMargin: Int = 0,
bottomHoverMargin: Int = 0,
- ) =
- createDarkAwareListener(
+ ): StatusOverlayHoverListener? {
+ val darkIconDispatcher = view.darkIconDispatcher ?: return null
+ return createDarkAwareListener(
view,
- view.darkIconDispatcher.darkChangeFlow(),
+ darkIconDispatcher.darkChangeFlow(),
leftHoverMargin,
rightHoverMargin,
topHoverMargin,
bottomHoverMargin,
)
+ }
/**
* Creates listener using provided [DarkChange] producer to determine light or dark color of the
* overlay
*/
- fun createDarkAwareListener(view: View, darkFlow: StateFlow<DarkChange>) =
- StatusOverlayHoverListener(
+ fun createDarkAwareListener(
+ view: View,
+ darkFlow: StateFlow<DarkChange>,
+ ): StatusOverlayHoverListener? {
+ val configurationController = view.statusBarConfigurationController ?: return null
+ return StatusOverlayHoverListener(
view,
- view.statusBarConfigurationController,
+ configurationController,
view.resources,
darkFlow.map { toHoverTheme(view, it) },
)
+ }
private fun createDarkAwareListener(
view: View,
@@ -107,10 +117,11 @@
rightHoverMargin: Int = 0,
topHoverMargin: Int = 0,
bottomHoverMargin: Int = 0,
- ) =
- StatusOverlayHoverListener(
+ ): StatusOverlayHoverListener? {
+ val configurationController = view.statusBarConfigurationController ?: return null
+ return StatusOverlayHoverListener(
view,
- view.statusBarConfigurationController,
+ configurationController,
view.resources,
darkFlow.map { toHoverTheme(view, it) },
leftHoverMargin,
@@ -118,11 +129,12 @@
topHoverMargin,
bottomHoverMargin,
)
+ }
- private val View.statusBarConfigurationController
+ private val View.statusBarConfigurationController: StatusBarConfigurationController?
get() = statusBarConfigurationControllerStore.forDisplay(context.displayId)
- private val View.darkIconDispatcher
+ private val View.darkIconDispatcher: SysuiDarkIconDispatcher?
get() = darkIconDispatcherStore.forDisplay(context.displayId)
private fun toHoverTheme(view: View, darkChange: DarkChange): HoverTheme {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index 4f32aaa26..037dda9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -31,8 +31,10 @@
import com.android.systemui.statusbar.core.StatusBarInitializerStore
import com.android.systemui.statusbar.core.StatusBarOrchestrator
import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
import com.android.systemui.statusbar.data.repository.PrivacyDotViewControllerStoreModule
import com.android.systemui.statusbar.data.repository.PrivacyDotWindowControllerStoreModule
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore
import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
import com.android.systemui.statusbar.events.PrivacyDotViewControllerModule
import com.android.systemui.statusbar.phone.AutoHideControllerStore
@@ -107,10 +109,14 @@
implFactory: StatusBarInitializerImpl.Factory,
statusBarWindowControllerStore: StatusBarWindowControllerStore,
statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
+ statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore,
+ darkIconDispatcherStore: DarkIconDispatcherStore,
): StatusBarInitializerImpl {
return implFactory.create(
statusBarWindowControllerStore.defaultDisplay,
statusBarModeRepositoryStore.defaultDisplay,
+ statusBarConfigurationControllerStore.defaultDisplay,
+ darkIconDispatcherStore.defaultDisplay,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt
index 49356eb..0464654 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/data/repository/DarkIconRepository.kt
@@ -15,12 +15,14 @@
*/
package com.android.systemui.statusbar.phone.data.repository
+import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.data.repository.SysuiDarkIconDispatcherStore
import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher.DarkChange
import dagger.Binds
import dagger.Module
import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
/** Dark-mode state for tinting icons. */
@@ -33,8 +35,22 @@
@Inject
constructor(private val darkIconDispatcherStore: SysuiDarkIconDispatcherStore) :
DarkIconRepository {
- override fun darkState(displayId: Int): StateFlow<DarkChange> =
- darkIconDispatcherStore.forDisplay(displayId).darkChangeFlow()
+ override fun darkState(displayId: Int): StateFlow<DarkChange> {
+ val perDisplayDakIconDispatcher = darkIconDispatcherStore.forDisplay(displayId)
+ if (perDisplayDakIconDispatcher == null) {
+ Log.e(
+ TAG,
+ "DarkIconDispatcher for display $displayId is null. Returning flow of " +
+ "DarkChange.EMPTY",
+ )
+ return MutableStateFlow(DarkChange.EMPTY)
+ }
+ return perDisplayDakIconDispatcher.darkChangeFlow()
+ }
+
+ private companion object {
+ const val TAG = "DarkIconRepositoryImpl"
+ }
}
@Module
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
index ed8b3e8..b15fffb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
@@ -34,8 +34,8 @@
@Inject
constructor(private val repository: StatusBarModeRepositoryStore) {
- fun isLowProfile(displayId: Int): Flow<Boolean> =
- repository.forDisplay(displayId).statusBarMode.map {
+ fun isLowProfile(displayId: Int): Flow<Boolean>? =
+ repository.forDisplay(displayId)?.statusBarMode?.map {
when (it) {
StatusBarMode.LIGHTS_OUT,
StatusBarMode.LIGHTS_OUT_TRANSPARENT -> true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index d257288..c31e34c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -47,6 +47,7 @@
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
@@ -59,6 +60,9 @@
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
import com.android.systemui.statusbar.core.StatusBarRootModernization;
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
@@ -78,6 +82,8 @@
import com.android.systemui.statusbar.pipeline.shared.ui.binder.StatusBarVisibilityChangeListener;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.statusbar.window.StatusBarWindowStateListener;
import com.android.systemui.util.CarrierConfigTracker;
@@ -156,6 +162,9 @@
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final NotificationIconContainerStatusBarViewBinder mNicViewBinder;
private final DemoModeController mDemoModeController;
+ private final StatusBarWindowControllerStore mStatusBarWindowControllerStore;
+ private final StatusBarConfigurationControllerStore mStatusBarConfigurationControllerStore;
+ private final DarkIconDispatcherStore mDarkIconDispatcherStore;
private List<String> mBlockedIcons = new ArrayList<>();
private Map<Startable, Startable.State> mStartableStates = new ArrayMap<>();
@@ -263,7 +272,10 @@
DumpManager dumpManager,
StatusBarWindowStateController statusBarWindowStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- DemoModeController demoModeController) {
+ DemoModeController demoModeController,
+ StatusBarWindowControllerStore statusBarWindowControllerStore,
+ StatusBarConfigurationControllerStore statusBarConfigurationControllerStore,
+ DarkIconDispatcherStore darkIconDispatcherStore) {
mHomeStatusBarComponentFactory = homeStatusBarComponentFactory;
mOngoingCallController = ongoingCallController;
mAnimationScheduler = animationScheduler;
@@ -287,6 +299,9 @@
mStatusBarWindowStateController = statusBarWindowStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mDemoModeController = demoModeController;
+ mStatusBarWindowControllerStore = statusBarWindowControllerStore;
+ mStatusBarConfigurationControllerStore = statusBarConfigurationControllerStore;
+ mDarkIconDispatcherStore = darkIconDispatcherStore;
}
private final DemoMode mDemoModeCallback = new DemoMode() {
@@ -337,8 +352,27 @@
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mDumpManager.registerDumpable(getDumpableName(), this);
- mHomeStatusBarComponent = mHomeStatusBarComponentFactory.create(
- (PhoneStatusBarView) getView());
+ int displayId = view.getContext().getDisplayId();
+ StatusBarConfigurationController configurationController =
+ mStatusBarConfigurationControllerStore.forDisplay(displayId);
+ if (configurationController == null) {
+ return;
+ }
+ StatusBarWindowController statusBarWindowController =
+ mStatusBarWindowControllerStore.forDisplay(displayId);
+ if (statusBarWindowController == null) {
+ return;
+ }
+ DarkIconDispatcher darkIconDispatcher = mDarkIconDispatcherStore.forDisplay(displayId);
+ if (darkIconDispatcher == null) {
+ return;
+ }
+ mHomeStatusBarComponent =
+ mHomeStatusBarComponentFactory.create(
+ (PhoneStatusBarView) getView(),
+ configurationController,
+ statusBarWindowController,
+ darkIconDispatcher);
mHomeStatusBarComponent.init();
mStartableStates.clear();
for (Startable startable : mHomeStatusBarComponent.getStartables()) {
@@ -453,6 +487,9 @@
@Override
public void onResume() {
super.onResume();
+ if (mHomeStatusBarComponent == null) {
+ return;
+ }
mCommandQueue.addCallback(this);
mStatusBarStateController.addCallback(this);
initOngoingCallChip();
@@ -468,6 +505,9 @@
@Override
public void onPause() {
super.onPause();
+ if (mHomeStatusBarComponent == null) {
+ return;
+ }
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
if (!StatusBarRootModernization.isEnabled()) {
@@ -480,6 +520,9 @@
@Override
public void onDestroyView() {
super.onDestroyView();
+ if (mHomeStatusBarComponent == null) {
+ return;
+ }
mStatusBarIconController.removeIconGroup(mDarkIconManager);
mCarrierConfigTracker.removeCallback(mCarrierConfigCallback);
mCarrierConfigTracker.removeDataSubscriptionChangedListener(mDefaultDataListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java
index f8ad0f2..5837752 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarComponent.java
@@ -20,6 +20,7 @@
import com.android.systemui.dagger.qualifiers.DisplaySpecific;
import com.android.systemui.dagger.qualifiers.RootView;
import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.LegacyLightsOutNotifController;
@@ -29,6 +30,7 @@
import com.android.systemui.statusbar.phone.StatusBarBoundsProvider;
import com.android.systemui.statusbar.phone.StatusBarDemoMode;
import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
import dagger.BindsInstance;
import dagger.Subcomponent;
@@ -57,7 +59,10 @@
interface Factory {
/** */
HomeStatusBarComponent create(
- @BindsInstance @RootView PhoneStatusBarView phoneStatusBarView);
+ @BindsInstance @RootView PhoneStatusBarView phoneStatusBarView,
+ @BindsInstance StatusBarConfigurationController configurationController,
+ @BindsInstance StatusBarWindowController statusBarWindowController,
+ @BindsInstance @DisplaySpecific DarkIconDispatcher darkIconDispatcher);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
index 182f8d7..6a331b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/HomeStatusBarModule.java
@@ -22,19 +22,14 @@
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.dagger.qualifiers.DisplaySpecific;
import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.HeadsUpStatusBarView;
-import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
-import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
-import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore;
import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
import com.android.systemui.statusbar.phone.StatusBarLocation;
import com.android.systemui.statusbar.policy.Clock;
import com.android.systemui.statusbar.window.StatusBarWindowController;
-import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
import dagger.Module;
import dagger.Provides;
@@ -149,29 +144,4 @@
static int displayId(@RootView PhoneStatusBarView view) {
return view.getContext().getDisplayId();
}
-
- /** */
- @Provides
- @HomeStatusBarScope
- static StatusBarConfigurationController configurationController(
- @DisplaySpecific int displayId, StatusBarConfigurationControllerStore store) {
- return store.forDisplay(displayId);
- }
-
- /** */
- @Provides
- @HomeStatusBarScope
- static StatusBarWindowController provideWindowController(
- @DisplaySpecific int displayId, StatusBarWindowControllerStore store) {
- return store.forDisplay(displayId);
- }
-
- /** */
- @Provides
- @HomeStatusBarScope
- @DisplaySpecific
- static DarkIconDispatcher darkIconDispatcher(
- @DisplaySpecific int displayId, DarkIconDispatcherStore store) {
- return store.forDisplay(displayId);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
index c3299bb..7243ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
@@ -70,6 +70,8 @@
) {
fun create(root: ViewGroup, andThen: (ViewGroup) -> Unit): ComposeView {
val composeView = ComposeView(root.context)
+ val darkIconDispatcher =
+ darkIconDispatcherStore.forDisplay(root.context.displayId) ?: return composeView
composeView.apply {
setContent {
StatusBarRoot(
@@ -80,7 +82,7 @@
darkIconManagerFactory = darkIconManagerFactory,
iconController = iconController,
ongoingCallController = ongoingCallController,
- darkIconDispatcher = darkIconDispatcherStore.forDisplay(root.context.displayId),
+ darkIconDispatcher = darkIconDispatcher,
eventAnimationInteractor = eventAnimationInteractor,
onViewCreated = andThen,
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index dcfbc5d..c9cc173 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -63,6 +63,7 @@
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -216,7 +217,7 @@
} else {
combine(
notificationsInteractor.areAnyNotificationsPresent,
- lightsOutInteractor.isLowProfile(displayId),
+ lightsOutInteractor.isLowProfile(displayId) ?: flowOf(false),
) { hasNotifications, isLowProfile ->
hasNotifications && isLowProfile
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
index 811a2ec..848e91d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
@@ -163,7 +163,18 @@
mLp = getBarLayoutParams(mContext.getDisplay().getRotation());
Trace.endSection();
- mWindowManager.addView(mStatusBarWindowView, mLp);
+ try {
+ mWindowManager.addView(mStatusBarWindowView, mLp);
+ } catch (WindowManager.InvalidDisplayException e) {
+ // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+ // after being added, and initialization hasn't finished yet.
+ Log.e(
+ TAG,
+ "Unable to add view to WindowManager. Display with id "
+ + mContext.getDisplayId()
+ + " doesn't exist anymore.",
+ e);
+ }
mLpChanged.copyFrom(mLp);
mContentInsetsProvider.addCallback(this::calculateStatusBarLocationsForAllRotations);
@@ -176,7 +187,15 @@
public void stop() {
StatusBarConnectedDisplays.assertInNewMode();
- mWindowManager.removeView(mStatusBarWindowView);
+ try {
+ mWindowManager.removeView(mStatusBarWindowView);
+ } catch (IllegalArgumentException e) {
+ // Wrapping this in a try/catch to avoid crashes when a display is instantly removed
+ // after being added, and initialization hasn't finished yet.
+ // When that happens, adding the View to WindowManager fails, and therefore removing
+ // it here will fail too, since it wasn't added in the first place.
+ Log.e(TAG, "Failed to remove View from WindowManager. View was not attached", e);
+ }
if (StatusBarRootModernization.isEnabled()) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
index 7403161..f7688d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
@@ -54,19 +54,23 @@
StatusBarConnectedDisplays.assertInNewMode()
}
- override fun createInstanceForDisplay(displayId: Int): StatusBarWindowController {
+ override fun createInstanceForDisplay(displayId: Int): StatusBarWindowController? {
val statusBarDisplayContext =
displayWindowPropertiesRepository.get(
displayId = displayId,
windowType = WindowManager.LayoutParams.TYPE_STATUS_BAR,
- )
+ ) ?: return null
+ val statusBarConfigurationController =
+ statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
+ val contentInsetsProvider =
+ statusBarContentInsetsProviderStore.forDisplay(displayId) ?: return null
val viewCaptureAwareWindowManager =
viewCaptureAwareWindowManagerFactory.create(statusBarDisplayContext.windowManager)
return controllerFactory.create(
statusBarDisplayContext.context,
viewCaptureAwareWindowManager,
- statusBarConfigurationControllerStore.forDisplay(displayId),
- statusBarContentInsetsProviderStore.forDisplay(displayId),
+ statusBarConfigurationController,
+ contentInsetsProvider,
)
}
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 411c81d13..1fcf02d 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
@@ -36,6 +36,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static kotlinx.coroutines.flow.FlowKt.flowOf;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -54,8 +56,6 @@
import static java.util.Collections.emptySet;
-import static kotlinx.coroutines.flow.FlowKt.flowOf;
-
import android.app.ActivityManager;
import android.app.IWallpaperManager;
import android.app.NotificationManager;
@@ -132,6 +132,7 @@
import com.android.systemui.notetask.NoteTaskController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -175,6 +176,7 @@
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
import com.android.systemui.statusbar.core.StatusBarInitializerImpl;
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -216,6 +218,10 @@
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.startingsurface.StartingSurface;
+import dagger.Lazy;
+
+import kotlinx.coroutines.test.TestScope;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -232,9 +238,6 @@
import javax.inject.Provider;
-import dagger.Lazy;
-import kotlinx.coroutines.test.TestScope;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
@RunWithLooper(setAsMainLooper = true)
@@ -536,6 +539,8 @@
new StatusBarInitializerImpl(
mStatusBarWindowController,
mStatusBarModePerDisplayRepository,
+ mock(StatusBarConfigurationController.class),
+ mock(DarkIconDispatcher.class),
mCollapsedStatusBarFragmentProvider,
mock(StatusBarRootFactory.class),
mock(HomeStatusBarComponent.Factory.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 0b443675..3a99328 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -61,6 +62,9 @@
import com.android.systemui.statusbar.OperatorNameViewController;
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
import com.android.systemui.statusbar.core.StatusBarRootModernization;
+import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController;
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore;
import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
@@ -75,6 +79,8 @@
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeHomeStatusBarViewModel;
import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.StatusBarOperatorNameViewModel;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
+import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.statusbar.window.StatusBarWindowStateListener;
import com.android.systemui.util.CarrierConfigTracker;
@@ -134,6 +140,12 @@
private StatusBarWindowStateController mStatusBarWindowStateController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private StatusBarWindowControllerStore mStatusBarWindowControllerStore;
+ @Mock private StatusBarWindowController mStatusBarWindowController;
+ @Mock private StatusBarConfigurationControllerStore mStatusBarConfigurationControllerStore;
+ @Mock private StatusBarConfigurationController mStatusBarConfigurationController;
+ @Mock private DarkIconDispatcherStore mDarkIconDispatcherStore;
+ @Mock private DarkIconDispatcher mDarkIconDispatcher;
@Rule
public final AnimatorTestRule mAnimatorTestRule = new AnimatorTestRule(this);
@@ -145,6 +157,12 @@
@Before
public void setup() {
+ when(mStatusBarWindowControllerStore.forDisplay(anyInt()))
+ .thenReturn(mStatusBarWindowController);
+ when(mStatusBarConfigurationControllerStore.forDisplay(anyInt()))
+ .thenReturn(mStatusBarConfigurationController);
+ when(mDarkIconDispatcherStore.forDisplay(anyInt())).thenReturn(mDarkIconDispatcher);
+
injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
mDependency.injectMockDependency(DarkIconDispatcher.class);
@@ -1276,11 +1294,14 @@
mDumpManager,
mStatusBarWindowStateController,
mKeyguardUpdateMonitor,
- mock(DemoModeController.class));
+ mock(DemoModeController.class),
+ mStatusBarWindowControllerStore,
+ mStatusBarConfigurationControllerStore,
+ mDarkIconDispatcherStore);
}
private void setUpDaggerComponent() {
- when(mStatusBarFragmentComponentFactory.create(any()))
+ when(mStatusBarFragmentComponentFactory.create(any(), any(), any(), any()))
.thenReturn(mHomeStatusBarComponent);
when(mHomeStatusBarComponent.getHeadsUpAppearanceController())
.thenReturn(mHeadsUpAppearanceController);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
index b8be6aa..64d89c5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
@@ -81,6 +81,14 @@
return super.getDisplay();
}
+ @Override
+ public int getDisplayId() {
+ if (mCustomDisplay != null) {
+ return mCustomDisplay.getDisplayId();
+ }
+ return super.getDisplayId();
+ }
+
public SysuiTestableContext createDefaultDisplayContext() {
Display display = getBaseContext().getSystemService(DisplayManager.class).getDisplays()[0];
return (SysuiTestableContext) createDisplayContext(display);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
index 50a19a9..fb2e2a3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.core
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController
import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository
import com.android.systemui.statusbar.window.StatusBarWindowController
@@ -24,5 +26,7 @@
override fun create(
statusBarWindowController: StatusBarWindowController,
statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+ statusBarConfigurationController: StatusBarConfigurationController,
+ darkIconDispatcher: DarkIconDispatcher,
): StatusBarInitializer = FakeStatusBarInitializer()
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
index 6e99027..b8dafb2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
@@ -19,7 +19,9 @@
import com.android.systemui.display.data.repository.displayRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.data.repository.darkIconDispatcherStore
import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
+import com.android.systemui.statusbar.data.repository.statusBarConfigurationControllerStore
import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore
val Kosmos.fakeStatusBarInitializer by Kosmos.Fixture { FakeStatusBarInitializer() }
@@ -39,6 +41,8 @@
fakeStatusBarInitializerFactory,
fakeStatusBarWindowControllerStore,
fakeStatusBarModeRepository,
+ statusBarConfigurationControllerStore,
+ darkIconDispatcherStore,
)
}
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 56cb6f49..febf24e 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -71,6 +71,9 @@
(reason) -> updateMouseSwapPrimaryButton()),
Map.entry(Settings.System.getUriFor(Settings.System.MOUSE_SCROLLING_ACCELERATION),
(reason) -> updateMouseScrollingAcceleration()),
+ Map.entry(Settings.System.getUriFor(
+ Settings.System.MOUSE_POINTER_ACCELERATION_ENABLED),
+ (reason) -> updateMouseAccelerationEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_POINTER_SPEED),
(reason) -> updateTouchpadPointerSpeed()),
Map.entry(Settings.System.getUriFor(Settings.System.TOUCHPAD_NATURAL_SCROLLING),
@@ -191,6 +194,11 @@
InputSettings.isMouseScrollingAccelerationEnabled(mContext));
}
+ private void updateMouseAccelerationEnabled() {
+ mNative.setMouseAccelerationEnabled(
+ InputSettings.isMousePointerAccelerationEnabled(mContext));
+ }
+
private void updateTouchpadPointerSpeed() {
mNative.setTouchpadPointerSpeed(
constrainPointerSpeedValue(InputSettings.getTouchpadPointerSpeed(mContext)));
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index ab5a680..7dbde64 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -138,6 +138,8 @@
void setMouseSwapPrimaryButtonEnabled(boolean enabled);
+ void setMouseAccelerationEnabled(boolean enabled);
+
void setTouchpadPointerSpeed(int speed);
void setTouchpadNaturalScrollingEnabled(boolean enabled);
@@ -429,6 +431,9 @@
public native void setMouseSwapPrimaryButtonEnabled(boolean enabled);
@Override
+ public native void setMouseAccelerationEnabled(boolean enabled);
+
+ @Override
public native void setTouchpadPointerSpeed(int speed);
@Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index eeae616..f50e8aa 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3082,16 +3082,42 @@
private void sendRegisteredOnlyBroadcast(Intent baseIntent) {
int[] userIds = mUmInternal.getProfileIds(mAmi.getCurrentUserId(), true);
- Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- for (int userId : userIds) {
- getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null);
- }
- // explicitly send the broadcast to all DND packages, even if they aren't currently running
- for (int userId : userIds) {
- for (String pkg : mConditionProviders.getAllowedPackages(userId)) {
- Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags(
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId));
+ if (Flags.nmBinderPerfReduceZenBroadcasts()) {
+ for (int userId : userIds) {
+ Context userContext = getContext().createContextAsUser(UserHandle.of(userId), 0);
+ String[] dndPackages = mConditionProviders.getAllowedPackages(userId)
+ .toArray(new String[0]);
+
+ // We send the broadcast to all DND packages in the second step, so leave them out
+ // of this first broadcast for *running* receivers. That ensures each package only
+ // receives it once.
+ Intent registeredOnlyIntent = new Intent(baseIntent)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ userContext.sendBroadcastMultiplePermissions(registeredOnlyIntent,
+ /* receiverPermissions= */ new String[0],
+ /* excludedPermissions= */ new String[0],
+ /* excludedPackages= */ dndPackages);
+
+ for (String pkg : dndPackages) {
+ Intent pkgIntent = new Intent(baseIntent).setPackage(pkg)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ userContext.sendBroadcast(pkgIntent);
+ }
+ }
+ } else {
+ Intent intent = new Intent(baseIntent).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ for (int userId : userIds) {
+ getContext().sendBroadcastAsUser(intent, UserHandle.of(userId), null);
+ }
+
+ // explicitly send the broadcast to all DND packages, even if they aren't currently
+ // running
+ for (int userId : userIds) {
+ for (String pkg : mConditionProviders.getAllowedPackages(userId)) {
+ Intent pkgIntent = new Intent(baseIntent).setPackage(pkg).setFlags(
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ getContext().sendBroadcastAsUser(pkgIntent, UserHandle.of(userId));
+ }
}
}
}
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index 65a38ae..f15c23e 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -187,3 +187,13 @@
description: "Enables sound uri with vibration source in notification channel"
bug: "351975435"
}
+
+flag {
+ name: "nm_binder_perf_reduce_zen_broadcasts"
+ namespace: "systemui"
+ description: "Don't send duplicate zen-related (policy changed, etc) broadcasts"
+ bug: "324376849"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index cba606c..98ed6f7 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -101,7 +101,8 @@
// 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 && isServerVisible() && !givenInsetsPending) {
+ if (!mGivenInsetsReady && isServerVisible() && !givenInsetsPending
+ && mControlTarget != null) {
mGivenInsetsReady = true;
ImeTracker.forLogging().onProgress(mStatsToken,
ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 7276007..d1585d0 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -384,7 +384,7 @@
}
final boolean serverVisibleChanged = mServerVisible != isServerVisible;
setServerVisible(isServerVisible);
- if (mControl != null) {
+ if (mControl != null && mControlTarget != null) {
final boolean positionChanged = updateInsetsControlPosition(windowState);
if (!(positionChanged || mHasPendingPosition)
// The insets hint would be updated while changing the position. Here updates it
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index ce85184..9df65f6 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -371,7 +371,7 @@
array.add(provider);
}
- void notifyControlChanged(InsetsControlTarget target, InsetsSourceProvider provider) {
+ void notifyControlChanged(@NonNull InsetsControlTarget target, InsetsSourceProvider provider) {
addToPendingControlMaps(target, provider);
notifyPendingInsetsControlChanged();
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 813fec1..f634beb 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -345,6 +345,7 @@
void setMouseReverseVerticalScrollingEnabled(bool enabled);
void setMouseScrollingAccelerationEnabled(bool enabled);
void setMouseSwapPrimaryButtonEnabled(bool enabled);
+ void setMouseAccelerationEnabled(bool enabled);
void setTouchpadPointerSpeed(int32_t speed);
void setTouchpadNaturalScrollingEnabled(bool enabled);
void setTouchpadTapToClickEnabled(bool enabled);
@@ -502,6 +503,9 @@
// True if the mouse primary button is swapped (left/right buttons).
bool mouseSwapPrimaryButtonEnabled{false};
+ // True if the mouse cursor will accelerate as the mouse moves faster.
+ bool mousePointerAccelerationEnabled{true};
+
// The touchpad pointer speed, as a number from -7 (slowest) to 7 (fastest).
int32_t touchpadPointerSpeed{0};
@@ -847,6 +851,7 @@
outConfig->mouseReverseVerticalScrollingEnabled =
mLocked.mouseReverseVerticalScrollingEnabled;
outConfig->mouseSwapPrimaryButtonEnabled = mLocked.mouseSwapPrimaryButtonEnabled;
+ outConfig->mousePointerAccelerationEnabled = mLocked.mousePointerAccelerationEnabled;
outConfig->touchpadPointerSpeed = mLocked.touchpadPointerSpeed;
outConfig->touchpadNaturalScrollingEnabled = mLocked.touchpadNaturalScrollingEnabled;
@@ -1458,6 +1463,21 @@
InputReaderConfiguration::Change::MOUSE_SETTINGS);
}
+void NativeInputManager::setMouseAccelerationEnabled(bool enabled) {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+
+ if (mLocked.mousePointerAccelerationEnabled == enabled) {
+ return;
+ }
+
+ mLocked.mousePointerAccelerationEnabled = enabled;
+ } // release lock
+
+ mInputManager->getReader().requestRefreshConfiguration(
+ InputReaderConfiguration::Change::POINTER_SPEED);
+}
+
void NativeInputManager::setPointerSpeed(int32_t speed) {
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -3220,6 +3240,11 @@
im->setMouseSwapPrimaryButtonEnabled(enabled);
}
+static void nativeSetMouseAccelerationEnabled(JNIEnv* env, jobject nativeImplObj, bool enabled) {
+ NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+ im->setMouseAccelerationEnabled(enabled);
+}
+
static jboolean nativeSetKernelWakeEnabled(JNIEnv* env, jobject nativeImplObj, jint deviceId,
jboolean enabled) {
NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
@@ -3280,6 +3305,7 @@
{"setMouseScrollingAccelerationEnabled", "(Z)V",
(void*)nativeSetMouseScrollingAccelerationEnabled},
{"setMouseSwapPrimaryButtonEnabled", "(Z)V", (void*)nativeSetMouseSwapPrimaryButtonEnabled},
+ {"setMouseAccelerationEnabled", "(Z)V", (void*)nativeSetMouseAccelerationEnabled},
{"setTouchpadPointerSpeed", "(I)V", (void*)nativeSetTouchpadPointerSpeed},
{"setTouchpadNaturalScrollingEnabled", "(Z)V",
(void*)nativeSetTouchpadNaturalScrollingEnabled},
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index bcda2c0..301165f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -644,6 +644,9 @@
doNothing().when(mContext).sendBroadcast(any(), anyString());
doNothing().when(mContext).sendBroadcastAsUser(any(), any());
doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
+ doNothing().when(mContext).sendBroadcastMultiplePermissions(any(), any(), any(), any());
+ doReturn(mContext).when(mContext).createContextAsUser(eq(mUser), anyInt());
+
TestableContentResolver cr = mock(TestableContentResolver.class);
when(mContext.getContentResolver()).thenReturn(cr);
doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt());
@@ -11235,7 +11238,8 @@
}
@Test
- public void onZenModeChanged_sendsBroadcasts() throws Exception {
+ @DisableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS)
+ public void onZenModeChanged_sendsBroadcasts_oldBehavior() throws Exception {
when(mAmi.getCurrentUserId()).thenReturn(100);
when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
@@ -11288,6 +11292,74 @@
}
@Test
+ @EnableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS)
+ public void onZenModeChanged_sendsBroadcasts() throws Exception {
+ when(mAmi.getCurrentUserId()).thenReturn(100);
+ when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102});
+ when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() {
+ @Override
+ public List<String> answer(InvocationOnMock invocation) {
+ int userId = invocation.getArgument(0);
+ switch (userId) {
+ case 100:
+ return Lists.newArrayList("a", "b", "c");
+ case 101:
+ return Lists.newArrayList();
+ case 102:
+ return Lists.newArrayList("b");
+ default:
+ throw new IllegalArgumentException(
+ "Why would you ask for packages of userId " + userId + "?");
+ }
+ }
+ });
+ Context context100 = mock(Context.class);
+ doReturn(context100).when(mContext).createContextAsUser(eq(UserHandle.of(100)), anyInt());
+ Context context101 = mock(Context.class);
+ doReturn(context101).when(mContext).createContextAsUser(eq(UserHandle.of(101)), anyInt());
+ Context context102 = mock(Context.class);
+ doReturn(context102).when(mContext).createContextAsUser(eq(UserHandle.of(102)), anyInt());
+
+ mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null,
+ "testing!", false);
+ waitForIdle();
+
+ // Verify broadcasts per user: registered receivers first, then DND packages.
+ InOrder inOrder = inOrder(context100, context101, context102);
+
+ inOrder.verify(context100).sendBroadcastMultiplePermissions(
+ eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
+ eq(new String[0]), eq(new String[0]), eq(new String[] {"a", "b", "c"}));
+ inOrder.verify(context100).sendBroadcast(
+ eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+ .setPackage("a")
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
+ inOrder.verify(context100).sendBroadcast(
+ eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+ .setPackage("b")
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
+ inOrder.verify(context100).sendBroadcast(
+ eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+ .setPackage("c")
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
+
+ inOrder.verify(context101).sendBroadcastMultiplePermissions(
+ eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
+ eq(new String[0]), eq(new String[0]), eq(new String[] {}));
+
+ inOrder.verify(context102).sendBroadcastMultiplePermissions(
+ eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)),
+ eq(new String[0]), eq(new String[0]), eq(new String[] {"b"}));
+ inOrder.verify(context102).sendBroadcast(
+ eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED)
+ .setPackage("b")
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)));
+ }
+
+ @Test
@EnableFlags(android.app.Flags.FLAG_MODES_API)
public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception {
mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged(
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index e7c9e92..e27dbe5 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1869,10 +1869,18 @@
}
private boolean shouldDeleteObsoleteData(UserHandle userHandle) {
- final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
- // If a profile owner is not defined for the given user, obsolete data should be deleted
- return dpmInternal == null
- || dpmInternal.getProfileOwnerOrDeviceOwnerSupervisionComponent(userHandle) == null;
+ if (android.app.supervision.flags.Flags.deprecateDpmSupervisionApis()) {
+ final SupervisionManagerInternal smInternal = getSupervisionManagerInternal();
+ // If supervision is not enabled for the given user, obsolete data should be deleted.
+ return smInternal == null
+ || !smInternal.isSupervisionEnabledForUser(userHandle.getIdentifier());
+ } else {
+ final DevicePolicyManagerInternal dpmInternal = getDpmInternal();
+ // If a profile owner is not defined for the given user, obsolete data should be deleted
+ return dpmInternal == null
+ || dpmInternal.getProfileOwnerOrDeviceOwnerSupervisionComponent(userHandle)
+ == null;
+ }
}
private String buildFullToken(String packageName, String token) {