summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/companion/virtual/flags/flags.aconfig8
-rw-r--r--packages/SettingsLib/aconfig/settingslib.aconfig24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java34
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java37
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt55
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java9
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt2
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java47
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java213
-rw-r--r--services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java8
22 files changed, 345 insertions, 194 deletions
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index ba1473cf5ed7..67ade79e1b94 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -135,3 +135,11 @@ flag {
description: "Show virtual devices in Settings"
bug: "338974320"
}
+
+flag {
+ name: "migrate_viewconfiguration_constants_to_resources"
+ namespace: "virtual_devices"
+ description: "Use resources instead of constants in ViewConfiguration"
+ is_fixed_read_only: true
+ bug: "370928384"
+}
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index d94450b1cabd..a029f56cf1d7 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -26,14 +26,14 @@ flag {
name: "enable_le_audio_sharing"
namespace: "pixel_cross_device_control"
description: "Gates whether to enable LE audio sharing"
- bug: "323125723"
+ bug: "388674074"
}
flag {
name: "enable_le_audio_qr_code_private_broadcast_sharing"
namespace: "pixel_cross_device_control"
description: "Gates whether to enable LE audio private broadcast sharing via QR code"
- bug: "323125723"
+ bug: "388674074"
}
flag {
@@ -229,3 +229,23 @@ flag {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "adopt_primary_group_management_api_v2"
+ namespace: "cross_device_experiences"
+ description: "Adopt more Bluetooth LE broadcast primary group management APIs post launch"
+ bug: "381946931"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "promote_audio_sharing_for_second_auto_connected_lea_device"
+ namespace: "cross_device_experiences"
+ description: "Show audio sharing promote notification or dialog when the second lea device is auto connected"
+ bug: "395786392"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index 572444edea29..bf86911ee683 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -30,13 +30,11 @@ import android.util.Log;
import androidx.annotation.ChecksSdkIntAtLeast;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.settingslib.flags.Flags;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -387,7 +385,7 @@ public class CsipDeviceManager {
preferredMainDevice.refresh();
hasChanged = true;
}
- syncAudioSharingStatusIfNeeded(preferredMainDevice);
+ syncAudioSharingSourceIfNeeded(preferredMainDevice);
}
if (hasChanged) {
log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
@@ -401,16 +399,13 @@ public class CsipDeviceManager {
return userManager != null && userManager.isManagedProfile();
}
- private void syncAudioSharingStatusIfNeeded(CachedBluetoothDevice mainDevice) {
+ private void syncAudioSharingSourceIfNeeded(CachedBluetoothDevice mainDevice) {
boolean isAudioSharingEnabled = BluetoothUtils.isAudioSharingUIAvailable(mContext);
- if (isAudioSharingEnabled && mainDevice != null) {
+ if (isAudioSharingEnabled) {
if (isWorkProfile()) {
- log("addMemberDevicesIntoMainDevice: skip sync audio sharing status, work profile");
+ log("addMemberDevicesIntoMainDevice: skip sync source for work profile");
return;
}
- Set<CachedBluetoothDevice> deviceSet = new HashSet<>();
- deviceSet.add(mainDevice);
- deviceSet.addAll(mainDevice.getMemberDevice());
boolean hasBroadcastSource = BluetoothUtils.isBroadcasting(mBtManager)
&& BluetoothUtils.hasConnectedBroadcastSource(
mainDevice, mBtManager);
@@ -424,6 +419,9 @@ public class CsipDeviceManager {
if (metadata != null && assistant != null) {
log("addMemberDevicesIntoMainDevice: sync audio sharing source after "
+ "combining the top level devices.");
+ Set<CachedBluetoothDevice> deviceSet = new HashSet<>();
+ deviceSet.add(mainDevice);
+ deviceSet.addAll(mainDevice.getMemberDevice());
Set<BluetoothDevice> sinksToSync = deviceSet.stream()
.map(CachedBluetoothDevice::getDevice)
.filter(device ->
@@ -437,24 +435,8 @@ public class CsipDeviceManager {
}
}
}
- if (Flags.enableTemporaryBondDevicesUi()) {
- log("addMemberDevicesIntoMainDevice: sync temp bond metadata for audio sharing "
- + "sinks after combining the top level devices.");
- Set<BluetoothDevice> sinksToSync = deviceSet.stream()
- .map(CachedBluetoothDevice::getDevice).filter(Objects::nonNull).collect(
- Collectors.toSet());
- if (sinksToSync.stream().anyMatch(BluetoothUtils::isTemporaryBondDevice)) {
- for (BluetoothDevice device : sinksToSync) {
- if (!BluetoothUtils.isTemporaryBondDevice(device)) {
- log("addMemberDevicesIntoMainDevice: sync temp bond metadata for "
- + device.getAnonymizedAddress());
- BluetoothUtils.setTemporaryBondMetadata(device);
- }
- }
- }
- }
} else {
- log("addMemberDevicesIntoMainDevice: skip sync audio sharing status, flag disabled");
+ log("addMemberDevicesIntoMainDevice: skip sync source, flag disabled");
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
index 2eccaa626f3b..fd14d1ff6786 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java
@@ -40,8 +40,6 @@ import android.content.Context;
import android.os.Looper;
import android.os.Parcel;
import android.os.UserManager;
-import android.platform.test.annotations.DisableFlags;
-import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import com.android.settingslib.flags.Flags;
@@ -76,9 +74,6 @@ public class CsipDeviceManagerTest {
private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11";
private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33";
- private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
- private static final String TEMP_BOND_METADATA =
- "<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
private final static int GROUP1 = 1;
private final BluetoothClass DEVICE_CLASS_1 =
createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
@@ -342,7 +337,6 @@ public class CsipDeviceManagerTest {
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_returnTrue() {
// Condition: The preferredDevice is main and there is another main device in top list
// Expected Result: return true and there is the preferredDevice in top list
@@ -352,6 +346,7 @@ public class CsipDeviceManagerTest {
mCachedDevices.add(preferredDevice);
mCachedDevices.add(mCachedDevice2);
mCachedDevices.add(mCachedDevice3);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
@@ -364,7 +359,6 @@ public class CsipDeviceManagerTest {
}
@Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
public void
addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_workProfile_doNothing() {
// Condition: The preferredDevice is main and there is another main device in top list
@@ -375,6 +369,7 @@ public class CsipDeviceManagerTest {
mCachedDevices.add(preferredDevice);
mCachedDevices.add(mCachedDevice2);
mCachedDevices.add(mCachedDevice3);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(true);
BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
@@ -382,8 +377,6 @@ public class CsipDeviceManagerTest {
BluetoothLeBroadcastReceiveState.class);
when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state));
- when(mDevice2.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
- .thenReturn(TEMP_BOND_METADATA.getBytes());
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
when(mUserManager.isManagedProfile()).thenReturn(true);
@@ -394,13 +387,10 @@ public class CsipDeviceManagerTest {
assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
verify(mAssistant, never()).addSource(mDevice1, metadata, /* isGroupOp= */ false);
- verify(mDevice1, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
}
@Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
- public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncState() {
+ public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncSource() {
// Condition: The preferredDevice is main and there is another main device in top list
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice1;
@@ -409,6 +399,7 @@ public class CsipDeviceManagerTest {
mCachedDevices.add(preferredDevice);
mCachedDevices.add(mCachedDevice2);
mCachedDevices.add(mCachedDevice3);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(true);
BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
@@ -416,8 +407,6 @@ public class CsipDeviceManagerTest {
BluetoothLeBroadcastReceiveState.class);
when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state));
- when(mDevice2.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
- .thenReturn(TEMP_BOND_METADATA.getBytes());
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
@@ -426,8 +415,6 @@ public class CsipDeviceManagerTest {
assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue();
assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2);
verify(mAssistant).addSource(mDevice1, metadata, /* isGroupOp= */ false);
- verify(mDevice1).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
}
@Test
@@ -449,13 +436,13 @@ public class CsipDeviceManagerTest {
}
@Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_returnTrue() {
// Condition: The preferredDevice is member and there are two main device in top list
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice2;
BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
mCachedDevice3.setGroupId(GROUP1);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(false);
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
@@ -470,20 +457,16 @@ public class CsipDeviceManagerTest {
assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
any(BluetoothLeBroadcastMetadata.class), anyBoolean());
- verify(mDevice2, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
- verify(mDevice3, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
}
@Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
- public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_syncState() {
+ public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_syncSource() {
// Condition: The preferredDevice is member and there are two main device in top list
// Expected Result: return true and there is the preferredDevice in top list
CachedBluetoothDevice preferredDevice = mCachedDevice2;
BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice();
mCachedDevice3.setGroupId(GROUP1);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(true);
BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class);
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
@@ -491,8 +474,6 @@ public class CsipDeviceManagerTest {
BluetoothLeBroadcastReceiveState.class);
when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
when(mAssistant.getAllSources(mDevice1)).thenReturn(ImmutableList.of(state));
- when(mDevice1.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS))
- .thenReturn(TEMP_BOND_METADATA.getBytes());
assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice))
.isTrue();
@@ -507,10 +488,6 @@ public class CsipDeviceManagerTest {
assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice);
verify(mAssistant).addSource(mDevice2, metadata, /* isGroupOp= */ false);
verify(mAssistant).addSource(mDevice3, metadata, /* isGroupOp= */ false);
- verify(mDevice2).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
- verify(mDevice3).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS,
- TEMP_BOND_METADATA.getBytes());
}
@Test
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
index 60eaa28e3822..b9aca25e1675 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt
@@ -21,7 +21,6 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionKey
-import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.observableTransitionState
import com.android.systemui.scene.shared.model.SceneDataSource
import kotlinx.coroutines.CoroutineScope
@@ -106,6 +105,6 @@ class SceneTransitionLayoutDataSource(
}
override fun freezeAndAnimateToCurrentState() {
- (state.transitionState as? TransitionState.Transition)?.freezeAndAnimateToCurrentState()
+ state.currentTransition?.freezeAndAnimateToCurrentState()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
index fee358a7c15d..83860ecf168b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java
@@ -63,6 +63,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
+import java.util.Optional;
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
@@ -100,7 +101,7 @@ public class RotationLockTileTest extends SysuiTestCase {
@Mock
private BatteryController mBatteryController;
@Mock
- DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+ Optional<DeviceStateRotationLockSettingController> mDeviceStateRotationLockSettingController;
@Mock
RotationPolicyWrapper mRotationPolicyWrapper;
@Mock
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
index 8593f6a08b5a..605e4a47275b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java
@@ -37,15 +37,19 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper
@SmallTest
public class RotationLockControllerImplTest extends SysuiTestCase {
- private static final String[] DEFAULT_SETTINGS = new String[] {"0:0", "1:2"};
+ private static final String[] DEFAULT_SETTINGS = new String[]{"0:0", "1:2"};
- @Mock RotationPolicyWrapper mRotationPolicyWrapper;
- @Mock DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
+ @Mock
+ RotationPolicyWrapper mRotationPolicyWrapper;
+ @Mock
+ DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController;
private ArgumentCaptor<RotationPolicy.RotationPolicyListener> mRotationPolicyListenerCaptor;
@@ -93,7 +97,7 @@ public class RotationLockControllerImplTest extends SysuiTestCase {
private void createRotationLockController(String[] deviceStateRotationLockDefaults) {
new RotationLockControllerImpl(
mRotationPolicyWrapper,
- mDeviceStateRotationLockSettingController,
+ Optional.of(mDeviceStateRotationLockSettingController),
deviceStateRotationLockDefaults);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 3c68e3a09f02..a25faa3a7aec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -56,6 +56,7 @@ import com.android.systemui.reardisplay.RearDisplayModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
import com.android.systemui.recents.RecentsModule;
+import com.android.systemui.rotationlock.DeviceStateAutoRotateModule;
import com.android.systemui.rotationlock.RotationLockModule;
import com.android.systemui.rotationlock.RotationLockNewModule;
import com.android.systemui.scene.SceneContainerFrameworkModule;
@@ -132,6 +133,7 @@ import javax.inject.Named;
CollapsedStatusBarFragmentStartableModule.class,
ConnectingDisplayViewModel.StartableModule.class,
DefaultBlueprintModule.class,
+ DeviceStateAutoRotateModule.class,
EmergencyGestureModule.class,
GestureModule.class,
HeadsUpModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index fe5a82cb5b8c..f8cf6b007041 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -105,6 +105,7 @@ import com.android.systemui.qs.footer.dagger.FooterActionsModule;
import com.android.systemui.recents.Recents;
import com.android.systemui.recordissue.RecordIssueModule;
import com.android.systemui.retail.RetailModeModule;
+import com.android.systemui.rotationlock.DeviceStateAutoRotateModule.BoundsDeviceStateAutoRotateModule;
import com.android.systemui.scene.shared.model.SceneContainerConfig;
import com.android.systemui.scene.shared.model.SceneDataSource;
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator;
@@ -145,6 +146,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.ConfigurationControllerModule;
import com.android.systemui.statusbar.phone.LetterboxModule;
import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule;
+import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.PolicyModule;
import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
@@ -391,6 +393,11 @@ public abstract class SystemUIModule {
@BindsOptionalOf
abstract LockscreenContent optionalLockscreenContent();
+ @BindsOptionalOf
+ @BoundsDeviceStateAutoRotateModule
+ abstract Optional<DeviceStateRotationLockSettingController>
+ optionalDeviceStateRotationLockSettingController();
+
@SysUISingleton
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
@@ -466,6 +473,16 @@ public abstract class SystemUIModule {
return new SceneDataSourceDelegator(applicationScope, config);
}
+ @Provides
+ @SysUISingleton
+ static Optional<DeviceStateRotationLockSettingController>
+ provideDeviceStateRotationLockSettingController(
+ @BoundsDeviceStateAutoRotateModule
+ Optional<Optional<DeviceStateRotationLockSettingController>> optionalOfOptional
+ ) {
+ return optionalOfOptional.orElseGet(Optional::empty);
+ }
+
@Binds
abstract SceneDataSource bindSceneDataSource(SceneDataSourceDelegator delegator);
diff --git a/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt b/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt
new file mode 100644
index 000000000000..628280210236
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.rotationlock
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController
+import com.android.window.flags.Flags
+import dagger.Module
+import dagger.Provides
+import java.util.Optional
+import javax.inject.Provider
+import javax.inject.Qualifier
+
+@Module
+class DeviceStateAutoRotateModule {
+ /** Qualifier for dependencies to be bound with [DeviceStateAutoRotateModule]. */
+ @Qualifier
+ @MustBeDocumented
+ @Retention(AnnotationRetention.RUNTIME)
+ annotation class BoundsDeviceStateAutoRotateModule
+
+ /**
+ * Provides an instance of [DeviceStateRotationLockSettingController].
+ *
+ * @param controllerProvider The provider for [DeviceStateRotationLockSettingController].
+ * @return An [Optional] containing the [DeviceStateRotationLockSettingController] instance if
+ * the `Flags.enableDeviceStateAutoRotateSettingRefactor()` flag is disabled, or an empty
+ * [Optional] otherwise.
+ */
+ @Provides
+ @BoundsDeviceStateAutoRotateModule
+ @SysUISingleton
+ fun provideDeviceStateRotationLockSettingController(
+ controllerProvider: Provider<DeviceStateRotationLockSettingController>
+ ): Optional<DeviceStateRotationLockSettingController> =
+ if (Flags.enableDeviceStateAutoRotateSettingRefactor()) {
+ Optional.empty()
+ } else {
+ Optional.of(controllerProvider.get())
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 6c8e1825ea0a..ba41fd4c40ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -65,6 +65,7 @@ import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeDisplayAware;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
+import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -116,6 +117,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final static String TAG = "StatusBarNotificationActivityStarter";
private final Context mContext;
+ private final ShadeDialogContextInteractor mContextInteractor;
private final Handler mMainThreadHandler;
private final Executor mUiBgExecutor;
@@ -156,6 +158,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@Inject
StatusBarNotificationActivityStarter(
@ShadeDisplayAware Context context,
+ ShadeDialogContextInteractor contextInteractor,
@Main Handler mainThreadHandler,
@Background Executor uiBgExecutor,
NotificationVisibilityProvider visibilityProvider,
@@ -188,6 +191,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
PowerInteractor powerInteractor,
UserTracker userTracker) {
mContext = context;
+ mContextInteractor = contextInteractor;
mMainThreadHandler = mainThreadHandler;
mUiBgExecutor = uiBgExecutor;
mVisibilityProvider = visibilityProvider;
@@ -491,7 +495,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
boolean animate,
boolean isActivityIntent) {
mLogger.logStartNotificationIntent(entry);
- final int displayId = mContext.getDisplayId();
+ final int displayId = mContextInteractor.getContext().getDisplayId();
try {
ActivityTransitionAnimator.Controller animationController =
new StatusBarTransitionAnimatorController(
@@ -532,7 +536,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
public void startNotificationGutsIntent(@NonNull final Intent intent, final int appUid,
@NonNull ExpandableNotificationRow row) {
boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */);
- final int displayId = mContext.getDisplayId();
+ final int displayId = mContextInteractor.getContext().getDisplayId();
ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() {
@Override
public boolean onDismiss() {
@@ -571,7 +575,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@Override
public void startHistoryIntent(View view, boolean showHistory) {
ModesEmptyShadeFix.assertInLegacyMode();
- final int displayId = mContext.getDisplayId();
+ final int displayId = mContextInteractor.getContext().getDisplayId();
boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */);
ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() {
@Override
@@ -621,7 +625,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
@Override
public void startSettingsIntent(@NonNull View view, @NonNull SettingsIntent intentInfo) {
- final int displayId = mContext.getDisplayId();
+ final int displayId = mContextInteractor.getContext().getDisplayId();
boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */);
ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
index 88cf46a0ca07..b13e01be40f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java
@@ -29,7 +29,6 @@ import androidx.annotation.NonNull;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
@@ -43,7 +42,6 @@ import javax.inject.Inject;
* Handles reading and writing of rotation lock settings per device state, as well as setting the
* rotation lock when device state changes.
*/
-@SysUISingleton
public final class DeviceStateRotationLockSettingController
implements Listenable, RotationLockController.RotationLockControllerCallback, Dumpable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index 797aa1f3a3dd..3ee7f33e3d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -27,8 +27,10 @@ import androidx.annotation.NonNull;
import com.android.internal.view.RotationPolicy.RotationPolicyListener;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.rotationlock.DeviceStateAutoRotateModule.BoundsDeviceStateAutoRotateModule;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
+import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Inject;
@@ -50,21 +52,25 @@ public final class RotationLockControllerImpl implements RotationLockController
};
private final RotationPolicyWrapper mRotationPolicy;
- private final DeviceStateRotationLockSettingController
+ private final Optional<DeviceStateRotationLockSettingController>
mDeviceStateRotationLockSettingController;
private final boolean mIsPerDeviceStateRotationLockEnabled;
@Inject
public RotationLockControllerImpl(
RotationPolicyWrapper rotationPolicyWrapper,
- DeviceStateRotationLockSettingController deviceStateRotationLockSettingController,
+ Optional<DeviceStateRotationLockSettingController>
+ deviceStateRotationLockSettingController,
@Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
) {
mRotationPolicy = rotationPolicyWrapper;
- mDeviceStateRotationLockSettingController = deviceStateRotationLockSettingController;
mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0;
- if (mIsPerDeviceStateRotationLockEnabled) {
- mCallbacks.add(mDeviceStateRotationLockSettingController);
+ mDeviceStateRotationLockSettingController =
+ deviceStateRotationLockSettingController;
+
+ if (mIsPerDeviceStateRotationLockEnabled
+ && mDeviceStateRotationLockSettingController.isPresent()) {
+ mCallbacks.add(mDeviceStateRotationLockSettingController.get());
}
setListening(true);
@@ -113,8 +119,9 @@ public final class RotationLockControllerImpl implements RotationLockController
} else {
mRotationPolicy.unregisterRotationPolicyListener(mRotationPolicyListener);
}
- if (mIsPerDeviceStateRotationLockEnabled) {
- mDeviceStateRotationLockSettingController.setListening(listening);
+ if (mIsPerDeviceStateRotationLockEnabled
+ && mDeviceStateRotationLockSettingController.isPresent()) {
+ mDeviceStateRotationLockSettingController.get().setListening(listening);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 3190d3ae8f16..28eafa937097 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -76,6 +76,7 @@ import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ShadeControllerImpl;
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.data.repository.ShadeAnimationRepository;
+import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl;
import com.android.systemui.statusbar.CommandQueue;
@@ -171,6 +172,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private final FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private ExpandableNotificationRow mNotificationRow;
private ExpandableNotificationRow mBubbleNotificationRow;
+ private FakeShadeDialogContextInteractor mContextInteractor;
private final Answer<Void> mCallOnDismiss = answerVoid(
(OnDismissAction dismissAction, Runnable cancel,
@@ -187,6 +189,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mDependency,
TestableLooper.get(this));
+ mContextInteractor = new FakeShadeDialogContextInteractor(mContext);
+
// Create standard notification with contentIntent
mNotificationRow = notificationTestHelper.createRow();
StatusBarNotification sbn = mNotificationRow.getEntry().getSbn();
@@ -199,10 +203,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
bubbleSbn.getNotification().contentIntent = mContentIntent;
bubbleSbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL;
-// ArrayList<NotificationEntry> activeNotifications = new ArrayList<>();
-// activeNotifications.add(mNotificationRow.getEntry());
-// activeNotifications.add(mBubbleNotificationRow.getEntry());
-// when(mEntryManager.getVisibleNotifications()).thenReturn(activeNotifications);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mOnUserInteractionCallback.registerFutureDismissal(eq(mNotificationRow.getEntry()),
anyInt())).thenReturn(mFutureDismissalRunnable);
@@ -232,6 +232,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mNotificationActivityStarter =
new StatusBarNotificationActivityStarter(
getContext(),
+ mContextInteractor,
mHandler,
mUiBgExecutor,
mVisibilityProvider,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
index d787e2c190c8..91404e0688ed 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
@@ -30,6 +30,7 @@ import com.android.systemui.kosmos.Kosmos
import com.android.systemui.plugins.activityStarter
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.settings.userTracker
+import com.android.systemui.shade.data.repository.shadeDialogContextInteractor
import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
import com.android.systemui.shade.domain.interactor.shadeAnimationInteractor
import com.android.systemui.shade.shadeController
@@ -52,6 +53,7 @@ val Kosmos.statusBarNotificationActivityStarter by
Kosmos.Fixture {
StatusBarNotificationActivityStarter(
applicationContext,
+ shadeDialogContextInteractor,
fakeExecutorHandler,
fakeExecutor,
notificationVisibilityProvider,
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fd322a5c6345..7eebbba00778 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -162,6 +162,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.content.ComponentCallbacks;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -456,6 +457,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
private DisplayInfo mLastDisplayInfoOverride;
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ @NonNull
private final DisplayPolicy mDisplayPolicy;
private final DisplayRotation mDisplayRotation;
@@ -542,6 +544,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/** Remove this display when animation on it has completed. */
private boolean mDeferredRemoval;
+ @NonNull
final PinnedTaskController mPinnedTaskController;
private final LinkedList<ActivityRecord> mTmpUpdateAllDrawn = new LinkedList();
@@ -1102,6 +1105,29 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
};
/**
+ * Called to update fields retrieve from {@link #getDisplayUiContext()} resources when
+ * there's a configuration update on {@link #getDisplayUiContext()}.
+ */
+ @NonNull
+ private final ComponentCallbacks mSysUiContextConfigCallback = new ComponentCallbacks() {
+
+ @Override
+ public void onConfigurationChanged(@NonNull Configuration newConfig) {
+ synchronized (mWmService.mGlobalLock) {
+ if (mDisplayReady) {
+ mDisplayPolicy.onConfigurationChanged();
+ mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
+ }
+ }
+ }
+
+ @Override
+ public void onLowMemory() {
+ // Do nothing.
+ }
+ };
+
+ /**
* Create new {@link DisplayContent} instance, add itself to the root window container and
* initialize direct children.
* @param display May not be null.
@@ -2797,11 +2823,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final int lastOrientation = getConfiguration().orientation;
final int lastWindowingMode = getWindowingMode();
super.onConfigurationChanged(newParentConfig);
- if (mDisplayPolicy != null) {
- mDisplayPolicy.onConfigurationChanged();
- mPinnedTaskController.onPostDisplayConfigurationChanged();
- mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp();
+ if (!Flags.trackSystemUiContextBeforeWms()) {
+ mSysUiContextConfigCallback.onConfigurationChanged(newParentConfig);
}
+ mPinnedTaskController.onPostDisplayConfigurationChanged();
// Update IME parent if needed.
updateImeParent();
@@ -3381,6 +3406,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
.getKeyguardController().onDisplayRemoved(mDisplayId);
mWallpaperController.resetLargestDisplay(mDisplay);
mWmService.mDisplayWindowSettings.onDisplayRemoved(this);
+ if (Flags.trackSystemUiContextBeforeWms()) {
+ getDisplayUiContext().unregisterComponentCallbacks(mSysUiContextConfigCallback);
+ }
} finally {
mDisplayReady = false;
}
@@ -5429,7 +5457,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
reconfigureDisplayLocked();
onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration());
mWmService.mDisplayNotificationController.dispatchDisplayAdded(this);
- // Attach the SystemUiContext to this DisplayContent the get latest configuration.
+ // Attach the SystemUiContext to this DisplayContent to get latest configuration.
// Note that the SystemUiContext will be removed automatically if this DisplayContent
// is detached.
registerSystemUiContext();
@@ -5437,11 +5465,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
private void registerSystemUiContext() {
+ final Context systemUiContext = getDisplayUiContext();
final WindowProcessController wpc = mAtmService.getProcessController(
- getDisplayUiContext().getIApplicationThread());
+ systemUiContext.getIApplicationThread());
mWmService.mWindowContextListenerController.registerWindowContainerListener(
- wpc, getDisplayUiContext().getWindowContextToken(), this,
+ wpc, systemUiContext.getWindowContextToken(), this,
INVALID_WINDOW_TYPE, null /* options */);
+ if (Flags.trackSystemUiContextBeforeWms()) {
+ systemUiContext.registerComponentCallbacks(mSysUiContextConfigCallback);
+ }
}
@Override
@@ -6620,6 +6652,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
forAllTasks((t) -> { t.getRootTask().removeChild(t, "removeAllTasks"); });
}
+ @NonNull
Context getDisplayUiContext() {
return mDisplayPolicy.getSystemUiContext();
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 10f591cfd379..fbe850198c50 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1865,6 +1865,7 @@ public class DisplayPolicy {
return mContext;
}
+ @NonNull
Context getSystemUiContext() {
return mUiContext;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d699a689459e..0b20911bcab2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1820,125 +1820,138 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean hideSystemAlertWindows = shouldHideNonSystemOverlayWindow(win);
win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows);
- boolean imMayMove = true;
-
- win.mToken.addWindow(win);
- displayPolicy.addWindowLw(win, attrs);
- displayPolicy.setDropInputModePolicy(win, win.mAttrs);
- if (type == TYPE_APPLICATION_STARTING && activity != null) {
- activity.attachStartingWindow(win);
- ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
- activity, win);
- } else if (type == TYPE_INPUT_METHOD
- // IME window is always touchable.
- // Ignore non-touchable windows e.g. Stylus InkWindow.java.
- && (win.getAttrs().flags & FLAG_NOT_TOUCHABLE) == 0) {
- displayContent.setInputMethodWindowLocked(win);
- imMayMove = false;
- } else if (type == TYPE_INPUT_METHOD_DIALOG) {
- displayContent.computeImeTarget(true /* updateImeTarget */);
- imMayMove = false;
- } else {
- if (type == TYPE_WALLPAPER) {
- displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- } else if (win.hasWallpaper()) {
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
- // If there is currently a wallpaper being shown, and
- // the base layer of the new window is below the current
- // layer of the target window, then adjust the wallpaper.
- // This is to avoid a new window being placed between the
- // wallpaper and its target.
- displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- }
- }
+ res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState,
+ outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs);
+ }
- final WindowStateAnimator winAnimator = win.mWinAnimator;
- winAnimator.mEnterAnimationPending = true;
- winAnimator.mEnteringAnimation = true;
+ Binder.restoreCallingIdentity(origId);
- if (displayPolicy.areSystemBarsForcedConsumedLw()) {
- res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
- }
- if (displayContent.isInTouchMode()) {
- res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
- }
- if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) {
- res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
+ return res;
+ }
+
+ private int addWindowInner(@NonNull WindowState win, @NonNull DisplayPolicy displayPolicy,
+ @NonNull ActivityRecord activity, @NonNull DisplayContent displayContent,
+ @NonNull InsetsState outInsetsState, @NonNull Rect outAttachedFrame,
+ @NonNull InsetsSourceControl.Array outActiveControls, @NonNull IWindow client,
+ @NonNull float[] outSizeCompatScale, @NonNull LayoutParams attrs) {
+ int res = 0;
+ final int type = attrs.type;
+ boolean imMayMove = true;
+
+ win.mToken.addWindow(win);
+ displayPolicy.addWindowLw(win, attrs);
+ displayPolicy.setDropInputModePolicy(win, win.mAttrs);
+ if (type == TYPE_APPLICATION_STARTING && activity != null) {
+ activity.attachStartingWindow(win);
+ ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
+ activity, win);
+ } else if (type == TYPE_INPUT_METHOD
+ // IME window is always touchable.
+ // Ignore non-touchable windows e.g. Stylus InkWindow.java.
+ && (win.getAttrs().flags & FLAG_NOT_TOUCHABLE) == 0) {
+ displayContent.setInputMethodWindowLocked(win);
+ imMayMove = false;
+ } else if (type == TYPE_INPUT_METHOD_DIALOG) {
+ displayContent.computeImeTarget(true /* updateImeTarget */);
+ imMayMove = false;
+ } else {
+ if (type == TYPE_WALLPAPER) {
+ displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
+ displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ } else if (win.hasWallpaper()) {
+ displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
+ // If there is currently a wallpaper being shown, and
+ // the base layer of the new window is below the current
+ // layer of the target window, then adjust the wallpaper.
+ // This is to avoid a new window being placed between the
+ // wallpaper and its target.
+ displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
+ }
- displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
+ winAnimator.mEnterAnimationPending = true;
+ winAnimator.mEnteringAnimation = true;
- boolean focusChanged = false;
- if (win.canReceiveKeys()) {
- focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
- false /*updateInputWindows*/);
- if (focusChanged) {
- imMayMove = false;
- }
- }
+ if (displayPolicy.areSystemBarsForcedConsumedLw()) {
+ res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
+ }
+ if (displayContent.isInTouchMode()) {
+ res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
+ }
+ if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) {
+ res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
+ }
- if (imMayMove) {
- displayContent.computeImeTarget(true /* updateImeTarget */);
- if (win.isImeOverlayLayeringTarget()) {
- dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type,
- win.isVisibleRequestedOrAdding(), false /* removed */,
- displayContent.getDisplayId());
- }
- }
+ displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
- // Don't do layout here, the window must call
- // relayout to be displayed, so we'll do it there.
- if (win.mActivityRecord != null && win.mActivityRecord.isEmbedded()) {
- // Assign child layers from the parent Task if the Activity is embedded.
- win.getTask().assignChildLayers();
- } else {
- win.getParent().assignChildLayers();
+ boolean focusChanged = false;
+ if (win.canReceiveKeys()) {
+ focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
+ false /*updateInputWindows*/);
+ if (focusChanged) {
+ imMayMove = false;
}
+ }
- if (focusChanged) {
- displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
- false /*updateInputWindows*/);
+ if (imMayMove) {
+ displayContent.computeImeTarget(true /* updateImeTarget */);
+ if (win.isImeOverlayLayeringTarget()) {
+ dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type,
+ win.isVisibleRequestedOrAdding(), false /* removed */,
+ displayContent.getDisplayId());
}
- displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
+ }
- ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
- + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
+ // Don't do layout here, the window must call
+ // relayout to be displayed, so we'll do it there.
+ if (win.mActivityRecord != null && win.mActivityRecord.isEmbedded()) {
+ // Assign child layers from the parent Task if the Activity is embedded.
+ win.getTask().assignChildLayers();
+ } else {
+ win.getParent().assignChildLayers();
+ }
- boolean needToSendNewConfiguration =
- win.isVisibleRequestedOrAdding() && displayContent.updateOrientation();
- if (win.providesDisplayDecorInsets()) {
- needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo();
- }
- if (needToSendNewConfiguration) {
- displayContent.sendNewConfiguration();
- }
+ if (focusChanged) {
+ displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
+ false /*updateInputWindows*/);
+ }
+ displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
- // This window doesn't have a frame yet. Don't let this window cause the insets change.
- displayContent.getInsetsStateController().updateAboveInsetsState(
- false /* notifyInsetsChanged */);
+ ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
+ + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
- win.fillInsetsState(outInsetsState, true /* copySources */);
- getInsetsSourceControls(win, outActiveControls);
+ boolean needToSendNewConfiguration =
+ win.isVisibleRequestedOrAdding() && displayContent.updateOrientation();
+ if (win.providesDisplayDecorInsets()) {
+ needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo();
+ }
+ if (needToSendNewConfiguration) {
+ displayContent.sendNewConfiguration();
+ }
- if (win.mLayoutAttached) {
- outAttachedFrame.set(win.getParentWindow().getFrame());
- if (win.mInvGlobalScale != 1f) {
- outAttachedFrame.scale(win.mInvGlobalScale);
- }
- } else {
- // Make this invalid which indicates a null attached frame.
- outAttachedFrame.set(0, 0, -1, -1);
- }
- outSizeCompatScale[0] = win.getCompatScaleForClient();
+ // This window doesn't have a frame yet. Don't let this window cause the insets change.
+ displayContent.getInsetsStateController().updateAboveInsetsState(
+ false /* notifyInsetsChanged */);
+
+ win.fillInsetsState(outInsetsState, true /* copySources */);
+ getInsetsSourceControls(win, outActiveControls);
- if (res >= ADD_OKAY && win.isPresentation()) {
- mPresentationController.onPresentationAdded(win);
+ if (win.mLayoutAttached) {
+ outAttachedFrame.set(win.getParentWindow().getFrame());
+ if (win.mInvGlobalScale != 1f) {
+ outAttachedFrame.scale(win.mInvGlobalScale);
}
+ } else {
+ // Make this invalid which indicates a null attached frame.
+ outAttachedFrame.set(0, 0, -1, -1);
}
+ outSizeCompatScale[0] = win.getCompatScaleForClient();
- Binder.restoreCallingIdentity(origId);
+ if (res >= ADD_OKAY && win.isPresentation()) {
+ mPresentationController.onPresentationAdded(win);
+ }
return res;
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 2d3f7231cc5c..ae5e85163e9a 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -866,6 +866,9 @@ public class InputMethodServiceTest {
() -> mActivity.showImeWithWindowInsetsController(),
EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ eventually(() -> assertWithMessage("IME navigation bar is shown")
+ .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue());
+
final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
verifyInputViewStatus(
() -> {
@@ -892,6 +895,9 @@ public class InputMethodServiceTest {
() -> mActivity.showImeWithWindowInsetsController(),
EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ eventually(() -> assertWithMessage("IME navigation bar is shown")
+ .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue());
+
final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID));
verifyInputViewStatus(
() -> {
@@ -927,6 +933,9 @@ public class InputMethodServiceTest {
},
EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ eventually(() -> assertWithMessage("IME navigation bar is shown")
+ .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue());
+
final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
imeSwitcherButton.click();
mInstrumentation.waitForIdleSync();
@@ -965,6 +974,9 @@ public class InputMethodServiceTest {
},
EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown");
+ eventually(() -> assertWithMessage("IME navigation bar is shown")
+ .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue());
+
final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID));
imeSwitcherButton.longClick();
mInstrumentation.waitForIdleSync();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 59335d3bb135..9406779c929d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -98,6 +98,7 @@ import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.testutils.StubTransaction;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.window.flags.Flags;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -657,6 +658,13 @@ public class SystemServicesTestRule implements TestRule {
AppWarnings appWarnings = getAppWarningsLocked();
spyOn(appWarnings);
doNothing().when(appWarnings).onStartActivity(any());
+
+ if (Flags.trackSystemUiContextBeforeWms()) {
+ final Context uiContext = getUiContext();
+ spyOn(uiContext);
+ doNothing().when(uiContext).registerComponentCallbacks(any());
+ doNothing().when(uiContext).unregisterComponentCallbacks(any());
+ }
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index ccce57a81e41..b1525cf00dc6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -30,6 +30,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -39,6 +40,7 @@ import android.view.DisplayCutout;
import android.view.DisplayInfo;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
+import com.android.window.flags.Flags;
class TestDisplayContent extends DisplayContent {
@@ -79,6 +81,13 @@ class TestDisplayContent extends DisplayContent {
WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getPermanentControlTarget());
WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getTransientControlTarget());
+ if (Flags.trackSystemUiContextBeforeWms()) {
+ final Context uiContext = getDisplayUiContext();
+ spyOn(uiContext);
+ doNothing().when(uiContext).registerComponentCallbacks(any());
+ doNothing().when(uiContext).unregisterComponentCallbacks(any());
+ }
+
// For devices that set the sysprop ro.bootanim.set_orientation_<display_id>
// See DisplayRotation#readDefaultDisplayRotation for context.
// Without that, meaning of height and width in context of the tests can be swapped if
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 7f9e591ca5e3..97c6ac6854c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -861,11 +861,9 @@ public class WindowTestsBase extends SystemServiceTestsBase {
/** Creates a {@link DisplayContent} and adds it to the system. */
private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy,
@Nullable SettingsEntry overrideSettings) {
- final DisplayContent display =
- new TestDisplayContent.Builder(mAtm, info)
- .setOverrideSettings(overrideSettings)
- .build();
- final DisplayContent dc = display.mDisplayContent;
+ final DisplayContent dc = new TestDisplayContent.Builder(mAtm, info)
+ .setOverrideSettings(overrideSettings)
+ .build();
// this display can show IME.
dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy);
return dc;