summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java278
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java6
-rw-r--r--core/java/android/app/ApplicationPackageManager.java23
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java32
-rw-r--r--core/java/android/app/appfunctions/AppFunctionManager.java23
-rw-r--r--core/java/android/app/appfunctions/AppFunctionManagerHelper.java17
-rw-r--r--core/java/android/companion/virtual/flags/flags.aconfig8
-rw-r--r--core/java/android/content/pm/PackageManager.java31
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java5
-rw-r--r--core/java/android/os/BaseBundle.java11
-rw-r--r--core/java/android/os/Bundle.java36
-rw-r--r--core/java/android/os/Parcel.java65
-rw-r--r--core/java/android/view/ViewConfiguration.java231
-rw-r--r--core/java/com/android/internal/jank/Cuj.java15
-rw-r--r--core/res/res/values/config.xml37
-rw-r--r--core/res/res/values/symbols.xml11
-rw-r--r--core/tests/coretests/src/android/content/IntentTest.java39
-rw-r--r--libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/draganddrop/DragAndDropConstants.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java67
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java27
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDragListener.kt7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java47
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt86
-rw-r--r--libs/hwui/OWNERS1
-rw-r--r--packages/SystemUI/Android.bp1
-rw-r--r--packages/SystemUI/compose/core/Android.bp5
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt18
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt8
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt9
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt9
-rw-r--r--packages/SystemUI/compose/scene/Android.bp5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java23
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt37
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt143
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java234
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardJankBinder.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubBlurProvider.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java166
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt39
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt116
-rw-r--r--services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java42
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java5
-rw-r--r--services/core/java/com/android/server/am/UserController.java38
-rw-r--r--services/core/java/com/android/server/pm/AppsFilterImpl.java5
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java56
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java25
-rw-r--r--services/tests/servicestests/src/com/android/server/am/UserControllerTest.java19
73 files changed, 1612 insertions, 829 deletions
diff --git a/apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java
index 7a7250b9e910..8e3ed6d9931c 100644
--- a/apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java
@@ -19,24 +19,27 @@ package android.view;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import android.content.Context;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
-@SmallTest
+@LargeTest
+@RunWith(AndroidJUnit4.class)
public class ViewConfigurationPerfTest {
@Rule
- public final BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final Context mContext = getInstrumentation().getTargetContext();
@Test
public void testGet_newViewConfiguration() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
@@ -50,7 +53,7 @@ public class ViewConfigurationPerfTest {
@Test
public void testGet_cachedViewConfiguration() {
- final BenchmarkState state = mBenchmarkRule.getState();
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
// Do `get` once to make sure there's something cached.
ViewConfiguration.get(mContext);
@@ -58,4 +61,265 @@ public class ViewConfigurationPerfTest {
ViewConfiguration.get(mContext);
}
}
+
+ @Test
+ public void testGetPressedStateDuration_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getPressedStateDuration();
+ }
+ }
+
+ @Test
+ public void testGetPressedStateDuration_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getPressedStateDuration();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getPressedStateDuration();
+ }
+ }
+
+ @Test
+ public void testGetTapTimeout_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getTapTimeout();
+ }
+ }
+
+ @Test
+ public void testGetTapTimeout_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getTapTimeout();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getTapTimeout();
+ }
+ }
+
+ @Test
+ public void testGetJumpTapTimeout_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getJumpTapTimeout();
+ }
+ }
+
+ @Test
+ public void testGetJumpTapTimeout_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getJumpTapTimeout();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getJumpTapTimeout();
+ }
+ }
+
+ @Test
+ public void testGetDoubleTapTimeout_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getDoubleTapTimeout();
+ }
+ }
+
+ @Test
+ public void testGetDoubleTapTimeout_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getDoubleTapTimeout();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getDoubleTapTimeout();
+ }
+ }
+
+ @Test
+ public void testGetDoubleTapMinTime_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getDoubleTapMinTime();
+ }
+ }
+
+ @Test
+ public void testGetDoubleTapMinTime_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getDoubleTapMinTime();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getDoubleTapMinTime();
+ }
+ }
+
+ @Test
+ public void testGetZoomControlsTimeout_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getZoomControlsTimeout();
+ }
+ }
+
+ @Test
+ public void testGetZoomControlsTimeout_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getZoomControlsTimeout();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getZoomControlsTimeout();
+ }
+ }
+
+ @Test
+ public void testGetLongPressTimeout() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getLongPressTimeout();
+ }
+ }
+
+ @Test
+ public void testGetMultiPressTimeout() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getMultiPressTimeout();
+ }
+ }
+
+ @Test
+ public void testGetKeyRepeatTimeout() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getKeyRepeatTimeout();
+ }
+ }
+
+ @Test
+ public void testGetKeyRepeatDelay() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getKeyRepeatDelay();
+ }
+ }
+
+ @Test
+ public void testGetHoverTapSlop_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getHoverTapSlop();
+ }
+ }
+
+ @Test
+ public void testGetHoverTapSlop_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getHoverTapSlop();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getHoverTapSlop();
+ }
+ }
+
+ @Test
+ public void testGetScrollFriction_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getScrollFriction();
+ }
+ }
+
+ @Test
+ public void testGetScrollFriction_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getScrollFriction();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getScrollFriction();
+ }
+ }
+
+ @Test
+ public void testGetDefaultActionModeHideDuration_unCached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ state.pauseTiming();
+ // Reset any caches.
+ ViewConfiguration.resetCacheForTesting();
+ state.resumeTiming();
+
+ ViewConfiguration.getDefaultActionModeHideDuration();
+ }
+ }
+
+ @Test
+ public void testGetDefaultActionModeHideDuration_cached() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ // Do `get` once to make sure the value gets cached.
+ ViewConfiguration.getDefaultActionModeHideDuration();
+
+ while (state.keepRunning()) {
+ ViewConfiguration.getDefaultActionModeHideDuration();
+ }
+ }
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 9871d713178e..ab8131ba5126 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -264,6 +264,8 @@ public class AppStandbyController
@GuardedBy("mCarrierPrivilegedLock")
private boolean mHaveCarrierPrivilegedApps;
+ private final boolean mHasFeatureTelephonySubscription;
+
/** List of carrier-privileged apps that should be excluded from standby */
@GuardedBy("mCarrierPrivilegedLock")
private List<String> mCarrierPrivilegedApps;
@@ -603,6 +605,8 @@ public class AppStandbyController
mContext = mInjector.getContext();
mHandler = new AppStandbyHandler(mInjector.getLooper());
mPackageManager = mContext.getPackageManager();
+ mHasFeatureTelephonySubscription = mPackageManager.hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION);
DeviceStateReceiver deviceStateReceiver = new DeviceStateReceiver();
IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
@@ -1515,7 +1519,7 @@ public class AppStandbyController
}
// Check this last, as it can be the most expensive check
- if (isCarrierApp(packageName)) {
+ if (mHasFeatureTelephonySubscription && isCarrierApp(packageName)) {
return STANDBY_BUCKET_EXEMPTED;
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 2dead565fa85..f2e7e8513116 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -17,7 +17,6 @@
package android.app;
import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;
-import static android.app.PropertyInvalidatedCache.createSystemCacheKey;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED;
import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_NOT_COLORED;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
@@ -1146,12 +1145,16 @@ public class ApplicationPackageManager extends PackageManager {
}
}
- private static final String CACHE_KEY_PACKAGES_FOR_UID_PROPERTY =
- createSystemCacheKey("get_packages_for_uid");
- private static final PropertyInvalidatedCache<Integer, GetPackagesForUidResult>
- mGetPackagesForUidCache =
- new PropertyInvalidatedCache<Integer, GetPackagesForUidResult>(
- 1024, CACHE_KEY_PACKAGES_FOR_UID_PROPERTY) {
+ private static final String CACHE_KEY_PACKAGES_FOR_UID_API = "get_packages_for_uid";
+
+ /** @hide */
+ @VisibleForTesting
+ public static final PropertyInvalidatedCache<Integer, GetPackagesForUidResult>
+ sGetPackagesForUidCache = new PropertyInvalidatedCache<>(
+ new PropertyInvalidatedCache.Args(MODULE_SYSTEM)
+ .maxEntries(1024).api(CACHE_KEY_PACKAGES_FOR_UID_API).cacheNulls(true),
+ CACHE_KEY_PACKAGES_FOR_UID_API, null) {
+
@Override
public GetPackagesForUidResult recompute(Integer uid) {
try {
@@ -1170,17 +1173,17 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public String[] getPackagesForUid(int uid) {
- return mGetPackagesForUidCache.query(uid).value();
+ return sGetPackagesForUidCache.query(uid).value();
}
/** @hide */
public static void disableGetPackagesForUidCache() {
- mGetPackagesForUidCache.disableLocal();
+ sGetPackagesForUidCache.disableLocal();
}
/** @hide */
public static void invalidateGetPackagesForUidCache() {
- PropertyInvalidatedCache.invalidateCache(CACHE_KEY_PACKAGES_FOR_UID_PROPERTY);
+ sGetPackagesForUidCache.invalidateCache();
}
@Override
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index bfb33f2b7cb1..c573161f30cc 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -1163,6 +1163,17 @@ public class PropertyInvalidatedCache<Query, Result> {
}
/**
+ * Return the current cache nonce.
+ * @hide
+ */
+ @VisibleForTesting
+ public long getNonce() {
+ synchronized (mLock) {
+ return mNonce.getNonce();
+ }
+ }
+
+ /**
* Complete key prefixes.
*/
private static final String PREFIX_TEST = CACHE_KEY_PREFIX + "." + MODULE_TEST + ".";
@@ -1314,7 +1325,7 @@ public class PropertyInvalidatedCache<Query, Result> {
/**
* Burst a property name into module and api. Throw if the key is invalid. This method is
- * used in to transition legacy cache constructors to the args constructor.
+ * used to transition legacy cache constructors to the Args constructor.
*/
private static Args argsFromProperty(@NonNull String name) {
throwIfInvalidCacheKey(name);
@@ -1327,6 +1338,15 @@ public class PropertyInvalidatedCache<Query, Result> {
}
/**
+ * Return the API porting of a legacy property. This method is used to transition caches to
+ * the Args constructor.
+ * @hide
+ */
+ public static String apiFromProperty(@NonNull String name) {
+ return argsFromProperty(name).mApi;
+ }
+
+ /**
* Make a new property invalidated cache. This constructor names the cache after the
* property name. New clients should prefer the constructor that takes an explicit
* cache name.
@@ -2036,11 +2056,11 @@ public class PropertyInvalidatedCache<Query, Result> {
}
/**
- * Disable all caches in the local process. This is primarily useful for testing when
- * the test needs to bypass the cache or when the test is for a server, and the test
- * process does not have privileges to write SystemProperties. Once disabled it is not
- * possible to re-enable caching in the current process. If a client wants to
- * temporarily disable caching, use the corking mechanism.
+ * Disable all caches in the local process. This is primarily useful for testing when the
+ * test needs to bypass the cache or when the test is for a server, and the test process does
+ * not have privileges to write the nonce. Once disabled it is not possible to re-enable
+ * caching in the current process. See {@link #testPropertyName} for a more focused way to
+ * bypass caches when the test is for a server.
* @hide
*/
public static void disableForTestMode() {
diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java
index 0a3891fe47a1..a66d59ba9cb6 100644
--- a/core/java/android/app/appfunctions/AppFunctionManager.java
+++ b/core/java/android/app/appfunctions/AppFunctionManager.java
@@ -27,6 +27,7 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.UserHandleAware;
+import android.app.appfunctions.AppFunctionManagerHelper.AppFunctionNotFoundException;
import android.app.appsearch.AppSearchManager;
import android.content.Context;
import android.os.CancellationSignal;
@@ -325,8 +326,28 @@ public final class AppFunctionManager {
return;
}
+ // Wrap the callback to convert AppFunctionNotFoundException to IllegalArgumentException
+ // to match the documentation.
+ OutcomeReceiver<Boolean, Exception> callbackWithExceptionInterceptor =
+ new OutcomeReceiver<>() {
+ @Override
+ public void onResult(@NonNull Boolean result) {
+ callback.onResult(result);
+ }
+
+ @Override
+ public void onError(@NonNull Exception exception) {
+ if (exception instanceof AppFunctionNotFoundException) {
+ exception = new IllegalArgumentException(exception);
+ }
+ callback.onError(exception);
+ }
+ };
+
AppFunctionManagerHelper.isAppFunctionEnabled(
- functionIdentifier, targetPackage, appSearchManager, executor, callback);
+ functionIdentifier, targetPackage, appSearchManager, executor,
+ callbackWithExceptionInterceptor);
+
}
private static class CallbackWrapper extends IAppFunctionEnabledCallback.Stub {
diff --git a/core/java/android/app/appfunctions/AppFunctionManagerHelper.java b/core/java/android/app/appfunctions/AppFunctionManagerHelper.java
index cc3ca03f423d..83abc048af8a 100644
--- a/core/java/android/app/appfunctions/AppFunctionManagerHelper.java
+++ b/core/java/android/app/appfunctions/AppFunctionManagerHelper.java
@@ -60,8 +60,8 @@ public class AppFunctionManagerHelper {
* <p>If operation fails, the callback's {@link OutcomeReceiver#onError} is called with errors:
*
* <ul>
- * <li>{@link IllegalArgumentException}, if the function is not found or the caller does not
- * have access to it.
+ * <li>{@link AppFunctionNotFoundException}, if the function is not found or the caller does
+ * not have access to it.
* </ul>
*
* @param functionIdentifier the identifier of the app function to check (unique within the
@@ -216,7 +216,7 @@ public class AppFunctionManagerHelper {
private static @NonNull Exception failedResultToException(
@NonNull AppSearchResult appSearchResult) {
return switch (appSearchResult.getResultCode()) {
- case AppSearchResult.RESULT_INVALID_ARGUMENT -> new IllegalArgumentException(
+ case AppSearchResult.RESULT_INVALID_ARGUMENT -> new AppFunctionNotFoundException(
appSearchResult.getErrorMessage());
case AppSearchResult.RESULT_IO_ERROR -> new IOException(
appSearchResult.getErrorMessage());
@@ -225,4 +225,15 @@ public class AppFunctionManagerHelper {
default -> new IllegalStateException(appSearchResult.getErrorMessage());
};
}
+
+ /**
+ * Throws when the app function is not found.
+ *
+ * @hide
+ */
+ public static class AppFunctionNotFoundException extends RuntimeException {
+ private AppFunctionNotFoundException(@NonNull String errorMessage) {
+ super(errorMessage);
+ }
+ }
}
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index fcdb02ab5da2..c3dc257e6535 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -125,3 +125,11 @@ flag {
description: "Show virtual devices in Settings"
bug: "338974320"
}
+
+flag {
+ name: "migrate_viewconfiguration_constants_to_resources"
+ namespace: "virtual_devices"
+ description: "Use resources instead of constants in ViewConfiguration"
+ is_fixed_read_only: true
+ bug: "370928384"
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0369b7d9bc28..6ae2df2cd7a2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;
import static android.content.pm.SigningInfo.AppSigningSchemeVersion;
import static android.media.audio.Flags.FLAG_FEATURE_SPATIAL_AUDIO_HEADTRACKING_LOW_LATENCY;
@@ -11659,11 +11660,22 @@ public abstract class PackageManager {
}
}
- private static final PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>
- sApplicationInfoCache =
- new PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>(
- 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE,
- "getApplicationInfo") {
+ private static String packageInfoApi() {
+ return PropertyInvalidatedCache.apiFromProperty(
+ PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE);
+ }
+
+ // The maximum number of entries to keep in the packageInfo and applicationInfo caches.
+ private final static int MAX_INFO_CACHE_ENTRIES = 2048;
+
+ /** @hide */
+ @VisibleForTesting
+ public static final PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>
+ sApplicationInfoCache = new PropertyInvalidatedCache<>(
+ new PropertyInvalidatedCache.Args(MODULE_SYSTEM)
+ .maxEntries(MAX_INFO_CACHE_ENTRIES).api(packageInfoApi()).cacheNulls(true),
+ "getApplicationInfo", null) {
+
@Override
public ApplicationInfo recompute(ApplicationInfoQuery query) {
return getApplicationInfoAsUserUncached(
@@ -11749,10 +11761,11 @@ public abstract class PackageManager {
}
private static final PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>
- sPackageInfoCache =
- new PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>(
- 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE,
- "getPackageInfo") {
+ sPackageInfoCache = new PropertyInvalidatedCache<>(
+ new PropertyInvalidatedCache.Args(MODULE_SYSTEM)
+ .maxEntries(MAX_INFO_CACHE_ENTRIES).api(packageInfoApi()).cacheNulls(true),
+ "getPackageInfo", null) {
+
@Override
public PackageInfo recompute(PackageInfoQuery query) {
return getPackageInfoAsUserUncached(
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 507f8f4fecad..bcb7ebfb286f 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -67,6 +67,7 @@ import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -1704,7 +1705,9 @@ public final class CameraManager {
return ICameraService.ROTATION_OVERRIDE_NONE;
}
- if (context != null) {
+ // Isolated process does not have access to ActivityTaskManager service, which is used
+ // indirectly in `ActivityManager.getAppTasks()`.
+ if (context != null && !Process.isIsolated()) {
final ActivityManager activityManager = context.getSystemService(ActivityManager.class);
if (activityManager != null) {
for (ActivityManager.AppTask appTask : activityManager.getAppTasks()) {
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index e79b2e7becce..26044545b8d1 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -45,7 +45,8 @@ import java.util.function.BiFunction;
* {@link PersistableBundle} subclass.
*/
@android.ravenwood.annotation.RavenwoodKeepWholeClass
-public class BaseBundle {
+@SuppressWarnings("HiddenSuperclass")
+public class BaseBundle implements Parcel.ClassLoaderProvider {
/** @hide */
protected static final String TAG = "Bundle";
static final boolean DEBUG = false;
@@ -311,8 +312,9 @@ public class BaseBundle {
/**
* Return the ClassLoader currently associated with this Bundle.
+ * @hide
*/
- ClassLoader getClassLoader() {
+ public ClassLoader getClassLoader() {
return mClassLoader;
}
@@ -426,6 +428,9 @@ public class BaseBundle {
if ((mFlags & Bundle.FLAG_VERIFY_TOKENS_PRESENT) != 0) {
Intent.maybeMarkAsMissingCreatorToken(object);
}
+ } else if (object instanceof Bundle) {
+ Bundle bundle = (Bundle) object;
+ bundle.setClassLoaderSameAsContainerBundleWhenRetrievedFirstTime(this);
}
return (clazz != null) ? clazz.cast(object) : (T) object;
}
@@ -499,7 +504,7 @@ public class BaseBundle {
int[] numLazyValues = new int[]{0};
try {
parcelledData.readArrayMap(map, count, !parcelledByNative,
- /* lazy */ ownsParcel, mClassLoader, numLazyValues);
+ /* lazy */ ownsParcel, this, numLazyValues);
} catch (BadParcelableException e) {
if (sShouldDefuse) {
Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index a24dc5739b7e..c0591e6899b6 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -141,6 +141,8 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
STRIPPED.putInt("STRIPPED", 1);
}
+ private boolean isFirstRetrievedFromABundle = false;
+
/**
* Constructs a new, empty Bundle.
*/
@@ -382,7 +384,15 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
bundle.unparcel();
mOwnsLazyValues = false;
bundle.mOwnsLazyValues = false;
- mMap.putAll(bundle.mMap);
+ int N = bundle.mMap.size();
+ for (int i = 0; i < N; i++) {
+ String key = bundle.mMap.keyAt(i);
+ Object value = bundle.mMap.valueAt(i);
+ if (value instanceof Bundle) {
+ ((Bundle) value).isFirstRetrievedFromABundle = true;
+ }
+ mMap.put(key, value);
+ }
// FD and Binders state is now known if and only if both bundles already knew
if ((bundle.mFlags & FLAG_HAS_FDS) != 0) {
@@ -592,6 +602,8 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
mFlags &= ~FLAG_HAS_BINDERS_KNOWN;
if (intentClass != null && intentClass.isInstance(value)) {
setHasIntent(true);
+ } else if (value instanceof Bundle) {
+ ((Bundle) value).isFirstRetrievedFromABundle = true;
}
}
@@ -793,6 +805,9 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
*/
public void putBundle(@Nullable String key, @Nullable Bundle value) {
unparcel();
+ if (value != null) {
+ value.isFirstRetrievedFromABundle = true;
+ }
mMap.put(key, value);
}
@@ -1020,7 +1035,9 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
return null;
}
try {
- return (Bundle) o;
+ Bundle bundle = (Bundle) o;
+ bundle.setClassLoaderSameAsContainerBundleWhenRetrievedFirstTime(this);
+ return bundle;
} catch (ClassCastException e) {
typeWarning(key, o, "Bundle", e);
return null;
@@ -1028,6 +1045,21 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
}
/**
+ * Set the ClassLoader of a bundle to its container bundle. This is necessary so that when a
+ * bundle's ClassLoader is changed, it can be propagated to its children. Do this only when it
+ * is retrieved from the container bundle first time though. Once it is accessed outside of its
+ * container, its ClassLoader should no longer be changed by its container anymore.
+ *
+ * @param containerBundle the bundle this bundle is retrieved from.
+ */
+ void setClassLoaderSameAsContainerBundleWhenRetrievedFirstTime(BaseBundle containerBundle) {
+ if (!isFirstRetrievedFromABundle) {
+ setClassLoader(containerBundle.getClassLoader());
+ isFirstRetrievedFromABundle = true;
+ }
+ }
+
+ /**
* Returns the value associated with the given key, or {@code null} if
* no mapping of the desired type exists for the given key or a {@code null}
* value is explicitly associated with the key.
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index e58934746c14..49d3f06eb80f 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -46,6 +46,7 @@ import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import dalvik.annotation.optimization.CriticalNative;
@@ -4661,7 +4662,7 @@ public final class Parcel {
* @hide
*/
@Nullable
- public Object readLazyValue(@Nullable ClassLoader loader) {
+ private Object readLazyValue(@Nullable ClassLoaderProvider loaderProvider) {
int start = dataPosition();
int type = readInt();
if (isLengthPrefixed(type)) {
@@ -4672,12 +4673,17 @@ public final class Parcel {
int end = MathUtils.addOrThrow(dataPosition(), objectLength);
int valueLength = end - start;
setDataPosition(end);
- return new LazyValue(this, start, valueLength, type, loader);
+ return new LazyValue(this, start, valueLength, type, loaderProvider);
} else {
- return readValue(type, loader, /* clazz */ null);
+ return readValue(type, getClassLoader(loaderProvider), /* clazz */ null);
}
}
+ @Nullable
+ private static ClassLoader getClassLoader(@Nullable ClassLoaderProvider loaderProvider) {
+ return loaderProvider == null ? null : loaderProvider.getClassLoader();
+ }
+
private static final class LazyValue implements BiFunction<Class<?>, Class<?>[], Object> {
/**
@@ -4691,7 +4697,12 @@ public final class Parcel {
private final int mPosition;
private final int mLength;
private final int mType;
- @Nullable private final ClassLoader mLoader;
+ // this member is set when a bundle that includes a LazyValue is unparceled. But it is used
+ // when apply method is called. Between these 2 events, the bundle's ClassLoader could have
+ // changed. Let the bundle be a ClassLoaderProvider allows the bundle provides its current
+ // ClassLoader at the time apply method is called.
+ @NonNull
+ private final ClassLoaderProvider mLoaderProvider;
@Nullable private Object mObject;
/**
@@ -4702,12 +4713,13 @@ public final class Parcel {
*/
@Nullable private volatile Parcel mSource;
- LazyValue(Parcel source, int position, int length, int type, @Nullable ClassLoader loader) {
+ LazyValue(Parcel source, int position, int length, int type,
+ @NonNull ClassLoaderProvider loaderProvider) {
mSource = requireNonNull(source);
mPosition = position;
mLength = length;
mType = type;
- mLoader = loader;
+ mLoaderProvider = loaderProvider;
}
@Override
@@ -4720,7 +4732,8 @@ public final class Parcel {
int restore = source.dataPosition();
try {
source.setDataPosition(mPosition);
- mObject = source.readValue(mLoader, clazz, itemTypes);
+ mObject = source.readValue(mLoaderProvider.getClassLoader(), clazz,
+ itemTypes);
} finally {
source.setDataPosition(restore);
}
@@ -4758,6 +4771,12 @@ public final class Parcel {
return Parcel.hasFileDescriptors(mObject);
}
+ /** @hide */
+ @VisibleForTesting
+ public ClassLoader getClassLoader() {
+ return mLoaderProvider.getClassLoader();
+ }
+
@Override
public String toString() {
return (mSource != null)
@@ -4793,7 +4812,8 @@ public final class Parcel {
return Objects.equals(mObject, value.mObject);
}
// Better safely fail here since this could mean we get different objects.
- if (!Objects.equals(mLoader, value.mLoader)) {
+ if (!Objects.equals(mLoaderProvider.getClassLoader(),
+ value.mLoaderProvider.getClassLoader())) {
return false;
}
// Otherwise compare metadata prior to comparing payload.
@@ -4807,10 +4827,24 @@ public final class Parcel {
@Override
public int hashCode() {
// Accessing mSource first to provide memory barrier for mObject
- return Objects.hash(mSource == null, mObject, mLoader, mType, mLength);
+ return Objects.hash(mSource == null, mObject, mLoaderProvider.getClassLoader(), mType,
+ mLength);
}
}
+ /**
+ * Provides a ClassLoader.
+ * @hide
+ */
+ public interface ClassLoaderProvider {
+ /**
+ * Returns a ClassLoader.
+ *
+ * @return ClassLoader
+ */
+ ClassLoader getClassLoader();
+ }
+
/** Same as {@link #readValue(ClassLoader, Class, Class[])} without any item types. */
private <T> T readValue(int type, @Nullable ClassLoader loader, @Nullable Class<T> clazz) {
// Avoids allocating Class[0] array
@@ -5551,8 +5585,8 @@ public final class Parcel {
}
private void readArrayMapInternal(@NonNull ArrayMap<? super String, Object> outVal,
- int size, @Nullable ClassLoader loader) {
- readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loader, null);
+ int size, @Nullable ClassLoaderProvider loaderProvider) {
+ readArrayMap(outVal, size, /* sorted */ true, /* lazy */ false, loaderProvider, null);
}
/**
@@ -5566,11 +5600,12 @@ public final class Parcel {
* @hide
*/
void readArrayMap(ArrayMap<? super String, Object> map, int size, boolean sorted,
- boolean lazy, @Nullable ClassLoader loader, int[] lazyValueCount) {
+ boolean lazy, @Nullable ClassLoaderProvider loaderProvider, int[] lazyValueCount) {
ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, size);
while (size > 0) {
String key = readString();
- Object value = (lazy) ? readLazyValue(loader) : readValue(loader);
+ Object value = (lazy) ? readLazyValue(loaderProvider) : readValue(
+ getClassLoader(loaderProvider));
if (value instanceof LazyValue) {
lazyValueCount[0]++;
}
@@ -5591,12 +5626,12 @@ public final class Parcel {
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void readArrayMap(@NonNull ArrayMap<? super String, Object> outVal,
- @Nullable ClassLoader loader) {
+ @Nullable ClassLoaderProvider loaderProvider) {
final int N = readInt();
if (N < 0) {
return;
}
- readArrayMapInternal(outVal, N, loader);
+ readArrayMapInternal(outVal, N, loaderProvider);
}
/**
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 9e97a8eb58aa..2895bf3f846a 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -21,7 +21,9 @@ import android.annotation.NonNull;
import android.annotation.TestApi;
import android.annotation.UiContext;
import android.app.Activity;
+import android.app.ActivityThread;
import android.app.AppGlobals;
+import android.app.Application;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Configuration;
@@ -39,14 +41,13 @@ import android.util.SparseArray;
import android.util.TypedValue;
import android.view.flags.Flags;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
/**
* Contains methods to standard constants used in the UI for timeouts, sizes, and distances.
*/
public class ViewConfiguration {
- private static final String TAG = "ViewConfiguration";
-
/**
* Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
* dips
@@ -349,6 +350,8 @@ public class ViewConfiguration {
*/
private static final int SMART_SELECTION_INITIALIZING_TIMEOUT_IN_MILLISECOND = 500;
+ private static ResourceCache sResourceCache = new ResourceCache();
+
private final boolean mConstructedWithContext;
private final int mEdgeSlop;
private final int mFadingEdgeLength;
@@ -374,7 +377,6 @@ public class ViewConfiguration {
private final int mOverscrollDistance;
private final int mOverflingDistance;
private final boolean mViewTouchScreenHapticScrollFeedbackEnabled;
- @UnsupportedAppUsage
private final boolean mFadingMarqueeEnabled;
private final long mGlobalActionsKeyTimeout;
private final float mVerticalScrollFactor;
@@ -468,14 +470,12 @@ public class ViewConfiguration {
mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
- mScrollbarSize = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_scrollbarSize);
+ mScrollbarSize = res.getDimensionPixelSize(R.dimen.config_scrollbarSize);
mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
final TypedValue multiplierValue = new TypedValue();
- res.getValue(
- com.android.internal.R.dimen.config_ambiguousGestureMultiplier,
+ res.getValue(R.dimen.config_ambiguousGestureMultiplier,
multiplierValue,
true /*resolveRefs*/);
mAmbiguousGestureMultiplier = Math.max(1.0f, multiplierValue.getFloat());
@@ -488,8 +488,7 @@ public class ViewConfiguration {
mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
if (!sHasPermanentMenuKeySet) {
- final int configVal = res.getInteger(
- com.android.internal.R.integer.config_overrideHasPermanentMenuKey);
+ final int configVal = res.getInteger(R.integer.config_overrideHasPermanentMenuKey);
switch (configVal) {
default:
@@ -516,32 +515,27 @@ public class ViewConfiguration {
}
}
- mFadingMarqueeEnabled = res.getBoolean(
- com.android.internal.R.bool.config_ui_enableFadingMarquee);
- mTouchSlop = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
+ mFadingMarqueeEnabled = res.getBoolean(R.bool.config_ui_enableFadingMarquee);
+ mTouchSlop = res.getDimensionPixelSize(R.dimen.config_viewConfigurationTouchSlop);
mHandwritingSlop = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_viewConfigurationHandwritingSlop);
- mHoverSlop = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_viewConfigurationHoverSlop);
+ R.dimen.config_viewConfigurationHandwritingSlop);
+ mHoverSlop = res.getDimensionPixelSize(R.dimen.config_viewConfigurationHoverSlop);
mMinScrollbarTouchTarget = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_minScrollbarTouchTarget);
+ R.dimen.config_minScrollbarTouchTarget);
mPagingTouchSlop = mTouchSlop * 2;
mDoubleTapTouchSlop = mTouchSlop;
mHandwritingGestureLineMargin = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_viewConfigurationHandwritingGestureLineMargin);
+ R.dimen.config_viewConfigurationHandwritingGestureLineMargin);
- mMinimumFlingVelocity = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_viewMinFlingVelocity);
- mMaximumFlingVelocity = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_viewMaxFlingVelocity);
+ mMinimumFlingVelocity = res.getDimensionPixelSize(R.dimen.config_viewMinFlingVelocity);
+ mMaximumFlingVelocity = res.getDimensionPixelSize(R.dimen.config_viewMaxFlingVelocity);
int configMinRotaryEncoderFlingVelocity = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_viewMinRotaryEncoderFlingVelocity);
+ R.dimen.config_viewMinRotaryEncoderFlingVelocity);
int configMaxRotaryEncoderFlingVelocity = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_viewMaxRotaryEncoderFlingVelocity);
+ R.dimen.config_viewMaxRotaryEncoderFlingVelocity);
if (configMinRotaryEncoderFlingVelocity < 0 || configMaxRotaryEncoderFlingVelocity < 0) {
mMinimumRotaryEncoderFlingVelocity = NO_FLING_MIN_VELOCITY;
mMaximumRotaryEncoderFlingVelocity = NO_FLING_MAX_VELOCITY;
@@ -551,8 +545,7 @@ public class ViewConfiguration {
}
int configRotaryEncoderHapticScrollFeedbackTickIntervalPixels =
- res.getDimensionPixelSize(
- com.android.internal.R.dimen
+ res.getDimensionPixelSize(R.dimen
.config_rotaryEncoderAxisScrollTickInterval);
mRotaryEncoderHapticScrollFeedbackTickIntervalPixels =
configRotaryEncoderHapticScrollFeedbackTickIntervalPixels > 0
@@ -560,41 +553,31 @@ public class ViewConfiguration {
: NO_HAPTIC_SCROLL_TICK_INTERVAL;
mRotaryEncoderHapticScrollFeedbackEnabled =
- res.getBoolean(
- com.android.internal.R.bool
+ res.getBoolean(R.bool
.config_viewRotaryEncoderHapticScrollFedbackEnabled);
- mGlobalActionsKeyTimeout = res.getInteger(
- com.android.internal.R.integer.config_globalActionsKeyTimeout);
+ mGlobalActionsKeyTimeout = res.getInteger(R.integer.config_globalActionsKeyTimeout);
- mHorizontalScrollFactor = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_horizontalScrollFactor);
- mVerticalScrollFactor = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_verticalScrollFactor);
+ mHorizontalScrollFactor = res.getDimensionPixelSize(R.dimen.config_horizontalScrollFactor);
+ mVerticalScrollFactor = res.getDimensionPixelSize(R.dimen.config_verticalScrollFactor);
mShowMenuShortcutsWhenKeyboardPresent = res.getBoolean(
- com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent);
+ R.bool.config_showMenuShortcutsWhenKeyboardPresent);
- mMinScalingSpan = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_minScalingSpan);
+ mMinScalingSpan = res.getDimensionPixelSize(R.dimen.config_minScalingSpan);
- mScreenshotChordKeyTimeout = res.getInteger(
- com.android.internal.R.integer.config_screenshotChordKeyTimeout);
+ mScreenshotChordKeyTimeout = res.getInteger(R.integer.config_screenshotChordKeyTimeout);
mSmartSelectionInitializedTimeout = res.getInteger(
- com.android.internal.R.integer.config_smartSelectionInitializedTimeoutMillis);
+ R.integer.config_smartSelectionInitializedTimeoutMillis);
mSmartSelectionInitializingTimeout = res.getInteger(
- com.android.internal.R.integer.config_smartSelectionInitializingTimeoutMillis);
- mPreferKeepClearForFocusEnabled = res.getBoolean(
- com.android.internal.R.bool.config_preferKeepClearForFocus);
+ R.integer.config_smartSelectionInitializingTimeoutMillis);
+ mPreferKeepClearForFocusEnabled = res.getBoolean(R.bool.config_preferKeepClearForFocus);
mViewBasedRotaryEncoderScrollHapticsEnabledConfig =
- res.getBoolean(
- com.android.internal.R.bool.config_viewBasedRotaryEncoderHapticsEnabled);
+ res.getBoolean(R.bool.config_viewBasedRotaryEncoderHapticsEnabled);
mViewTouchScreenHapticScrollFeedbackEnabled =
Flags.enableScrollFeedbackForTouch()
- ? res.getBoolean(
- com.android.internal.R.bool
- .config_viewTouchScreenHapticScrollFeedbackEnabled)
+ ? res.getBoolean(R.bool.config_viewTouchScreenHapticScrollFeedbackEnabled)
: false;
}
@@ -632,6 +615,7 @@ public class ViewConfiguration {
@VisibleForTesting
public static void resetCacheForTesting() {
sConfigurations.clear();
+ sResourceCache = new ResourceCache();
}
/**
@@ -707,7 +691,7 @@ public class ViewConfiguration {
* components.
*/
public static int getPressedStateDuration() {
- return PRESSED_STATE_DURATION;
+ return sResourceCache.getPressedStateDuration();
}
/**
@@ -752,7 +736,7 @@ public class ViewConfiguration {
* considered to be a tap.
*/
public static int getTapTimeout() {
- return TAP_TIMEOUT;
+ return sResourceCache.getTapTimeout();
}
/**
@@ -761,7 +745,7 @@ public class ViewConfiguration {
* considered to be a tap.
*/
public static int getJumpTapTimeout() {
- return JUMP_TAP_TIMEOUT;
+ return sResourceCache.getJumpTapTimeout();
}
/**
@@ -770,7 +754,7 @@ public class ViewConfiguration {
* double-tap.
*/
public static int getDoubleTapTimeout() {
- return DOUBLE_TAP_TIMEOUT;
+ return sResourceCache.getDoubleTapTimeout();
}
/**
@@ -782,7 +766,7 @@ public class ViewConfiguration {
*/
@UnsupportedAppUsage
public static int getDoubleTapMinTime() {
- return DOUBLE_TAP_MIN_TIME;
+ return sResourceCache.getDoubleTapMinTime();
}
/**
@@ -792,7 +776,7 @@ public class ViewConfiguration {
* @hide
*/
public static int getHoverTapTimeout() {
- return HOVER_TAP_TIMEOUT;
+ return sResourceCache.getHoverTapTimeout();
}
/**
@@ -803,7 +787,7 @@ public class ViewConfiguration {
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static int getHoverTapSlop() {
- return HOVER_TAP_SLOP;
+ return sResourceCache.getHoverTapSlop();
}
/**
@@ -1044,7 +1028,7 @@ public class ViewConfiguration {
* in milliseconds.
*/
public static long getZoomControlsTimeout() {
- return ZOOM_CONTROLS_TIMEOUT;
+ return sResourceCache.getZoomControlsTimeout();
}
/**
@@ -1113,14 +1097,14 @@ public class ViewConfiguration {
* friction.
*/
public static float getScrollFriction() {
- return SCROLL_FRICTION;
+ return sResourceCache.getScrollFriction();
}
/**
* @return the default duration in milliseconds for {@link ActionMode#hide(long)}.
*/
public static long getDefaultActionModeHideDuration() {
- return ACTION_MODE_HIDE_DURATION_DEFAULT;
+ return sResourceCache.getDefaultActionModeHideDuration();
}
/**
@@ -1471,8 +1455,137 @@ public class ViewConfiguration {
return HOVER_TOOLTIP_HIDE_SHORT_TIMEOUT;
}
- private static final int getDisplayDensity(Context context) {
+ private static int getDisplayDensity(Context context) {
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return (int) (100.0f * metrics.density);
}
+
+ /**
+ * Fetches resource values statically and caches them locally for fast lookup. Note that these
+ * values will not be updated during the lifetime of a process, even if resource overlays are
+ * applied.
+ */
+ private static final class ResourceCache {
+
+ private int mPressedStateDuration = -1;
+ private int mTapTimeout = -1;
+ private int mJumpTapTimeout = -1;
+ private int mDoubleTapTimeout = -1;
+ private int mDoubleTapMinTime = -1;
+ private int mHoverTapTimeout = -1;
+ private int mHoverTapSlop = -1;
+ private long mZoomControlsTimeout = -1L;
+ private float mScrollFriction = -1f;
+ private long mDefaultActionModeHideDuration = -1L;
+
+ public int getPressedStateDuration() {
+ if (mPressedStateDuration < 0) {
+ Resources resources = getCurrentResources();
+ mPressedStateDuration = resources != null
+ ? resources.getInteger(R.integer.config_pressedStateDurationMillis)
+ : PRESSED_STATE_DURATION;
+ }
+ return mPressedStateDuration;
+ }
+
+ public int getTapTimeout() {
+ if (mTapTimeout < 0) {
+ Resources resources = getCurrentResources();
+ mTapTimeout = resources != null
+ ? resources.getInteger(R.integer.config_tapTimeoutMillis)
+ : TAP_TIMEOUT;
+ }
+ return mTapTimeout;
+ }
+
+ public int getJumpTapTimeout() {
+ if (mJumpTapTimeout < 0) {
+ Resources resources = getCurrentResources();
+ mJumpTapTimeout = resources != null
+ ? resources.getInteger(R.integer.config_jumpTapTimeoutMillis)
+ : JUMP_TAP_TIMEOUT;
+ }
+ return mJumpTapTimeout;
+ }
+
+ public int getDoubleTapTimeout() {
+ if (mDoubleTapTimeout < 0) {
+ Resources resources = getCurrentResources();
+ mDoubleTapTimeout = resources != null
+ ? resources.getInteger(R.integer.config_doubleTapTimeoutMillis)
+ : DOUBLE_TAP_TIMEOUT;
+ }
+ return mDoubleTapTimeout;
+ }
+
+ public int getDoubleTapMinTime() {
+ if (mDoubleTapMinTime < 0) {
+ Resources resources = getCurrentResources();
+ mDoubleTapMinTime = resources != null
+ ? resources.getInteger(R.integer.config_doubleTapMinTimeMillis)
+ : DOUBLE_TAP_MIN_TIME;
+ }
+ return mDoubleTapMinTime;
+ }
+
+ public int getHoverTapTimeout() {
+ if (mHoverTapTimeout < 0) {
+ Resources resources = getCurrentResources();
+ mHoverTapTimeout = resources != null
+ ? resources.getInteger(R.integer.config_hoverTapTimeoutMillis)
+ : HOVER_TAP_TIMEOUT;
+ }
+ return mHoverTapTimeout;
+ }
+
+ public int getHoverTapSlop() {
+ if (mHoverTapSlop < 0) {
+ Resources resources = getCurrentResources();
+ mHoverTapSlop = resources != null
+ ? resources.getDimensionPixelSize(R.dimen.config_hoverTapSlop)
+ : HOVER_TAP_SLOP;
+ }
+ return mHoverTapSlop;
+ }
+
+ public long getZoomControlsTimeout() {
+ if (mZoomControlsTimeout < 0) {
+ Resources resources = getCurrentResources();
+ mZoomControlsTimeout = resources != null
+ ? resources.getInteger(R.integer.config_zoomControlsTimeoutMillis)
+ : ZOOM_CONTROLS_TIMEOUT;
+ }
+ return mZoomControlsTimeout;
+ }
+
+ public float getScrollFriction() {
+ if (mScrollFriction < 0) {
+ Resources resources = getCurrentResources();
+ mScrollFriction = resources != null
+ ? resources.getFloat(R.dimen.config_scrollFriction)
+ : SCROLL_FRICTION;
+ }
+ return mScrollFriction;
+ }
+
+ public long getDefaultActionModeHideDuration() {
+ if (mDefaultActionModeHideDuration < 0) {
+ Resources resources = getCurrentResources();
+ mDefaultActionModeHideDuration = resources != null
+ ? resources.getInteger(R.integer.config_defaultActionModeHideDurationMillis)
+ : ACTION_MODE_HIDE_DURATION_DEFAULT;
+ }
+ return mDefaultActionModeHideDuration;
+ }
+
+ private static Resources getCurrentResources() {
+ if (!android.companion.virtualdevice.flags.Flags
+ .migrateViewconfigurationConstantsToResources()) {
+ return null;
+ }
+ Application application = ActivityThread.currentApplication();
+ Context context = application != null ? application.getApplicationContext() : null;
+ return context != null ? context.getResources() : null;
+ }
+ }
}
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 7c5335cc753c..9085bbec949f 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -306,8 +306,15 @@ public class Cuj {
/** Track work utility view animation shrinking when scrolling down app list. */
public static final int CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK = 127;
+ /**
+ * Track task transitions
+ *
+ * <p>Tracking starts and ends with the animation.</p>
+ */
+ public static final int CUJ_DEFAULT_TASK_TO_TASK_ANIMATION = 128;
+
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
- @VisibleForTesting static final int LAST_CUJ = CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK;
+ @VisibleForTesting static final int LAST_CUJ = CUJ_DEFAULT_TASK_TO_TASK_ANIMATION;
/** @hide */
@IntDef({
@@ -426,7 +433,8 @@ public class Cuj {
CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON,
CUJ_DESKTOP_MODE_KEYBOARD_QUICK_SWITCH_APP_LAUNCH,
CUJ_LAUNCHER_WORK_UTILITY_VIEW_EXPAND,
- CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK
+ CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK,
+ CUJ_DEFAULT_TASK_TO_TASK_ANIMATION
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {}
@@ -556,6 +564,7 @@ public class Cuj {
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_KEYBOARD_QUICK_SWITCH_APP_LAUNCH] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_KEYBOARD_QUICK_SWITCH_APP_LAUNCH;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_WORK_UTILITY_VIEW_EXPAND] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_WORK_UTILITY_VIEW_EXPAND;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_WORK_UTILITY_VIEW_SHRINK;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DEFAULT_TASK_TO_TASK_ANIMATION] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DEFAULT_TASK_TO_TASK_ANIMATION;
}
private Cuj() {
@@ -806,6 +815,8 @@ public class Cuj {
return "LAUNCHER_WORK_UTILITY_VIEW_EXPAND";
case CUJ_LAUNCHER_WORK_UTILITY_VIEW_SHRINK:
return "LAUNCHER_WORK_UTILITY_VIEW_SHRINK";
+ case CUJ_DEFAULT_TASK_TO_TASK_ANIMATION:
+ return "CUJ_DEFAULT_TASK_TO_TASK_ANIMATION";
}
return "UNKNOWN";
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8db94a420e4c..37e553ea3827 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3061,6 +3061,43 @@
{@link MotionEvent#ACTION_SCROLL} event. -->
<dimen name="config_scrollFactor">64dp</dimen>
+ <!-- Duration in milliseconds of the pressed state in child components. -->
+ <integer name="config_pressedStateDurationMillis">64</integer>
+
+ <!-- Duration in milliseconds we will wait to see if a touch event is a tap or a scroll.
+ If the user does not move within this interval, it is considered to be a tap. -->
+ <integer name="config_tapTimeoutMillis">100</integer>
+
+ <!-- Duration in milliseconds we will wait to see if a touch event is a jump tap.
+ If the user does not move within this interval, it is considered to be a tap. -->
+ <integer name="config_jumpTapTimeoutMillis">500</integer>
+
+ <!-- Duration in milliseconds between the first tap's up event and the second tap's down
+ event for an interaction to be considered a double-tap. -->
+ <integer name="config_doubleTapTimeoutMillis">300</integer>
+
+ <!-- Minimum duration in milliseconds between the first tap's up event and the second tap's
+ down event for an interaction to be considered a double-tap. -->
+ <integer name="config_doubleTapMinTimeMillis">40</integer>
+
+ <!-- Maximum duration in milliseconds between a touch pad touch and release for a given touch
+ to be considered a tap (click) as opposed to a hover movement gesture. -->
+ <integer name="config_hoverTapTimeoutMillis">150</integer>
+
+ <!-- The amount of time in milliseconds that the zoom controls should be displayed on the
+ screen. -->
+ <integer name="config_zoomControlsTimeoutMillis">3000</integer>
+
+ <!-- Default duration in milliseconds for {@link ActionMode#hide(long)}. -->
+ <integer name="config_defaultActionModeHideDurationMillis">2000</integer>
+
+ <!-- Maximum distance in pixels that a touch pad touch can move before being released
+ for it to be considered a tap (click) as opposed to a hover movement gesture. -->
+ <dimen name="config_hoverTapSlop">20px</dimen>
+
+ <!-- The amount of friction applied to scrolls and flings. -->
+ <item name="config_scrollFriction" format="float" type="dimen">0.015</item>
+
<!-- Maximum number of grid columns permitted in the ResolverActivity
used for picking activities to handle an intent. -->
<integer name="config_maxResolverActivityColumns">3</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8c2ca97af493..a34fbb89c629 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4153,6 +4153,17 @@
<java-symbol type="string" name="config_headlineFontFamily" />
<java-symbol type="string" name="config_headlineFontFamilyMedium" />
+ <java-symbol type="integer" name="config_pressedStateDurationMillis" />
+ <java-symbol type="integer" name="config_tapTimeoutMillis" />
+ <java-symbol type="integer" name="config_jumpTapTimeoutMillis" />
+ <java-symbol type="integer" name="config_doubleTapTimeoutMillis" />
+ <java-symbol type="integer" name="config_doubleTapMinTimeMillis" />
+ <java-symbol type="integer" name="config_hoverTapTimeoutMillis" />
+ <java-symbol type="integer" name="config_zoomControlsTimeoutMillis" />
+ <java-symbol type="integer" name="config_defaultActionModeHideDurationMillis" />
+ <java-symbol type="dimen" name="config_hoverTapSlop" />
+ <java-symbol type="dimen" name="config_scrollFriction" />
+
<java-symbol type="drawable" name="stat_sys_vitals" />
<java-symbol type="color" name="text_color_primary" />
diff --git a/core/tests/coretests/src/android/content/IntentTest.java b/core/tests/coretests/src/android/content/IntentTest.java
index fdfb0c34cdeb..fa1948d9786c 100644
--- a/core/tests/coretests/src/android/content/IntentTest.java
+++ b/core/tests/coretests/src/android/content/IntentTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -238,4 +239,42 @@ public class IntentTest {
// Not all keys from intent are kept - clip data keys are dropped.
assertFalse(intent.getExtraIntentKeys().containsAll(originalIntentKeys));
}
+
+ @Test
+ public void testSetIntentExtrasClassLoaderEffectiveAfterExtraBundleUnparcel() {
+ Intent intent = new Intent();
+ intent.putExtra("bundle", new Bundle());
+
+ final Parcel parcel = Parcel.obtain();
+ intent.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ final Intent target = new Intent();
+ target.readFromParcel(parcel);
+ target.collectExtraIntentKeys();
+ ClassLoader cl = new ClassLoader() {
+ };
+ target.setExtrasClassLoader(cl);
+ assertThat(target.getBundleExtra("bundle").getClassLoader()).isEqualTo(cl);
+ }
+
+ @Test
+ public void testBundlePutAllClassLoader() {
+ Intent intent = new Intent();
+ Bundle b1 = new Bundle();
+ b1.putBundle("bundle", new Bundle());
+ intent.putExtra("b1", b1);
+ final Parcel parcel = Parcel.obtain();
+ intent.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ final Intent target = new Intent();
+ target.readFromParcel(parcel);
+
+ ClassLoader cl = new ClassLoader() {
+ };
+ target.setExtrasClassLoader(cl);
+ Bundle b2 = new Bundle();
+ b2.putAll(target.getBundleExtra("b1"));
+ assertThat(b2.getBundle("bundle").getClassLoader()).isEqualTo(cl);
+ }
+
}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/draganddrop/DragAndDropConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/draganddrop/DragAndDropConstants.java
index 4127adc1f901..12938db07ece 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/draganddrop/DragAndDropConstants.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/draganddrop/DragAndDropConstants.java
@@ -24,4 +24,9 @@ public class DragAndDropConstants {
* ignore drag events.
*/
public static final String EXTRA_DISALLOW_HIT_REGION = "DISALLOW_HIT_REGION";
+
+ /**
+ * An Intent extra that Launcher can use to specify the {@link android.content.pm.ShortcutInfo}
+ */
+ public static final String EXTRA_SHORTCUT_INFO = "EXTRA_SHORTCUT_INFO";
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index ddcdf9f8c617..d9489287ff42 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -54,6 +54,7 @@ import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.Flags;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
+import com.android.wm.shell.common.ComponentUtils;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.bubbles.BubbleInfo;
@@ -282,6 +283,29 @@ public class Bubble implements BubbleViewProvider {
mPackageName = intent.getPackage();
}
+ private Bubble(
+ PendingIntent intent,
+ UserHandle user,
+ String key,
+ @ShellMainThread Executor mainExecutor,
+ @ShellBackgroundThread Executor bgExecutor) {
+ mGroupKey = null;
+ mLocusId = null;
+ mFlags = 0;
+ mUser = user;
+ mIcon = null;
+ mType = BubbleType.TYPE_APP;
+ mKey = key;
+ mShowBubbleUpdateDot = false;
+ mMainExecutor = mainExecutor;
+ mBgExecutor = bgExecutor;
+ mTaskId = INVALID_TASK_ID;
+ mPendingIntent = intent;
+ mIntent = null;
+ mDesiredHeight = Integer.MAX_VALUE;
+ mPackageName = ComponentUtils.getPackageName(intent);
+ }
+
private Bubble(ShortcutInfo info, @ShellMainThread Executor mainExecutor,
@ShellBackgroundThread Executor bgExecutor) {
mGroupKey = null;
@@ -336,6 +360,15 @@ public class Bubble implements BubbleViewProvider {
}
/** Creates an app bubble. */
+ public static Bubble createAppBubble(PendingIntent intent, UserHandle user,
+ @ShellMainThread Executor mainExecutor, @ShellBackgroundThread Executor bgExecutor) {
+ return new Bubble(intent,
+ user,
+ /* key= */ getAppBubbleKeyForApp(ComponentUtils.getPackageName(intent), user),
+ mainExecutor, bgExecutor);
+ }
+
+ /** Creates an app bubble. */
public static Bubble createAppBubble(Intent intent, UserHandle user, @Nullable Icon icon,
@ShellMainThread Executor mainExecutor, @ShellBackgroundThread Executor bgExecutor) {
return new Bubble(intent,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index b93b7b86e661..8cf2370df48d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -46,6 +46,7 @@ import android.app.NotificationChannel;
import android.app.PendingIntent;
import android.app.TaskInfo;
import android.content.BroadcastReceiver;
+import android.content.ClipDescription;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -118,6 +119,7 @@ import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.bubbles.BubbleBarUpdate;
import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider;
import com.android.wm.shell.shared.bubbles.DeviceConfig;
+import com.android.wm.shell.shared.draganddrop.DragAndDropConstants;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
@@ -872,11 +874,19 @@ public class BubbleController implements ConfigurationChangeListener,
}
@Override
- public void onItemDroppedOverBubbleBarDragZone(BubbleBarLocation location, Intent appIntent,
- UserHandle userHandle) {
- if (isShowingAsBubbleBar() && BubbleAnythingFlagHelper.enableCreateAnyBubble()) {
- hideBubbleBarExpandedViewDropTarget();
- expandStackAndSelectBubble(appIntent, userHandle, location);
+ public void onItemDroppedOverBubbleBarDragZone(BubbleBarLocation location, Intent itemIntent) {
+ hideBubbleBarExpandedViewDropTarget();
+ ShortcutInfo shortcutInfo = (ShortcutInfo) itemIntent
+ .getExtra(DragAndDropConstants.EXTRA_SHORTCUT_INFO);
+ if (shortcutInfo != null) {
+ expandStackAndSelectBubble(shortcutInfo, location);
+ return;
+ }
+ UserHandle user = (UserHandle) itemIntent.getExtra(Intent.EXTRA_USER);
+ PendingIntent pendingIntent = (PendingIntent) itemIntent
+ .getExtra(ClipDescription.EXTRA_PENDING_INTENT);
+ if (pendingIntent != null && user != null) {
+ expandStackAndSelectBubble(pendingIntent, user, location);
}
}
@@ -1506,9 +1516,16 @@ public class BubbleController implements ConfigurationChangeListener,
* Expands and selects a bubble created or found via the provided shortcut info.
*
* @param info the shortcut info for the bubble.
+ * @param bubbleBarLocation optional location in case bubble bar should be repositioned.
*/
- public void expandStackAndSelectBubble(ShortcutInfo info) {
+ public void expandStackAndSelectBubble(ShortcutInfo info,
+ @Nullable BubbleBarLocation bubbleBarLocation) {
if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return;
+ if (bubbleBarLocation != null) {
+ //TODO (b/388894910) combine location update with the setSelectedBubbleAndExpandStack &
+ // fix bubble bar flicking
+ setBubbleBarLocation(bubbleBarLocation, BubbleBarLocation.UpdateSource.APP_ICON_DRAG);
+ }
Bubble b = mBubbleData.getOrCreateBubble(info); // Removes from overflow
ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - shortcut=%s", info);
if (b.isInflated()) {
@@ -1524,7 +1541,25 @@ public class BubbleController implements ConfigurationChangeListener,
*
* @param intent the intent for the bubble.
*/
- public void expandStackAndSelectBubble(Intent intent, UserHandle user,
+ public void expandStackAndSelectBubble(Intent intent, UserHandle user) {
+ if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return;
+ Bubble b = mBubbleData.getOrCreateBubble(intent, user); // Removes from overflow
+ ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", intent);
+ if (b.isInflated()) {
+ mBubbleData.setSelectedBubbleAndExpandStack(b);
+ } else {
+ b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE);
+ inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
+ }
+ }
+
+ /**
+ * Expands and selects a bubble created or found for this app.
+ *
+ * @param pendingIntent the intent for the bubble.
+ * @param bubbleBarLocation optional location in case bubble bar should be repositioned.
+ */
+ public void expandStackAndSelectBubble(PendingIntent pendingIntent, UserHandle user,
@Nullable BubbleBarLocation bubbleBarLocation) {
if (!BubbleAnythingFlagHelper.enableCreateAnyBubble()) return;
if (bubbleBarLocation != null) {
@@ -1532,8 +1567,9 @@ public class BubbleController implements ConfigurationChangeListener,
// fix bubble bar flicking
setBubbleBarLocation(bubbleBarLocation, BubbleBarLocation.UpdateSource.APP_ICON_DRAG);
}
- Bubble b = mBubbleData.getOrCreateBubble(intent, user); // Removes from overflow
- ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", intent);
+ Bubble b = mBubbleData.getOrCreateBubble(pendingIntent, user);
+ ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - pendingIntent=%s",
+ pendingIntent);
if (b.isInflated()) {
mBubbleData.setSelectedBubbleAndExpandStack(b);
} else {
@@ -2756,13 +2792,13 @@ public class BubbleController implements ConfigurationChangeListener,
@Override
public void showShortcutBubble(ShortcutInfo info) {
- mMainExecutor.execute(() -> mController.expandStackAndSelectBubble(info));
+ mMainExecutor.execute(() -> mController
+ .expandStackAndSelectBubble(info, /* bubbleBarLocation = */ null));
}
@Override
public void showAppBubble(Intent intent, UserHandle user) {
- mMainExecutor.execute(() -> mController.expandStackAndSelectBubble(intent,
- user, /* bubbleBarLocation = */ null));
+ mMainExecutor.execute(() -> mController.expandStackAndSelectBubble(intent, user));
}
@Override
@@ -2983,9 +3019,10 @@ public class BubbleController implements ConfigurationChangeListener,
@Override
public void expandStackAndSelectBubble(ShortcutInfo info) {
- mMainExecutor.execute(() -> {
- BubbleController.this.expandStackAndSelectBubble(info);
- });
+ mMainExecutor.execute(() ->
+ BubbleController.this
+ .expandStackAndSelectBubble(info, /* bubbleBarLocation = */ null)
+ );
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 96d0f6d5654e..f97133a4c3d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -471,6 +471,16 @@ public class BubbleData {
return bubbleToReturn;
}
+ Bubble getOrCreateBubble(PendingIntent pendingIntent, UserHandle user) {
+ String bubbleKey = Bubble.getAppBubbleKeyForApp(pendingIntent.getCreatorPackage(), user);
+ Bubble bubbleToReturn = findAndRemoveBubbleFromOverflow(bubbleKey);
+ if (bubbleToReturn == null) {
+ bubbleToReturn = Bubble.createAppBubble(pendingIntent, user, mMainExecutor,
+ mBgExecutor);
+ }
+ return bubbleToReturn;
+ }
+
Bubble getOrCreateBubble(TaskInfo taskInfo) {
UserHandle user = UserHandle.of(mCurrentUserId);
String bubbleKey = Bubble.getAppBubbleKeyForTask(taskInfo);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index 4a0eee861d21..e47ac61a53dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -117,15 +117,24 @@ public class BubbleTaskViewHelper {
Context context =
mContext.createContextAsUser(
mBubble.getUser(), Context.CONTEXT_RESTRICTED);
- PendingIntent pi = PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- mBubble.getIntent()
- .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
- PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
- /* options= */ null);
- mTaskView.startActivity(pi, /* fillInIntent= */ null, options,
- launchBounds);
+ Intent fillInIntent = null;
+ //first try get pending intent from the bubble
+ PendingIntent pi = mBubble.getPendingIntent();
+ if (pi == null) {
+ // if null - create new one
+ pi = PendingIntent.getActivity(
+ context,
+ /* requestCode= */ 0,
+ mBubble.getIntent()
+ .addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
+ PendingIntent.FLAG_IMMUTABLE
+ | PendingIntent.FLAG_UPDATE_CURRENT,
+ /* options= */ null);
+ } else {
+ fillInIntent = new Intent(pi.getIntent());
+ fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ mTaskView.startActivity(pi, fillInIntent, options, launchBounds);
} else if (isShortcutBubble) {
options.setLaunchedFromBubble(true);
options.setApplyActivityFlagsForBubbles(true);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDragListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDragListener.kt
index afe5c87604d9..3ff80b5ab8ac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDragListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarDragListener.kt
@@ -18,7 +18,6 @@ package com.android.wm.shell.bubbles.bar
import android.content.Intent
import android.graphics.Rect
-import android.os.UserHandle
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
/** Controller that takes care of the bubble bar drag events. */
@@ -31,11 +30,7 @@ interface BubbleBarDragListener {
fun onItemDraggedOutsideBubbleBarDropZone()
/** Called when the drop event happens over the bubble bar drop zone. */
- fun onItemDroppedOverBubbleBarDragZone(
- location: BubbleBarLocation,
- intent: Intent,
- userHandle: UserHandle
- )
+ fun onItemDroppedOverBubbleBarDragZone(location: BubbleBarLocation, itemIntent: Intent)
/**
* Returns mapping of the bubble bar locations to the corresponding
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 3c7780711a14..f48b34d0d646 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -3074,6 +3074,7 @@ class DesktopTasksController(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS
pendingIntentLaunchFlags =
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+ splashScreenStyle = SPLASH_SCREEN_STYLE_ICON
}
if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
dragAndDropFullscreenCookie = Binder()
@@ -3082,7 +3083,12 @@ class DesktopTasksController(
val wct = WindowContainerTransaction()
wct.sendPendingIntent(launchIntent, null, opts.toBundle())
if (windowingMode == WINDOWING_MODE_FREEFORM) {
- desktopModeDragAndDropTransitionHandler.handleDropEvent(wct)
+ if (DesktopModeFlags.ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX.isTrue()) {
+ // TODO b/376389593: Use a custom tab tearing transition/animation
+ startLaunchTransition(TRANSIT_OPEN, wct, launchingTaskId = null)
+ } else {
+ desktopModeDragAndDropTransitionHandler.handleDropEvent(wct)
+ }
} else {
transitions.startTransition(TRANSIT_OPEN, wct, null)
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 2571e0e36cd9..b3c1a92f5e1d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -47,7 +47,6 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
import android.view.DragEvent;
import android.view.SurfaceControl;
import android.view.View;
@@ -70,6 +69,7 @@ import com.android.wm.shell.bubbles.bar.BubbleBarDragListener;
import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.animation.Interpolators;
+import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -627,8 +627,7 @@ public class DragLayout extends LinearLayout
@Nullable
private BubbleBarLocation getBubbleBarLocation(int x, int y) {
Intent appData = mSession.appData;
- if (appData == null || appData.getExtra(Intent.EXTRA_INTENT) == null
- || appData.getExtra(Intent.EXTRA_USER) == null) {
+ if (appData == null) {
// there is no app data, so drop event over the bubble bar can not be handled
return null;
}
@@ -686,11 +685,10 @@ public class DragLayout extends LinearLayout
// Process the drop exclusive by DropTarget OR by the BubbleBar
if (mCurrentTarget != null) {
mPolicy.onDropped(mCurrentTarget, hideTaskToken);
- } else if (appData != null && mCurrentBubbleBarTarget != null) {
- Intent appIntent = (Intent) appData.getExtra(Intent.EXTRA_INTENT);
- UserHandle user = (UserHandle) appData.getExtra(Intent.EXTRA_USER);
+ } else if (appData != null && mCurrentBubbleBarTarget != null
+ && BubbleAnythingFlagHelper.enableCreateAnyBubble()) {
mBubbleBarDragListener.onItemDroppedOverBubbleBarDragZone(mCurrentBubbleBarTarget,
- appIntent, user);
+ appData);
}
// Start animating the drop UI out with the drag surface
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 0689205a1110..a5a5fd73d5c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -39,9 +39,12 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_RELAUNCH;
import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
@@ -55,6 +58,7 @@ import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
+import static com.android.internal.jank.Cuj.CUJ_DEFAULT_TASK_TO_TASK_ANIMATION;
import static com.android.internal.policy.TransitionAnimation.DEFAULT_APP_TRANSITION_DURATION;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CHANGE;
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
@@ -101,6 +105,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.ProtoLog;
@@ -144,6 +149,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
private Drawable mEnterpriseThumbnailDrawable;
+ static final InteractionJankMonitor sInteractionJankMonitor =
+ InteractionJankMonitor.getInstance();
+
private BroadcastReceiver mEnterpriseResourceUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -321,8 +329,17 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
final ArrayList<Animator> animations = new ArrayList<>();
mAnimations.put(transition, animations);
+ final boolean isTaskTransition = isTaskTransition(info);
+ if (isTaskTransition) {
+ sInteractionJankMonitor.begin(info.getRoot(0).getLeash(), mContext,
+ mMainHandler, CUJ_DEFAULT_TASK_TO_TASK_ANIMATION);
+ }
+
final Runnable onAnimFinish = () -> {
if (!animations.isEmpty()) return;
+ if (isTaskTransition) {
+ sInteractionJankMonitor.end(CUJ_DEFAULT_TASK_TO_TASK_ANIMATION);
+ }
mAnimations.remove(transition);
finishCallback.onTransitionFinished(null /* wct */);
};
@@ -678,6 +695,30 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
}
/**
+ * A task transition is defined as a transition where there is exaclty one open/to_front task
+ * and one close/to_back task. Nothing else is allowed to be included in the transition
+ */
+ public static boolean isTaskTransition(@NonNull TransitionInfo info) {
+ if (info.getChanges().size() != 2) {
+ return false;
+ }
+ boolean hasOpeningTask = false;
+ boolean hasClosingTask = false;
+
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getTaskInfo() == null) {
+ // A non-task is in the transition
+ return false;
+ }
+ int mode = change.getMode();
+ hasOpeningTask |= mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT;
+ hasClosingTask |= mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK;
+ }
+ return hasOpeningTask && hasClosingTask;
+ }
+
+ /**
* Does `info` only contain translucent visibility changes (CHANGEs are ignored). We select
* different animations and z-orders for these
*/
@@ -986,4 +1027,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|| animType == ANIM_CLIP_REVEAL || animType == ANIM_OPEN_CROSS_PROFILE_APPS
|| animType == ANIM_FROM_STYLE;
}
+
+ @Override
+ public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
+ @Nullable SurfaceControl.Transaction finishTransaction) {
+ sInteractionJankMonitor.cancel(CUJ_DEFAULT_TASK_TO_TASK_ANIMATION);
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index edb9b2d2fede..cd1c16a93475 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -5427,38 +5427,90 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- fun onUnhandledDrag_newFreeformIntent() {
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX)
+ fun onUnhandledDrag_newFreeformIntent_tabTearingAnimationBugfixFlagEnabled() {
testOnUnhandledDrag(
DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR,
PointF(1200f, 700f),
Rect(240, 700, 2160, 1900),
+ tabTearingAnimationFlagEnabled = true,
)
}
@Test
- fun onUnhandledDrag_newFreeformIntentSplitLeft() {
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX)
+ fun onUnhandledDrag_newFreeformIntent_tabTearingAnimationBugfixFlagDisabled() {
+ testOnUnhandledDrag(
+ DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR,
+ PointF(1200f, 700f),
+ Rect(240, 700, 2160, 1900),
+ tabTearingAnimationFlagEnabled = false,
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX)
+ fun onUnhandledDrag_newFreeformIntentSplitLeft_tabTearingAnimationBugfixFlagEnabled() {
+ testOnUnhandledDrag(
+ DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR,
+ PointF(50f, 700f),
+ Rect(0, 0, 500, 1000),
+ tabTearingAnimationFlagEnabled = true,
+ )
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX)
+ fun onUnhandledDrag_newFreeformIntentSplitLeft_tabTearingAnimationBugfixFlagDisabled() {
testOnUnhandledDrag(
DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR,
PointF(50f, 700f),
Rect(0, 0, 500, 1000),
+ tabTearingAnimationFlagEnabled = false,
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX)
+ fun onUnhandledDrag_newFreeformIntentSplitRight_tabTearingAnimationBugfixFlagEnabled() {
+ testOnUnhandledDrag(
+ DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR,
+ PointF(2500f, 700f),
+ Rect(500, 0, 1000, 1000),
+ tabTearingAnimationFlagEnabled = true,
)
}
@Test
- fun onUnhandledDrag_newFreeformIntentSplitRight() {
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX)
+ fun onUnhandledDrag_newFreeformIntentSplitRight_tabTearingAnimationBugfixFlagDisabled() {
testOnUnhandledDrag(
DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR,
PointF(2500f, 700f),
Rect(500, 0, 1000, 1000),
+ tabTearingAnimationFlagEnabled = false,
)
}
@Test
- fun onUnhandledDrag_newFullscreenIntent() {
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX)
+ fun onUnhandledDrag_newFullscreenIntent_tabTearingAnimationBugfixFlagEnabled() {
testOnUnhandledDrag(
DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
PointF(1200f, 50f),
Rect(),
+ tabTearingAnimationFlagEnabled = true,
+ )
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_TAB_TEARING_MINIMIZE_ANIMATION_BUGFIX)
+ fun onUnhandledDrag_newFullscreenIntent_tabTearingAnimationBugfixFlagDisabled() {
+ testOnUnhandledDrag(
+ DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+ PointF(1200f, 50f),
+ Rect(),
+ tabTearingAnimationFlagEnabled = false,
)
}
@@ -5812,6 +5864,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
indicatorType: DesktopModeVisualIndicator.IndicatorType,
inputCoordinate: PointF,
expectedBounds: Rect,
+ tabTearingAnimationFlagEnabled: Boolean,
) {
setUpLandscapeDisplay()
val task = setUpFreeformTask()
@@ -5842,6 +5895,16 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
anyOrNull(),
eq(DesktopModeVisualIndicator.DragStartState.DRAGGED_INTENT),
)
+ whenever(
+ desktopMixedTransitionHandler.startLaunchTransition(
+ eq(TRANSIT_OPEN),
+ any(),
+ anyOrNull(),
+ anyOrNull(),
+ anyOrNull(),
+ )
+ )
+ .thenReturn(Binder())
spyController.onUnhandledDrag(
mockPendingIntent,
@@ -5858,8 +5921,19 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
verify(transitions).startTransition(any(), capture(arg), anyOrNull())
} else {
expectedWindowingMode = WINDOWING_MODE_FREEFORM
- // All other launches use a special handler.
- verify(dragAndDropTransitionHandler).handleDropEvent(capture(arg))
+ if (tabTearingAnimationFlagEnabled) {
+ verify(desktopMixedTransitionHandler)
+ .startLaunchTransition(
+ eq(TRANSIT_OPEN),
+ capture(arg),
+ anyOrNull(),
+ anyOrNull(),
+ anyOrNull(),
+ )
+ } else {
+ // All other launches use a special handler.
+ verify(dragAndDropTransitionHandler).handleDropEvent(capture(arg))
+ }
}
assertThat(
ActivityOptions.fromBundle(arg.value.hierarchyOps[0].launchOptions)
diff --git a/libs/hwui/OWNERS b/libs/hwui/OWNERS
index bc174599a4d3..70d13ab8b3e5 100644
--- a/libs/hwui/OWNERS
+++ b/libs/hwui/OWNERS
@@ -4,7 +4,6 @@ alecmouri@google.com
djsollen@google.com
jreck@google.com
njawad@google.com
-scroggo@google.com
sumir@google.com
# For text, e.g. Typeface, Font, Minikin, etc.
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 744388f47d0e..1a6365433be5 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -538,6 +538,7 @@ android_library {
kotlincflags: [
"-Xjvm-default=all",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
+ "-P plugin:androidx.compose.compiler.plugins.kotlin:sourceInformation=true",
],
plugins: [
diff --git a/packages/SystemUI/compose/core/Android.bp b/packages/SystemUI/compose/core/Android.bp
index c63c2b48638c..9c6bb2c8f778 100644
--- a/packages/SystemUI/compose/core/Android.bp
+++ b/packages/SystemUI/compose/core/Android.bp
@@ -42,6 +42,9 @@ android_library {
"//frameworks/libs/systemui:tracinglib-platform",
],
- kotlincflags: ["-Xjvm-default=all"],
+ kotlincflags: [
+ "-Xjvm-default=all",
+ "-P plugin:androidx.compose.compiler.plugins.kotlin:sourceInformation=true",
+ ],
use_resource_processor: true,
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 4a4607b6e8fc..2ca70558f18b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -207,12 +207,7 @@ fun CommunalContainer(
Box(modifier = Modifier.fillMaxSize())
}
- scene(
- CommunalScenes.Communal,
- userActions =
- if (viewModel.v2FlagEnabled()) emptyMap()
- else mapOf(Swipe.End to CommunalScenes.Blank),
- ) {
+ scene(CommunalScenes.Communal, userActions = mapOf(Swipe.End to CommunalScenes.Blank)) {
CommunalScene(
backgroundType = backgroundType,
colors = colors,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
index ba25719f1d60..0abed39dce6b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt
@@ -26,18 +26,16 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalDensity
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.plugins.clocks.ClockController
import kotlin.math.min
import kotlin.math.roundToInt
/** Produces a [BurnInState] that can be used to query the `LockscreenBurnInViewModel` flows. */
@Composable
-fun rememberBurnIn(
- clockInteractor: KeyguardClockInteractor,
-): BurnInState {
- val clock by clockInteractor.currentClock.collectAsStateWithLifecycle()
+fun rememberBurnIn(clockViewModel: KeyguardClockViewModel): BurnInState {
+ val clock by clockViewModel.currentClock.collectAsStateWithLifecycle()
val (smartspaceTop, onSmartspaceTopChanged) = remember { mutableStateOf<Float?>(null) }
val (smallClockTop, onSmallClockTopChanged) = remember { mutableStateOf<Float?>(null) }
@@ -62,18 +60,12 @@ fun rememberBurnIn(
}
@Composable
-private fun rememberBurnInParameters(
- clock: ClockController?,
- topmostTop: Int,
-): BurnInParameters {
+private fun rememberBurnInParameters(clock: ClockController?, topmostTop: Int): BurnInParameters {
val density = LocalDensity.current
val topInset = WindowInsets.systemBars.union(WindowInsets.displayCutout).getTop(density)
return remember(clock, topInset, topmostTop) {
- BurnInParameters(
- topInset = topInset,
- minViewY = topmostTop,
- )
+ BurnInParameters(topInset = topInset, minViewY = topmostTop)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index abf7fdc05f2e..f51049a10569 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -38,11 +38,11 @@ import com.android.compose.animation.scene.ContentScope
import com.android.compose.modifiers.thenIf
import com.android.systemui.common.ui.ConfigurationState
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn
import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.notifications.ui.composable.ConstrainedNotificationStack
@@ -89,7 +89,7 @@ constructor(
private val nicAodIconViewStore: AlwaysOnDisplayNotificationIconViewStore,
private val aodPromotedNotificationViewModelFactory: AODPromotedNotificationViewModel.Factory,
private val systemBarUtilsState: SystemBarUtilsState,
- private val clockInteractor: KeyguardClockInteractor,
+ private val keyguardClockViewModel: KeyguardClockViewModel,
) {
init {
@@ -118,7 +118,7 @@ constructor(
val isVisible by
keyguardRootViewModel.isAodPromotedNotifVisible.collectAsStateWithLifecycle()
- val burnIn = rememberBurnIn(clockInteractor)
+ val burnIn = rememberBurnIn(keyguardClockViewModel)
AnimatedVisibility(
visible = isVisible,
@@ -141,7 +141,7 @@ constructor(
isVisible.stopAnimating()
}
}
- val burnIn = rememberBurnIn(clockInteractor)
+ val burnIn = rememberBurnIn(keyguardClockViewModel)
AnimatedVisibility(
visibleState = transitionState,
enter = fadeIn(),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
index 410499a3c23f..6293fc26f96a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt
@@ -37,7 +37,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
import com.android.compose.modifiers.thenIf
-import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.largeClockScene
import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.smallClockScene
import com.android.systemui.keyguard.ui.composable.blueprint.ClockScenes.splitShadeLargeClockScene
@@ -56,7 +55,7 @@ constructor(
private val mediaCarouselSection: MediaCarouselSection,
private val clockSection: DefaultClockSection,
private val weatherClockSection: WeatherClockSection,
- private val clockInteractor: KeyguardClockInteractor,
+ private val keyguardClockViewModel: KeyguardClockViewModel,
) {
@Composable
fun ContentScope.DefaultClockLayout(
@@ -138,7 +137,7 @@ constructor(
smartSpacePaddingTop: (Resources) -> Int,
modifier: Modifier = Modifier,
) {
- val burnIn = rememberBurnIn(clockInteractor)
+ val burnIn = rememberBurnIn(keyguardClockViewModel)
Column(modifier = modifier) {
with(clockSection) {
@@ -163,7 +162,7 @@ constructor(
smartSpacePaddingTop: (Resources) -> Int,
shouldOffSetClockToOneHalf: Boolean = false,
) {
- val burnIn = rememberBurnIn(clockInteractor)
+ val burnIn = rememberBurnIn(keyguardClockViewModel)
val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsStateWithLifecycle()
LaunchedEffect(isLargeClockVisible) {
@@ -204,7 +203,7 @@ constructor(
smartSpacePaddingTop: (Resources) -> Int,
modifier: Modifier = Modifier,
) {
- val burnIn = rememberBurnIn(clockInteractor)
+ val burnIn = rememberBurnIn(keyguardClockViewModel)
val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsStateWithLifecycle()
val currentClockState = clockViewModel.currentClock.collectAsStateWithLifecycle()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
index 7c50d6f8af12..db1358a5a28a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt
@@ -30,9 +30,9 @@ import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn
import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayActionsViewModel
import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlayContentViewModel
@@ -57,7 +57,7 @@ constructor(
private val shadeSession: SaveableSession,
private val stackScrollView: Lazy<NotificationScrollView>,
private val clockSection: DefaultClockSection,
- private val clockInteractor: KeyguardClockInteractor,
+ private val keyguardClockViewModel: KeyguardClockViewModel,
) : Overlay {
override val key = Overlays.NotificationsShade
@@ -105,7 +105,7 @@ constructor(
Box {
Column {
if (viewModel.showClock) {
- val burnIn = rememberBurnIn(clockInteractor)
+ val burnIn = rememberBurnIn(keyguardClockViewModel)
with(clockSection) {
SmallClock(
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 da4e5824eb3e..619b4280d954 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
@@ -46,6 +46,8 @@ import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
import com.android.compose.gesture.effect.rememberOffsetOverscrollEffectFactory
+import com.android.systemui.keyguard.ui.composable.blueprint.rememberBurnIn
+import com.android.systemui.keyguard.ui.composable.modifier.burnInAware
import com.android.systemui.lifecycle.rememberActivated
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.qs.ui.composable.QuickSettingsTheme
@@ -239,7 +241,12 @@ fun SceneContainer(
BottomRightCornerRibbon(
content = { Text(text = "flexi\uD83E\uDD43", color = Color.White) },
colorSaturation = { viewModel.ribbonColorSaturation },
- modifier = Modifier.align(Alignment.BottomEnd),
+ modifier =
+ Modifier.align(Alignment.BottomEnd)
+ .burnInAware(
+ viewModel = viewModel.burnIn,
+ params = rememberBurnIn(viewModel.clock).parameters,
+ ),
)
}
}
diff --git a/packages/SystemUI/compose/scene/Android.bp b/packages/SystemUI/compose/scene/Android.bp
index 090e9ccedda0..42dd85a3d0a7 100644
--- a/packages/SystemUI/compose/scene/Android.bp
+++ b/packages/SystemUI/compose/scene/Android.bp
@@ -45,6 +45,9 @@ android_library {
"mechanics",
],
- kotlincflags: ["-Xjvm-default=all"],
+ kotlincflags: [
+ "-Xjvm-default=all",
+ "-P plugin:androidx.compose.compiler.plugins.kotlin:sourceInformation=true",
+ ],
use_resource_processor: true,
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
index bd33e52689c2..f53f964cd3d9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerFullscreenSwipeTouchHandlerTest.java
@@ -64,12 +64,12 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-import java.util.Optional;
-
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
+import java.util.List;
+import java.util.Optional;
+
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@EnableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
@@ -171,6 +171,7 @@ public class BouncerFullscreenSwipeTouchHandlerTest extends SysuiTestCase {
mActivityStarter,
mKeyguardInteractor,
mSceneInteractor,
+ mKosmos.getShadeRepository(),
Optional.of(() -> mWindowRootView));
when(mScrimManager.getCurrentController()).thenReturn(mScrimController);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
index 494e0b4deef4..dd43d817cccc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandlerTest.java
@@ -74,12 +74,12 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-import java.util.Optional;
-
import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
import platform.test.runner.parameterized.Parameters;
+import java.util.List;
+import java.util.Optional;
+
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
@DisableFlags(Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX)
@@ -187,6 +187,7 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
mActivityStarter,
mKeyguardInteractor,
mSceneInteractor,
+ mKosmos.getShadeRepository(),
Optional.of(() -> mWindowRootView)
);
@@ -627,6 +628,22 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
onRemovedCallbackCaptor.getValue().onRemoved();
}
+ @Test
+ public void testTouchSessionStart_notifiesShadeOfUserInteraction() {
+ mTouchHandler.onSessionStart(mTouchSession);
+
+ mKosmos.getTestScope().getTestScheduler().runCurrent();
+ assertThat(mKosmos.getShadeRepository().getLegacyShadeTracking().getValue()).isTrue();
+
+ ArgumentCaptor<TouchHandler.TouchSession.Callback> onRemovedCallbackCaptor =
+ ArgumentCaptor.forClass(TouchHandler.TouchSession.Callback.class);
+ verify(mTouchSession).registerCallback(onRemovedCallbackCaptor.capture());
+ onRemovedCallbackCaptor.getValue().onRemoved();
+
+ mKosmos.getTestScope().getTestScheduler().runCurrent();
+ assertThat(mKosmos.getShadeRepository().getLegacyShadeTracking().getValue()).isFalse();
+ }
+
private void swipeToPosition(float percent, float velocityY) {
Mockito.clearInvocations(mTouchSession);
mTouchHandler.onSessionStart(mTouchSession);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 3d3178793a09..c6801f1ad9d5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -460,14 +460,14 @@ public class CommandQueueTest extends SysuiTestCase {
}
@Test
- public void testonDisplayAddSystemDecorations() {
+ public void testOnDisplayAddSystemDecorations() {
mCommandQueue.onDisplayAddSystemDecorations(DEFAULT_DISPLAY);
waitForIdleSync();
verify(mCallbacks).onDisplayAddSystemDecorations(eq(DEFAULT_DISPLAY));
}
@Test
- public void testonDisplayAddSystemDecorationsForSecondaryDisplay() {
+ public void testOnDisplayAddSystemDecorationsForSecondaryDisplay() {
mCommandQueue.onDisplayAddSystemDecorations(SECONDARY_DISPLAY);
waitForIdleSync();
verify(mCallbacks).onDisplayAddSystemDecorations(eq(SECONDARY_DISPLAY));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
index d14ff35f824a..e5cb0fbc9e4b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt
@@ -49,6 +49,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
private val sectionsManager = mock<NotificationSectionsManager>()
private val msdlPlayer = kosmos.fakeMSDLPlayer
private var canRowBeDismissed = true
+ private var magneticAnimationsCancelled = false
private val underTest = kosmos.magneticNotificationRowManagerImpl
@@ -64,6 +65,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
children = notificationTestHelper.createGroup(childrenNumber).childrenContainer
swipedRow = children.attachedChildren[childrenNumber / 2]
configureMagneticRowListener(swipedRow)
+ magneticAnimationsCancelled = false
}
@Test
@@ -247,6 +249,35 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
assertThat(underTest.currentState).isEqualTo(State.IDLE)
}
+ @Test
+ fun onMagneticInteractionEnd_whenDetached_cancelsMagneticAnimations() =
+ kosmos.testScope.runTest {
+ // GIVEN the swiped row is detached
+ setDetachedState()
+
+ // WHEN the interaction ends on the row
+ underTest.onMagneticInteractionEnd(swipedRow, velocity = null)
+
+ // THEN magnetic animations are cancelled
+ assertThat(magneticAnimationsCancelled).isTrue()
+ }
+
+ @Test
+ fun onMagneticInteractionEnd_forMagneticNeighbor_cancelsMagneticAnimations() =
+ kosmos.testScope.runTest {
+ val neighborRow = children.attachedChildren[childrenNumber / 2 - 1]
+ configureMagneticRowListener(neighborRow)
+
+ // GIVEN that targets are set
+ setTargets()
+
+ // WHEN the interactionEnd is called on a target different from the swiped row
+ underTest.onMagneticInteractionEnd(neighborRow, null)
+
+ // THEN magnetic animations are cancelled
+ assertThat(magneticAnimationsCancelled).isTrue()
+ }
+
private fun setDetachedState() {
val threshold = 100f
underTest.setSwipeThresholdPx(threshold)
@@ -284,7 +315,11 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() {
startVelocity: Float,
) {}
- override fun cancelMagneticAnimations() {}
+ override fun cancelMagneticAnimations() {
+ magneticAnimationsCancelled = true
+ }
+
+ override fun cancelTranslationAnimations() {}
override fun canRowBeDismissed(): Boolean = canRowBeDismissed
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 766ae73cb49d..789701f5e4b0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -405,7 +405,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
doNothing().when(mSwipeHelper).superSnapChild(mNotificationRow, 0, 0);
mSwipeHelper.snapChild(mNotificationRow, 0, 0);
- verify(mCallback, times(1)).onDragCancelledWithVelocity(mNotificationRow, 0);
+ verify(mCallback, times(1)).onDragCancelled(mNotificationRow);
verify(mSwipeHelper, times(1)).superSnapChild(mNotificationRow, 0, 0);
verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
}
@@ -416,7 +416,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
doNothing().when(mSwipeHelper).superSnapChild(mNotificationRow, 10, 0);
mSwipeHelper.snapChild(mNotificationRow, 10, 0);
- verify(mCallback, times(1)).onDragCancelledWithVelocity(mNotificationRow, 0);
+ verify(mCallback, times(1)).onDragCancelled(mNotificationRow);
verify(mSwipeHelper, times(1)).superSnapChild(mNotificationRow, 10, 0);
verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed();
}
@@ -426,7 +426,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0);
mSwipeHelper.snapChild(mView, 10, 0);
- verify(mCallback).onDragCancelledWithVelocity(mView, 0);
+ verify(mCallback).onDragCancelled(mView);
verify(mSwipeHelper, never()).superSnapChild(mView, 10, 0);
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 2e12336f6e93..6f785a3731e1 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN;
import static com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE;
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
import static org.junit.Assert.assertFalse;
@@ -76,6 +77,7 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInte
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.bouncer.ui.BouncerView;
import com.android.systemui.bouncer.ui.BouncerViewDelegate;
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dreams.DreamOverlayStateController;
@@ -171,6 +173,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock private SceneInteractor mSceneInteractor;
@Mock private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock private BouncerInteractor mBouncerInteractor;
+ @Mock private CommunalSceneInteractor mCommunalSceneInteractor;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback
@@ -209,6 +212,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
.thenReturn(mNotificationShadeWindowView);
when(mNotificationShadeWindowView.getWindowInsetsController())
.thenReturn(mWindowInsetsController);
+ when(mCommunalSceneInteractor.isIdleOnCommunal()).thenReturn(MutableStateFlow(false));
mStatusBarKeyguardViewManager =
new StatusBarKeyguardViewManager(
@@ -245,7 +249,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mExecutor,
() -> mDeviceEntryInteractor,
mDismissCallbackRegistry,
- () -> mBouncerInteractor) {
+ () -> mBouncerInteractor,
+ mCommunalSceneInteractor) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
@@ -749,7 +754,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mExecutor,
() -> mDeviceEntryInteractor,
mDismissCallbackRegistry,
- () -> mBouncerInteractor) {
+ () -> mBouncerInteractor,
+ mCommunalSceneInteractor) {
@Override
public ViewRootImpl getViewRootImpl() {
return mViewRootImpl;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
index 73c191b32393..f0823e2f645e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone.ongoingcall.domain.interactor
import android.app.PendingIntent
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -30,12 +31,12 @@ import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.statusbar.StatusBarIconView
import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
import com.android.systemui.statusbar.gesture.swipeStatusBarAwayGestureHandler
-import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
-import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
-import com.android.systemui.statusbar.notification.shared.CallType
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.setNoCallState
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.setOngoingCallState
import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -50,6 +51,7 @@ import org.mockito.kotlin.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
+@EnableFlags(StatusBarChipsModernization.FLAG_NAME)
class OngoingCallInteractorTest : SysuiTestCase() {
private val kosmos = Kosmos().useUnconfinedTestDispatcher()
private val repository = kosmos.activeNotificationListRepository
@@ -76,21 +78,14 @@ class OngoingCallInteractorTest : SysuiTestCase() {
val testIntent: PendingIntent = mock()
val testPromotedContent =
PromotedNotificationContentModel.Builder("promotedCall").build()
- repository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "promotedCall",
- whenTime = 1000L,
- callType = CallType.Ongoing,
- statusBarChipIcon = testIconView,
- contentIntent = testIntent,
- promotedContent = testPromotedContent,
- )
- )
- }
- .build()
+ setOngoingCallState(
+ kosmos = this,
+ key = "promotedCall",
+ startTimeMs = 1000L,
+ statusBarChipIconView = testIconView,
+ contentIntent = testIntent,
+ promotedContent = testPromotedContent,
+ )
// Verify model is InCall and has the correct icon, intent, and promoted content.
assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
@@ -101,45 +96,13 @@ class OngoingCallInteractorTest : SysuiTestCase() {
}
@Test
- fun ongoingCallNotification_emitsInCall() =
- kosmos.runTest {
- val latest by collectLastValue(underTest.ongoingCallState)
-
- repository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "notif1",
- whenTime = 1000L,
- callType = CallType.Ongoing,
- )
- )
- }
- .build()
-
- assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
- }
-
- @Test
fun notificationRemoved_emitsNoCall() =
kosmos.runTest {
val latest by collectLastValue(underTest.ongoingCallState)
- repository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "notif1",
- whenTime = 1000L,
- callType = CallType.Ongoing,
- )
- )
- }
- .build()
-
- repository.activeNotifications.value = ActiveNotificationsStore()
+ setOngoingCallState(kosmos = this)
+ setNoCallState(kosmos = this)
+
assertThat(latest).isInstanceOf(OngoingCallModel.NoCall::class.java)
}
@@ -149,19 +112,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = true
val latest by collectLastValue(underTest.ongoingCallState)
- repository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "notif1",
- whenTime = 1000L,
- callType = CallType.Ongoing,
- uid = UID,
- )
- )
- }
- .build()
+ setOngoingCallState(kosmos = this, uid = UID)
assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
}
@@ -172,19 +123,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false
val latest by collectLastValue(underTest.ongoingCallState)
- repository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "notif1",
- whenTime = 1000L,
- callType = CallType.Ongoing,
- uid = UID,
- )
- )
- }
- .build()
+ setOngoingCallState(kosmos = this, uid = UID)
assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
}
@@ -196,19 +135,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
// Start with notification and app not visible
kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false
- repository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "notif1",
- whenTime = 1000L,
- callType = CallType.Ongoing,
- uid = UID,
- )
- )
- }
- .build()
+ setOngoingCallState(kosmos = this, uid = UID)
assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
// App becomes visible
@@ -234,7 +161,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
kosmos.fakeStatusBarWindowControllerStore.defaultDisplay
.ongoingProcessRequiresStatusBarVisible
)
- postOngoingCallNotification()
+ setOngoingCallState(kosmos = this)
assertThat(isStatusBarRequired).isTrue()
assertThat(requiresStatusBarVisibleInRepository).isTrue()
@@ -256,9 +183,9 @@ class OngoingCallInteractorTest : SysuiTestCase() {
.ongoingProcessRequiresStatusBarVisible
)
- postOngoingCallNotification()
+ setOngoingCallState(kosmos = this)
- repository.activeNotifications.value = ActiveNotificationsStore()
+ setNoCallState(kosmos = this)
assertThat(isStatusBarRequired).isFalse()
assertThat(requiresStatusBarVisibleInRepository).isFalse()
@@ -283,7 +210,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false
- postOngoingCallNotification()
+ setOngoingCallState(kosmos = this, uid = UID)
assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java)
assertThat(requiresStatusBarVisibleInRepository).isTrue()
@@ -305,7 +232,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
clearInvocations(kosmos.swipeStatusBarAwayGestureHandler)
// Set up notification but not in fullscreen
kosmos.fakeStatusBarModeRepository.defaultDisplay.isInFullscreenMode.value = false
- postOngoingCallNotification()
+ setOngoingCallState(kosmos = this)
assertThat(ongoingCallState).isInstanceOf(OngoingCallModel.InCall::class.java)
verify(kosmos.swipeStatusBarAwayGestureHandler, never())
@@ -319,7 +246,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
// Set up notification and fullscreen mode
kosmos.fakeStatusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
- postOngoingCallNotification()
+ setOngoingCallState(kosmos = this)
assertThat(isGestureListeningEnabled).isTrue()
verify(kosmos.swipeStatusBarAwayGestureHandler)
@@ -333,7 +260,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
// Set up notification and fullscreen mode
kosmos.fakeStatusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
- postOngoingCallNotification()
+ setOngoingCallState(kosmos = this)
clearInvocations(kosmos.swipeStatusBarAwayGestureHandler)
@@ -360,7 +287,7 @@ class OngoingCallInteractorTest : SysuiTestCase() {
)
// Start with an ongoing call (which should set status bar required)
- postOngoingCallNotification()
+ setOngoingCallState(kosmos = this)
assertThat(isStatusBarRequiredForOngoingCall).isTrue()
assertThat(requiresStatusBarVisibleInRepository).isTrue()
@@ -374,22 +301,6 @@ class OngoingCallInteractorTest : SysuiTestCase() {
assertThat(requiresStatusBarVisibleInWindowController).isFalse()
}
- private fun postOngoingCallNotification() {
- repository.activeNotifications.value =
- ActiveNotificationsStore.Builder()
- .apply {
- addIndividualNotif(
- activeNotificationModel(
- key = "notif1",
- whenTime = 1000L,
- callType = CallType.Ongoing,
- uid = UID,
- )
- )
- }
- .build()
- }
-
companion object {
private const val UID = 885
}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index f835ad689132..e2065f175c79 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -352,6 +352,7 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
&& Math.abs(delta) > Math.abs(deltaPerpendicular)) {
if (mCallback.canChildBeDragged(mTouchedView)) {
mIsSwiping = true;
+ mCallback.setMagneticAndRoundableTargets(mTouchedView);
mCallback.onBeginDrag(mTouchedView);
mInitialTouchPos = getPos(ev);
mTranslation = getTranslation(mTouchedView);
@@ -444,6 +445,7 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
};
Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
+ mCallback.onMagneticInteractionEnd(animView, velocity);
if (anim == null) {
onDismissChildWithAnimationFinished();
return;
@@ -733,7 +735,8 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
dismissChild(mTouchedView, velocity,
!swipedFastEnough() /* useAccelerateInterpolator */);
} else {
- mCallback.onDragCancelledWithVelocity(mTouchedView, velocity);
+ mCallback.onMagneticInteractionEnd(mTouchedView, velocity);
+ mCallback.onDragCancelled(mTouchedView);
snapChild(mTouchedView, 0 /* leftTarget */, velocity);
}
mTouchedView = null;
@@ -935,18 +938,24 @@ public class SwipeHelper implements Gefingerpoken, Dumpable {
void onBeginDrag(View v);
+ /**
+ * Set magnetic and roundable targets for a view.
+ */
+ void setMagneticAndRoundableTargets(View v);
+
void onChildDismissed(View v);
void onDragCancelled(View v);
/**
- * A drag operation has been cancelled on a view with a final velocity.
- * @param v View that was dragged.
- * @param finalVelocity Final velocity of the drag.
+ * Notify that a magnetic interaction ended on a view with a velocity.
+ * <p>
+ * This method should be called when a view will snap back or be dismissed.
+ *
+ * @param view The {@link View} whose magnetic interaction ended.
+ * @param velocity The velocity when the interaction ended.
*/
- default void onDragCancelledWithVelocity(View v, float finalVelocity) {
- onDragCancelled(v);
- }
+ void onMagneticInteractionEnd(View view, float velocity);
/**
* Called when the child is long pressed and available to start drag and drop.
diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
index e365b770c203..d8e7a168ef3c 100644
--- a/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/BouncerSwipeTouchHandler.kt
@@ -43,6 +43,7 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.ShadeExpansionChangeEvent
+import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.phone.CentralSurfaces
import com.android.wm.shell.animation.FlingAnimationUtils
@@ -79,6 +80,7 @@ constructor(
private val activityStarter: ActivityStarter,
private val keyguardInteractor: KeyguardInteractor,
private val sceneInteractor: SceneInteractor,
+ private val shadeRepository: ShadeRepository,
private val windowRootViewProvider: Optional<Provider<WindowRootView>>,
) : TouchHandler {
/** An interface for creating ValueAnimators. */
@@ -260,6 +262,8 @@ constructor(
}
scrimManager.addCallback(scrimManagerCallback)
currentScrimController = scrimManager.currentController
+
+ shadeRepository.setLegacyShadeTracking(true)
session.registerCallback {
velocityTracker?.apply { recycle() }
velocityTracker = null
@@ -270,6 +274,7 @@ constructor(
if (!Flags.communalBouncerDoNotModifyPluginOpen()) {
notificationShadeWindowController.setForcePluginOpen(false, this)
}
+ shadeRepository.setLegacyShadeTracking(false)
}
session.registerGestureListener(onGestureListener)
session.registerInputListener { ev: InputEvent -> onMotionEvent(ev) }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index 23be5c52ab5c..c61530c3dbcc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -163,10 +163,6 @@ constructor(
}
private fun bindJankViewModel() {
- if (SceneContainerFlag.isEnabled) {
- return
- }
-
jankHandle?.dispose()
jankHandle =
KeyguardJankBinder.bind(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index efa9c21f96b4..caf0fd4450fc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -16,7 +16,6 @@
package com.android.systemui.keyguard;
-import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT;
import static android.provider.Settings.System.LOCKSCREEN_SOUNDS_ENABLED;
@@ -76,7 +75,6 @@ import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -194,8 +192,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -286,9 +282,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private static final int SYSTEM_READY = 18;
private static final int CANCEL_KEYGUARD_EXIT_ANIM = 19;
private static final int BOOT_INTERACTOR = 20;
- private static final int BEFORE_USER_SWITCHING = 21;
- private static final int USER_SWITCHING = 22;
- private static final int USER_SWITCH_COMPLETE = 23;
/** Enum for reasons behind updating wakeAndUnlock state. */
@Retention(RetentionPolicy.SOURCE)
@@ -306,8 +299,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
int WAKE_AND_UNLOCK = 3;
}
- private final List<LockNowCallback> mLockNowCallbacks = new ArrayList<>();
-
/**
* The default amount of time we stay awake (used for all key input)
*/
@@ -366,18 +357,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
private final Lazy<NotificationShadeDepthController> mNotificationShadeDepthController;
private final Lazy<ShadeController> mShadeController;
private final Lazy<CommunalSceneInteractor> mCommunalSceneInteractor;
- /*
- * Records the user id on request to go away, for validation when WM calls back to start the
- * exit animation.
- */
- private int mGoingAwayRequestedForUserId = -1;
-
private boolean mSystemReady;
private boolean mBootCompleted;
private boolean mBootSendUserPresent;
private boolean mShuttingDown;
private boolean mDozing;
private boolean mAnimatingScreenOff;
+ private boolean mIgnoreDismiss;
private final Context mContext;
private final FalsingCollector mFalsingCollector;
@@ -640,78 +626,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
};
- @VisibleForTesting
- protected UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() {
-
- @Override
- public void onBeforeUserSwitching(int newUser, @NonNull Runnable resultCallback) {
- mHandler.sendMessage(mHandler.obtainMessage(BEFORE_USER_SWITCHING,
- newUser, 0, resultCallback));
- }
-
- @Override
- public void onUserChanging(int newUser, @NonNull Context userContext,
- @NonNull Runnable resultCallback) {
- mHandler.sendMessage(mHandler.obtainMessage(USER_SWITCHING,
- newUser, 0, resultCallback));
- }
-
- @Override
- public void onUserChanged(int newUser, Context userContext) {
- mHandler.sendMessage(mHandler.obtainMessage(USER_SWITCH_COMPLETE,
- newUser, 0));
- }
- };
-
- /**
- * Handle {@link #BEFORE_USER_SWITCHING}
- */
- @VisibleForTesting
- void handleBeforeUserSwitching(int userId, Runnable resultCallback) {
- Log.d(TAG, String.format("onBeforeUserSwitching %d", userId));
- synchronized (KeyguardViewMediator.this) {
- mHandler.removeMessages(DISMISS);
- notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
- resetKeyguardDonePendingLocked();
- adjustStatusBarLocked();
- mKeyguardStateController.notifyKeyguardGoingAway(false);
- if (mLockPatternUtils.isSecure(userId) && !mShowing) {
- doKeyguardLocked(null);
- } else {
- resetStateLocked();
- }
- resultCallback.run();
- }
- }
-
- /**
- * Handle {@link #USER_SWITCHING}
- */
- @VisibleForTesting
- void handleUserSwitching(int userId, Runnable resultCallback) {
- Log.d(TAG, String.format("onUserSwitching %d", userId));
- synchronized (KeyguardViewMediator.this) {
- if (!mLockPatternUtils.isSecure(userId)) {
- dismiss(null, null);
- }
- resultCallback.run();
- }
- }
-
- /**
- * Handle {@link #USER_SWITCH_COMPLETE}
- */
- @VisibleForTesting
- void handleUserSwitchComplete(int userId) {
- Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
- // Calling dismiss on a secure user will show the bouncer
- if (mLockPatternUtils.isSecure(userId)) {
- // We are calling dismiss with a delay as there are race conditions in some scenarios
- // caused by async layout listeners
- mHandler.postDelayed(() -> dismiss(null /* callback */, null /* message */), 500);
- }
- }
-
KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@Override
@@ -728,6 +642,27 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
@Override
+ public void onUserSwitching(int userId) {
+ Log.d(TAG, String.format("onUserSwitching %d", userId));
+ synchronized (KeyguardViewMediator.this) {
+ mIgnoreDismiss = true;
+ notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
+ resetKeyguardDonePendingLocked();
+ resetStateLocked();
+ adjustStatusBarLocked();
+ }
+ }
+
+ @Override
+ public void onUserSwitchComplete(int userId) {
+ mIgnoreDismiss = false;
+ Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
+ // We are calling dismiss with a delay as there are race conditions in some scenarios
+ // caused by async layout listeners
+ mHandler.postDelayed(() -> dismiss(null /* callback */, null /* message */), 500);
+ }
+
+ @Override
public void onDeviceProvisioned() {
sendUserPresentBroadcast();
}
@@ -1736,13 +1671,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
com.android.internal.R.anim.lock_screen_behind_enter);
mWorkLockController = new WorkLockActivityController(mContext, mUserTracker);
- mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
- // start() can be invoked in the middle of user switching, so check for this state and issue
- // the call manually as that important event was missed.
- if (mUserTracker.isUserSwitching()) {
- handleBeforeUserSwitching(mUserTracker.getUserId(), () -> {});
- handleUserSwitching(mUserTracker.getUserId(), () -> {});
- }
+
mJavaAdapter.alwaysCollectFlow(
mWallpaperRepository.getWallpaperSupportsAmbientMode(),
this::setWallpaperSupportsAmbientMode);
@@ -1791,7 +1720,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// System ready can be invoked in the middle of user switching, so check for this state
// and issue the call manually as that important event was missed.
if (mUserTracker.isUserSwitching()) {
- mUserChangedCallback.onUserChanging(mUserTracker.getUserId(), mContext, () -> {});
+ mUpdateCallback.onUserSwitching(mUserTracker.getUserId());
}
}
// Most services aren't available until the system reaches the ready state, so we
@@ -2432,23 +2361,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mCommunalSceneInteractor.get().showHubFromPowerButton();
}
- int currentUserId = mSelectedUserInteractor.getSelectedUserId();
- if (options != null && options.getBinder(LOCK_ON_USER_SWITCH_CALLBACK) != null) {
- LockNowCallback callback = new LockNowCallback(currentUserId,
- IRemoteCallback.Stub.asInterface(
- options.getBinder(LOCK_ON_USER_SWITCH_CALLBACK)));
- synchronized (mLockNowCallbacks) {
- mLockNowCallbacks.add(callback);
- }
- Log.d(TAG, "LockNowCallback required for user: " + callback.mUserId);
- }
-
// if another app is disabling us, don't show
if (!mExternallyEnabled
&& !mLockPatternUtils.isUserInLockdown(
mSelectedUserInteractor.getSelectedUserId())) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
- notifyLockNowCallback();
+
mNeedToReshowWhenReenabled = true;
return;
}
@@ -2466,7 +2384,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// We're removing "reset" in the refactor - "resetting" the views will happen
// as a reaction to the root cause of the "reset" signal.
if (KeyguardWmStateRefactor.isEnabled()) {
- notifyLockNowCallback();
return;
}
@@ -2479,7 +2396,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
+ "previously hiding. It should be safe to short-circuit "
+ "here.");
resetStateLocked(/* hideBouncer= */ false);
- notifyLockNowCallback();
return;
}
} else {
@@ -2506,7 +2422,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
Log.d(TAG, "doKeyguard: not showing because device isn't provisioned and the sim is"
+ " not locked or missing");
}
- notifyLockNowCallback();
return;
}
@@ -2514,7 +2429,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
if (mLockPatternUtils.isLockScreenDisabled(mSelectedUserInteractor.getSelectedUserId())
&& !lockedOrMissing && !forceShow) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
- notifyLockNowCallback();
return;
}
@@ -2562,6 +2476,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
public void dismiss(IKeyguardDismissCallback callback, CharSequence message) {
+ if (mIgnoreDismiss) {
+ android.util.Log.i(TAG, "Ignoring request to dismiss (user switch in progress?)");
+ return;
+ }
+
if (mKeyguardStateController.isKeyguardGoingAway()) {
Log.i(TAG, "Ignoring dismiss because we're already going away.");
return;
@@ -2579,7 +2498,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
private void resetStateLocked(boolean hideBouncer) {
- if (DEBUG) Log.d(TAG, "resetStateLocked");
+ if (DEBUG) Log.e(TAG, "resetStateLocked");
Message msg = mHandler.obtainMessage(RESET, hideBouncer ? 1 : 0, 0);
mHandler.sendMessage(msg);
}
@@ -2827,18 +2746,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
message = "BOOT_INTERACTOR";
handleBootInteractor();
break;
- case BEFORE_USER_SWITCHING:
- message = "BEFORE_USER_SWITCHING";
- handleBeforeUserSwitching(msg.arg1, (Runnable) msg.obj);
- break;
- case USER_SWITCHING:
- message = "USER_SWITCHING";
- handleUserSwitching(msg.arg1, (Runnable) msg.obj);
- break;
- case USER_SWITCH_COMPLETE:
- message = "USER_SWITCH_COMPLETE";
- handleUserSwitchComplete(msg.arg1);
- break;
}
Log.d(TAG, "KeyguardViewMediator queue processing message: " + message);
}
@@ -2980,9 +2887,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mUiBgExecutor.execute(() -> {
Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ", "
+ reason + ")");
- if (showing) {
- notifyLockNowCallback();
- }
if (KeyguardWmStateRefactor.isEnabled()) {
// Handled in WmLockscreenVisibilityManager if flag is enabled.
@@ -3027,7 +2931,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
synchronized (KeyguardViewMediator.this) {
if (!mSystemReady) {
if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
- notifyLockNowCallback();
return;
}
if (DEBUG) Log.d(TAG, "handleShow");
@@ -3086,11 +2989,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
}
- final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
+ private final Runnable mKeyguardGoingAwayRunnable = new Runnable() {
@SuppressLint("MissingPermission")
@Override
public void run() {
Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable");
+ Log.d(TAG, "keyguardGoingAwayRunnable");
mKeyguardViewControllerLazy.get().keyguardGoingAway();
int flags = 0;
@@ -3127,10 +3031,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
// Handled in WmLockscreenVisibilityManager if flag is enabled.
if (!KeyguardWmStateRefactor.isEnabled()) {
- mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
- Log.d(TAG, "keyguardGoingAway requested for userId: "
- + mGoingAwayRequestedForUserId);
-
// Don't actually hide the Keyguard at the moment, wait for window manager
// until it tells us it's safe to do so with startKeyguardExitAnimation.
// Posting to mUiOffloadThread to ensure that calls to ActivityTaskManager
@@ -3269,30 +3169,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
+ " fadeoutDuration=" + fadeoutDuration);
- int currentUserId = mSelectedUserInteractor.getSelectedUserId();
- if (!KeyguardWmStateRefactor.isEnabled() && mGoingAwayRequestedForUserId != currentUserId) {
- Log.e(TAG, "Not executing handleStartKeyguardExitAnimationInner() due to userId "
- + "mismatch. Requested: " + mGoingAwayRequestedForUserId + ", current: "
- + currentUserId);
- if (finishedCallback != null) {
- // There will not execute animation, send a finish callback to ensure the remote
- // animation won't hang there.
- try {
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to call onAnimationFinished", e);
- }
- }
- mHiding = false;
- if (mLockPatternUtils.isSecure(currentUserId)) {
- doKeyguardLocked(null);
- } else {
- resetStateLocked();
- dismiss(null, null);
- }
- return;
- }
-
synchronized (KeyguardViewMediator.this) {
mIsKeyguardExitAnimationCanceled = false;
// Tell ActivityManager that we canceled the keyguard animation if
@@ -3537,13 +3413,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
* app transition before finishing the current RemoteAnimation, or the keyguard being re-shown).
*/
private void handleCancelKeyguardExitAnimation() {
- if (!KeyguardWmStateRefactor.isEnabled()
- && mGoingAwayRequestedForUserId != mSelectedUserInteractor.getSelectedUserId()) {
- Log.e(TAG, "Setting pendingLock = true due to userId mismatch. Requested: "
- + mGoingAwayRequestedForUserId + ", current: "
- + mSelectedUserInteractor.getSelectedUserId());
- setPendingLock(true);
- }
if (mPendingLock) {
Log.d(TAG, "#handleCancelKeyguardExitAnimation: keyguard exit animation cancelled. "
+ "There's a pending lock, so we were cancelled because the device was locked "
@@ -3644,7 +3513,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mSurfaceBehindRemoteAnimationRequested = true;
if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS && !KeyguardWmStateRefactor.isEnabled()) {
- mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */);
return;
}
@@ -3665,9 +3533,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
if (!KeyguardWmStateRefactor.isEnabled()) {
// Handled in WmLockscreenVisibilityManager.
- mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
- Log.d(TAG, "keyguardGoingAway requested for userId: "
- + mGoingAwayRequestedForUserId);
mActivityTaskManagerService.keyguardGoingAway(flags);
}
} catch (RemoteException e) {
@@ -4123,29 +3988,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
mUiBgExecutor.execute(mTrustManager::reportKeyguardShowingChanged);
}
- private void notifyLockNowCallback() {
- List<LockNowCallback> callbacks;
- synchronized (mLockNowCallbacks) {
- callbacks = new ArrayList<LockNowCallback>(mLockNowCallbacks);
- mLockNowCallbacks.clear();
- }
- Iterator<LockNowCallback> iter = callbacks.listIterator();
- while (iter.hasNext()) {
- LockNowCallback callback = iter.next();
- iter.remove();
- if (callback.mUserId != mSelectedUserInteractor.getSelectedUserId()) {
- Log.i(TAG, "Not notifying lockNowCallback due to user mismatch");
- continue;
- }
- Log.i(TAG, "Notifying lockNowCallback");
- try {
- callback.mRemoteCallback.sendResult(null);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not issue LockNowCallback sendResult", e);
- }
- }
- }
-
private void notifyTrustedChangedLocked(boolean trusted) {
int size = mKeyguardStateCallbacks.size();
for (int i = size - 1; i >= 0; i--) {
@@ -4310,14 +4152,4 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
}
};
}
-
- private class LockNowCallback {
- final int mUserId;
- final IRemoteCallback mRemoteCallback;
-
- LockNowCallback(int userId, IRemoteCallback remoteCallback) {
- mUserId = userId;
- mRemoteCallback = remoteCallback;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index 5c03d65e570f..8f6815829ba2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -69,7 +69,7 @@ constructor(
* Note that [onCancel] isn't used when the scene framework is enabled.
*/
fun sharedFlow(
- duration: Duration,
+ duration: Duration = transitionDuration,
onStep: (Float) -> Float,
startTime: Duration = 0.milliseconds,
onStart: (() -> Unit)? = null,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardJankBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardJankBinder.kt
index 0cb684a1aabe..38263be33c82 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardJankBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardJankBinder.kt
@@ -30,6 +30,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.KeyguardJankViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -79,15 +80,18 @@ object KeyguardJankBinder {
}
}
- launch {
- viewModel.lockscreenToAodTransition.collect {
- processStep(it, CUJ_LOCKSCREEN_TRANSITION_TO_AOD)
+ // The following is already done in KeyguardTransitionAnimationCallbackImpl.
+ if (!SceneContainerFlag.isEnabled) {
+ launch {
+ viewModel.lockscreenToAodTransition.collect {
+ processStep(it, CUJ_LOCKSCREEN_TRANSITION_TO_AOD)
+ }
}
- }
- launch {
- viewModel.aodToLockscreenTransition.collect {
- processStep(it, CUJ_LOCKSCREEN_TRANSITION_FROM_AOD)
+ launch {
+ viewModel.aodToLockscreenTransition.collect {
+ processStep(it, CUJ_LOCKSCREEN_TRANSITION_FROM_AOD)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubBlurProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubBlurProvider.kt
index 19cd501fa787..50f8e086ac6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubBlurProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/GlanceableHubBlurProvider.kt
@@ -16,6 +16,7 @@
package com.android.systemui.keyguard.ui.transitions
+import android.util.MathUtils
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -33,8 +34,18 @@ constructor(
blurConfig: BlurConfig,
) {
val exitBlurRadius: Flow<Float> =
- transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx)
+ transitionAnimation.sharedFlow(
+ onStep = { MathUtils.lerp(blurConfig.maxBlurRadiusPx, blurConfig.minBlurRadiusPx, it) },
+ onStart = { blurConfig.maxBlurRadiusPx },
+ onFinish = { blurConfig.minBlurRadiusPx },
+ onCancel = { blurConfig.maxBlurRadiusPx },
+ )
val enterBlurRadius: Flow<Float> =
- transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx)
+ transitionAnimation.sharedFlow(
+ onStep = { MathUtils.lerp(blurConfig.minBlurRadiusPx, blurConfig.maxBlurRadiusPx, it) },
+ onStart = { blurConfig.minBlurRadiusPx },
+ onFinish = { blurConfig.maxBlurRadiusPx },
+ onCancel = { blurConfig.minBlurRadiusPx },
+ )
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
index f0f476e65e2f..364da5f8e80d 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
@@ -30,19 +30,14 @@ import com.android.systemui.compose.ComposeInitializer
import com.android.systemui.res.R
/** A view that can serve as the root of the main SysUI window. */
-open class WindowRootView(
- context: Context,
- attrs: AttributeSet?,
-) :
- FrameLayout(
- context,
- attrs,
- ) {
+open class WindowRootView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
private lateinit var layoutInsetsController: LayoutInsetsController
private var leftInset = 0
private var rightInset = 0
+ private var previousInsets: WindowInsets? = null
+
override fun onAttachedToWindow() {
super.onAttachedToWindow()
@@ -66,11 +61,14 @@ open class WindowRootView(
override fun generateDefaultLayoutParams(): FrameLayout.LayoutParams? {
return LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT
+ FrameLayout.LayoutParams.MATCH_PARENT,
)
}
override fun onApplyWindowInsets(windowInsets: WindowInsets): WindowInsets? {
+ if (windowInsets == previousInsets) {
+ return windowInsets
+ }
val insets = windowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
if (fitsSystemWindows) {
val paddingChanged = insets.top != paddingTop || insets.bottom != paddingBottom
@@ -95,7 +93,7 @@ open class WindowRootView(
leftInset = pairInsets.first
rightInset = pairInsets.second
applyMargins()
- return windowInsets
+ return windowInsets.also { previousInsets = WindowInsets(it) }
}
fun setLayoutInsetsController(layoutInsetsController: LayoutInsetsController) {
@@ -143,37 +141,22 @@ open class WindowRootView(
interface LayoutInsetsController {
/** Update the insets and calculate them accordingly. */
- fun getinsets(
- windowInsets: WindowInsets?,
- displayCutout: DisplayCutout?,
- ): Pair<Int, Int>
+ fun getinsets(windowInsets: WindowInsets?, displayCutout: DisplayCutout?): Pair<Int, Int>
}
private class LayoutParams : FrameLayout.LayoutParams {
var ignoreRightInset = false
- constructor(
- width: Int,
- height: Int,
- ) : super(
- width,
- height,
- )
+ constructor(width: Int, height: Int) : super(width, height)
@SuppressLint("CustomViewStyleable")
- constructor(
- context: Context,
- attrs: AttributeSet?,
- ) : super(
- context,
- attrs,
- ) {
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
val obtainedAttributes =
context.obtainStyledAttributes(attrs, R.styleable.StatusBarWindowView_Layout)
ignoreRightInset =
obtainedAttributes.getBoolean(
R.styleable.StatusBarWindowView_Layout_ignoreRightInset,
- false
+ false,
)
obtainedAttributes.recycle()
}
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 fbcd8ea9b9e4..233e15846450 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,8 @@ import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.domain.interactor.FalsingInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
@@ -68,6 +70,8 @@ constructor(
val lightRevealScrim: LightRevealScrimViewModel,
val wallpaperViewModel: WallpaperViewModel,
keyguardInteractor: KeyguardInteractor,
+ val burnIn: AodBurnInViewModel,
+ val clock: KeyguardClockViewModel,
@Assisted view: View,
@Assisted private val motionEventHandlerReceiver: (MotionEventHandler?) -> Unit,
) : ExclusiveActivatable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 76ba7f9ea901..2bc48746f847 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -106,7 +106,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro
@Override
public void triggerMagneticForce(float endTranslation, @NonNull SpringForce springForce,
float startVelocity) {
- cancelMagneticAnimations();
+ cancelTranslationAnimations();
mMagneticAnimator.setSpring(springForce);
mMagneticAnimator.setStartVelocity(startVelocity);
mMagneticAnimator.animateToFinalPosition(endTranslation);
@@ -114,11 +114,15 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro
@Override
public void cancelMagneticAnimations() {
- cancelTranslationAnimations();
mMagneticAnimator.cancel();
}
@Override
+ public void cancelTranslationAnimations() {
+ ExpandableView.this.cancelTranslationAnimations();
+ }
+
+ @Override
public boolean canRowBeDismissed() {
return canExpandableViewBeDismissed();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
index 3941700496f4..5a29a699a7e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt
@@ -97,6 +97,7 @@ constructor(
stackScrollLayout,
MAGNETIC_TRANSLATION_MULTIPLIERS.size,
)
+ currentMagneticListeners.swipedListener()?.cancelTranslationAnimations()
newListeners.forEach {
if (currentMagneticListeners.contains(it)) {
it?.cancelMagneticAnimations()
@@ -214,22 +215,32 @@ constructor(
}
override fun onMagneticInteractionEnd(row: ExpandableNotificationRow, velocity: Float?) {
- if (!row.isSwipedTarget()) return
-
- when (currentState) {
- State.PULLING -> {
- snapNeighborsBack(velocity)
- currentState = State.IDLE
- }
- State.DETACHED -> {
- currentState = State.IDLE
+ if (row.isSwipedTarget()) {
+ when (currentState) {
+ State.PULLING -> {
+ snapNeighborsBack(velocity)
+ currentState = State.IDLE
+ }
+ State.DETACHED -> {
+ // Cancel any detaching animation that may be occurring
+ currentMagneticListeners.swipedListener()?.cancelMagneticAnimations()
+ currentState = State.IDLE
+ }
+ else -> {}
}
- else -> {}
+ } else {
+ // A magnetic neighbor may be dismissing. In this case, we need to cancel any snap back
+ // magnetic animation to let the external dismiss animation proceed.
+ val listener = currentMagneticListeners.find { it == row.magneticRowListener }
+ listener?.cancelMagneticAnimations()
}
}
override fun reset() {
- currentMagneticListeners.forEach { it?.cancelMagneticAnimations() }
+ currentMagneticListeners.forEach {
+ it?.cancelMagneticAnimations()
+ it?.cancelTranslationAnimations()
+ }
currentState = State.IDLE
currentMagneticListeners = listOf()
currentRoundableTargets = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
index 46036d4c1fad..5959ef1e093b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticRowListener.kt
@@ -42,6 +42,9 @@ interface MagneticRowListener {
/** Cancel any animations related to the magnetic interactions of the row */
fun cancelMagneticAnimations()
+ /** Cancel any other animations related to the row's translation */
+ fun cancelTranslationAnimations()
+
/** Can the row be dismissed. */
fun canRowBeDismissed(): Boolean
}
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 48a6a4c057df..810d0b43b0dd 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
@@ -463,6 +463,13 @@ public class NotificationStackScrollLayoutController implements Dumpable {
}
@Override
+ public void onMagneticInteractionEnd(View view, float velocity) {
+ if (view instanceof ExpandableNotificationRow row) {
+ mMagneticNotificationRowManager.onMagneticInteractionEnd(row, velocity);
+ }
+ }
+
+ @Override
public float getTotalTranslationLength(View animView) {
return mView.getTotalTranslationLength(animView);
}
@@ -504,14 +511,6 @@ public class NotificationStackScrollLayoutController implements Dumpable {
public void onDragCancelled(View v) {
}
- @Override
- public void onDragCancelledWithVelocity(View v, float finalVelocity) {
- if (v instanceof ExpandableNotificationRow row) {
- mMagneticNotificationRowManager.onMagneticInteractionEnd(
- row, finalVelocity);
- }
- }
-
/**
* Handles cleanup after the given {@code view} has been fully swiped out (including
* re-invoking dismiss logic in case the notification has not made its way out yet).
@@ -539,10 +538,6 @@ public class NotificationStackScrollLayoutController implements Dumpable {
*/
public void handleChildViewDismissed(View view) {
- if (view instanceof ExpandableNotificationRow row) {
- mMagneticNotificationRowManager.onMagneticInteractionEnd(
- row, null /* velocity */);
- }
// The View needs to clean up the Swipe states, e.g. roundness.
mView.onSwipeEnd();
if (mView.getClearAllInProgress()) {
@@ -614,11 +609,15 @@ public class NotificationStackScrollLayoutController implements Dumpable {
@Override
public void onBeginDrag(View v) {
+ mView.onSwipeBegin(v);
+ }
+
+ @Override
+ public void setMagneticAndRoundableTargets(View v) {
if (v instanceof ExpandableNotificationRow row) {
mMagneticNotificationRowManager.setMagneticAndRoundableTargets(
row, mView, mSectionsManager);
}
- mView.onSwipeBegin(v);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index d476d482226d..6f4047f48205 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -362,7 +362,8 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
superSnapChild(animView, targetLeft, velocity);
}
- mCallback.onDragCancelledWithVelocity(animView, velocity);
+ mCallback.onMagneticInteractionEnd(animView, velocity);
+ mCallback.onDragCancelled(animView);
if (targetLeft == 0) {
handleMenuCoveredOrDismissed();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index a339bc98457e..58326dbb3a34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -61,6 +61,7 @@ import kotlinx.coroutines.flow.StateFlowKt;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Objects;
/**
* The header group on Keyguard.
@@ -103,6 +104,9 @@ public class KeyguardStatusBarView extends RelativeLayout {
*/
private int mCutoutSideNudge = 0;
+ @Nullable
+ private WindowInsets mPreviousInsets = null;
+
private DisplayCutout mDisplayCutout;
private int mRoundedCornerPadding = 0;
// right and left padding applied to this view to account for cutouts and rounded corners
@@ -284,9 +288,12 @@ public class KeyguardStatusBarView extends RelativeLayout {
WindowInsets updateWindowInsets(
WindowInsets insets,
StatusBarContentInsetsProvider insetsProvider) {
- mLayoutState = LAYOUT_NONE;
- if (updateLayoutConsideringCutout(insetsProvider)) {
- requestLayout();
+ if (!Objects.equals(mPreviousInsets, insets)) {
+ mLayoutState = LAYOUT_NONE;
+ if (updateLayoutConsideringCutout(insetsProvider)) {
+ requestLayout();
+ }
+ mPreviousInsets = new WindowInsets(insets);
}
return super.onApplyWindowInsets(insets);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index b2c4ef95242b..01de925f3d78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -65,6 +65,7 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags;
import com.android.systemui.bouncer.ui.BouncerView;
import com.android.systemui.bouncer.util.BouncerTestUtilsKt;
+import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor;
@@ -170,6 +171,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private final Lazy<SceneInteractor> mSceneInteractorLazy;
private final Lazy<DeviceEntryInteractor> mDeviceEntryInteractorLazy;
private final DismissCallbackRegistry mDismissCallbackRegistry;
+ private final CommunalSceneInteractor mCommunalSceneInteractor;
private Job mListenForAlternateBouncerTransitionSteps = null;
private Job mListenForKeyguardAuthenticatedBiometricsHandled = null;
@@ -406,7 +408,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
@Main DelayableExecutor executor,
Lazy<DeviceEntryInteractor> deviceEntryInteractorLazy,
DismissCallbackRegistry dismissCallbackRegistry,
- Lazy<BouncerInteractor> bouncerInteractor
+ Lazy<BouncerInteractor> bouncerInteractor,
+ CommunalSceneInteractor communalSceneInteractor
) {
mContext = context;
mExecutor = executor;
@@ -443,6 +446,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mStatusBarKeyguardViewManagerInteractor = statusBarKeyguardViewManagerInteractor;
mDeviceEntryInteractorLazy = deviceEntryInteractorLazy;
mDismissCallbackRegistry = dismissCallbackRegistry;
+ mCommunalSceneInteractor = communalSceneInteractor;
}
KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@@ -1364,11 +1368,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
- boolean hideBouncerOverDream = isBouncerShowing()
- && mDreamOverlayStateController.isOverlayActive();
+ boolean hideBouncerOverDreamOrHub = isBouncerShowing()
+ && (mDreamOverlayStateController.isOverlayActive()
+ || mCommunalSceneInteractor.isIdleOnCommunal().getValue());
mCentralSurfaces.endAffordanceLaunch();
// The second condition is for SIM card locked bouncer
- if (hideBouncerOverDream || (primaryBouncerIsScrimmed() && !needsFullscreenBouncer())) {
+ if (hideBouncerOverDreamOrHub
+ || (primaryBouncerIsScrimmed() && !needsFullscreenBouncer())) {
hideBouncer(false);
updateStates();
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt b/packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt
index 6b7de982e00a..22a74c86e0f1 100644
--- a/packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/window/data/repository/WindowRootViewBlurRepository.kt
@@ -16,10 +16,8 @@
package com.android.systemui.window.data.repository
-import android.annotation.SuppressLint
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
-import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
/** Repository that maintains state for the window blur effect. */
@@ -28,6 +26,4 @@ class WindowRootViewBlurRepository @Inject constructor() {
val blurRadius = MutableStateFlow(0)
val isBlurOpaque = MutableStateFlow(false)
-
- @SuppressLint("SharedFlowCreation") val onBlurApplied = MutableSharedFlow<Int>()
}
diff --git a/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt b/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt
index e21e0a1cadc7..9e369347dea5 100644
--- a/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/window/domain/interactor/WindowRootViewBlurInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.window.domain.interactor
+import android.annotation.SuppressLint
import android.util.Log
import com.android.systemui.Flags
import com.android.systemui.communal.domain.interactor.CommunalInteractor
@@ -28,6 +29,7 @@ import com.android.systemui.window.data.repository.WindowRootViewBlurRepository
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -52,6 +54,8 @@ constructor(
private val communalInteractor: CommunalInteractor,
private val repository: WindowRootViewBlurRepository,
) {
+ @SuppressLint("SharedFlowCreation") private val _onBlurAppliedEvent = MutableSharedFlow<Int>()
+
private var isBouncerTransitionInProgress: StateFlow<Boolean> =
if (Flags.bouncerUiRevamp()) {
keyguardTransitionInteractor
@@ -68,7 +72,7 @@ constructor(
* root view.
*/
suspend fun onBlurApplied(appliedBlurRadius: Int) {
- repository.onBlurApplied.emit(appliedBlurRadius)
+ _onBlurAppliedEvent.emit(appliedBlurRadius)
}
/** Radius of blur to be applied on the window root view. */
@@ -77,7 +81,7 @@ constructor(
/**
* Emits the applied blur radius whenever blur is successfully applied to the window root view.
*/
- val onBlurAppliedEvent: Flow<Int> = repository.onBlurApplied
+ val onBlurAppliedEvent: Flow<Int> = _onBlurAppliedEvent
/** Whether the blur applied is opaque or transparent. */
val isBlurOpaque: Flow<Boolean> =
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 e8054c07eac8..4ccfa29d4ba0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -206,7 +206,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock ShadeInteractor mShadeInteractor;
private @Mock ShadeWindowLogger mShadeWindowLogger;
private @Mock SelectedUserInteractor mSelectedUserInteractor;
- private @Mock UserTracker.Callback mUserTrackerCallback;
private @Mock KeyguardInteractor mKeyguardInteractor;
private @Mock KeyguardTransitionBootInteractor mKeyguardTransitionBootInteractor;
private @Captor ArgumentCaptor<KeyguardStateController.Callback>
@@ -281,7 +280,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
() -> mShadeInteractor,
mShadeWindowLogger,
() -> mSelectedUserInteractor,
- mock(UserTracker.class),
+ mUserTracker,
mKosmos.getNotificationShadeWindowModel(),
mSecureSettings,
mKosmos::getCommunalInteractor,
@@ -319,7 +318,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
} catch (Exception e) {
// Just so we don't have to add the exception signature to every test.
- fail(e.getMessage());
+ fail();
}
}
@@ -331,156 +330,18 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
/* First test the default behavior: handleUserSwitching() is not invoked */
when(mUserTracker.isUserSwitching()).thenReturn(false);
+ mViewMediator.mUpdateCallback = mock(KeyguardUpdateMonitorCallback.class);
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
- verify(mUserTrackerCallback, never()).onUserChanging(eq(userId), eq(mContext),
- any(Runnable.class));
+ verify(mViewMediator.mUpdateCallback, never()).onUserSwitching(userId);
/* Next test user switching is already in progress when started */
when(mUserTracker.isUserSwitching()).thenReturn(true);
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
- verify(mUserTrackerCallback).onUserChanging(eq(userId), eq(mContext),
- any(Runnable.class));
- }
-
- @Test
- @TestableLooper.RunWithLooper(setAsMainLooper = true)
- public void testGoingAwayFollowedByBeforeUserSwitchDoesNotHideKeyguard() {
- setCurrentUser(/* userId= */1099, /* isSecure= */false);
-
- // Setup keyguard
- mViewMediator.onSystemReady();
- processAllMessagesAndBgExecutorMessages();
- mViewMediator.setShowingLocked(true, "");
-
- // Request keyguard going away
- when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
- mViewMediator.mKeyguardGoingAwayRunnable.run();
-
- // After the request, begin a switch to a new secure user
- int nextUserId = 500;
- setCurrentUser(nextUserId, /* isSecure= */true);
- Runnable result = mock(Runnable.class);
- mViewMediator.handleBeforeUserSwitching(nextUserId, result);
- processAllMessagesAndBgExecutorMessages();
- verify(result).run();
-
- // After that request has begun, have WM tell us to exit keyguard
- RemoteAnimationTarget[] apps = new RemoteAnimationTarget[]{
- mock(RemoteAnimationTarget.class)
- };
- RemoteAnimationTarget[] wallpapers = new RemoteAnimationTarget[]{
- mock(RemoteAnimationTarget.class)
- };
- IRemoteAnimationFinishedCallback callback = mock(IRemoteAnimationFinishedCallback.class);
- mViewMediator.startKeyguardExitAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, apps, wallpapers,
- null, callback);
- processAllMessagesAndBgExecutorMessages();
-
- // The call to exit should be rejected, and keyguard should still be visible
- verify(mKeyguardUnlockAnimationController, never()).notifyStartSurfaceBehindRemoteAnimation(
- any(), any(), any(), anyLong(), anyBoolean());
- try {
- assertATMSLockScreenShowing(true);
- } catch (Exception e) {
- fail(e.getMessage());
- }
- assertTrue(mViewMediator.isShowingAndNotOccluded());
- }
-
- @Test
- @TestableLooper.RunWithLooper(setAsMainLooper = true)
- public void testUserSwitchToSecureUserShowsBouncer() {
- setCurrentUser(/* userId= */1099, /* isSecure= */true);
-
- // Setup keyguard
- mViewMediator.onSystemReady();
- processAllMessagesAndBgExecutorMessages();
- mViewMediator.setShowingLocked(true, "");
-
- // After the request, begin a switch to a new secure user
- int nextUserId = 500;
- setCurrentUser(nextUserId, /* isSecure= */true);
-
- Runnable beforeResult = mock(Runnable.class);
- mViewMediator.handleBeforeUserSwitching(nextUserId, beforeResult);
- processAllMessagesAndBgExecutorMessages();
- verify(beforeResult).run();
-
- // Dismiss should not be called while user switch is in progress
- Runnable onSwitchResult = mock(Runnable.class);
- mViewMediator.handleUserSwitching(nextUserId, onSwitchResult);
- processAllMessagesAndBgExecutorMessages();
- verify(onSwitchResult).run();
- verify(mStatusBarKeyguardViewManager, never()).dismissAndCollapse();
-
- // The attempt to dismiss only comes on user switch complete, which will trigger a call to
- // show the bouncer in StatusBarKeyguardViewManager
- mViewMediator.handleUserSwitchComplete(nextUserId);
- TestableLooper.get(this).moveTimeForward(600);
- processAllMessagesAndBgExecutorMessages();
-
- verify(mStatusBarKeyguardViewManager).dismissAndCollapse();
- }
-
- @Test
- @TestableLooper.RunWithLooper(setAsMainLooper = true)
- public void testUserSwitchToInsecureUserDismissesKeyguard() {
- int userId = 1099;
- when(mUserTracker.getUserId()).thenReturn(userId);
-
- // Setup keyguard
- mViewMediator.onSystemReady();
- processAllMessagesAndBgExecutorMessages();
- mViewMediator.setShowingLocked(true, "");
-
- // After the request, begin a switch to an insecure user
- int nextUserId = 500;
- when(mLockPatternUtils.isSecure(nextUserId)).thenReturn(false);
-
- Runnable beforeResult = mock(Runnable.class);
- mViewMediator.handleBeforeUserSwitching(nextUserId, beforeResult);
- processAllMessagesAndBgExecutorMessages();
- verify(beforeResult).run();
-
- // The call to dismiss comes during the user switch
- Runnable onSwitchResult = mock(Runnable.class);
- mViewMediator.handleUserSwitching(nextUserId, onSwitchResult);
- processAllMessagesAndBgExecutorMessages();
- verify(onSwitchResult).run();
-
- verify(mStatusBarKeyguardViewManager).dismissAndCollapse();
- }
-
- @Test
- @TestableLooper.RunWithLooper(setAsMainLooper = true)
- public void testUserSwitchToSecureUserWhileKeyguardNotVisibleShowsKeyguard() {
- setCurrentUser(/* userId= */1099, /* isSecure= */true);
-
- // Setup keyguard as not visible
- mViewMediator.onSystemReady();
- processAllMessagesAndBgExecutorMessages();
- mViewMediator.setShowingLocked(false, "");
- processAllMessagesAndBgExecutorMessages();
-
- // Begin a switch to a new secure user
- int nextUserId = 500;
- setCurrentUser(nextUserId, /* isSecure= */true);
-
- Runnable beforeResult = mock(Runnable.class);
- mViewMediator.handleBeforeUserSwitching(nextUserId, beforeResult);
- processAllMessagesAndBgExecutorMessages();
- verify(beforeResult).run();
-
- try {
- assertATMSLockScreenShowing(true);
- } catch (Exception e) {
- fail();
- }
- assertTrue(mViewMediator.isShowingAndNotOccluded());
+ verify(mViewMediator.mUpdateCallback).onUserSwitching(userId);
}
@Test
@@ -1244,7 +1105,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
processAllMessagesAndBgExecutorMessages();
verify(mStatusBarKeyguardViewManager, never()).reset(anyBoolean());
-
+ assertATMSAndKeyguardViewMediatorStatesMatch();
}
@Test
@@ -1288,7 +1149,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
IRemoteAnimationFinishedCallback callback = mock(IRemoteAnimationFinishedCallback.class);
when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true);
- mViewMediator.mKeyguardGoingAwayRunnable.run();
mViewMediator.startKeyguardExitAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, apps, wallpapers,
null, callback);
processAllMessagesAndBgExecutorMessages();
@@ -1343,6 +1203,13 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
// The captor will have the most recent setLockScreenShown call's value.
assertEquals(showing, showingCaptor.getValue());
+
+ // We're now just after the last setLockScreenShown call. If we expect the lockscreen to be
+ // showing, ensure that we didn't subsequently ask for it to go away.
+ if (showing) {
+ orderedSetLockScreenShownCalls.verify(mActivityTaskManagerService, never())
+ .keyguardGoingAway(anyInt());
+ }
}
/**
@@ -1504,7 +1371,6 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mKeyguardTransitionBootInteractor,
mKosmos::getCommunalSceneInteractor,
mock(WindowManagerOcclusionManager.class));
- mViewMediator.mUserChangedCallback = mUserTrackerCallback;
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null);
@@ -1518,10 +1384,4 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private void captureKeyguardUpdateMonitorCallback() {
verify(mUpdateMonitor).registerCallback(mKeyguardUpdateMonitorCallbackCaptor.capture());
}
-
- private void setCurrentUser(int userId, boolean isSecure) {
- when(mUserTracker.getUserId()).thenReturn(userId);
- when(mSelectedUserInteractor.getSelectedUserId()).thenReturn(userId);
- when(mLockPatternUtils.isSecure(userId)).thenReturn(isSecure);
- }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
index ce298bb90ba2..825e0143800b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneKosmos.kt
@@ -5,6 +5,8 @@ import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.classifier.domain.interactor.falsingInteractor
import com.android.systemui.haptics.msdl.msdlPlayer
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
+import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel
+import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.lightRevealScrimViewModel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
@@ -105,6 +107,8 @@ val Kosmos.sceneContainerViewModelFactory by Fixture {
lightRevealScrim = lightRevealScrimViewModel,
wallpaperViewModel = wallpaperViewModel,
keyguardInteractor = keyguardInteractor,
+ burnIn = aodBurnInViewModel,
+ clock = keyguardClockViewModel,
)
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt
deleted file mode 100644
index 923b36d4f2cf..000000000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModelBuilder.kt
+++ /dev/null
@@ -1,39 +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.systemui.statusbar.phone.ongoingcall.shared.model
-
-import android.app.PendingIntent
-import com.android.systemui.statusbar.StatusBarIconView
-import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
-
-/** Helper for building [OngoingCallModel.InCall] instances in tests. */
-fun inCallModel(
- startTimeMs: Long,
- notificationIcon: StatusBarIconView? = null,
- intent: PendingIntent? = null,
- notificationKey: String = "test",
- appName: String = "",
- promotedContent: PromotedNotificationContentModel? = null,
-) =
- OngoingCallModel.InCall(
- startTimeMs,
- notificationIcon,
- intent,
- notificationKey,
- appName,
- promotedContent,
- )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt
new file mode 100644
index 000000000000..7bcedcaa99d1
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallTestHelper.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.ongoingcall.shared.model
+
+import android.app.PendingIntent
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.notification.shared.CallType
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
+import org.mockito.kotlin.mock
+
+/** Helper for building [OngoingCallModel.InCall] instances in tests. */
+fun inCallModel(
+ startTimeMs: Long,
+ notificationIcon: StatusBarIconView? = null,
+ intent: PendingIntent? = null,
+ notificationKey: String = "test",
+ appName: String = "",
+ promotedContent: PromotedNotificationContentModel? = null,
+) =
+ OngoingCallModel.InCall(
+ startTimeMs,
+ notificationIcon,
+ intent,
+ notificationKey,
+ appName,
+ promotedContent,
+ )
+
+object OngoingCallTestHelper {
+ /**
+ * Sets the call state to be no call, and does it correctly based on whether
+ * [StatusBarChipsModernization] is enabled or not.
+ */
+ fun setNoCallState(kosmos: Kosmos) {
+ if (StatusBarChipsModernization.isEnabled) {
+ // TODO(b/372657935): Maybe don't clear *all* notifications
+ kosmos.activeNotificationListRepository.activeNotifications.value =
+ ActiveNotificationsStore()
+ } else {
+ kosmos.ongoingCallRepository.setOngoingCallState(OngoingCallModel.NoCall)
+ }
+ }
+
+ /**
+ * Sets the ongoing call state correctly based on whether [StatusBarChipsModernization] is
+ * enabled or not.
+ */
+ fun setOngoingCallState(
+ kosmos: Kosmos,
+ startTimeMs: Long = 1000L,
+ key: String = "notif",
+ statusBarChipIconView: StatusBarIconView? = createStatusBarIconViewOrNull(),
+ promotedContent: PromotedNotificationContentModel? = null,
+ contentIntent: PendingIntent? = null,
+ uid: Int = DEFAULT_UID,
+ ) {
+ if (StatusBarChipsModernization.isEnabled) {
+ kosmos.activeNotificationListRepository.activeNotifications.value =
+ ActiveNotificationsStore.Builder()
+ .apply {
+ addIndividualNotif(
+ activeNotificationModel(
+ key = key,
+ whenTime = startTimeMs,
+ callType = CallType.Ongoing,
+ statusBarChipIcon = statusBarChipIconView,
+ contentIntent = contentIntent,
+ promotedContent = promotedContent,
+ uid = uid,
+ )
+ )
+ }
+ .build()
+ } else {
+ kosmos.ongoingCallRepository.setOngoingCallState(
+ inCallModel(
+ startTimeMs = startTimeMs,
+ notificationIcon = statusBarChipIconView,
+ intent = contentIntent,
+ notificationKey = key,
+ promotedContent = promotedContent,
+ )
+ )
+ }
+ }
+
+ private fun createStatusBarIconViewOrNull(): StatusBarIconView? =
+ if (StatusBarConnectedDisplays.isEnabled) {
+ null
+ } else {
+ mock<StatusBarIconView>()
+ }
+
+ private const val DEFAULT_UID = 886
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
index 0354d2be60c9..2ef11f4b78e1 100644
--- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
@@ -20,11 +20,14 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M
import android.content.Context;
import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.widget.ImageButton;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
@@ -51,6 +54,8 @@ public class AutoclickTypePanel {
private final LinearLayout mDragButton;
private final LinearLayout mScrollButton;
+ private LinearLayout mSelectedButton;
+
public AutoclickTypePanel(Context context, WindowManager windowManager) {
mContext = context;
mWindowManager = windowManager;
@@ -80,6 +85,40 @@ public class AutoclickTypePanel {
// Initializes panel as collapsed state and only displays the left click button.
hideAllClickTypeButtons();
mLeftClickButton.setVisibility(View.VISIBLE);
+ setSelectedButton(/* selectedButton= */ mLeftClickButton);
+ }
+
+ /** Sets the selected button and updates the newly and previously selected button styling. */
+ private void setSelectedButton(@NonNull LinearLayout selectedButton) {
+ // Updates the previously selected button styling.
+ if (mSelectedButton != null) {
+ toggleSelectedButtonStyle(mSelectedButton, /* isSelected= */ false);
+ }
+
+ mSelectedButton = selectedButton;
+
+ // Updates the newly selected button styling.
+ toggleSelectedButtonStyle(selectedButton, /* isSelected= */ true);
+ }
+
+ private void toggleSelectedButtonStyle(@NonNull LinearLayout button, boolean isSelected) {
+ // Sets icon background color.
+ GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground();
+ gradientDrawable.setColor(
+ mContext.getColor(
+ isSelected
+ ? R.color.materialColorPrimary
+ : R.color.materialColorSurfaceContainer));
+
+ // Sets icon color.
+ ImageButton imageButton = (ImageButton) button.getChildAt(/* index= */ 0);
+ Drawable drawable = imageButton.getDrawable();
+ drawable.mutate()
+ .setTint(
+ mContext.getColor(
+ isSelected
+ ? R.color.materialColorSurfaceContainer
+ : R.color.materialColorPrimary));
}
public void show() {
@@ -97,6 +136,9 @@ public class AutoclickTypePanel {
// buttons except the one user selected.
hideAllClickTypeButtons();
button.setVisibility(View.VISIBLE);
+
+ // Sets the newly selected button.
+ setSelectedButton(/* selectedButton= */ button);
} else {
// If the panel is already collapsed, we just need to expand it.
showAllClickTypeButtons();
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index 43764442e2cf..d0ee7af1bbfb 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -27,6 +27,7 @@ import android.annotation.WorkerThread;
import android.app.appfunctions.AppFunctionException;
import android.app.appfunctions.AppFunctionManager;
import android.app.appfunctions.AppFunctionManagerHelper;
+import android.app.appfunctions.AppFunctionManagerHelper.AppFunctionNotFoundException;
import android.app.appfunctions.AppFunctionRuntimeMetadata;
import android.app.appfunctions.AppFunctionStaticMetadataHelper;
import android.app.appfunctions.ExecuteAppFunctionAidlRequest;
@@ -513,7 +514,9 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
e = e.getCause();
}
int resultCode = AppFunctionException.ERROR_SYSTEM_ERROR;
- if (e instanceof AppSearchException appSearchException) {
+ if (e instanceof AppFunctionNotFoundException) {
+ resultCode = AppFunctionException.ERROR_FUNCTION_NOT_FOUND;
+ } else if (e instanceof AppSearchException appSearchException) {
resultCode =
mapAppSearchResultFailureCodeToExecuteAppFunctionResponse(
appSearchException.getResultCode());
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index e0fbaf43ea43..27e9e44f1090 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -31,7 +31,6 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
-import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -3905,6 +3904,10 @@ class UserController implements Handler.Callback {
return mService.mWindowManager;
}
+ ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+ return mService.mAtmInternal;
+ }
+
void activityManagerOnUserStopped(@UserIdInt int userId) {
LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId);
}
@@ -4119,25 +4122,40 @@ class UserController implements Handler.Callback {
}
void lockDeviceNowAndWaitForKeyguardShown() {
+ if (getWindowManager().isKeyguardLocked()) {
+ Slogf.w(TAG, "Not locking the device since the keyguard is already locked");
+ return;
+ }
+
final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
t.traceBegin("lockDeviceNowAndWaitForKeyguardShown");
final CountDownLatch latch = new CountDownLatch(1);
- Bundle bundle = new Bundle();
- bundle.putBinder(LOCK_ON_USER_SWITCH_CALLBACK, new IRemoteCallback.Stub() {
- public void sendResult(Bundle data) {
- latch.countDown();
- }
- });
- getWindowManager().lockNow(bundle);
+ ActivityTaskManagerInternal.ScreenObserver screenObserver =
+ new ActivityTaskManagerInternal.ScreenObserver() {
+ @Override
+ public void onAwakeStateChanged(boolean isAwake) {
+
+ }
+
+ @Override
+ public void onKeyguardStateChanged(boolean isShowing) {
+ if (isShowing) {
+ latch.countDown();
+ }
+ }
+ };
+
+ getActivityTaskManagerInternal().registerScreenObserver(screenObserver);
+ getWindowManager().lockDeviceNow();
try {
if (!latch.await(20, TimeUnit.SECONDS)) {
- throw new RuntimeException("User controller expected a callback while waiting "
- + "to show the keyguard. Timed out after 20 seconds.");
+ throw new RuntimeException("Keyguard is not shown in 20 seconds");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
+ getActivityTaskManagerInternal().unregisterScreenObserver(screenObserver);
t.traceEnd();
}
}
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index cc4c2b5bf893..068d68d25017 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -40,6 +40,7 @@ import static com.android.server.pm.AppsFilterUtils.canQueryViaUsesLibrary;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ApplicationPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SigningDetails;
@@ -173,6 +174,10 @@ public final class AppsFilterImpl extends AppsFilterLocked implements Watchable,
* Report a change to observers.
*/
private void onChanged() {
+ // App visibility may have changed, which means that earlier fetches from these caches may
+ // be invalid.
+ PackageManager.invalidatePackageInfoCache();
+ ApplicationPackageManager.invalidateGetPackagesForUidCache();
dispatchChange(this);
}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
index 66aaa562b873..a01df8bf108d 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
@@ -37,6 +37,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.UserInfo;
+import android.app.PropertyInvalidatedCache;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
@@ -50,6 +51,8 @@ import android.util.SparseArray;
import androidx.annotation.NonNull;
+import android.app.ApplicationPackageManager;
+import android.content.pm.PackageManager;
import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedActivity;
@@ -64,8 +67,10 @@ import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.om.OverlayReferenceMapper;
import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableTester;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -244,6 +249,55 @@ public class AppsFilterImplTest {
(Answer<Boolean>) invocation ->
((AndroidPackage) invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion()
>= Build.VERSION_CODES.R);
+ PropertyInvalidatedCache.setTestMode(true);
+ PackageManager.sApplicationInfoCache.testPropertyName();
+ ApplicationPackageManager.sGetPackagesForUidCache.testPropertyName();
+ }
+
+ @After
+ public void tearDown() {
+ PropertyInvalidatedCache.setTestMode(false);
+ }
+
+ /**
+ * A class to make it easier to verify that PM caches are properly invalidated by
+ * AppsFilterImpl operations. This extends WatchableTester to test the cache nonces along
+ * with change reporting.
+ */
+ private static class NonceTester extends WatchableTester {
+ // The nonces from caches under consideration. The no-parameter constructor fetches the
+ // values from the cacches.
+ private static record Nonces(long applicationInfo, long packageInfo) {
+ Nonces() {
+ this(ApplicationPackageManager.sGetPackagesForUidCache.getNonce(),
+ PackageManager.sApplicationInfoCache.getNonce());
+ }
+ }
+
+ // Track the latest cache nonces.
+ private Nonces mNonces;
+
+ NonceTester(Watchable w, String k) {
+ super(w, k);
+ mNonces = new Nonces();
+ }
+
+ @Override
+ public void verifyChangeReported(String msg) {
+ super.verifyChangeReported(msg);
+ Nonces update = new Nonces();
+ assertTrue(msg, update.applicationInfo != mNonces.applicationInfo);
+ assertTrue(msg, update.packageInfo != mNonces.packageInfo);
+ mNonces = update;
+ }
+
+ @Override
+ public void verifyNoChangeReported(String msg) {
+ super.verifyNoChangeReported(msg);
+ Nonces update = new Nonces();
+ assertTrue(msg, update.applicationInfo == mNonces.applicationInfo);
+ assertTrue(msg, update.packageInfo == mNonces.packageInfo);
+ }
}
@Test
@@ -1167,7 +1221,7 @@ public class AppsFilterImplTest {
final AppsFilterImpl appsFilter =
new AppsFilterImpl(mFeatureConfigMock, new String[]{}, /* systemAppsQueryable */
false, /* overlayProvider */ null, mMockHandler);
- final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ final WatchableTester watcher = new NonceTester(appsFilter, "onChange");
watcher.register();
simulateAddBasicAndroid(appsFilter);
watcher.verifyChangeReported("addBasicAndroid");
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
index f0334598bd30..7b8824cb0e3d 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
@@ -21,6 +21,7 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.graphics.drawable.GradientDrawable;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableLooper;
@@ -28,6 +29,8 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
+import androidx.annotation.NonNull;
+
import com.android.internal.R;
import org.junit.Before;
@@ -87,6 +90,11 @@ public class AutoclickTypePanelTest {
}
@Test
+ public void AutoclickTypePanel_initialState_correctButtonStyle() {
+ verifyButtonHasSelectedStyle(mLeftClickButton);
+ }
+
+ @Test
public void togglePanelExpansion_onClick_expandedTrue() {
// On clicking left click button, the panel is expanded and all buttons are visible.
mLeftClickButton.callOnClick();
@@ -116,4 +124,21 @@ public class AutoclickTypePanelTest {
assertThat(mDoubleClickButton.getVisibility()).isEqualTo(View.GONE);
assertThat(mDragButton.getVisibility()).isEqualTo(View.GONE);
}
+
+ @Test
+ public void togglePanelExpansion_selectButton_correctStyle() {
+ // By first click, the panel is expanded.
+ mLeftClickButton.callOnClick();
+
+ // Clicks any button in the expanded state to select a type button.
+ mScrollButton.callOnClick();
+
+ verifyButtonHasSelectedStyle(mScrollButton);
+ }
+
+ private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) {
+ GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground();
+ assertThat(gradientDrawable.getColor().getDefaultColor())
+ .isEqualTo(mTestableContext.getColor(R.color.materialColorPrimary));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 1627f683cd3e..06958b81d846 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -25,7 +25,6 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
-import static android.app.KeyguardManager.LOCK_ON_USER_SWITCH_CALLBACK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
@@ -116,6 +115,7 @@ import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.UserTypeDetails;
import com.android.server.pm.UserTypeFactory;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerService;
import com.google.common.collect.Range;
@@ -1563,11 +1563,11 @@ public class UserControllerTest {
// and the thread is still alive
assertTrue(threadStartUser.isAlive());
- // mock the binder response for the user switch completion
- ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
- verify(mInjector.mWindowManagerMock).lockNow(captor.capture());
- IRemoteCallback.Stub.asInterface(captor.getValue().getBinder(
- LOCK_ON_USER_SWITCH_CALLBACK)).sendResult(null);
+ // mock send the keyguard shown event
+ ArgumentCaptor<ActivityTaskManagerInternal.ScreenObserver> captor = ArgumentCaptor.forClass(
+ ActivityTaskManagerInternal.ScreenObserver.class);
+ verify(mInjector.mActivityTaskManagerInternal).registerScreenObserver(captor.capture());
+ captor.getValue().onKeyguardStateChanged(true);
// verify the switch now moves on...
Thread.sleep(1000);
@@ -1757,6 +1757,7 @@ public class UserControllerTest {
private final IStorageManager mStorageManagerMock;
private final UserManagerInternal mUserManagerInternalMock;
private final WindowManagerService mWindowManagerMock;
+ private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
private final PowerManagerInternal mPowerManagerInternal;
private final AlarmManagerInternal mAlarmManagerInternal;
private final KeyguardManager mKeyguardManagerMock;
@@ -1778,6 +1779,7 @@ public class UserControllerTest {
mUserManagerMock = mock(UserManagerService.class);
mUserManagerInternalMock = mock(UserManagerInternal.class);
mWindowManagerMock = mock(WindowManagerService.class);
+ mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
mStorageManagerMock = mock(IStorageManager.class);
mPowerManagerInternal = mock(PowerManagerInternal.class);
mAlarmManagerInternal = mock(AlarmManagerInternal.class);
@@ -1841,6 +1843,11 @@ public class UserControllerTest {
}
@Override
+ ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+ return mActivityTaskManagerInternal;
+ }
+
+ @Override
PowerManagerInternal getPowerManagerInternal() {
return mPowerManagerInternal;
}