summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/system-current.txt4
-rw-r--r--core/java/android/companion/virtual/flags/flags.aconfig7
-rw-r--r--core/java/android/companion/virtual/sensor/VirtualSensorConfig.java73
-rw-r--r--core/java/android/service/dreams/DreamOverlayService.java10
-rw-r--r--core/java/android/view/ViewGroup.java110
-rw-r--r--core/java/android/view/ViewRootImpl.java9
-rw-r--r--core/java/android/widget/Editor.java186
-rw-r--r--core/java/android/widget/TextView.java32
-rw-r--r--core/java/com/android/internal/protolog/TEST_MAPPING7
-rw-r--r--core/tests/coretests/src/android/widget/TextViewContextMenuTest.java156
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java22
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt11
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModelTest.kt67
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt45
-rw-r--r--packages/SystemUI/res/values-sw600dp-land/config.xml2
-rw-r--r--packages/SystemUI/res/values-sw600dp/config.xml2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt77
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt157
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/StatusBarStartable.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt189
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt20
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeWindowModelKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt2
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/ActionChain.java239
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/Transition.java18
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java11
-rw-r--r--services/core/java/com/android/server/wm/TrustedOverlayHost.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java152
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java45
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java2
66 files changed, 1304 insertions, 810 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 47e12aef9926..5413c6606bcb 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3694,9 +3694,11 @@ package android.companion.virtual.sensor {
method public int getMinDelay();
method @NonNull public String getName();
method public float getPower();
+ method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") public int getReportingMode();
method public float getResolution();
method public int getType();
method @Nullable public String getVendor();
+ method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") public boolean isWakeUpSensor();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.sensor.VirtualSensorConfig> CREATOR;
}
@@ -3710,8 +3712,10 @@ package android.companion.virtual.sensor {
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setMaximumRange(float);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setMinDelay(int);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setPower(float);
+ method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setReportingMode(int);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setResolution(float);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setVendor(@Nullable String);
+ method @FlaggedApi("android.companion.virtualdevice.flags.device_aware_display_power") @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setWakeUpSensor(boolean);
}
public interface VirtualSensorDirectChannelCallback {
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index c3c3f0ef32e1..b4c36e1bc513 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -103,3 +103,10 @@ flag {
description: "Expose multiple surface for the virtual camera owner for different stream resolution"
bug: "341083465"
}
+
+flag {
+ namespace: "virtual_devices"
+ name: "device_aware_display_power"
+ description: "Device awareness in power and display APIs"
+ bug: "285020111"
+}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
index 21ad914bbc29..82f183fd1d62 100644
--- a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
@@ -17,12 +17,14 @@
package android.companion.virtual.sensor;
+import android.annotation.FlaggedApi;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.companion.virtualdevice.flags.Flags;
import android.hardware.Sensor;
import android.hardware.SensorDirectChannel;
import android.os.Parcel;
@@ -42,6 +44,13 @@ import java.util.Objects;
public final class VirtualSensorConfig implements Parcelable {
private static final String TAG = "VirtualSensorConfig";
+ // Defined in sensors.h
+ private static final int FLAG_WAKE_UP_SENSOR = 1;
+
+ // Mask for the reporting mode, bit 2, 3, 4.
+ private static final int REPORTING_MODE_MASK = 0xE;
+ private static final int REPORTING_MODE_SHIFT = 1;
+
// Mask for direct mode highest rate level, bit 7, 8, 9.
private static final int DIRECT_REPORT_MASK = 0x380;
private static final int DIRECT_REPORT_SHIFT = 7;
@@ -193,8 +202,7 @@ public final class VirtualSensorConfig implements Parcelable {
@SensorDirectChannel.RateLevel
public int getHighestDirectReportRateLevel() {
int rateLevel = ((mFlags & DIRECT_REPORT_MASK) >> DIRECT_REPORT_SHIFT);
- return rateLevel <= SensorDirectChannel.RATE_VERY_FAST
- ? rateLevel : SensorDirectChannel.RATE_VERY_FAST;
+ return Math.min(rateLevel, SensorDirectChannel.RATE_VERY_FAST);
}
/**
@@ -215,6 +223,28 @@ public final class VirtualSensorConfig implements Parcelable {
}
/**
+ * Returns whether the sensor is a wake-up sensor.
+ *
+ * @see Builder#setWakeUpSensor(boolean)
+ * @see Sensor#isWakeUpSensor()
+ */
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
+ public boolean isWakeUpSensor() {
+ return (mFlags & FLAG_WAKE_UP_SENSOR) > 0;
+ }
+
+ /**
+ * Returns the reporting mode of this sensor.
+ *
+ * @see Builder#setReportingMode(int)
+ * @see Sensor#getReportingMode()
+ */
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
+ public int getReportingMode() {
+ return ((mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT);
+ }
+
+ /**
* Returns the sensor flags.
*
* @hide
@@ -383,6 +413,45 @@ public final class VirtualSensorConfig implements Parcelable {
}
return this;
}
+
+ /**
+ * Sets whether this sensor is a wake up sensor.
+ *
+ * @see Sensor#isWakeUpSensor()
+ */
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
+ @NonNull
+ public VirtualSensorConfig.Builder setWakeUpSensor(boolean wakeUpSensor) {
+ if (wakeUpSensor) {
+ mFlags |= FLAG_WAKE_UP_SENSOR;
+ } else {
+ mFlags &= ~FLAG_WAKE_UP_SENSOR;
+ }
+ return this;
+ }
+
+ /**
+ * Sets the reporting mode of this sensor.
+ *
+ * @throws IllegalArgumentException if the reporting mode is not one of
+ * {@link Sensor#REPORTING_MODE_CONTINUOUS}, {@link Sensor#REPORTING_MODE_ON_CHANGE},
+ * {@link Sensor#REPORTING_MODE_ONE_SHOT}, or
+ * {@link Sensor#REPORTING_MODE_SPECIAL_TRIGGER}.
+ *
+ * @see Sensor#getReportingMode()
+ */
+ @FlaggedApi(Flags.FLAG_DEVICE_AWARE_DISPLAY_POWER)
+ @NonNull
+ public VirtualSensorConfig.Builder setReportingMode(int reportingMode) {
+ if (reportingMode != Sensor.REPORTING_MODE_CONTINUOUS
+ && reportingMode != Sensor.REPORTING_MODE_ON_CHANGE
+ && reportingMode != Sensor.REPORTING_MODE_ONE_SHOT
+ && reportingMode != Sensor.REPORTING_MODE_SPECIAL_TRIGGER) {
+ throw new IllegalArgumentException("Invalid reporting mode: " + reportingMode);
+ }
+ mFlags |= reportingMode << REPORTING_MODE_SHIFT;
+ return this;
+ }
}
@NonNull
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 013ec5f35761..244257cb61c8 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -51,6 +51,8 @@ public abstract class DreamOverlayService extends Service {
*/
private Executor mExecutor;
+ private boolean mCurrentRedirectToWake;
+
// An {@link IDreamOverlayClient} implementation that identifies itself when forwarding
// requests to the {@link DreamOverlayService}
private static class OverlayClient extends IDreamOverlayClient.Stub {
@@ -132,6 +134,10 @@ public abstract class DreamOverlayService extends Service {
mExecutor.execute(() -> {
endDreamInternal(mCurrentClient);
mCurrentClient = client;
+ if (Flags.dreamWakeRedirect()) {
+ mCurrentClient.redirectWake(mCurrentRedirectToWake);
+ }
+
onStartDream(params);
});
}
@@ -282,8 +288,10 @@ public abstract class DreamOverlayService extends Service {
return;
}
+ mCurrentRedirectToWake = redirect;
+
if (mCurrentClient == null) {
- throw new IllegalStateException("redirected wake with no dream present");
+ return;
}
mCurrentClient.redirectWake(redirect);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 6f8838619808..3b5286a04b3d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3093,74 +3093,74 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
- final boolean handled;
-
- // Canceling motions is a special case. We don't need to perform any transformations
- // or filtering. The important part is the action, not the contents.
final int oldAction = event.getAction();
- if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
- event.setAction(MotionEvent.ACTION_CANCEL);
- if (child == null) {
- handled = super.dispatchTouchEvent(event);
- } else {
- handled = child.dispatchTouchEvent(event);
+ try {
+ final boolean handled;
+ if (cancel) {
+ event.setAction(MotionEvent.ACTION_CANCEL);
}
- event.setAction(oldAction);
- return handled;
- }
- // Calculate the number of pointers to deliver.
- final int oldPointerIdBits = event.getPointerIdBits();
- final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
-
- // If for some reason we ended up in an inconsistent state where it looks like we
- // might produce a motion event with no pointers in it, then drop the event.
- if (newPointerIdBits == 0) {
- return false;
- }
+ // Calculate the number of pointers to deliver.
+ final int oldPointerIdBits = event.getPointerIdBits();
+ int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
- // If the number of pointers is the same and we don't need to perform any fancy
- // irreversible transformations, then we can reuse the motion event for this
- // dispatch as long as we are careful to revert any changes we make.
- // Otherwise we need to make a copy.
- final MotionEvent transformedEvent;
- if (newPointerIdBits == oldPointerIdBits) {
- if (child == null || child.hasIdentityMatrix()) {
- if (child == null) {
- handled = super.dispatchTouchEvent(event);
+ // If for some reason we ended up in an inconsistent state where it looks like we
+ // might produce a non-cancel motion event with no pointers in it, then drop the event.
+ // Make sure that we don't drop any cancel events.
+ if (newPointerIdBits == 0) {
+ if (event.getAction() != MotionEvent.ACTION_CANCEL) {
+ return false;
} else {
- final float offsetX = mScrollX - child.mLeft;
- final float offsetY = mScrollY - child.mTop;
- event.offsetLocation(offsetX, offsetY);
+ newPointerIdBits = oldPointerIdBits;
+ }
+ }
+
+ // If the number of pointers is the same and we don't need to perform any fancy
+ // irreversible transformations, then we can reuse the motion event for this
+ // dispatch as long as we are careful to revert any changes we make.
+ // Otherwise we need to make a copy.
+ final MotionEvent transformedEvent;
+ if (newPointerIdBits == oldPointerIdBits) {
+ if (child == null || child.hasIdentityMatrix()) {
+ if (child == null) {
+ handled = super.dispatchTouchEvent(event);
+ } else {
+ final float offsetX = mScrollX - child.mLeft;
+ final float offsetY = mScrollY - child.mTop;
+ event.offsetLocation(offsetX, offsetY);
- handled = child.dispatchTouchEvent(event);
+ handled = child.dispatchTouchEvent(event);
- event.offsetLocation(-offsetX, -offsetY);
+ event.offsetLocation(-offsetX, -offsetY);
+ }
+ return handled;
}
- return handled;
+ transformedEvent = MotionEvent.obtain(event);
+ } else {
+ transformedEvent = event.split(newPointerIdBits);
}
- transformedEvent = MotionEvent.obtain(event);
- } else {
- transformedEvent = event.split(newPointerIdBits);
- }
- // Perform any necessary transformations and dispatch.
- if (child == null) {
- handled = super.dispatchTouchEvent(transformedEvent);
- } else {
- final float offsetX = mScrollX - child.mLeft;
- final float offsetY = mScrollY - child.mTop;
- transformedEvent.offsetLocation(offsetX, offsetY);
- if (! child.hasIdentityMatrix()) {
- transformedEvent.transform(child.getInverseMatrix());
+ // Perform any necessary transformations and dispatch.
+ if (child == null) {
+ handled = super.dispatchTouchEvent(transformedEvent);
+ } else {
+ final float offsetX = mScrollX - child.mLeft;
+ final float offsetY = mScrollY - child.mTop;
+ transformedEvent.offsetLocation(offsetX, offsetY);
+ if (!child.hasIdentityMatrix()) {
+ transformedEvent.transform(child.getInverseMatrix());
+ }
+
+ handled = child.dispatchTouchEvent(transformedEvent);
}
- handled = child.dispatchTouchEvent(transformedEvent);
- }
+ // Done.
+ transformedEvent.recycle();
+ return handled;
- // Done.
- transformedEvent.recycle();
- return handled;
+ } finally {
+ event.setAction(oldAction);
+ }
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0e0262715d2f..0e1625aaedd8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4388,14 +4388,7 @@ public final class ViewRootImpl implements ViewParent,
mReportNextDraw = false;
mLastReportNextDrawReason = null;
mActiveSurfaceSyncGroup = null;
- if (mHasPendingTransactions) {
- // TODO: We shouldn't ever actually hit this, it means mPendingTransaction wasn't
- // merged with a sync group or BLASTBufferQueue before making it to this point
- // But better a one or two frame flicker than steady-state broken from dropping
- // whatever is in this transaction
- mPendingTransaction.apply();
- mHasPendingTransactions = false;
- }
+ mHasPendingTransactions = false;
mSyncBuffer = false;
if (isInWMSRequestedSync()) {
mWmsRequestSyncGroup.markSyncReady();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 03a26722da8f..0acc6bde5bfd 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -20,6 +20,7 @@ import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP;
import static android.widget.TextView.ACCESSIBILITY_ACTION_SMART_START_ID;
import static com.android.graphics.hwui.flags.Flags.highContrastTextSmallTextRect;
+import static com.android.text.flags.Flags.contextMenuHideUnavailableItems;
import android.R;
import android.animation.ValueAnimator;
@@ -3250,62 +3251,135 @@ public class Editor {
final int menuItemOrderShare = 9;
final int menuItemOrderAutofill = 10;
- menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo,
- com.android.internal.R.string.undo)
- .setAlphabeticShortcut('z')
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
- .setIcon(a.getDrawable(0))
- .setEnabled(mTextView.canUndo());
- menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, menuItemOrderRedo,
- com.android.internal.R.string.redo)
- .setAlphabeticShortcut('z', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
- .setIcon(a.getDrawable(1))
- .setEnabled(mTextView.canRedo());
-
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, menuItemOrderCut,
- com.android.internal.R.string.cut)
- .setAlphabeticShortcut('x')
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
- .setIcon(a.getDrawable(2))
- .setEnabled(mTextView.canCut());
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, menuItemOrderCopy,
- com.android.internal.R.string.copy)
- .setAlphabeticShortcut('c')
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
- .setIcon(a.getDrawable(3))
- .setEnabled(mTextView.canCopy());
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, menuItemOrderPaste,
- com.android.internal.R.string.paste)
- .setAlphabeticShortcut('v')
- .setEnabled(mTextView.canPaste())
- .setIcon(a.getDrawable(4))
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE_AS_PLAIN_TEXT,
- menuItemOrderPasteAsPlainText,
- com.android.internal.R.string.paste_as_plain_text)
- .setAlphabeticShortcut('v', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
- .setEnabled(mTextView.canPasteAsPlainText())
- .setIcon(a.getDrawable(4))
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
- menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_SELECT_ALL,
- menuItemOrderSelectAll, com.android.internal.R.string.selectAll)
- .setAlphabeticShortcut('a')
- .setEnabled(mTextView.canSelectAllText())
- .setIcon(a.getDrawable(5))
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
-
- menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, menuItemOrderShare,
- com.android.internal.R.string.share)
- .setEnabled(mTextView.canShare())
- .setIcon(a.getDrawable(6))
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
- final String selected = mTextView.getSelectedText();
- menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, menuItemOrderAutofill,
- android.R.string.autofill)
- .setEnabled(mTextView.canRequestAutofill()
- && (selected == null || selected.isEmpty()))
- .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ if (contextMenuHideUnavailableItems()) {
+ if (mTextView.canUndo()) {
+ menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo,
+ com.android.internal.R.string.undo)
+ .setAlphabeticShortcut('z')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setIcon(a.getDrawable(0));
+ }
+
+ if (mTextView.canRedo()) {
+ menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, menuItemOrderRedo,
+ com.android.internal.R.string.redo)
+ .setAlphabeticShortcut('z', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setIcon(a.getDrawable(1));
+ }
+
+ if (mTextView.canCut()) {
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, menuItemOrderCut,
+ com.android.internal.R.string.cut)
+ .setAlphabeticShortcut('x')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setIcon(a.getDrawable(2));
+ }
+
+ if (mTextView.canCopy()) {
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, menuItemOrderCopy,
+ com.android.internal.R.string.copy)
+ .setAlphabeticShortcut('c')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setIcon(a.getDrawable(3));
+ }
+
+ if (mTextView.canPaste()) {
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, menuItemOrderPaste,
+ com.android.internal.R.string.paste)
+ .setAlphabeticShortcut('v')
+ .setIcon(a.getDrawable(4))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ }
+
+ if (mTextView.canPasteAsPlainText()) {
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE_AS_PLAIN_TEXT,
+ menuItemOrderPasteAsPlainText,
+ com.android.internal.R.string.paste_as_plain_text)
+ .setAlphabeticShortcut('v', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
+ .setIcon(a.getDrawable(4))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ }
+
+ if (mTextView.canSelectAllText()) {
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_SELECT_ALL,
+ menuItemOrderSelectAll, com.android.internal.R.string.selectAll)
+ .setAlphabeticShortcut('a')
+ .setIcon(a.getDrawable(5))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ }
+
+ if (mTextView.canShare()) {
+ menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, menuItemOrderShare,
+ com.android.internal.R.string.share)
+ .setIcon(a.getDrawable(6))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ }
+
+ final String selected = mTextView.getSelectedText();
+ if (mTextView.canRequestAutofill() && (selected == null || selected.isEmpty())) {
+ menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, menuItemOrderAutofill,
+ android.R.string.autofill)
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ }
+ } else {
+ menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_UNDO, menuItemOrderUndo,
+ com.android.internal.R.string.undo)
+ .setAlphabeticShortcut('z')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setIcon(a.getDrawable(0))
+ .setEnabled(mTextView.canUndo());
+ menu.add(CONTEXT_MENU_GROUP_UNDO_REDO, TextView.ID_REDO, menuItemOrderRedo,
+ com.android.internal.R.string.redo)
+ .setAlphabeticShortcut('z', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setIcon(a.getDrawable(1))
+ .setEnabled(mTextView.canRedo());
+
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_CUT, menuItemOrderCut,
+ com.android.internal.R.string.cut)
+ .setAlphabeticShortcut('x')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setIcon(a.getDrawable(2))
+ .setEnabled(mTextView.canCut());
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_COPY, menuItemOrderCopy,
+ com.android.internal.R.string.copy)
+ .setAlphabeticShortcut('c')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setIcon(a.getDrawable(3))
+ .setEnabled(mTextView.canCopy());
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE, menuItemOrderPaste,
+ com.android.internal.R.string.paste)
+ .setAlphabeticShortcut('v')
+ .setEnabled(mTextView.canPaste())
+ .setIcon(a.getDrawable(4))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_PASTE_AS_PLAIN_TEXT,
+ menuItemOrderPasteAsPlainText,
+ com.android.internal.R.string.paste_as_plain_text)
+ .setAlphabeticShortcut('v', KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)
+ .setEnabled(mTextView.canPasteAsPlainText())
+ .setIcon(a.getDrawable(4))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ menu.add(CONTEXT_MENU_GROUP_CLIPBOARD, TextView.ID_SELECT_ALL,
+ menuItemOrderSelectAll, com.android.internal.R.string.selectAll)
+ .setAlphabeticShortcut('a')
+ .setEnabled(mTextView.canSelectAllText())
+ .setIcon(a.getDrawable(5))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+
+ menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_SHARE, menuItemOrderShare,
+ com.android.internal.R.string.share)
+ .setEnabled(mTextView.canShare())
+ .setIcon(a.getDrawable(6))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ final String selected = mTextView.getSelectedText();
+ menu.add(CONTEXT_MENU_GROUP_MISC, TextView.ID_AUTOFILL, menuItemOrderAutofill,
+ android.R.string.autofill)
+ .setEnabled(mTextView.canRequestAutofill()
+ && (selected == null || selected.isEmpty()))
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ }
a.recycle();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1ea20fa85bd4..a346a679ea00 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -15552,15 +15552,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- boolean canUndo() {
+ /** @hide */
+ @VisibleForTesting
+ public boolean canUndo() {
return mEditor != null && mEditor.canUndo();
}
- boolean canRedo() {
+ /** @hide */
+ @VisibleForTesting
+ public boolean canRedo() {
return mEditor != null && mEditor.canRedo();
}
- boolean canCut() {
+ /** @hide */
+ @VisibleForTesting
+ public boolean canCut() {
if (hasPasswordTransformationMethod()) {
return false;
}
@@ -15573,7 +15579,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return false;
}
- boolean canCopy() {
+ /** @hide */
+ @VisibleForTesting
+ public boolean canCopy() {
if (hasPasswordTransformationMethod()) {
return false;
}
@@ -15594,7 +15602,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
&& isSuggestionsEnabled() && mEditor.shouldOfferToShowSuggestions();
}
- boolean canShare() {
+ /** @hide */
+ @VisibleForTesting
+ public boolean canShare() {
if (!getContext().canStartActivityForResult() || !isDeviceProvisioned()
|| !getContext().getResources().getBoolean(
com.android.internal.R.bool.config_textShareSupported)) {
@@ -15613,8 +15623,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return mDeviceProvisionedState == DEVICE_PROVISIONED_YES;
}
+ /** @hide */
+ @VisibleForTesting
@UnsupportedAppUsage
- boolean canPaste() {
+ public boolean canPaste() {
return (mText instanceof Editable
&& mEditor != null && mEditor.mKeyListener != null
&& getSelectionStart() >= 0
@@ -15622,7 +15634,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
&& getClipboardManagerForUser().hasPrimaryClip());
}
- boolean canPasteAsPlainText() {
+ /** @hide */
+ @VisibleForTesting
+ public boolean canPasteAsPlainText() {
if (!canPaste()) {
return false;
}
@@ -15644,7 +15658,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return canShare();
}
- boolean canSelectAllText() {
+ /** @hide */
+ @VisibleForTesting
+ public boolean canSelectAllText() {
return canSelectText() && !hasPasswordTransformationMethod()
&& !(getSelectionStart() == 0 && getSelectionEnd() == mText.length());
}
diff --git a/core/java/com/android/internal/protolog/TEST_MAPPING b/core/java/com/android/internal/protolog/TEST_MAPPING
new file mode 100644
index 000000000000..37d57eed8cf4
--- /dev/null
+++ b/core/java/com/android/internal/protolog/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "ProtologPerfTests"
+ }
+ ]
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewContextMenuTest.java b/core/tests/coretests/src/android/widget/TextViewContextMenuTest.java
index bcf1053e8ddd..3e76977c99fa 100644
--- a/core/tests/coretests/src/android/widget/TextViewContextMenuTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewContextMenuTest.java
@@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -40,6 +41,9 @@ import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.Icon;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.textclassifier.TextClassification;
@@ -47,9 +51,12 @@ import android.view.textclassifier.TextClassification;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.verification.VerificationMode;
/**
* TextViewTest tests {@link TextView}.
@@ -86,6 +93,10 @@ public class TextViewContextMenuTest {
private SelectionActionModeHelper mMockHelper;
+ @ClassRule public static final SetFlagsRule.ClassRule SET_FLAGS_CLASS_RULE =
+ new SetFlagsRule.ClassRule();
+ @Rule public final SetFlagsRule mSetFlagsRule = SET_FLAGS_CLASS_RULE.createSetFlagsRule();
+
@Before
public void setUp() {
mMockHelper = mock(SelectionActionModeHelper.class);
@@ -234,6 +245,7 @@ public class TextViewContextMenuTest {
}
@Test
+ @DisableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
public void testAutofillMenuItemEnabledWhenNoTextSelected() {
ContextMenu menu = mock(ContextMenu.class);
MenuItem mockMenuItem = newMockMenuItem();
@@ -254,6 +266,7 @@ public class TextViewContextMenuTest {
}
@Test
+ @DisableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
public void testAutofillMenuItemNotEnabledWhenTextSelected() {
ContextMenu menu = mock(ContextMenu.class);
MenuItem mockMenuItem = newMockMenuItem();
@@ -271,4 +284,147 @@ public class TextViewContextMenuTest {
verify(menu).add(anyInt(), eq(TextView.ID_AUTOFILL), anyInt(), anyInt());
verify(mockAutofillMenuItem).setEnabled(false);
}
+
+ private interface EditTextSetup {
+ void run(EditText et);
+ }
+
+ private void verifyMenuItemNotAdded(EditTextSetup setup, int id, VerificationMode times) {
+ ContextMenu menu = mock(ContextMenu.class);
+ MenuItem mockMenuItem = newMockMenuItem();
+ when(menu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mockMenuItem);
+ EditText et = spy(new EditText(getInstrumentation().getContext()));
+ setup.run(et);
+ Editor editor = new Editor(et);
+ editor.setTextContextMenuItems(menu);
+ verify(menu, times).add(anyInt(), eq(id), anyInt(), anyInt());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuUndoNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canUndo(),
+ TextView.ID_UNDO, never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuUndoAddedWhenAvailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canUndo(), TextView.ID_UNDO,
+ times(1));
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuRedoNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canRedo(), TextView.ID_REDO,
+ never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuRedoAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canRedo(), TextView.ID_REDO,
+ times(1));
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuCutNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canCut(), TextView.ID_CUT,
+ never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuCutAddedWhenAvailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canCut(), TextView.ID_CUT,
+ times(1));
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuCopyNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canCopy(), TextView.ID_COPY,
+ never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuCopyAddedWhenAvailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canCopy(), TextView.ID_COPY,
+ times(1));
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuPasteNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canPaste(), TextView.ID_PASTE,
+ never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuPasteAddedWhenAvailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canPaste(), TextView.ID_PASTE,
+ times(1));
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuPasteAsPlaintextNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canPasteAsPlainText(),
+ TextView.ID_PASTE_AS_PLAIN_TEXT, never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuPasteAsPlaintextAddedWhenAvailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canPasteAsPlainText(),
+ TextView.ID_PASTE_AS_PLAIN_TEXT, times(1));
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuSelectAllNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canSelectAllText(),
+ TextView.ID_SELECT_ALL, never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuSelectAllAddedWhenAvailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canSelectAllText(),
+ TextView.ID_SELECT_ALL, times(1));
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuShareNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canShare(), TextView.ID_SHARE,
+ never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuShareAddedWhenAvailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(true).when(spy).canShare(), TextView.ID_SHARE,
+ times(1));
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuAutofillNotAddedWhenUnavailable() {
+ verifyMenuItemNotAdded((spy) -> doReturn(false).when(spy).canRequestAutofill(),
+ TextView.ID_AUTOFILL, never());
+ }
+
+ @Test
+ @EnableFlags(com.android.text.flags.Flags.FLAG_CONTEXT_MENU_HIDE_UNAVAILABLE_ITEMS)
+ public void testContextMenuAutofillNotAddedWhenUnavailableBecauseTextSelected() {
+ verifyMenuItemNotAdded((spy) -> {
+ doReturn(true).when(spy).canRequestAutofill();
+ doReturn("test").when(spy).getSelectedText();
+ }, TextView.ID_AUTOFILL, never());
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt
index a489c4ffdd94..423fe579a29a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellCoroutinesModule.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.dagger
+import android.os.Handler
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.shared.annotations.ShellBackgroundThread
import com.android.wm.shell.shared.annotations.ShellMainThread
@@ -24,22 +25,37 @@ import dagger.Provides
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainCoroutineDispatcher
import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.android.asCoroutineDispatcher
import kotlinx.coroutines.asCoroutineDispatcher
-/** Providers for various WmShell-specific coroutines-related constructs. */
+/**
+ * Providers for various WmShell-specific coroutines-related constructs.
+ *
+ * Providers of [MainCoroutineDispatcher] intentionally creates the dispatcher with a [Handler]
+ * backing it instead of a [ShellExecutor] because [ShellExecutor.asCoroutineDispatcher] will
+ * create a [CoroutineDispatcher] whose [CoroutineDispatcher.isDispatchNeeded] is effectively never
+ * dispatching. This is because even if dispatched, the backing [ShellExecutor.execute] always runs
+ * the [Runnable] immediately if called from the same thread, whereas
+ * [Handler.asCoroutineDispatcher] will create a [MainCoroutineDispatcher] that correctly
+ * dispatches (queues) when [CoroutineDispatcher.isDispatchNeeded] is true using [Handler.post].
+ * For callers that do need a non-dispatching version, [MainCoroutineDispatcher.immediate] is
+ * available.
+ */
@Module
class WMShellCoroutinesModule {
@Provides
@ShellMainThread
- fun provideMainDispatcher(@ShellMainThread mainExecutor: ShellExecutor): CoroutineDispatcher =
- mainExecutor.asCoroutineDispatcher()
+ fun provideMainDispatcher(
+ @ShellMainThread mainHandler: Handler
+ ): MainCoroutineDispatcher = mainHandler.asCoroutineDispatcher()
@Provides
@ShellBackgroundThread
fun provideBackgroundDispatcher(
- @ShellBackgroundThread backgroundExecutor: ShellExecutor
- ): CoroutineDispatcher = backgroundExecutor.asCoroutineDispatcher()
+ @ShellBackgroundThread backgroundHandler: Handler
+ ): MainCoroutineDispatcher = backgroundHandler.asCoroutineDispatcher()
@Provides
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 95f864a775be..8921ceb6175d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -21,6 +21,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -684,6 +685,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
+ prepareTasksForSplitScreen(new int[] {taskId1, taskId2}, wct);
wct.startTask(taskId1, options1);
startWithTask(wct, taskId2, options2, snapPosition, remoteTransition, instanceId);
@@ -714,6 +716,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
+ prepareTasksForSplitScreen(new int[] {taskId}, wct);
startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId);
}
@@ -757,11 +760,30 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
+ prepareTasksForSplitScreen(new int[] {taskId}, wct);
startWithTask(wct, taskId, options2, snapPosition, remoteTransition, instanceId);
}
/**
+ * Prepares the tasks whose IDs are provided in `taskIds` for split screen by clearing their
+ * bounds and windowing mode so that they can inherit the bounds and the windowing mode of
+ * their root stages.
+ *
+ * @param taskIds an array of task IDs whose bounds will be cleared.
+ * @param wct transaction to clear the bounds on the tasks.
+ */
+ private void prepareTasksForSplitScreen(int[] taskIds, WindowContainerTransaction wct) {
+ for (int taskId : taskIds) {
+ ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
+ if (task != null) {
+ wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED)
+ .setBounds(task.token, null);
+ }
+ }
+ }
+
+ /**
* Starts with the second task to a split pair in one transition.
*
* @param wct transaction to start the first task
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index d5874d1a7d3f..e17cb31407da 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -16,6 +16,8 @@
package com.android.systemui.scene.ui.composable
+import androidx.compose.foundation.gestures.awaitEachGesture
+import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
@@ -28,6 +30,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.input.pointer.pointerInput
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
@@ -100,7 +103,13 @@ fun SceneContainer(
}
Box(
- modifier = Modifier.fillMaxSize(),
+ modifier =
+ Modifier.fillMaxSize().pointerInput(Unit) {
+ awaitEachGesture {
+ awaitFirstDown(false)
+ viewModel.onSceneContainerUserInputStarted()
+ }
+ },
) {
SceneTransitionLayout(state = state, modifier = modifier.fillMaxSize()) {
sceneByKey.forEach { (sceneKey, composableScene) ->
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
index d850f17cd89a..65236f02b635 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt
@@ -30,8 +30,6 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
-import com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER
-import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.kosmos.testScope
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
@@ -90,8 +88,6 @@ class BouncerActionButtonInteractorTest : SysuiTestCase() {
.thenReturn(needsEmergencyAffordance)
whenever(telecomManager.isInCall).thenReturn(false)
- kosmos.fakeFeatureFlagsClassic.set(REFACTOR_GETCURRENTUSER, true)
-
kosmos.fakeTelephonyRepository.setHasTelephonyRadio(true)
kosmos.telecomManager = telecomManager
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index c63381687f18..5b987b309b6b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -175,10 +175,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
emergencyAffordanceManager = kosmos.emergencyAffordanceManager
whenever(emergencyAffordanceManager.needsEmergencyAffordance()).thenReturn(true)
- kosmos.fakeFeatureFlagsClassic.apply {
- set(Flags.NEW_NETWORK_SLICE_UI, false)
- set(Flags.REFACTOR_GETCURRENTUSER, true)
- }
+ kosmos.fakeFeatureFlagsClassic.apply { set(Flags.NEW_NETWORK_SLICE_UI, false) }
mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository
mobileConnectionsRepository.isAnySimSecure.value = false
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index e3a69a964b45..35cefa6b58df 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -401,10 +401,10 @@ class SceneInteractorTest : SysuiTestCase() {
underTest.setVisible(false, "reason")
val isVisible by collectLastValue(underTest.isVisible)
assertThat(isVisible).isFalse()
- underTest.onRemoteUserInteractionStarted("reason")
+ underTest.onRemoteUserInputStarted("reason")
assertThat(isVisible).isTrue()
- underTest.onUserInteractionFinished()
+ underTest.onUserInputFinished()
assertThat(isVisible).isFalse()
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index f856c559454c..832e7b1bcc0c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -237,7 +237,7 @@ class SceneContainerViewModelTest : SysuiTestCase() {
sceneInteractor.setVisible(false, "reason")
runCurrent()
assertThat(underTest.isVisible).isFalse()
- sceneInteractor.onRemoteUserInteractionStarted("reason")
+ sceneInteractor.onRemoteUserInputStarted("reason")
runCurrent()
assertThat(underTest.isVisible).isTrue()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModelTest.kt
index 6a886643cebb..8b97739af1db 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModelTest.kt
@@ -22,6 +22,8 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -83,4 +85,69 @@ class NotificationShadeWindowModelTest : SysuiTestCase() {
)
assertThat(isKeyguardOccluded).isFalse()
}
+
+ @Test
+ fun transitionFromOccludedToDreamingTransitionRemainsTrue() =
+ testScope.runTest {
+ val isKeyguardOccluded by collectLastValue(underTest.isKeyguardOccluded)
+ assertThat(isKeyguardOccluded).isFalse()
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DREAMING,
+ value = 0f,
+ transitionState = TransitionState.STARTED,
+ ),
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DREAMING,
+ value = 0.5f,
+ transitionState = TransitionState.RUNNING,
+ ),
+ ),
+ testScope,
+ )
+ assertThat(isKeyguardOccluded).isFalse()
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DREAMING,
+ value = 1f,
+ transitionState = TransitionState.FINISHED,
+ ),
+ )
+ assertThat(isKeyguardOccluded).isTrue()
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ listOf(
+ TransitionStep(
+ from = KeyguardState.DREAMING,
+ to = KeyguardState.OCCLUDED,
+ value = 0f,
+ transitionState = TransitionState.STARTED,
+ ),
+ TransitionStep(
+ from = KeyguardState.DREAMING,
+ to = KeyguardState.OCCLUDED,
+ value = 0.5f,
+ transitionState = TransitionState.RUNNING,
+ ),
+ ),
+ testScope,
+ )
+ assertThat(isKeyguardOccluded).isTrue()
+
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.DREAMING,
+ to = KeyguardState.OCCLUDED,
+ value = 1f,
+ transitionState = TransitionState.FINISHED,
+ ),
+ )
+ assertThat(isKeyguardOccluded).isTrue()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
index 1356e93db549..06a2c5af2986 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorTest.kt
@@ -21,6 +21,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding
@@ -84,4 +85,48 @@ class NotificationStackAppearanceInteractorTest : SysuiTestCase() {
)
)
}
+
+ @Test
+ fun shouldCloseGuts_userInputOngoing_currentGestureInGuts() =
+ testScope.runTest {
+ val shouldCloseGuts by collectLastValue(underTest.shouldCloseGuts)
+
+ kosmos.sceneInteractor.onSceneContainerUserInputStarted()
+ underTest.setCurrentGestureInGuts(true)
+
+ assertThat(shouldCloseGuts).isFalse()
+ }
+
+ @Test
+ fun shouldCloseGuts_userInputOngoing_currentGestureNotInGuts() =
+ testScope.runTest {
+ val shouldCloseGuts by collectLastValue(underTest.shouldCloseGuts)
+
+ kosmos.sceneInteractor.onSceneContainerUserInputStarted()
+ underTest.setCurrentGestureInGuts(false)
+
+ assertThat(shouldCloseGuts).isTrue()
+ }
+
+ @Test
+ fun shouldCloseGuts_userInputNotOngoing_currentGestureInGuts() =
+ testScope.runTest {
+ val shouldCloseGuts by collectLastValue(underTest.shouldCloseGuts)
+
+ kosmos.sceneInteractor.onUserInputFinished()
+ underTest.setCurrentGestureInGuts(true)
+
+ assertThat(shouldCloseGuts).isFalse()
+ }
+
+ @Test
+ fun shouldCloseGuts_userInputNotOngoing_currentGestureNotInGuts() =
+ testScope.runTest {
+ val shouldCloseGuts by collectLastValue(underTest.shouldCloseGuts)
+
+ kosmos.sceneInteractor.onUserInputFinished()
+ underTest.setCurrentGestureInGuts(false)
+
+ assertThat(shouldCloseGuts).isFalse()
+ }
}
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index 0c11d2fa1d11..fc6d20e11d3b 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -27,8 +27,6 @@
<!-- Whether to use the split 2-column notification shade -->
<bool name="config_use_split_notification_shade">true</bool>
- <bool name="config_use_large_screen_shade_header">true</bool>
-
<!-- The number of columns in the QuickSettings -->
<integer name="quick_settings_num_columns">2</integer>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index c594f1cd9313..b4383156dc71 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -35,6 +35,8 @@
<!-- How many lines to show in the security footer -->
<integer name="qs_security_footer_maxLines">1</integer>
+ <bool name="config_use_large_screen_shade_header">true</bool>
+
<!-- Whether to show bottom sheets edge to edge -->
<bool name="config_edgeToEdgeBottomSheetDialog">false</bool>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 60fff282d041..9b45fa47cf21 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -483,22 +483,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@VisibleForTesting
SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
- private static int sCurrentUser;
-
- @Deprecated
- public synchronized static void setCurrentUser(int currentUser) {
- sCurrentUser = currentUser;
- }
-
- /**
- * @deprecated This can potentially return unexpected values in a multi user scenario
- * as this state is managed by another component. Consider using {@link SelectedUserInteractor}.
- */
- @Deprecated
- public synchronized static int getCurrentUser() {
- return sCurrentUser;
- }
-
@Override
public void onTrustChanged(boolean enabled, boolean newlyUnlocked, int userId, int flags,
List<String> trustGrantedMessages) {
@@ -969,7 +953,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mHandler.removeCallbacks(mFpCancelNotReceived);
}
try {
- final int userId = mSelectedUserInteractor.getSelectedUserId(true);
+ final int userId = mSelectedUserInteractor.getSelectedUserId();
if (userId != authUserId) {
mLogger.logFingerprintAuthForWrongUser(authUserId);
return;
@@ -1220,7 +1204,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLogger.d("Aborted successful auth because device is going to sleep.");
return;
}
- final int userId = mSelectedUserInteractor.getSelectedUserId(true);
+ final int userId = mSelectedUserInteractor.getSelectedUserId();
if (userId != authUserId) {
mLogger.logFaceAuthForWrongUser(authUserId);
return;
@@ -2462,7 +2446,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
mTaskStackChangeListeners.registerTaskStackListener(mTaskStackListener);
- int user = mSelectedUserInteractor.getSelectedUserId(true);
+ int user = mSelectedUserInteractor.getSelectedUserId();
boolean isUserUnlocked = mUserManager.isUserUnlocked(user);
mLogger.logUserUnlockedInitialState(user, isUserUnlocked);
mUserIsUnlocked.put(user, isUserUnlocked);
@@ -4081,7 +4065,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
pw.println(" " + subId + "=" + mServiceStates.get(subId));
}
if (isFingerprintSupported()) {
- final int userId = mSelectedUserInteractor.getSelectedUserId(true);
+ final int userId = mSelectedUserInteractor.getSelectedUserId();
final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
pw.println(" Fingerprint state (user=" + userId + ")");
@@ -4124,7 +4108,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mFingerprintListenBuffer.toList()
).printTableData(pw);
} else if (mFpm != null && mFingerprintSensorProperties.isEmpty()) {
- final int userId = mSelectedUserInteractor.getSelectedUserId(true);
+ final int userId = mSelectedUserInteractor.getSelectedUserId();
pw.println(" Fingerprint state (user=" + userId + ")");
pw.println(" mFingerprintSensorProperties.isEmpty="
+ mFingerprintSensorProperties.isEmpty());
@@ -4137,7 +4121,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mFingerprintListenBuffer.toList()
).printTableData(pw);
}
- final int userId = mSelectedUserInteractor.getSelectedUserId(true);
+ final int userId = mSelectedUserInteractor.getSelectedUserId();
final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
pw.println(" authSinceBoot="
+ getStrongAuthTracker().hasUserAuthenticatedSinceBoot());
diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
index 6757edba8ac3..b2d02edf3c45 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
@@ -120,7 +120,7 @@ constructor(
Intent.FLAG_ACTIVITY_NEW_TASK,
null,
activityOptions.toBundle(),
- selectedUserInteractor.getSelectedUserId(true),
+ selectedUserInteractor.getSelectedUserId(),
)
} catch (e: RemoteException) {
Log.w("CameraGestureHelper", "Unable to start camera activity", e)
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index e07b5c228585..21922ff22afe 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -256,7 +256,7 @@ public class DozeSensors {
Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
mConfig.wakeScreenGestureAvailable()
&& mConfig.alwaysOnEnabled(
- mSelectedUserInteractor.getSelectedUserId(true)),
+ mSelectedUserInteractor.getSelectedUserId()),
DozeLog.REASON_SENSOR_WAKE_UP_PRESENCE,
false /* reports touch coordinates */,
false /* touchscreen */
@@ -297,7 +297,7 @@ public class DozeSensors {
private boolean udfpsLongPressConfigured() {
return mUdfpsEnrolled
- && (mConfig.alwaysOnEnabled(mSelectedUserInteractor.getSelectedUserId(true))
+ && (mConfig.alwaysOnEnabled(mSelectedUserInteractor.getSelectedUserId())
|| mScreenOffUdfpsEnabled);
}
@@ -477,7 +477,7 @@ public class DozeSensors {
private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
- if (userId != mSelectedUserInteractor.getSelectedUserId(true)) {
+ if (userId != mSelectedUserInteractor.getSelectedUserId()) {
return;
}
for (TriggerSensor s : mTriggerSensors) {
@@ -703,13 +703,13 @@ public class DozeSensors {
}
protected boolean enabledBySetting() {
- if (!mConfig.enabled(mSelectedUserInteractor.getSelectedUserId(true))) {
+ if (!mConfig.enabled(mSelectedUserInteractor.getSelectedUserId())) {
return false;
} else if (TextUtils.isEmpty(mSetting)) {
return true;
}
return mSecureSettings.getIntForUser(mSetting, mSettingDefault ? 1 : 0,
- mSelectedUserInteractor.getSelectedUserId(true)) != 0;
+ mSelectedUserInteractor.getSelectedUserId()) != 0;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 4a9f741494f4..dd08d3262546 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -251,7 +251,7 @@ public class DozeTriggers implements DozeMachine.Part {
return;
}
mNotificationPulseTime = SystemClock.elapsedRealtime();
- if (!mConfig.pulseOnNotificationEnabled(mSelectedUserInteractor.getSelectedUserId(true))) {
+ if (!mConfig.pulseOnNotificationEnabled(mSelectedUserInteractor.getSelectedUserId())) {
runIfNotNull(onPulseSuppressedListener);
mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled");
return;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 4d75d661de49..bb73f569d945 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -55,19 +55,13 @@ object Flags {
// TODO(b/254512624): Tracking Bug
@JvmField
val NOTIFICATION_DRAG_TO_CONTENTS =
- resourceBooleanFlag(
- R.bool.config_notificationToContents,
- "notification_drag_to_contents"
- )
+ resourceBooleanFlag(R.bool.config_notificationToContents, "notification_drag_to_contents")
// TODO(b/280783617): Tracking Bug
@Keep
@JvmField
val BUILDER_EXTRAS_OVERRIDE =
- sysPropBooleanFlag(
- "persist.sysui.notification.builder_extras_override",
- default = true
- )
+ sysPropBooleanFlag("persist.sysui.notification.builder_extras_override", default = true)
// 200 - keyguard/lockscreen
// ** Flag retired **
@@ -81,10 +75,7 @@ object Flags {
// TODO(b/254512676): Tracking Bug
@JvmField
val LOCKSCREEN_CUSTOM_CLOCKS =
- resourceBooleanFlag(
- R.bool.config_enableLockScreenCustomClocks,
- "lockscreen_custom_clocks"
- )
+ resourceBooleanFlag(R.bool.config_enableLockScreenCustomClocks, "lockscreen_custom_clocks")
/**
* Whether the clock on a wide lock screen should use the new "stepping" animation for moving
@@ -99,10 +90,6 @@ object Flags {
// TODO(b/255607168): Tracking Bug
@JvmField val DOZING_MIGRATION_1 = unreleasedFlag("dozing_migration_1")
- // TODO(b/305984787):
- @JvmField
- val REFACTOR_GETCURRENTUSER = unreleasedFlag("refactor_getcurrentuser", teamfood = true)
-
/** Flag to control the revamp of keyguard biometrics progress animation */
// TODO(b/244313043): Tracking bug
@JvmField val BIOMETRICS_ANIMATION_REVAMP = unreleasedFlag("biometrics_animation_revamp")
@@ -125,13 +112,11 @@ object Flags {
/** Whether the long-press gesture to open wallpaper picker is enabled. */
// TODO(b/266242192): Tracking Bug
- @JvmField
- val LOCK_SCREEN_LONG_PRESS_ENABLED = releasedFlag("lock_screen_long_press_enabled")
+ @JvmField val LOCK_SCREEN_LONG_PRESS_ENABLED = releasedFlag("lock_screen_long_press_enabled")
/** Inflate and bind views upon emitting a blueprint value . */
// TODO(b/297365780): Tracking Bug
- @JvmField
- val LAZY_INFLATE_KEYGUARD = releasedFlag("lazy_inflate_keyguard")
+ @JvmField val LAZY_INFLATE_KEYGUARD = releasedFlag("lazy_inflate_keyguard")
/** Enables UI updates for AI wallpapers in the wallpaper picker. */
// TODO(b/267722622): Tracking Bug
@@ -145,8 +130,7 @@ object Flags {
/** Add "Apply" button to wall paper picker's grid preview page. */
// TODO(b/294866904): Tracking bug.
@JvmField
- val WALLPAPER_PICKER_GRID_APPLY_BUTTON =
- unreleasedFlag("wallpaper_picker_grid_apply_button")
+ val WALLPAPER_PICKER_GRID_APPLY_BUTTON = unreleasedFlag("wallpaper_picker_grid_apply_button")
/** Flag meant to guard the talkback fix for the KeyguardIndicationTextView */
// TODO(b/286563884): Tracking bug
@@ -190,10 +174,7 @@ object Flags {
// TODO(b/254512383): Tracking Bug
@JvmField
val FULL_SCREEN_USER_SWITCHER =
- resourceBooleanFlag(
- R.bool.config_enableFullscreenUserSwitcher,
- "full_screen_user_switcher"
- )
+ resourceBooleanFlag(R.bool.config_enableFullscreenUserSwitcher, "full_screen_user_switcher")
// TODO(b/244064524): Tracking Bug
@JvmField val QS_SECONDARY_DATA_SUB_INFO = releasedFlag("qs_secondary_data_sub_info")
@@ -212,16 +193,15 @@ object Flags {
@JvmField val NEW_NETWORK_SLICE_UI = releasedFlag("new_network_slice_ui")
// TODO(b/311222557): Tracking bug
- val ROAMING_INDICATOR_VIA_DISPLAY_INFO =
- releasedFlag("roaming_indicator_via_display_info")
+ val ROAMING_INDICATOR_VIA_DISPLAY_INFO = releasedFlag("roaming_indicator_via_display_info")
// TODO(b/308138154): Tracking bug
val FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS =
releasedFlag("filter_provisioning_network_subscriptions")
// TODO(b/293863612): Tracking Bug
- @JvmField val INCOMPATIBLE_CHARGING_BATTERY_ICON =
- releasedFlag("incompatible_charging_battery_icon")
+ @JvmField
+ val INCOMPATIBLE_CHARGING_BATTERY_ICON = releasedFlag("incompatible_charging_battery_icon")
// TODO(b/293585143): Tracking Bug
val INSTANT_TETHER = releasedFlag("instant_tether")
@@ -230,8 +210,7 @@ object Flags {
val WIFI_SECONDARY_NETWORKS = releasedFlag("wifi_secondary_networks")
// TODO(b/290676905): Tracking Bug
- val NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS =
- releasedFlag("new_shade_carrier_group_mobile_icons")
+ val NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS = releasedFlag("new_shade_carrier_group_mobile_icons")
// 800 - general visual/theme
@JvmField val MONET = resourceBooleanFlag(R.bool.flag_monet, "monet")
@@ -280,8 +259,7 @@ object Flags {
// TODO(b/273509374): Tracking Bug
@JvmField
- val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS =
- releasedFlag("always_show_home_controls_on_dreams")
+ val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS = releasedFlag("always_show_home_controls_on_dreams")
// 1100 - windowing
@Keep
@@ -304,9 +282,7 @@ object Flags {
)
// TODO(b/293252410) : Tracking Bug
- @JvmField
- val LOCKSCREEN_ENABLE_LANDSCAPE =
- unreleasedFlag("lockscreen.enable_landscape")
+ @JvmField val LOCKSCREEN_ENABLE_LANDSCAPE = unreleasedFlag("lockscreen.enable_landscape")
// 1200 - predictive back
@Keep
@@ -327,8 +303,7 @@ object Flags {
val QUICK_TAP_IN_PCC = releasedFlag("quick_tap_in_pcc")
// TODO(b/261979569): Tracking Bug
- val QUICK_TAP_FLOW_FRAMEWORK =
- unreleasedFlag("quick_tap_flow_framework", teamfood = false)
+ val QUICK_TAP_FLOW_FRAMEWORK = unreleasedFlag("quick_tap_flow_framework", teamfood = false)
// 1500 - chooser aka sharesheet
@@ -364,14 +339,12 @@ object Flags {
// TODO(b/265764985): Tracking Bug
@Keep
@JvmField
- val ENABLE_DARK_VIGNETTE_WHEN_FOLDING =
- unreleasedFlag("enable_dark_vignette_when_folding")
+ val ENABLE_DARK_VIGNETTE_WHEN_FOLDING = unreleasedFlag("enable_dark_vignette_when_folding")
// TODO(b/265764985): Tracking Bug
@Keep
@JvmField
- val ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS =
- unreleasedFlag("enable_unfold_status_bar_animations")
+ val ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS = unreleasedFlag("enable_unfold_status_bar_animations")
// TODO(b/316157842): Tracking Bug
// Adds extra delay to notifications measure
@@ -415,28 +388,26 @@ object Flags {
unreleasedFlag("bigpicture_notification_lazy_loading")
// TODO(b/283740863): Tracking Bug
- @JvmField
- val ENABLE_NEW_PRIVACY_DIALOG = releasedFlag("enable_new_privacy_dialog")
+ @JvmField val ENABLE_NEW_PRIVACY_DIALOG = releasedFlag("enable_new_privacy_dialog")
// TODO(b/302144438): Tracking Bug
- @JvmField val DECOUPLE_REMOTE_INPUT_DELEGATE_AND_CALLBACK_UPDATE =
- unreleasedFlag("decouple_remote_input_delegate_and_callback_update")
+ @JvmField
+ val DECOUPLE_REMOTE_INPUT_DELEGATE_AND_CALLBACK_UPDATE =
+ unreleasedFlag("decouple_remote_input_delegate_and_callback_update")
/** TODO(b/296223317): Enables the new keyguard presentation containing a clock. */
@JvmField
val ENABLE_CLOCK_KEYGUARD_PRESENTATION = releasedFlag("enable_clock_keyguard_presentation")
/** Enable the share wifi button in Quick Settings internet dialog. */
- @JvmField
- val SHARE_WIFI_QS_BUTTON = releasedFlag("share_wifi_qs_button")
+ @JvmField val SHARE_WIFI_QS_BUTTON = releasedFlag("share_wifi_qs_button")
/** Enable showing a dialog when clicking on Quick Settings bluetooth tile. */
- @JvmField
- val BLUETOOTH_QS_TILE_DIALOG = releasedFlag("bluetooth_qs_tile_dialog")
+ @JvmField val BLUETOOTH_QS_TILE_DIALOG = releasedFlag("bluetooth_qs_tile_dialog")
// TODO(b/300995746): Tracking Bug
/** A resource flag for whether the communal service is enabled. */
@JvmField
- val COMMUNAL_SERVICE_ENABLED = resourceBooleanFlag(R.bool.config_communalServiceEnabled,
- "communal_service_enabled")
+ val COMMUNAL_SERVICE_ENABLED =
+ resourceBooleanFlag(R.bool.config_communalServiceEnabled, "communal_service_enabled")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index fe3a1e447b07..0feb5ec277b4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -35,8 +35,6 @@ import static android.view.WindowManager.TransitionFlags;
import static android.view.WindowManager.TransitionOldType;
import static android.view.WindowManager.TransitionType;
-import static com.android.systemui.Flags.refactorGetCurrentUser;
-
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -680,9 +678,6 @@ public class KeyguardService extends Service {
public void setCurrentUser(int userId) {
trace("Deprecated/NOT USED: setCurrentUser userId=" + userId);
checkPermission();
- if (!refactorGetCurrentUser()) {
- mKeyguardViewMediator.setCurrentUser(userId);
- }
}
@Override // Binder interface
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 17c5977fc80a..8c82900810be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -41,7 +41,6 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
-import static com.android.systemui.Flags.refactorGetCurrentUser;
import static com.android.systemui.Flags.relockWithPowerButtonImmediately;
import static com.android.systemui.Flags.translucentOccludingActivityFix;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
@@ -626,11 +625,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
@Override
public void onUserSwitching(int userId) {
- if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId));
+ Log.d(TAG, String.format("onUserSwitching %d", userId));
synchronized (KeyguardViewMediator.this) {
- if (refactorGetCurrentUser()) {
- notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
- }
+ notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
resetKeyguardDonePendingLocked();
dismiss(null /* callback */, null /* message */);
adjustStatusBarLocked();
@@ -639,7 +636,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
@Override
public void onUserSwitchComplete(int userId) {
- if (DEBUG) Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
+ Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
// We are calling dismiss again and with a delay as there are race conditions
// in some scenarios caused by async layout listeners
mHandler.postDelayed(() -> dismiss(null /* callback */, null /* message */), 500);
@@ -1580,10 +1577,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- if (!refactorGetCurrentUser()) {
- KeyguardUpdateMonitor.setCurrentUser(mUserTracker.getUserId());
- }
-
// Assume keyguard is showing (unless it's disabled) until we know for sure, unless Keyguard
// is disabled.
if (isKeyguardServiceEnabled()) {
@@ -2546,19 +2539,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
/**
- * Update the newUserId. Call while holding WindowManagerService lock.
- * NOTE: Should only be called by KeyguardViewMediator in response to the user id changing.
- *
- * @param newUserId The id of the incoming user.
- */
- public void setCurrentUser(int newUserId) {
- KeyguardUpdateMonitor.setCurrentUser(newUserId);
- synchronized (this) {
- notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(newUserId));
- }
- }
-
- /**
* This broadcast receiver should be registered with the SystemUI permission.
*/
private final BroadcastReceiver mDelayedLockBroadcastReceiver = new BroadcastReceiver() {
@@ -3553,7 +3533,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
try {
mStatusBarService.disableForUser(flags, mStatusBarDisableToken,
mContext.getPackageName(),
- mSelectedUserInteractor.getSelectedUserId(true));
+ mSelectedUserInteractor.getSelectedUserId());
} catch (RemoteException e) {
Log.d(TAG, "Failed to force clear flags", e);
}
@@ -3591,7 +3571,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
try {
mStatusBarService.disableForUser(flags, mStatusBarDisableToken,
mContext.getPackageName(),
- mSelectedUserInteractor.getSelectedUserId(true));
+ mSelectedUserInteractor.getSelectedUserId());
} catch (RemoteException e) {
Log.d(TAG, "Failed to set disable flags: " + flags, e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index 31b0bf7fe425..d9c48fa7e581 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -28,6 +28,7 @@ constructor(
private val interactors: Set<TransitionInteractor>,
private val auditLogger: KeyguardTransitionAuditLogger,
private val bootInteractor: KeyguardTransitionBootInteractor,
+ private val statusBarDisableFlagsInteractor: StatusBarDisableFlagsInteractor,
) : CoreStartable {
override fun start() {
@@ -53,6 +54,7 @@ constructor(
}
auditLogger.start()
bootInteractor.start()
+ statusBarDisableFlagsInteractor.start()
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
new file mode 100644
index 000000000000..47818cbfd2f2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StatusBarDisableFlagsInteractor.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.annotation.SuppressLint
+import android.app.StatusBarManager
+import android.content.Context
+import android.os.Binder
+import android.os.IBinder
+import android.os.RemoteException
+import android.provider.DeviceConfig
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
+import com.android.internal.statusbar.IStatusBarService
+import com.android.systemui.CoreStartable
+import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
+import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.deviceconfig.domain.interactor.DeviceConfigInteractor
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
+import com.android.systemui.keyguard.KeyguardWmStateRefactor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.navigation.domain.interactor.NavigationInteractor
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessModel
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+/**
+ * Logic around StatusBarService#disableForUser, which is used to disable the home and recents
+ * button in certain device states.
+ *
+ * TODO(b/362313975): Remove post-Flexiglass, this duplicates StatusBarStartable logic.
+ */
+@SysUISingleton
+class StatusBarDisableFlagsInteractor
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+ @Application private val applicationContext: Context,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
+ private val statusBarService: IStatusBarService,
+ keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ selectedUserInteractor: SelectedUserInteractor,
+ deviceConfigInteractor: DeviceConfigInteractor,
+ navigationInteractor: NavigationInteractor,
+ authenticationInteractor: AuthenticationInteractor,
+ powerInteractor: PowerInteractor,
+) : CoreStartable {
+
+ private val disableToken: IBinder = Binder()
+
+ private val disableFlagsForUserId =
+ combine(
+ selectedUserInteractor.selectedUser,
+ keyguardTransitionInteractor.startedKeyguardState,
+ deviceConfigInteractor.property(
+ namespace = DeviceConfig.NAMESPACE_SYSTEMUI,
+ name = SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN,
+ default = true,
+ ),
+ navigationInteractor.isGesturalMode,
+ authenticationInteractor.authenticationMethod,
+ powerInteractor.detailedWakefulness,
+ ) { values ->
+ val selectedUserId = values[0] as Int
+ val startedState = values[1] as KeyguardState
+ val isShowHomeOverLockscreen = values[2] as Boolean
+ val isGesturalMode = values[3] as Boolean
+ val authenticationMethod = values[4] as AuthenticationMethodModel
+ val wakefulnessModel = values[5] as WakefulnessModel
+ val isOccluded = startedState == KeyguardState.OCCLUDED
+
+ val hideHomeAndRecentsForBouncer =
+ startedState == KeyguardState.PRIMARY_BOUNCER ||
+ startedState == KeyguardState.ALTERNATE_BOUNCER
+ val isKeyguardShowing = startedState != KeyguardState.GONE
+ val isPowerGestureIntercepted =
+ with(wakefulnessModel) {
+ isAwake() &&
+ powerButtonLaunchGestureTriggered &&
+ lastSleepReason == WakeSleepReason.POWER_BUTTON
+ }
+
+ var flags = StatusBarManager.DISABLE_NONE
+
+ if (hideHomeAndRecentsForBouncer || (isKeyguardShowing && !isOccluded)) {
+ if (!isShowHomeOverLockscreen || !isGesturalMode) {
+ flags = flags or StatusBarManager.DISABLE_HOME
+ }
+ flags = flags or StatusBarManager.DISABLE_RECENT
+ }
+
+ if (
+ isPowerGestureIntercepted &&
+ isOccluded &&
+ authenticationMethod.isSecure &&
+ deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
+ ) {
+ flags = flags or StatusBarManager.DISABLE_RECENT
+ }
+
+ selectedUserId to flags
+ }
+ .distinctUntilChanged()
+
+ @SuppressLint("WrongConstant", "NonInjectedService")
+ override fun start() {
+ if (!KeyguardWmStateRefactor.isEnabled) {
+ return
+ }
+
+ scope.launch {
+ disableFlagsForUserId.collect { (selectedUserId, flags) ->
+ if (applicationContext.getSystemService(Context.STATUS_BAR_SERVICE) == null) {
+ return@collect
+ }
+
+ withContext(backgroundDispatcher) {
+ try {
+ statusBarService.disableForUser(
+ flags,
+ disableToken,
+ applicationContext.packageName,
+ selectedUserId,
+ )
+ } catch (e: RemoteException) {
+ e.printStackTrace()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 7c2d50c9a3a3..9abc494e56e6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -71,6 +71,7 @@ import com.android.systemui.qs.SideLabelTileLayout;
import com.android.systemui.qs.logging.QSLogger;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* Base quick-settings tile, extend this to create a new tile.
@@ -668,6 +669,18 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
public String toString() {
return "DrawableIcon";
}
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ // No need to compare equality of the mInvisibleDrawable as that's generated from
+ // mDrawable's constant state.
+ return other instanceof DrawableIcon && ((DrawableIcon) other).mDrawable == mDrawable;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDrawable);
+ }
}
public static class DrawableIconWithRes extends DrawableIcon {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a37a722e13e0..fe5cbb18f046 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -230,7 +230,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// If scene framework is enabled, set the scene container window to
// visible and let the touch "slip" into that window.
if (SceneContainerFlag.isEnabled()) {
- mSceneInteractor.get().onRemoteUserInteractionStarted("launcher swipe");
+ mSceneInteractor.get().onRemoteUserInputStarted("launcher swipe");
} else {
mShadeViewControllerLazy.get().startInputFocusTransfer();
}
@@ -266,7 +266,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
if (SceneContainerFlag.isEnabled()) {
int action = event.getActionMasked();
if (action == ACTION_DOWN) {
- mSceneInteractor.get().onRemoteUserInteractionStarted(
+ mSceneInteractor.get().onRemoteUserInputStarted(
"trackpad swipe");
} else if (action == ACTION_UP) {
mSceneInteractor.get().changeScene(
diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
index 3e2c6306467f..beb6816d70a9 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt
@@ -56,7 +56,10 @@ constructor(
*
* For more information see the logic in `SceneInteractor` that mutates this.
*/
- val isRemoteUserInteractionOngoing = MutableStateFlow(false)
+ val isRemoteUserInputOngoing = MutableStateFlow(false)
+
+ /** Whether there's ongoing user input on the scene container Composable hierarchy */
+ val isSceneContainerUserInputOngoing = MutableStateFlow(false)
private val defaultTransitionState = ObservableTransitionState.Idle(config.initialSceneKey)
private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 1b9c346129c6..4c404e29018d 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -148,11 +148,11 @@ constructor(
val isVisible: StateFlow<Boolean> =
combine(
repository.isVisible,
- repository.isRemoteUserInteractionOngoing,
+ repository.isRemoteUserInputOngoing,
) { isVisible, isRemoteUserInteractionOngoing ->
isVisibleInternal(
raw = isVisible,
- isRemoteUserInteractionOngoing = isRemoteUserInteractionOngoing,
+ isRemoteUserInputOngoing = isRemoteUserInteractionOngoing,
)
}
.stateIn(
@@ -162,8 +162,13 @@ constructor(
)
/** Whether there's an ongoing remotely-initiated user interaction. */
- val isRemoteUserInteractionOngoing: StateFlow<Boolean> =
- repository.isRemoteUserInteractionOngoing
+ val isRemoteUserInteractionOngoing: StateFlow<Boolean> = repository.isRemoteUserInputOngoing
+
+ /**
+ * Whether there's an ongoing user interaction started in the scene container Compose hierarchy.
+ */
+ val isSceneContainerUserInputOngoing: StateFlow<Boolean> =
+ repository.isSceneContainerUserInputOngoing
/**
* The amount of transition into or out of the given [scene].
@@ -284,7 +289,7 @@ constructor(
* Please do not call this from outside of the scene framework. If you are trying to force the
* visibility to visible or invisible, prefer making changes to the existing caller of this
* method or to upstream state used to calculate [isVisible]; for an example of the latter,
- * please see [onRemoteUserInteractionStarted] and [onUserInteractionFinished].
+ * please see [onRemoteUserInputStarted] and [onUserInputFinished].
*/
fun setVisible(isVisible: Boolean, loggingReason: String) {
val wasVisible = repository.isVisible.value
@@ -301,6 +306,16 @@ constructor(
}
/**
+ * Notifies that a scene container user interaction has begun.
+ *
+ * This is a user interaction that originates within the Composable hierarchy of the scene
+ * container.
+ */
+ fun onSceneContainerUserInputStarted() {
+ repository.isSceneContainerUserInputOngoing.value = true
+ }
+
+ /**
* Notifies that a remote user interaction has begun.
*
* This is a user interaction that originates outside of the UI of the scene container and
@@ -311,18 +326,19 @@ constructor(
* then rerouted by window manager to System UI. While the user interaction definitely continues
* within the System UI process and code, it also originates remotely.
*/
- fun onRemoteUserInteractionStarted(loggingReason: String) {
- logger.logRemoteUserInteractionStarted(loggingReason)
- repository.isRemoteUserInteractionOngoing.value = true
+ fun onRemoteUserInputStarted(loggingReason: String) {
+ logger.logRemoteUserInputStarted(loggingReason)
+ repository.isRemoteUserInputOngoing.value = true
}
/**
* Notifies that the current user interaction (internally or remotely started, see
- * [onRemoteUserInteractionStarted]) has finished.
+ * [onSceneContainerUserInputStarted] and [onRemoteUserInputStarted]) has finished.
*/
- fun onUserInteractionFinished() {
- logger.logUserInteractionFinished()
- repository.isRemoteUserInteractionOngoing.value = false
+ fun onUserInputFinished() {
+ logger.logUserInputFinished()
+ repository.isSceneContainerUserInputOngoing.value = false
+ repository.isRemoteUserInputOngoing.value = false
}
/**
@@ -351,9 +367,9 @@ constructor(
private fun isVisibleInternal(
raw: Boolean = repository.isVisible.value,
- isRemoteUserInteractionOngoing: Boolean = repository.isRemoteUserInteractionOngoing.value,
+ isRemoteUserInputOngoing: Boolean = repository.isRemoteUserInputOngoing.value,
): Boolean {
- return raw || isRemoteUserInteractionOngoing
+ return raw || isRemoteUserInputOngoing
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/StatusBarStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/StatusBarStartable.kt
index 893f030fab4d..d7413687eeae 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/StatusBarStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/StatusBarStartable.kt
@@ -166,7 +166,7 @@ constructor(
StatusBarManager.DISABLE_NONE,
disableToken,
applicationContext.packageName,
- selectedUserInteractor.getSelectedUserId(true),
+ selectedUserInteractor.getSelectedUserId(),
)
} catch (e: RemoteException) {
Log.d(TAG, "Failed to clear flags", e)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
index 94c94e22a10b..045a8879f572 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt
@@ -115,7 +115,7 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
)
}
- fun logRemoteUserInteractionStarted(
+ fun logRemoteUserInputStarted(
reason: String,
) {
logBuffer.log(
@@ -126,7 +126,7 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer:
)
}
- fun logUserInteractionFinished() {
+ fun logUserInputFinished() {
logBuffer.log(
tag = TAG,
level = LogLevel.INFO,
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index 9dfb7450fd3f..8b4b77f83218 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -31,6 +31,7 @@ import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.logger.SceneLogger
import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -97,7 +98,9 @@ constructor(
}
/**
- * Notifies that a [MotionEvent] is first seen at the top of the scene container UI.
+ * Notifies that a [MotionEvent] is first seen at the top of the scene container UI. This
+ * includes gestures on [SharedNotificationContainer] as well as the Composable scene container
+ * hierarchy.
*
* Call this before the [MotionEvent] starts to propagate through the UI hierarchy.
*/
@@ -108,11 +111,21 @@ constructor(
event.actionMasked == MotionEvent.ACTION_UP ||
event.actionMasked == MotionEvent.ACTION_CANCEL
) {
- sceneInteractor.onUserInteractionFinished()
+ sceneInteractor.onUserInputFinished()
}
}
/**
+ * Notifies that a scene container user interaction has begun.
+ *
+ * This is a user interaction that has reached the Composable hierarchy of the scene container,
+ * rather than being handled by [SharedNotificationContainer].
+ */
+ fun onSceneContainerUserInputStarted() {
+ sceneInteractor.onSceneContainerUserInputStarted()
+ }
+
+ /**
* Notifies that a [MotionEvent] that was previously sent to [onMotionEvent] has passed through
* the scene container UI.
*
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 0a1f649691a1..ed590c37c384 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -36,6 +36,13 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.util.Assert
+import java.io.PrintWriter
+import java.lang.ref.WeakReference
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.Executor
+import javax.inject.Provider
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.KProperty
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@@ -44,30 +51,23 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
-import java.io.PrintWriter
-import java.lang.ref.WeakReference
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.Executor
-import javax.inject.Provider
-import kotlin.properties.ReadWriteProperty
-import kotlin.reflect.KProperty
/**
* SystemUI cache for keeping track of the current user and associated values.
*
- * The values provided asynchronously are NOT copies, but shared among all requesters. Do not
- * modify them.
+ * The values provided asynchronously are NOT copies, but shared among all requesters. Do not modify
+ * them.
*
* This class purposefully doesn't use [BroadcastDispatcher] in order to receive the broadcast as
- * soon as possible (and reduce its dependency graph).
- * Other classes that want to listen to the broadcasts listened here SHOULD
- * subscribe to this class instead.
+ * soon as possible (and reduce its dependency graph). Other classes that want to listen to the
+ * broadcasts listened here SHOULD subscribe to this class instead.
*
* @see UserTracker
*
* Class constructed and initialized in [SettingsModule].
*/
-open class UserTrackerImpl internal constructor(
+open class UserTrackerImpl
+internal constructor(
private val context: Context,
private val featureFlagsProvider: Provider<FeatureFlagsClassic>,
private val userManager: UserManager,
@@ -87,8 +87,8 @@ open class UserTrackerImpl internal constructor(
private set
private val mutex = Any()
- private val isBackgroundUserSwitchEnabled: Boolean get() =
- featureFlagsProvider.get().isEnabled(Flags.USER_TRACKER_BACKGROUND_CALLBACKS)
+ private val isBackgroundUserSwitchEnabled: Boolean
+ get() = featureFlagsProvider.get().isEnabled(Flags.USER_TRACKER_BACKGROUND_CALLBACKS)
@Deprecated("Use UserInteractor.getSelectedUserId()")
override var userId: Int by SynchronizedDelegate(context.userId)
@@ -118,8 +118,7 @@ open class UserTrackerImpl internal constructor(
override var userProfiles: List<UserInfo> by SynchronizedDelegate(emptyList())
protected set
- @GuardedBy("callbacks")
- private val callbacks: MutableList<DataItem> = ArrayList()
+ @GuardedBy("callbacks") private val callbacks: MutableList<DataItem> = ArrayList()
private var userSwitchingJob: Job? = null
private var afterUserSwitchingJob: Job? = null
@@ -128,23 +127,25 @@ open class UserTrackerImpl internal constructor(
if (initialized) {
return
}
+ Log.i(TAG, "Starting user: $startingUser")
initialized = true
setUserIdInternal(startingUser)
- val filter = IntentFilter().apply {
- addAction(Intent.ACTION_LOCALE_CHANGED)
- addAction(Intent.ACTION_USER_INFO_CHANGED)
- addAction(Intent.ACTION_PROFILE_ADDED)
- addAction(Intent.ACTION_PROFILE_REMOVED)
- addAction(Intent.ACTION_PROFILE_AVAILABLE)
- addAction(Intent.ACTION_PROFILE_UNAVAILABLE)
- // These get called when a managed profile goes in or out of quiet mode.
- addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
- addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
- addAction(Intent.ACTION_MANAGED_PROFILE_ADDED)
- addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)
- addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)
- }
+ val filter =
+ IntentFilter().apply {
+ addAction(Intent.ACTION_LOCALE_CHANGED)
+ addAction(Intent.ACTION_USER_INFO_CHANGED)
+ addAction(Intent.ACTION_PROFILE_ADDED)
+ addAction(Intent.ACTION_PROFILE_REMOVED)
+ addAction(Intent.ACTION_PROFILE_AVAILABLE)
+ addAction(Intent.ACTION_PROFILE_UNAVAILABLE)
+ // These get called when a managed profile goes in or out of quiet mode.
+ addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
+ addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
+ addAction(Intent.ACTION_MANAGED_PROFILE_ADDED)
+ addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED)
+ addAction(Intent.ACTION_MANAGED_PROFILE_UNLOCKED)
+ }
context.registerReceiverForAllUsers(this, filter, null, backgroundHandler)
registerUserSwitchObserver()
@@ -191,36 +192,39 @@ open class UserTrackerImpl internal constructor(
}
private fun registerUserSwitchObserver() {
- iActivityManager.registerUserSwitchObserver(object : UserSwitchObserver() {
- override fun onBeforeUserSwitching(newUserId: Int) {
- handleBeforeUserSwitching(newUserId)
- }
+ iActivityManager.registerUserSwitchObserver(
+ object : UserSwitchObserver() {
+ override fun onBeforeUserSwitching(newUserId: Int) {
+ handleBeforeUserSwitching(newUserId)
+ }
- override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
- if (isBackgroundUserSwitchEnabled) {
- userSwitchingJob?.cancel()
- userSwitchingJob = appScope.launch(backgroundContext) {
- handleUserSwitchingCoroutines(newUserId) {
- reply?.sendResult(null)
- }
+ override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
+ if (isBackgroundUserSwitchEnabled) {
+ userSwitchingJob?.cancel()
+ userSwitchingJob =
+ appScope.launch(backgroundContext) {
+ handleUserSwitchingCoroutines(newUserId) { reply?.sendResult(null) }
+ }
+ } else {
+ handleUserSwitching(newUserId)
+ reply?.sendResult(null)
}
- } else {
- handleUserSwitching(newUserId)
- reply?.sendResult(null)
}
- }
- override fun onUserSwitchComplete(newUserId: Int) {
- if (isBackgroundUserSwitchEnabled) {
- afterUserSwitchingJob?.cancel()
- afterUserSwitchingJob = appScope.launch(backgroundContext) {
+ override fun onUserSwitchComplete(newUserId: Int) {
+ if (isBackgroundUserSwitchEnabled) {
+ afterUserSwitchingJob?.cancel()
+ afterUserSwitchingJob =
+ appScope.launch(backgroundContext) {
+ handleUserSwitchComplete(newUserId)
+ }
+ } else {
handleUserSwitchComplete(newUserId)
}
- } else {
- handleUserSwitchComplete(newUserId)
}
- }
- }, TAG)
+ },
+ TAG
+ )
}
@WorkerThread
@@ -228,9 +232,10 @@ open class UserTrackerImpl internal constructor(
setUserIdInternal(newUserId)
notifySubscribers { callback, resultCallback ->
- callback.onBeforeUserSwitching(newUserId)
- resultCallback.run()
- }.await()
+ callback.onBeforeUserSwitching(newUserId)
+ resultCallback.run()
+ }
+ .await()
}
@WorkerThread
@@ -239,31 +244,34 @@ open class UserTrackerImpl internal constructor(
Log.i(TAG, "Switching to user $newUserId")
notifySubscribers { callback, resultCallback ->
- callback.onUserChanging(newUserId, userContext, resultCallback)
- }.await()
+ callback.onUserChanging(newUserId, userContext, resultCallback)
+ }
+ .await()
}
@WorkerThread
protected open suspend fun handleUserSwitchingCoroutines(newUserId: Int, onDone: () -> Unit) =
- coroutineScope {
- Assert.isNotMainThread()
- Log.i(TAG, "Switching to user $newUserId")
+ coroutineScope {
+ Assert.isNotMainThread()
+ Log.i(TAG, "Switching to user $newUserId")
- for (callbackDataItem in synchronized(callbacks) { callbacks.toList() }) {
- val callback: UserTracker.Callback = callbackDataItem.callback.get() ?: continue
- launch(callbackDataItem.executor.asCoroutineDispatcher()) {
+ for (callbackDataItem in synchronized(callbacks) { callbacks.toList() }) {
+ val callback: UserTracker.Callback = callbackDataItem.callback.get() ?: continue
+ launch(callbackDataItem.executor.asCoroutineDispatcher()) {
val mutex = Mutex(true)
- val thresholdLogJob = launch(backgroundContext) {
- delay(USER_CHANGE_THRESHOLD)
- Log.e(TAG, "Failed to finish $callback in time")
- }
+ val thresholdLogJob =
+ launch(backgroundContext) {
+ delay(USER_CHANGE_THRESHOLD)
+ Log.e(TAG, "Failed to finish $callback in time")
+ }
callback.onUserChanging(userId, userContext) { mutex.unlock() }
mutex.lock()
thresholdLogJob.cancel()
- }.join()
- }
- onDone()
+ }
+ .join()
}
+ onDone()
+ }
@WorkerThread
protected open fun handleUserSwitchComplete(newUserId: Int) {
@@ -284,36 +292,26 @@ open class UserTrackerImpl internal constructor(
synchronized(mutex) {
userProfiles = profiles.map { UserInfo(it) } // save a "deep" copy
}
- notifySubscribers { callback, _ ->
- callback.onProfilesChanged(profiles)
- }
+ notifySubscribers { callback, _ -> callback.onProfilesChanged(profiles) }
}
override fun addCallback(callback: UserTracker.Callback, executor: Executor) {
- synchronized(callbacks) {
- callbacks.add(DataItem(WeakReference(callback), executor))
- }
+ synchronized(callbacks) { callbacks.add(DataItem(WeakReference(callback), executor)) }
}
override fun removeCallback(callback: UserTracker.Callback) {
- synchronized(callbacks) {
- callbacks.removeIf { it.sameOrEmpty(callback) }
- }
+ synchronized(callbacks) { callbacks.removeIf { it.sameOrEmpty(callback) } }
}
private inline fun notifySubscribers(
- crossinline action: (UserTracker.Callback, resultCallback: Runnable) -> Unit
+ crossinline action: (UserTracker.Callback, resultCallback: Runnable) -> Unit
): CountDownLatch {
- val list = synchronized(callbacks) {
- callbacks.toList()
- }
+ val list = synchronized(callbacks) { callbacks.toList() }
val latch = CountDownLatch(list.size)
list.forEach {
val callback = it.callback.get()
if (callback != null) {
- it.executor.execute {
- action(callback) { latch.countDown() }
- }
+ it.executor.execute { action(callback) { latch.countDown() } }
} else {
latch.countDown()
}
@@ -328,20 +326,13 @@ open class UserTrackerImpl internal constructor(
val ids = userProfiles.map { it.toFullString() }
pw.println("userProfiles: $ids")
}
- val list = synchronized(callbacks) {
- callbacks.toList()
- }
+ val list = synchronized(callbacks) { callbacks.toList() }
pw.println("Callbacks:")
- list.forEach {
- it.callback.get()?.let {
- pw.println(" $it")
- }
- }
+ list.forEach { it.callback.get()?.let { pw.println(" $it") } }
}
- private class SynchronizedDelegate<T : Any>(
- private var value: T
- ) : ReadWriteProperty<UserTrackerImpl, T> {
+ private class SynchronizedDelegate<T : Any>(private var value: T) :
+ ReadWriteProperty<UserTrackerImpl, T> {
@GuardedBy("mutex")
override fun getValue(thisRef: UserTrackerImpl, property: KProperty<*>): T {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt
index 2f9848863059..f270e821840a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/NotificationShadeWindowModel.kt
@@ -17,14 +17,15 @@
package com.android.systemui.shade.ui.viewmodel
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
+import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
-import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.util.kotlin.BooleanFlowOperators.any
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
/** Models UI state for the shade window. */
@SysUISingleton
@@ -32,11 +33,38 @@ class NotificationShadeWindowModel
@Inject
constructor(
keyguardTransitionInteractor: KeyguardTransitionInteractor,
- keyguardInteractor: KeyguardInteractor,
) {
+ /**
+ * Considered to be occluded if in OCCLUDED, DREAMING, GLANCEABLE_HUB/Communal, or transitioning
+ * between those states. Every permutation is listed so we can use optimal flows and support
+ * Scenes.
+ */
val isKeyguardOccluded: Flow<Boolean> =
- anyOf(
- keyguardTransitionInteractor.transitionValue(OCCLUDED).map { it == 1f },
- keyguardTransitionInteractor.transitionValue(DREAMING).map { it == 1f },
- )
+ listOf(
+ // Finished in state...
+ keyguardTransitionInteractor.isFinishedIn(OCCLUDED),
+ keyguardTransitionInteractor.isFinishedIn(DREAMING),
+ keyguardTransitionInteractor.isFinishedIn(Scenes.Communal, GLANCEABLE_HUB),
+
+ // ... or transitions between those states
+ keyguardTransitionInteractor.isInTransition(Edge.create(OCCLUDED, DREAMING)),
+ keyguardTransitionInteractor.isInTransition(Edge.create(DREAMING, OCCLUDED)),
+ keyguardTransitionInteractor.isInTransition(
+ edge = Edge.create(from = OCCLUDED, to = Scenes.Communal),
+ edgeWithoutSceneContainer = Edge.create(from = OCCLUDED, to = GLANCEABLE_HUB),
+ ),
+ keyguardTransitionInteractor.isInTransition(
+ edge = Edge.create(from = Scenes.Communal, to = OCCLUDED),
+ edgeWithoutSceneContainer = Edge.create(from = GLANCEABLE_HUB, to = OCCLUDED),
+ ),
+ keyguardTransitionInteractor.isInTransition(
+ edge = Edge.create(from = DREAMING, to = Scenes.Communal),
+ edgeWithoutSceneContainer = Edge.create(from = DREAMING, to = GLANCEABLE_HUB),
+ ),
+ keyguardTransitionInteractor.isInTransition(
+ edge = Edge.create(from = Scenes.Communal, to = DREAMING),
+ edgeWithoutSceneContainer = Edge.create(from = GLANCEABLE_HUB, to = DREAMING),
+ ),
+ )
+ .any()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index d0c51bc28126..bf00a39c42ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1255,6 +1255,11 @@ public class NotificationStackScrollLayout
}
@Override
+ public void closeGutsOnSceneTouch() {
+ mController.closeControlsDueToOutsideTouch();
+ }
+
+ @Override
public void setSyntheticScrollConsumer(@Nullable Consumer<Float> consumer) {
mScrollViewFields.setSyntheticScrollConsumer(consumer);
}
@@ -1265,6 +1270,11 @@ public class NotificationStackScrollLayout
}
@Override
+ public void setCurrentGestureInGutsConsumer(@Nullable Consumer<Boolean> consumer) {
+ mScrollViewFields.setCurrentGestureInGutsConsumer(consumer);
+ }
+
+ @Override
public void setHeadsUpHeightConsumer(@Nullable Consumer<Float> consumer) {
mScrollViewFields.setHeadsUpHeightConsumer(consumer);
}
@@ -3548,33 +3558,41 @@ public class NotificationStackScrollLayout
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
- if (SceneContainerFlag.isEnabled() && mIsBeingDragged) {
+ if (SceneContainerFlag.isEnabled()) {
int action = ev.getActionMasked();
- boolean isUpOrCancel = action == ACTION_UP || action == ACTION_CANCEL;
- if (mSendingTouchesToSceneFramework) {
- MotionEvent adjustedEvent = MotionEvent.obtain(ev);
- adjustedEvent.setLocation(ev.getRawX(), ev.getRawY());
- mController.sendTouchToSceneFramework(adjustedEvent);
- mScrollViewFields.sendCurrentGestureOverscroll(
- getExpandedInThisMotion() && !isUpOrCancel);
- adjustedEvent.recycle();
- } else if (!isUpOrCancel) {
- // if this is the first touch being sent to the scene framework,
- // convert it into a synthetic DOWN event.
- mSendingTouchesToSceneFramework = true;
- MotionEvent downEvent = MotionEvent.obtain(ev);
- downEvent.setAction(MotionEvent.ACTION_DOWN);
- downEvent.setLocation(ev.getRawX(), ev.getRawY());
- mController.sendTouchToSceneFramework(downEvent);
- mScrollViewFields.sendCurrentGestureOverscroll(getExpandedInThisMotion());
- downEvent.recycle();
- }
-
- if (isUpOrCancel) {
- mScrollViewFields.sendCurrentGestureOverscroll(false);
- setIsBeingDragged(false);
+ boolean isTouchInGuts = mController.isTouchInGutsView(ev);
+ if (action == MotionEvent.ACTION_DOWN && !isTouchInGuts) {
+ mController.closeControlsDueToOutsideTouch();
+ }
+ if (mIsBeingDragged) {
+ boolean isUpOrCancel = action == ACTION_UP || action == ACTION_CANCEL;
+ if (mSendingTouchesToSceneFramework) {
+ MotionEvent adjustedEvent = MotionEvent.obtain(ev);
+ adjustedEvent.setLocation(ev.getRawX(), ev.getRawY());
+ mScrollViewFields.sendCurrentGestureOverscroll(
+ getExpandedInThisMotion() && !isUpOrCancel);
+ mController.sendTouchToSceneFramework(adjustedEvent);
+ adjustedEvent.recycle();
+ } else if (!isUpOrCancel) {
+ // if this is the first touch being sent to the scene framework,
+ // convert it into a synthetic DOWN event.
+ mSendingTouchesToSceneFramework = true;
+ MotionEvent downEvent = MotionEvent.obtain(ev);
+ downEvent.setAction(MotionEvent.ACTION_DOWN);
+ downEvent.setLocation(ev.getRawX(), ev.getRawY());
+ mScrollViewFields.sendCurrentGestureInGuts(isTouchInGuts);
+ mScrollViewFields.sendCurrentGestureOverscroll(getExpandedInThisMotion());
+ mController.sendTouchToSceneFramework(downEvent);
+ downEvent.recycle();
+ }
+
+ if (isUpOrCancel) {
+ mScrollViewFields.sendCurrentGestureInGuts(false);
+ mScrollViewFields.sendCurrentGestureOverscroll(false);
+ setIsBeingDragged(false);
+ }
+ return false;
}
- return false;
}
return TouchLogger.logDispatchTouch(TAG, ev, super.dispatchTouchEvent(ev));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index c25b30db7754..4e73529b911d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1690,7 +1690,7 @@ public class NotificationStackScrollLayoutController implements Dumpable {
mVisibilityProvider.obtain(entry, true));
}
- public void closeControlsIfOutsideTouch(MotionEvent ev) {
+ private View getGutsView() {
NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
View translatingParentView = mSwipeHelper.getTranslatingParentView();
@@ -1703,15 +1703,35 @@ public class NotificationStackScrollLayoutController implements Dumpable {
// Checking menu
view = translatingParentView;
}
+ return view;
+ }
+
+ public void closeControlsIfOutsideTouch(MotionEvent ev) {
+ SceneContainerFlag.assertInLegacyMode();
+ View view = getGutsView();
if (view != null && !NotificationSwipeHelper.isTouchInView(ev, view)) {
// Touch was outside visible guts / menu notification, close what's visible
- mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
- false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
- false /* resetMenu */);
- mSwipeHelper.resetExposedMenuView(true /* animate */, true /* force */);
+ closeAndSaveGuts();
}
}
+ void closeControlsDueToOutsideTouch() {
+ if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
+ closeAndSaveGuts();
+ }
+
+ private void closeAndSaveGuts() {
+ mNotificationGutsManager.closeAndSaveGuts(false /* removeLeavebehind */,
+ false /* force */, true /* removeControls */, -1 /* x */, -1 /* y */,
+ false /* resetMenu */);
+ mSwipeHelper.resetExposedMenuView(true /* animate */, true /* force */);
+ }
+
+ boolean isTouchInGutsView(MotionEvent event) {
+ View view = getGutsView();
+ return NotificationSwipeHelper.isTouchInView(event, view);
+ }
+
public void clearSilentNotifications() {
FooterViewRefactor.assertInLegacyMode();
// Leave the shade open if there will be other notifs left over to clear
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
index 383d8b3b26b5..aa3953987c10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt
@@ -53,6 +53,11 @@ class ScrollViewFields {
*/
var currentGestureOverscrollConsumer: Consumer<Boolean>? = null
/**
+ * When a gesture is on open notification guts, which means scene container should not close the
+ * guts off of this gesture, we can notify the placeholder through here.
+ */
+ var currentGestureInGutsConsumer: Consumer<Boolean>? = null
+ /**
* Any time the heads up height is recalculated, it should be updated here to be used by the
* placeholder
*/
@@ -66,6 +71,10 @@ class ScrollViewFields {
fun sendCurrentGestureOverscroll(isCurrentGestureOverscroll: Boolean) =
currentGestureOverscrollConsumer?.accept(isCurrentGestureOverscroll)
+ /** send [isCurrentGestureInGuts] to the [currentGestureInGutsConsumer], if present. */
+ fun sendCurrentGestureInGuts(isCurrentGestureInGuts: Boolean) =
+ currentGestureInGutsConsumer?.accept(isCurrentGestureInGuts)
+
/** send the [headsUpHeight] to the [headsUpHeightConsumer], if present. */
fun sendHeadsUpHeight(headsUpHeight: Float) = headsUpHeightConsumer?.accept(headsUpHeight)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt
index f6d9351952f1..4907d444070d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt
@@ -39,4 +39,7 @@ class NotificationViewHeightRepository @Inject constructor() {
* consumed part of the gesture.
*/
val isCurrentGestureOverscroll = MutableStateFlow(false)
+
+ /** Whether the current touch gesture is on any open notification guts. */
+ val isCurrentGestureInGuts = MutableStateFlow(false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
index 8557afc6ebd3..756cd87970a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
@@ -18,6 +18,7 @@
package com.android.systemui.statusbar.notification.stack.domain.interactor
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
import com.android.systemui.statusbar.notification.stack.data.repository.NotificationPlaceholderRepository
@@ -39,6 +40,7 @@ class NotificationStackAppearanceInteractor
constructor(
private val viewHeightRepository: NotificationViewHeightRepository,
private val placeholderRepository: NotificationPlaceholderRepository,
+ sceneInteractor: SceneInteractor,
shadeInteractor: ShadeInteractor,
) {
/** The bounds of the notification stack in the current scene. */
@@ -93,6 +95,15 @@ constructor(
val isCurrentGestureOverscroll: Flow<Boolean> =
viewHeightRepository.isCurrentGestureOverscroll.asStateFlow()
+ /** Whether we should close any notification guts that are currently open. */
+ val shouldCloseGuts: Flow<Boolean> =
+ combine(
+ sceneInteractor.isSceneContainerUserInputOngoing,
+ viewHeightRepository.isCurrentGestureInGuts
+ ) { isUserInputOngoing, isCurrentGestureInGuts ->
+ isUserInputOngoing && !isCurrentGestureInGuts
+ }
+
/** Sets the alpha to apply to the NSSL for the brightness mirror */
fun setAlphaForBrightnessMirror(alpha: Float) {
placeholderRepository.alphaForBrightnessMirror.value = alpha
@@ -119,6 +130,10 @@ constructor(
viewHeightRepository.isCurrentGestureOverscroll.value = isOverscroll
}
+ fun setCurrentGestureInGuts(isInGuts: Boolean) {
+ viewHeightRepository.isCurrentGestureInGuts.value = isInGuts
+ }
+
fun setConstrainedAvailableSpace(height: Int) {
placeholderRepository.constrainedAvailableSpace.value = height
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
index 1289cec3a282..235b4da3f029 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt
@@ -71,6 +71,9 @@ interface NotificationScrollView {
/** Set a consumer for current gesture overscroll events */
fun setCurrentGestureOverscrollConsumer(consumer: Consumer<Boolean>?)
+ /** Set a consumer for current gesture in guts events */
+ fun setCurrentGestureInGutsConsumer(consumer: Consumer<Boolean>?)
+
/** Set a consumer for heads up height changed events */
fun setHeadsUpHeightConsumer(consumer: Consumer<Float>?)
@@ -92,6 +95,12 @@ interface NotificationScrollView {
/** Gets the inset for HUNs when they are not visible */
fun getHeadsUpInset(): Int
+ /**
+ * Signals that any open Notification guts should be closed, as scene container is handling
+ * touch events.
+ */
+ fun closeGutsOnSceneTouch()
+
/** Adds a listener to be notified, when the stack height might have changed. */
fun addStackHeightChangedListener(runnable: Runnable)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index c044f6f6a9b1..3cc6e81986c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -36,6 +36,7 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
/** Binds the [NotificationScrollView]. */
@@ -98,13 +99,18 @@ constructor(
.filter { it }
.collect { view.setStackTop(-(view.getHeadsUpInset().toFloat())) }
}
+ launch {
+ viewModel.shouldCloseGuts.filter { it }.collect { view.closeGutsOnSceneTouch() }
+ }
launchAndDispose {
view.setSyntheticScrollConsumer(viewModel.syntheticScrollConsumer)
view.setCurrentGestureOverscrollConsumer(viewModel.currentGestureOverscrollConsumer)
+ view.setCurrentGestureInGutsConsumer(viewModel.currentGestureInGutsConsumer)
DisposableHandle {
view.setSyntheticScrollConsumer(null)
view.setCurrentGestureOverscrollConsumer(null)
+ view.setCurrentGestureInGutsConsumer(null)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
index b2045fe7569a..3999578b83e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt
@@ -136,6 +136,9 @@ constructor(
val qsExpandFraction: Flow<Float> =
shadeInteractor.qsExpansion.dumpWhileCollecting("qsExpandFraction")
+ /** Whether we should close any open notification guts. */
+ val shouldCloseGuts: Flow<Boolean> = stackAppearanceInteractor.shouldCloseGuts
+
val shouldResetStackTop: Flow<Boolean> =
sceneInteractor.transitionState
.mapNotNull { state -> state is Idle && state.currentScene == Scenes.Gone }
@@ -202,6 +205,10 @@ constructor(
val currentGestureOverscrollConsumer: (Boolean) -> Unit =
stackAppearanceInteractor::setCurrentGestureOverscroll
+ /** Receives whether the current touch gesture is inside any open guts. */
+ val currentGestureInGutsConsumer: (Boolean) -> Unit =
+ stackAppearanceInteractor::setCurrentGestureInGuts
+
/** Whether the notification stack is scrollable or not. */
val isScrollable: Flow<Boolean> =
sceneInteractor.currentScene
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
index 59c819d41493..cd32718dbe82 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
@@ -3,8 +3,6 @@ package com.android.systemui.user.domain.interactor
import android.annotation.UserIdInt
import android.content.pm.UserInfo
import android.os.UserManager
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.Flags.refactorGetCurrentUser
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
@@ -21,23 +19,11 @@ class SelectedUserInteractor @Inject constructor(private val repository: UserRep
/** Flow providing the [UserInfo] of the currently selected user. */
val selectedUserInfo = repository.selectedUserInfo
- /**
- * Returns the ID of the currently-selected user.
- *
- * @param bypassFlag this will ignore the feature flag and get the data from the repository
- * instead. This is used for refactored methods that were previously pointing to `userTracker`
- * and therefore should not be routed back to KeyguardUpdateMonitor when flag is disabled.
- * KeyguardUpdateMonitor.getCurrentUser() is deprecated and will be removed soon (together
- * with this flag).
- */
+ /** Returns the ID of the currently-selected user. */
@UserIdInt
@JvmOverloads
- fun getSelectedUserId(bypassFlag: Boolean = false): Int {
- return if (bypassFlag || refactorGetCurrentUser()) {
- repository.getSelectedUserInfo().id
- } else {
- KeyguardUpdateMonitor.getCurrentUser()
- }
+ fun getSelectedUserId(): Int {
+ return repository.getSelectedUserInfo().id
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 7aa415b64316..52fde7ed72c9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -354,7 +354,6 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
ExtendedMockito.doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
.when(SubscriptionManager::getDefaultSubscriptionId);
when(mSelectedUserInteractor.getSelectedUserId()).thenReturn(mCurrentUserId);
- when(mSelectedUserInteractor.getSelectedUserId(anyBoolean())).thenReturn(mCurrentUserId);
mContext.getOrCreateTestableResources().addOverride(
com.android.systemui.res.R.integer.config_face_auth_supported_posture,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 37f1a3d73b0c..597ffef20ace 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -26,7 +26,6 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR;
-import static com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER;
import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
@@ -250,7 +249,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
when(mCommunalTransitionViewModel.getTransitionFromOccludedEnded())
.thenReturn(mock(Flow.class));
when(mSelectedUserInteractor.getSelectedUserId()).thenReturn(mDefaultUserId);
- when(mSelectedUserInteractor.getSelectedUserId(anyBoolean())).thenReturn(mDefaultUserId);
when(mProcessWrapper.isSystemUser()).thenReturn(true);
mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(
mContext,
@@ -275,7 +273,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mKosmos.getNotificationShadeWindowModel(),
mKosmos::getCommunalInteractor);
mFeatureFlags = new FakeFeatureFlags();
- mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER);
mSetFlagsRule.disableFlags(FLAG_KEYGUARD_WM_STATE_REFACTOR);
DejankUtils.setImmediate(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
index 230ddf9d25db..48c2cc7f11c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManagerTest.kt
@@ -56,11 +56,11 @@ class StatusBarTouchableRegionManagerTest : SysuiTestCase() {
runCurrent()
assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
- sceneRepository.isRemoteUserInteractionOngoing.value = true
+ sceneRepository.isRemoteUserInputOngoing.value = true
runCurrent()
assertThat(underTest.shouldMakeEntireScreenTouchable()).isTrue()
- sceneRepository.isRemoteUserInteractionOngoing.value = false
+ sceneRepository.isRemoteUserInputOngoing.value = false
runCurrent()
assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
}
@@ -71,7 +71,7 @@ class StatusBarTouchableRegionManagerTest : SysuiTestCase() {
testScope.runTest {
assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
- sceneRepository.isRemoteUserInteractionOngoing.value = true
+ sceneRepository.isRemoteUserInputOngoing.value = true
runCurrent()
assertThat(underTest.shouldMakeEntireScreenTouchable()).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
index 78028f819fa0..26f6f3131585 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
@@ -3,7 +3,6 @@ package com.android.systemui.user.domain.interactor
import android.content.pm.UserInfo
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER
import com.android.systemui.SysuiTestCase
import com.android.systemui.user.data.repository.FakeUserRepository
import com.google.common.truth.Truth.assertThat
@@ -28,7 +27,6 @@ class SelectedUserInteractorTest : SysuiTestCase() {
@Test
fun getSelectedUserIdReturnsId() {
- mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER)
runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[0]) }
val actualId = underTest.getSelectedUserId()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeWindowModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeWindowModelKosmos.kt
index 6252d4498a5e..4b42e07f1f54 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeWindowModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/NotificationsShadeWindowModelKosmos.kt
@@ -16,7 +16,6 @@
package com.android.systemui.shade.ui.viewmodel
-import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
@@ -24,6 +23,5 @@ val Kosmos.notificationShadeWindowModel: NotificationShadeWindowModel by
Kosmos.Fixture {
NotificationShadeWindowModel(
keyguardTransitionInteractor,
- keyguardInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt
index dbfd9de2aa8c..2772d3698d88 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractorKosmos.kt
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.notification.stack.data.repository.notificationPlaceholderRepository
import com.android.systemui.statusbar.notification.stack.data.repository.notificationViewHeightRepository
@@ -26,6 +27,7 @@ val Kosmos.notificationStackAppearanceInteractor by Fixture {
NotificationStackAppearanceInteractor(
viewHeightRepository = notificationViewHeightRepository,
placeholderRepository = notificationPlaceholderRepository,
+ sceneInteractor = sceneInteractor,
shadeInteractor = shadeInteractor,
)
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 19279a887d11..07e5f2e34ab8 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3527,7 +3527,8 @@ class StorageManagerService extends IStorageManager.Stub
// of the calling App
final long token = Binder.clearCallingIdentity();
try {
- Context targetAppContext = mContext.createPackageContext(packageName, 0);
+ Context targetAppContext = mContext.createPackageContextAsUser(packageName,
+ /* flags= */ 0, UserHandle.of(UserHandle.getUserId(originalUid)));
Intent intent = new Intent(Intent.ACTION_DEFAULT);
intent.setClassName(packageName,
appInfo.manageSpaceActivityName);
diff --git a/services/core/java/com/android/server/wm/ActionChain.java b/services/core/java/com/android/server/wm/ActionChain.java
deleted file mode 100644
index c697d33ed4e2..000000000000
--- a/services/core/java/com/android/server/wm/ActionChain.java
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.Slog;
-
-import com.android.window.flags.Flags;
-
-/**
- * Represents a chain of WM actions where each action is "caused by" the prior action (except the
- * first one of course). A whole chain is associated with one Transition (in fact, the purpose
- * of this object is to communicate, to all callees, which transition they are part of).
- *
- * A single action is defined as "one logical thing requested of WM". This usually corresponds to
- * each ingress-point into the process. For example, when starting an activity:
- * * the first action is to pause the current/top activity.
- * At this point, control leaves the process while the activity pauses.
- * * Then WM receives completePause (a new ingress). This is a new action that gets linked
- * to the prior action. This action involves resuming the next activity, at which point,
- * control leaves the process again.
- * * Eventually, when everything is done, we will have formed a chain of actions.
- *
- * We don't technically need to hold onto each prior action in the chain once a new action has
- * been linked to the same transition; however, keeping the whole chain enables improved
- * debugging and the ability to detect anomalies.
- */
-public class ActionChain {
- private static final String TAG = "TransitionChain";
-
- /**
- * Normal link type. This means the action was expected and is properly linked to the
- * current chain.
- */
- static final int TYPE_NORMAL = 0;
-
- /**
- * This is the "default" link. It means we haven't done anything to properly track this case
- * so it may or may not be correct. It represents the behavior as if there was no tracking.
- *
- * Any type that has "default" behavior uses the global "collecting transition" if it exists,
- * otherwise it doesn't use any transition.
- */
- static final int TYPE_DEFAULT = 1;
-
- /**
- * This means the action was performed via a legacy code-path. These should be removed
- * eventually. This will have the "default" behavior.
- */
- static final int TYPE_LEGACY = 2;
-
- /** This is for a test. */
- static final int TYPE_TEST = 3;
-
- /** This is finishing a transition. Collection isn't supported during this. */
- static final int TYPE_FINISH = 4;
-
- /**
- * Something unexpected happened so this action was started to recover from the unexpected
- * state. This means that a "real" chain-link couldn't be determined. For now, the behavior of
- * this is the same as "default".
- */
- static final int TYPE_FAILSAFE = 5;
-
- /**
- * Types of chain links (ie. how is this action associated with the chain it is linked to).
- * @hide
- */
- @IntDef(prefix = { "TYPE_" }, value = {
- TYPE_NORMAL,
- TYPE_DEFAULT,
- TYPE_LEGACY,
- TYPE_TEST,
- TYPE_FINISH,
- TYPE_FAILSAFE
- })
- public @interface LinkType {}
-
- /** Identifies the entry-point of this action. */
- @NonNull
- final String mSource;
-
- /** Reference to ATMS. TEMPORARY! ONLY USE THIS WHEN tracker_plumbing flag is DISABLED! */
- @Nullable
- ActivityTaskManagerService mTmpAtm;
-
- /** The transition that this chain's changes belong to. */
- @Nullable
- Transition mTransition;
-
- /** The previous action in the chain. */
- @Nullable
- ActionChain mPrevious = null;
-
- /** Classification of how this action is connected to the chain. */
- @LinkType int mType = TYPE_NORMAL;
-
- /** When this Action started. */
- long mCreateTimeMs;
-
- private ActionChain(String source, @LinkType int type, Transition transit) {
- mSource = source;
- mCreateTimeMs = System.currentTimeMillis();
- mType = type;
- mTransition = transit;
- if (mTransition != null) {
- mTransition.recordChain(this);
- }
- }
-
- private Transition getTransition() {
- if (!Flags.transitTrackerPlumbing()) {
- return mTmpAtm.getTransitionController().getCollectingTransition();
- }
- return mTransition;
- }
-
- boolean isFinishing() {
- return mType == TYPE_FINISH;
- }
-
- /**
- * Some common checks to determine (and report) whether this chain has a collecting transition.
- */
- private boolean expectCollecting() {
- if (getTransition() == null) {
- Slog.e(TAG, "Can't collect into a chain with no transition");
- return false;
- }
- if (isFinishing()) {
- Slog.e(TAG, "Trying to collect into a finished transition");
- return false;
- }
- if (mTransition.mController.getCollectingTransition() != mTransition) {
- Slog.e(TAG, "Mismatch between current collecting ("
- + mTransition.mController.getCollectingTransition() + ") and chain ("
- + mTransition + ")");
- return false;
- }
- return true;
- }
-
- /**
- * Helper to collect a container into the associated transition. This will automatically do
- * nothing if the chain isn't associated with a collecting transition.
- */
- void collect(@NonNull WindowContainer wc) {
- if (!wc.mTransitionController.isShellTransitionsEnabled()) return;
- if (!expectCollecting()) return;
- getTransition().collect(wc);
- }
-
- /**
- * An interface for creating and tracking action chains.
- */
- static class Tracker {
- private final ActivityTaskManagerService mAtm;
-
- Tracker(ActivityTaskManagerService atm) {
- mAtm = atm;
- }
-
- private ActionChain makeChain(String source, @LinkType int type, Transition transit) {
- final ActionChain out = new ActionChain(source, type, transit);
- if (!Flags.transitTrackerPlumbing()) {
- out.mTmpAtm = mAtm;
- }
- return out;
- }
-
- private ActionChain makeChain(String source, @LinkType int type) {
- return makeChain(source, type,
- mAtm.getTransitionController().getCollectingTransition());
- }
-
- /**
- * Starts tracking a normal action.
- * @see #TYPE_NORMAL
- */
- @NonNull
- ActionChain start(String source, Transition transit) {
- return makeChain(source, TYPE_NORMAL, transit);
- }
-
- /** @see #TYPE_DEFAULT */
- @NonNull
- ActionChain startDefault(String source) {
- return makeChain(source, TYPE_DEFAULT);
- }
-
- /**
- * Starts tracking an action that finishes a transition.
- * @see #TYPE_NORMAL
- */
- @NonNull
- ActionChain startFinish(String source, Transition finishTransit) {
- return makeChain(source, TYPE_FINISH, finishTransit);
- }
-
- /** @see #TYPE_LEGACY */
- @NonNull
- ActionChain startLegacy(String source) {
- return makeChain(source, TYPE_LEGACY, null);
- }
-
- /** @see #TYPE_FAILSAFE */
- @NonNull
- ActionChain startFailsafe(String source) {
- return makeChain(source, TYPE_FAILSAFE);
- }
- }
-
- /** Helpers for usage in tests. */
- @NonNull
- static ActionChain test() {
- return new ActionChain("test", TYPE_TEST, null /* transition */);
- }
-
- @NonNull
- static ActionChain testFinish(Transition toFinish) {
- return new ActionChain("test", TYPE_FINISH, toFinish);
- }
-}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 03c7fd1e3ffe..0f108c5ed5d7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -795,7 +795,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
WindowOrganizerController mWindowOrganizerController;
TaskOrganizerController mTaskOrganizerController;
TaskFragmentOrganizerController mTaskFragmentOrganizerController;
- ActionChain.Tracker mChainTracker;
@Nullable
private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
@@ -870,7 +869,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mInternal = new LocalService();
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED);
mWindowOrganizerController = new WindowOrganizerController(this);
- mChainTracker = new ActionChain.Tracker(this);
mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController;
mTaskFragmentOrganizerController =
mWindowOrganizerController.mTaskFragmentOrganizerController;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 82ede7efda5a..e25db7e2a3ec 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -181,7 +181,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
final @TransitionType int mType;
private int mSyncId = -1;
private @TransitionFlags int mFlags;
- final TransitionController mController;
+ private final TransitionController mController;
private final BLASTSyncEngine mSyncEngine;
private final Token mToken;
@@ -329,9 +329,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
*/
ArrayList<ActivityRecord> mConfigAtEndActivities = null;
- /** The current head of the chain of actions related to this transition. */
- ActionChain mChainHead = null;
-
@VisibleForTesting
Transition(@TransitionType int type, @TransitionFlags int flags,
TransitionController controller, BLASTSyncEngine syncEngine) {
@@ -1210,14 +1207,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
* The transition has finished animating and is ready to finalize WM state. This should not
* be called directly; use {@link TransitionController#finishTransition} instead.
*/
- void finishTransition(@NonNull ActionChain chain) {
+ void finishTransition() {
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER) && mIsPlayerEnabled) {
asyncTraceEnd(System.identityHashCode(this));
}
- if (!chain.isFinishing()) {
- throw new IllegalStateException("Can't finish on a non-finishing transition "
- + chain.mTransition);
- }
mLogger.mFinishTimeNs = SystemClock.elapsedRealtimeNanos();
mController.mLoggerHandler.post(mLogger::logOnFinish);
mController.mTransitionTracer.logFinishedTransition(this);
@@ -2170,7 +2163,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
if (mFinishTransaction != null) {
mFinishTransaction.apply();
}
- mController.finishTransition(mController.mAtm.mChainTracker.startFinish("clean-up", this));
+ mController.finishTransition(this);
}
private void cleanUpInternal() {
@@ -3386,11 +3379,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
return false;
}
- void recordChain(@NonNull ActionChain chain) {
- chain.mPrevious = mChainHead;
- mChainHead = chain;
- }
-
@VisibleForTesting
static class ChangeInfo {
private static final int FLAG_NONE = 0;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 56a24dd4ca49..9bbf10243133 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -52,8 +52,8 @@ import android.window.WindowContainerTransaction;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLog;
import com.android.internal.protolog.ProtoLogGroup;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.FgThread;
import com.android.window.flags.Flags;
@@ -921,12 +921,7 @@ class TransitionController {
}
/** @see Transition#finishTransition */
- void finishTransition(@NonNull ActionChain chain) {
- if (!chain.isFinishing()) {
- throw new IllegalStateException("Can't finish on a non-finishing transition "
- + chain.mTransition);
- }
- final Transition record = chain.mTransition;
+ void finishTransition(Transition record) {
// It is usually a no-op but make sure that the metric consumer is removed.
mTransitionMetricsReporter.reportAnimationStart(record.getToken(), 0 /* startTime */);
// It is a no-op if the transition did not change the display.
@@ -942,7 +937,7 @@ class TransitionController {
mTrackCount = 0;
}
updateRunningRemoteAnimation(record, false /* isPlaying */);
- record.finishTransition(chain);
+ record.finishTransition();
for (int i = mAnimatingExitWindows.size() - 1; i >= 0; i--) {
final WindowState w = mAnimatingExitWindows.get(i);
if (w.mAnimatingExit && w.mHasSurface && !w.inTransition()) {
diff --git a/services/core/java/com/android/server/wm/TrustedOverlayHost.java b/services/core/java/com/android/server/wm/TrustedOverlayHost.java
index 9b868bebd868..5f3c5583e024 100644
--- a/services/core/java/com/android/server/wm/TrustedOverlayHost.java
+++ b/services/core/java/com/android/server/wm/TrustedOverlayHost.java
@@ -112,11 +112,16 @@ class TrustedOverlayHost {
final SurfaceControl.Transaction t = mWmService.mTransactionFactory.get();
for (int i = mOverlays.size() - 1; i >= 0; i--) {
- SurfaceControlViewHost.SurfacePackage l = mOverlays.get(i);
- if (l.getSurfaceControl().isSameSurface(p.getSurfaceControl())) {
- mOverlays.remove(i);
- t.reparent(l.getSurfaceControl(), null);
- l.release();
+ SurfaceControlViewHost.SurfacePackage l = mOverlays.get(i);
+ SurfaceControl overlaySurfaceControl = l.getSurfaceControl();
+ if (overlaySurfaceControl == null) {
+ // Remove the overlay if the surfacepackage was released. Ownership
+ // is shared, so this may happen.
+ mOverlays.remove(i);
+ } else if (overlaySurfaceControl.isSameSurface(p.getSurfaceControl())) {
+ mOverlays.remove(i);
+ t.reparent(l.getSurfaceControl(), null);
+ l.release();
}
}
t.apply();
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 60ccdc72ee09..e1e64ee10245 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -223,8 +223,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- final ActionChain chain = mService.mChainTracker.startLegacy("applyTransactLegacy");
- applyTransaction(t, -1 /*syncId*/, chain, caller);
+ applyTransaction(t, -1 /*syncId*/, null /*transition*/, caller);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -243,8 +242,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
try {
synchronized (mGlobalLock) {
if (callback == null) {
- final ActionChain chain = mService.mChainTracker.startLegacy("applySyncLegacy");
- applyTransaction(t, -1 /* syncId*/, chain, caller);
+ applyTransaction(t, -1 /* syncId*/, null /*transition*/, caller);
return -1;
}
@@ -264,15 +262,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final int syncId = syncGroup.mSyncId;
if (mTransitionController.isShellTransitionsEnabled()) {
mTransitionController.startLegacySyncOrQueue(syncGroup, (deferred) -> {
- applyTransaction(t, syncId, mService.mChainTracker.startLegacy(
- "applySyncLegacy"), caller, deferred);
+ applyTransaction(t, syncId, null /* transition */, caller, deferred);
setSyncReady(syncId);
});
} else {
if (!mService.mWindowManager.mSyncEngine.hasActiveSync()) {
mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup);
- applyTransaction(t, syncId, mService.mChainTracker.startLegacy(
- "applySyncLegacy"), caller);
+ applyTransaction(t, syncId, null /*transition*/, caller);
setSyncReady(syncId);
} else {
// Because the BLAST engine only supports one sync at a time, queue the
@@ -280,8 +276,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
mService.mWindowManager.mSyncEngine.queueSyncSet(
() -> mService.mWindowManager.mSyncEngine.startSyncSet(syncGroup),
() -> {
- applyTransaction(t, syncId, mService.mChainTracker.startLegacy(
- "applySyncLegacy"), caller);
+ applyTransaction(t, syncId, null /*transition*/, caller);
setSyncReady(syncId);
});
}
@@ -318,8 +313,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
throw new IllegalArgumentException("Can't use legacy transitions in"
+ " compatibility mode with no WCT.");
}
- applyTransaction(t, -1 /* syncId */,
- mService.mChainTracker.startLegacy("wrongLegacyTransit"), caller);
+ applyTransaction(t, -1 /* syncId */, null, caller);
return null;
}
final WindowContainerTransaction wct =
@@ -340,11 +334,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
nextTransition.calcParallelCollectType(wct);
mTransitionController.startCollectOrQueue(nextTransition,
(deferred) -> {
- final ActionChain chain = mService.mChainTracker.start(
- "startNewTransit", nextTransition);
nextTransition.start();
nextTransition.mLogger.mStartWCT = wct;
- applyTransaction(wct, -1 /* syncId */, chain, caller, deferred);
+ applyTransaction(wct, -1 /* syncId */, nextTransition, caller,
+ deferred);
wctApplied.meet();
if (needsSetReady) {
setAllReadyIfNeeded(nextTransition, wct);
@@ -358,9 +351,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
Slog.e(TAG, "Trying to start a transition that isn't collecting. This probably"
+ " means Shell took too long to respond to a request. WM State may be"
+ " incorrect now, please file a bug");
- final ActionChain chain = mService.mChainTracker.startFailsafe("startTransit");
- chain.mTransition = null;
- applyTransaction(wct, -1 /*syncId*/, chain, caller);
+ applyTransaction(wct, -1 /*syncId*/, null /*transition*/, caller);
return transition.getToken();
}
// Currently, application of wct can span multiple looper loops (ie.
@@ -376,20 +367,16 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (transition.shouldApplyOnDisplayThread()) {
mService.mH.post(() -> {
synchronized (mService.mGlobalLock) {
- final ActionChain chain = mService.mChainTracker.start(
- "startTransit", transition);
transition.start();
- applyTransaction(wct, -1 /* syncId */, chain, caller);
+ applyTransaction(wct, -1 /* syncId */, transition, caller);
if (wctApplied != null) {
wctApplied.meet();
}
}
});
} else {
- final ActionChain chain = mService.mChainTracker.start("startTransit",
- transition);
transition.start();
- applyTransaction(wct, -1 /* syncId */, chain, caller);
+ applyTransaction(wct, -1 /* syncId */, transition, caller);
if (wctApplied != null) {
wctApplied.meet();
}
@@ -488,8 +475,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
dc.mAppTransition.overridePendingAppTransitionRemote(adapter, true /* sync */,
false /* isActivityEmbedding */);
syncId = startSyncWithOrganizer(callback);
- applyTransaction(t, syncId, mService.mChainTracker.startLegacy("legacyTransit"),
- caller);
+ applyTransaction(t, syncId, null /* transition */, caller);
setSyncReady(syncId);
}
} finally {
@@ -507,8 +493,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
try {
synchronized (mGlobalLock) {
final Transition transition = Transition.fromBinder(transitionToken);
- final ActionChain chain =
- mService.mChainTracker.startFinish("finishTransit", transition);
// apply the incoming transaction before finish in case it alters the visibility
// of the participants.
if (t != null) {
@@ -516,9 +500,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// changes of the transition participants will only set visible-requested
// and still let finishTransition handle the participants.
mTransitionController.mFinishingTransition = transition;
- applyTransaction(t, -1 /* syncId */, chain, caller);
+ applyTransaction(t, -1 /* syncId */, null /*transition*/, caller, transition);
}
- mTransitionController.finishTransition(chain);
+ mTransitionController.finishTransition(transition);
mTransitionController.mFinishingTransition = null;
}
} finally {
@@ -553,10 +537,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final CallerInfo caller = new CallerInfo();
final long ident = Binder.clearCallingIdentity();
try {
- if (!mTransitionController.isShellTransitionsEnabled()) {
+ if (mTransitionController.getTransitionPlayer() == null) {
// No need to worry about transition when Shell transition is not enabled.
- applyTransaction(wct, -1 /* syncId */,
- mService.mChainTracker.startLegacy("legacyTFTransact"), caller);
+ applyTransaction(wct, -1 /* syncId */, null /* transition */, caller);
return;
}
@@ -565,8 +548,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// Although there is an active sync, we want to apply the transaction now.
// TODO(b/232042367) Redesign the organizer update on activity callback so that we
// we will know about the transition explicitly.
- final ActionChain chain = mService.mChainTracker.startDefault("tfTransact");
- if (chain.mTransition == null) {
+ final Transition transition = mTransitionController.getCollectingTransition();
+ if (transition == null) {
// This should rarely happen, and we should try to avoid using
// {@link #applySyncTransaction} with Shell transition.
// We still want to apply and merge the transaction to the active sync
@@ -576,7 +559,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
+ " because there is an ongoing sync for"
+ " applySyncTransaction().");
}
- applyTransaction(wct, -1 /* syncId */, chain, caller);
+ applyTransaction(wct, -1 /* syncId */, transition, caller);
return;
}
@@ -587,9 +570,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
transition.abort();
return;
}
- final ActionChain chain = mService.mChainTracker.start("tfTransact", transition);
- final int effects = applyTransaction(wct, -1 /* syncId */, chain, caller, deferred);
- if (effects == TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) {
+ if (applyTransaction(wct, -1 /* syncId */, transition, caller, deferred)
+ == TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) {
transition.abort();
return;
}
@@ -604,10 +586,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
- @NonNull ActionChain chain, @NonNull CallerInfo caller, boolean deferred) {
+ @Nullable Transition transition, @NonNull CallerInfo caller) {
+ return applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
+ }
+
+ private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
+ @Nullable Transition transition, @NonNull CallerInfo caller, boolean deferred) {
if (deferred) {
try {
- return applyTransaction(t, syncId, chain, caller);
+ return applyTransaction(t, syncId, transition, caller);
} catch (RuntimeException e) {
// If the transaction is deferred, the caller could be from TransitionController
// #tryStartCollectFromQueue that executes on system's worker thread rather than
@@ -617,17 +604,19 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
return TRANSACT_EFFECTS_NONE;
}
- return applyTransaction(t, syncId, chain, caller);
+ return applyTransaction(t, syncId, transition, caller);
}
/**
* @param syncId If non-null, this will be a sync-transaction.
- * @param chain A lifecycle-chain to acculumate changes into.
+ * @param transition A transition to collect changes into.
* @param caller Info about the calling process.
+ * @param finishTransition The transition that is currently being finished.
* @return The effects of the window container transaction.
*/
private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
- @NonNull ActionChain chain, @NonNull CallerInfo caller) {
+ @Nullable Transition transition, @NonNull CallerInfo caller,
+ @Nullable Transition finishTransition) {
int effects = TRANSACT_EFFECTS_NONE;
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
mService.deferWindowLayout();
@@ -635,21 +624,20 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
boolean deferResume = true;
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
boolean deferTransitionReady = false;
- if (chain.mTransition != null && !t.isEmpty() && !chain.isFinishing()) {
- if (chain.mTransition.isCollecting()) {
+ if (transition != null && !t.isEmpty()) {
+ if (transition.isCollecting()) {
deferTransitionReady = true;
- chain.mTransition.deferTransitionReady();
+ transition.deferTransitionReady();
} else {
Slog.w(TAG, "Transition is not collecting when applyTransaction."
- + " transition=" + chain.mTransition + " state="
- + chain.mTransition.getState());
- chain.mTransition = null;
+ + " transition=" + transition + " state=" + transition.getState());
+ transition = null;
}
}
try {
final ArraySet<WindowContainer<?>> haveConfigChanges = new ArraySet<>();
- if (chain.mTransition != null) {
- chain.mTransition.applyDisplayChangeIfNeeded(haveConfigChanges);
+ if (transition != null) {
+ transition.applyDisplayChangeIfNeeded(haveConfigChanges);
if (!haveConfigChanges.isEmpty()) {
effects |= TRANSACT_EFFECTS_CLIENT_CONFIG;
}
@@ -657,7 +645,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
final int hopSize = hops.size();
Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries;
- if (chain.mTransition != null) {
+ if (transition != null) {
// Mark any config-at-end containers before applying config changes so that
// the config changes don't dispatch to client.
entries = t.getChanges().entrySet().iterator();
@@ -667,7 +655,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (!entry.getValue().getConfigAtTransitionEnd()) continue;
final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
if (wc == null || !wc.isAttached()) continue;
- chain.mTransition.setConfigAtEnd(wc);
+ transition.setConfigAtEnd(wc);
}
}
entries = t.getChanges().entrySet().iterator();
@@ -684,13 +672,15 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (syncId >= 0) {
addToSyncSet(syncId, wc);
}
- chain.collect(wc);
+ if (transition != null) transition.collect(wc);
if ((entry.getValue().getChangeMask()
& WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) {
// Disable entering pip (eg. when recents pretends to finish itself)
- if (chain.mTransition != null) {
- chain.mTransition.setCanPipOnFinish(false /* canPipOnFinish */);
+ if (finishTransition != null) {
+ finishTransition.setCanPipOnFinish(false /* canPipOnFinish */);
+ } else if (transition != null) {
+ transition.setCanPipOnFinish(false /* canPipOnFinish */);
}
}
// A bit hacky, but we need to detect "remove PiP" so that we can "wrap" the
@@ -738,9 +728,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (hopSize > 0) {
final boolean isInLockTaskMode = mService.isInLockTaskMode();
for (int i = 0; i < hopSize; ++i) {
- effects |= applyHierarchyOp(hops.get(i), effects, syncId, chain,
+ effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,
isInLockTaskMode, caller, t.getErrorCallbackToken(),
- t.getTaskFragmentOrganizer());
+ t.getTaskFragmentOrganizer(), finishTransition);
}
}
// Queue-up bounds-change transactions for tasks which are now organized. Do
@@ -799,7 +789,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
} finally {
if (deferTransitionReady) {
- chain.mTransition.continueTransitionReady();
+ transition.continueTransitionReady();
}
mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
if (deferResume) {
@@ -1089,9 +1079,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,
- int syncId, @NonNull ActionChain chain, boolean isInLockTaskMode,
+ int syncId, @Nullable Transition transition, boolean isInLockTaskMode,
@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,
- @Nullable ITaskFragmentOrganizer organizer) {
+ @Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {
final int type = hop.getType();
switch (type) {
case HIERARCHY_OP_TYPE_REMOVE_TASK: {
@@ -1161,7 +1151,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
break;
}
case HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT: {
- effects |= reparentChildrenTasksHierarchyOp(hop, chain.mTransition, syncId,
+ effects |= reparentChildrenTasksHierarchyOp(hop, transition, syncId,
isInLockTaskMode);
break;
}
@@ -1214,13 +1204,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if (syncId >= 0) {
addToSyncSet(syncId, wc);
}
- if (chain.mTransition != null) {
- chain.mTransition.collect(wc);
+ if (transition != null) {
+ transition.collect(wc);
if (hop.isReparent()) {
if (wc.getParent() != null) {
// Collect the current parent. It's visibility may change as
// a result of this reparenting.
- chain.mTransition.collect(wc.getParent());
+ transition.collect(wc.getParent());
}
if (hop.getNewParent() != null) {
final WindowContainer parentWc =
@@ -1229,7 +1219,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
Slog.e(TAG, "Can't resolve parent window from token");
break;
}
- chain.mTransition.collect(parentWc);
+ transition.collect(parentWc);
}
}
}
@@ -1243,8 +1233,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
break;
}
case HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION: {
- effects |= applyTaskFragmentOperation(hop, chain, isInLockTaskMode,
- caller, errorCallbackToken, organizer);
+ effects |= applyTaskFragmentOperation(hop, transition, isInLockTaskMode, caller,
+ errorCallbackToken, organizer);
break;
}
case HIERARCHY_OP_TYPE_PENDING_INTENT: {
@@ -1358,13 +1348,13 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
break;
}
case HIERARCHY_OP_TYPE_RESTORE_TRANSIENT_ORDER: {
- if (!chain.isFinishing()) break;
+ if (finishTransition == null) break;
final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
if (container == null) break;
final Task thisTask = container.asActivityRecord() != null
? container.asActivityRecord().getTask() : container.asTask();
if (thisTask == null) break;
- final Task restoreAt = chain.mTransition.getTransientLaunchRestoreTarget(container);
+ final Task restoreAt = finishTransition.getTransientLaunchRestoreTarget(container);
if (restoreAt == null) break;
final TaskDisplayArea taskDisplayArea = thisTask.getTaskDisplayArea();
taskDisplayArea.moveRootTaskBehindRootTask(thisTask.getRootTask(), restoreAt);
@@ -1454,7 +1444,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
* {@link #TRANSACT_EFFECTS_LIFECYCLE} or {@link #TRANSACT_EFFECTS_CLIENT_CONFIG}.
*/
private int applyTaskFragmentOperation(@NonNull WindowContainerTransaction.HierarchyOp hop,
- @NonNull ActionChain chain, boolean isInLockTaskMode, @NonNull CallerInfo caller,
+ @Nullable Transition transition, boolean isInLockTaskMode, @NonNull CallerInfo caller,
@Nullable IBinder errorCallbackToken, @Nullable ITaskFragmentOrganizer organizer) {
if (!validateTaskFragmentOperation(hop, errorCallbackToken, organizer)) {
return TRANSACT_EFFECTS_NONE;
@@ -1477,7 +1467,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
break;
}
createTaskFragment(taskFragmentCreationParams, errorCallbackToken, caller,
- chain.mTransition);
+ transition);
break;
}
case OP_TYPE_DELETE_TASK_FRAGMENT: {
@@ -1494,7 +1484,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
break;
}
}
- effects |= deleteTaskFragment(taskFragment, chain.mTransition);
+ effects |= deleteTaskFragment(taskFragment, transition);
break;
}
case OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
@@ -1543,14 +1533,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
opType, exception);
break;
}
- if (chain.mTransition != null) {
- chain.collect(activity);
+ if (transition != null) {
+ transition.collect(activity);
if (activity.getParent() != null) {
// Collect the current parent. Its visibility may change as a result of
// this reparenting.
- chain.collect(activity.getParent());
+ transition.collect(activity.getParent());
}
- chain.collect(taskFragment);
+ transition.collect(taskFragment);
}
activity.reparent(taskFragment, POSITION_TOP);
effects |= TRANSACT_EFFECTS_LIFECYCLE;
@@ -1706,8 +1696,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// If any TaskFragment in the Task is collected by the transition, we make the decor
// surface visible in sync with the TaskFragment transition. Otherwise, we make the
// decor surface visible immediately.
- final TaskFragment syncTaskFragment = chain.mTransition != null
- ? task.getTaskFragment(chain.mTransition.mParticipants::contains)
+ final TaskFragment syncTaskFragment = transition != null
+ ? task.getTaskFragment(transition.mParticipants::contains)
: null;
if (syncTaskFragment != null) {
@@ -1759,7 +1749,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
// The decor surface boost/unboost must be applied after the transition is
// completed. Otherwise, the decor surface could be moved before Shell completes
// the transition, causing flicker.
- runAfterTransition(chain.mTransition, task::commitDecorSurfaceBoostedState);
+ runAfterTransition(transition, task::commitDecorSurfaceBoostedState);
}
break;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index da3ada8671df..c5c371ff85d5 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -106,7 +106,9 @@ import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.policy.AttributeCache;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.protolog.ProtoLogConfigurationService;
+import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.EmergencyAffordanceManager;
import com.android.internal.util.FrameworkStatsLog;
@@ -1099,6 +1101,10 @@ public final class SystemServer implements Dumpable {
t.traceEnd();
}
+ t.traceBegin("InitializeProtoLog");
+ ProtoLog.init(ProtoLogGroup.values());
+ t.traceEnd();
+
// Platform compat service is used by ActivityManagerService, PackageManagerService, and
// possibly others in the future. b/135010838.
t.traceBegin("PlatformCompat");
diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
index 54f46078d30b..698ce13aa6db 100644
--- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
+++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamOverlayServiceTest.java
@@ -18,7 +18,9 @@ package com.android.server.dreams;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -27,7 +29,9 @@ import android.content.ComponentName;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
+import android.platform.test.annotations.EnableFlags;
import android.service.dreams.DreamOverlayService;
+import android.service.dreams.Flags;
import android.service.dreams.IDreamOverlay;
import android.service.dreams.IDreamOverlayCallback;
import android.service.dreams.IDreamOverlayClient;
@@ -221,6 +225,47 @@ public class DreamOverlayServiceTest {
verify(monitor, never()).onWakeUp();
}
+ /**
+ * Verifies that only the currently started dream is able to affect the overlay.
+ */
+ @Test
+ @EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT)
+ public void testRedirectToWakeAcrossClients() throws RemoteException {
+ doAnswer(invocation -> {
+ ((Runnable) invocation.getArgument(0)).run();
+ return null;
+ }).when(mExecutor).execute(any());
+
+ final TestDreamOverlayService.Monitor monitor = Mockito.mock(
+ TestDreamOverlayService.Monitor.class);
+ final TestDreamOverlayService service = new TestDreamOverlayService(monitor, mExecutor);
+ final IBinder binder = service.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(binder);
+
+ service.redirectWake(true);
+
+ final IDreamOverlayClient client = getClient(overlay);
+
+ // Start the dream.
+ client.startDream(mLayoutParams, mOverlayCallback,
+ FIRST_DREAM_COMPONENT.flattenToString(), false);
+ // Make sure redirect state is set on dream.
+ verify(mOverlayCallback).onRedirectWake(eq(true));
+
+ // Make sure new changes are propagated.
+ clearInvocations(mOverlayCallback);
+ service.redirectWake(false);
+ verify(mOverlayCallback).onRedirectWake(eq(false));
+
+
+ // Start another dream, make sure new dream is informed of current state.
+ service.redirectWake(true);
+ clearInvocations(mOverlayCallback);
+ client.startDream(mLayoutParams, mOverlayCallback,
+ FIRST_DREAM_COMPONENT.flattenToString(), false);
+ verify(mOverlayCallback).onRedirectWake(eq(true));
+ }
+
private static IDreamOverlayClient getClient(IDreamOverlay overlay) throws RemoteException {
final OverlayClientCallback callback = new OverlayClientCallback();
overlay.getClient(callback);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 52a80b01971d..56fca31afa37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1251,7 +1251,7 @@ public class TransitionTests extends WindowTestsBase {
final Transition transition = app.mTransitionController.createTransition(TRANSIT_OPEN);
app.mTransitionController.requestStartTransition(transition, app.getTask(),
null /* remoteTransition */, null /* displayChange */);
- transition.collectExistenceChange(app.getTask());
+ app.mTransitionController.collectExistenceChange(app.getTask());
mDisplayContent.setFixedRotationLaunchingAppUnchecked(app);
final AsyncRotationController asyncRotationController =
mDisplayContent.getAsyncRotationController();
@@ -1416,8 +1416,7 @@ public class TransitionTests extends WindowTestsBase {
activity1.setVisibleRequested(false);
activity2.setVisibleRequested(true);
- final ActionChain chain = ActionChain.testFinish(null);
- openTransition.finishTransition(chain);
+ openTransition.finishTransition();
// We finished the openTransition. Even though activity1 is visibleRequested=false, since
// the closeTransition animation hasn't played yet, make sure that we didn't commit
@@ -1430,7 +1429,7 @@ public class TransitionTests extends WindowTestsBase {
// normally.
mWm.mSyncEngine.abort(closeTransition.getSyncId());
- closeTransition.finishTransition(chain);
+ closeTransition.finishTransition();
assertFalse(activity1.isVisible());
assertTrue(activity2.isVisible());
@@ -1450,7 +1449,7 @@ public class TransitionTests extends WindowTestsBase {
activity1.setState(ActivityRecord.State.INITIALIZING, "test");
activity1.mLaunchTaskBehind = true;
mWm.mSyncEngine.abort(noChangeTransition.getSyncId());
- noChangeTransition.finishTransition(chain);
+ noChangeTransition.finishTransition();
assertTrue(activity1.mLaunchTaskBehind);
}
@@ -1469,7 +1468,7 @@ public class TransitionTests extends WindowTestsBase {
// We didn't call abort on the transition itself, so it will still run onTransactionReady
// normally.
mWm.mSyncEngine.abort(transition1.getSyncId());
- transition1.finishTransition(ActionChain.testFinish(transition1));
+ transition1.finishTransition();
verify(transitionEndedListener).run();
@@ -1531,7 +1530,7 @@ public class TransitionTests extends WindowTestsBase {
verify(taskSnapshotController, times(1)).recordSnapshot(eq(task2));
- controller.finishTransition(ActionChain.testFinish(openTransition));
+ controller.finishTransition(openTransition);
// We are now going to simulate closing task1 to return back to (open) task2.
final Transition closeTransition = createTestTransition(TRANSIT_CLOSE, controller);
@@ -1596,7 +1595,7 @@ public class TransitionTests extends WindowTestsBase {
doReturn(true).when(task1).isTranslucentForTransition();
assertFalse(controller.canApplyDim(task1));
- controller.finishTransition(ActionChain.testFinish(closeTransition));
+ controller.finishTransition(closeTransition);
assertTrue(wasInFinishingTransition[0]);
assertFalse(calledListenerOnOtherDisplay[0]);
assertNull(controller.mFinishingTransition);
@@ -1652,7 +1651,7 @@ public class TransitionTests extends WindowTestsBase {
// to avoid the latency to resume the current top, i.e. appB.
assertTrue(controller.isTransientVisible(taskRecent));
// The recent is paused after the transient transition is finished.
- controller.finishTransition(ActionChain.testFinish(transition));
+ controller.finishTransition(transition);
assertFalse(controller.isTransientVisible(taskRecent));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 9602ae29604f..7652861449de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -407,7 +407,7 @@ public class WallpaperControllerTests extends WindowTestsBase {
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
token.finishSync(t, token.getSyncGroup(), false /* cancel */);
transit.onTransactionReady(transit.getSyncId(), t);
- dc.mTransitionController.finishTransition(ActionChain.testFinish(transit));
+ dc.mTransitionController.finishTransition(transit);
assertFalse(wallpaperWindow.isVisible());
assertFalse(token.isVisible());
}
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 a215c0a80b46..bcf4ebcd9740 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -2131,7 +2131,7 @@ public class WindowTestsBase extends SystemServiceTestsBase {
}
public void finish() {
- mController.finishTransition(ActionChain.testFinish(mLastTransit));
+ mController.finishTransition(mLastTransit);
}
}
}