summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Notification.java8
-rw-r--r--core/java/android/content/pm/PackageParser.java18
-rw-r--r--core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java33
-rw-r--r--core/java/android/util/IntArray.java2
-rw-r--r--core/java/android/util/LongArray.java2
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java4
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/tests/coretests/src/android/animation/ValueAnimatorTests.java25
-rw-r--r--data/etc/Android.bp6
-rw-r--r--data/etc/preinstalled-packages-asl-files.xml26
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java99
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java96
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java65
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt16
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt6
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt2
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java20
-rw-r--r--packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java81
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt52
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java39
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java21
-rw-r--r--services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java18
-rw-r--r--services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java3
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java9
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java4
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java23
-rw-r--r--tools/validatekeymaps/Android.bp2
54 files changed, 903 insertions, 135 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 63da0a231286..d37576092af2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2916,6 +2916,14 @@ public class Notification implements Parcelable
}
}
+ if (isStyle(CallStyle.class) & extras != null) {
+ Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON);
+ if (callPerson != null) {
+ visitor.accept(callPerson.getIconUri());
+ }
+ visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON));
+ }
+
if (mBubbleMetadata != null) {
visitIconUri(visitor, mBubbleMetadata.getIcon());
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 048289f56a0c..960d10adbfbb 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2628,6 +2628,15 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + targetCode
@@ -2699,6 +2708,15 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 3e1c5bb3d7ec..8cc4cdb955ca 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -316,6 +316,15 @@ public class FrameworkParsingPackageUtils {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Parsed package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -368,19 +377,27 @@ public class FrameworkParsingPackageUtils {
return input.success(targetVers);
}
+ // If it's a pre-release SDK and the codename matches this platform, it
+ // definitely targets this SDK.
+ if (matchTargetCode(platformSdkCodenames, targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Parsed package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
try {
if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
} catch (IllegalArgumentException e) {
- // isAtMost() throws it when encountering an older SDK codename
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage());
- }
-
- // If it's a pre-release SDK and the codename matches this platform, it
- // definitely targets this SDK.
- if (matchTargetCode(platformSdkCodenames, targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
}
// Otherwise, we're looking at an incompatible pre-release SDK.
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index bc0e35da37c3..511cb2df712d 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -43,7 +43,7 @@ public class IntArray implements Cloneable {
* Creates an empty IntArray with the default initial capacity.
*/
public IntArray() {
- this(10);
+ this(0);
}
/**
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 53dddeb5ad0b..9f269ed74048 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -48,7 +48,7 @@ public class LongArray implements Cloneable {
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public LongArray() {
- this(10);
+ this(0);
}
/**
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 2b08a5525d82..853fe2f114f7 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -77,6 +77,10 @@ public class SystemUiSystemPropertiesFlags {
/** Gating the removal of sorting-notifications-by-interruptiveness. */
public static final Flag NO_SORT_BY_INTERRUPTIVENESS =
devFlag("persist.sysui.notification.no_sort_by_interruptiveness");
+
+ /** Gating the logging of DND state change events. */
+ public static final Flag LOG_DND_STATE_EVENTS =
+ devFlag("persist.sysui.notification.log_dnd_state_events");
}
//// == End of flags. Everything below this line is the implementation. == ////
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e62477f0dbe3..f6c9fabb7896 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1036,9 +1036,9 @@
android:protectionLevel="dangerous" />
<!-- @SystemApi @hide Allows an application to communicate over satellite.
- Only granted if the application is a system app. -->
+ Only granted if the application is a system app or privileged app. -->
<permission android:name="android.permission.SATELLITE_COMMUNICATION"
- android:protectionLevel="internal|role" />
+ android:protectionLevel="role|signature|privileged" />
<!-- ====================================================================== -->
<!-- Permissions for accessing external storage -->
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index a53d57f0383c..a102b3ed9971 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -1127,6 +1127,31 @@ public class ValueAnimatorTests {
mActivityRule.runOnUiThread(() -> {});
}
+ @Test
+ public void restartValueAnimator() throws Throwable {
+ CountDownLatch latch = new CountDownLatch(1);
+ ValueAnimator.AnimatorUpdateListener listener = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ if (((float) animation.getAnimatedValue()) != A1_START_VALUE) {
+ latch.countDown();
+ }
+ }
+ };
+ a1.addUpdateListener(listener);
+
+ mActivityRule.runOnUiThread(() -> {
+ a1.start();
+ });
+
+ // wait for a change in the value
+ assertTrue(latch.await(2, TimeUnit.SECONDS));
+
+ mActivityRule.runOnUiThread(() -> {
+ a1.start();
+ assertEquals(A1_START_VALUE, a1.getAnimatedValue());
+ });
+ }
class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
boolean wasRunning = false;
long firstRunningFrameTime = -1;
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index f233c6eca13b..6a1f3f959185 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -54,6 +54,12 @@ prebuilt_etc {
src: "hiddenapi-package-whitelist.xml",
}
+prebuilt_etc {
+ name: "preinstalled-packages-asl-files.xml",
+ sub_dir: "sysconfig",
+ src: "preinstalled-packages-asl-files.xml",
+}
+
// Privapp permission whitelist files
prebuilt_etc {
diff --git a/data/etc/preinstalled-packages-asl-files.xml b/data/etc/preinstalled-packages-asl-files.xml
new file mode 100644
index 000000000000..6b5401c921f1
--- /dev/null
+++ b/data/etc/preinstalled-packages-asl-files.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<!--
+This XML file declares which preinstalled apps have Android Security Label data by declaring the
+path to the XML file containing this data.
+
+Example usage:
+ <asl-file package="com.foo.bar" path="/vendor/etc/asl/com.foo.bar.xml"/>
+-->
+
+<config></config>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8ece337971a9..40cb7f2194e9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -518,6 +518,8 @@ applications that come with the platform
<permission name="android.permission.LOG_FOREGROUND_RESOURCE_USE"/>
<!-- Permission required for CTS test - CtsVoiceInteractionTestCases -->
<permission name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
+ <!-- Permission required for CTS test - SatelliteManagerTest -->
+ <permission name="android.permission.SATELLITE_COMMUNICATION"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 47d3a5c52074..dc27ceb7f51c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -20,6 +20,9 @@ import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTas
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
@@ -37,7 +40,9 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Global;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.MathUtils;
import android.util.SparseArray;
import android.view.IRemoteAnimationRunner;
import android.view.InputDevice;
@@ -56,6 +61,7 @@ import android.window.IOnBackInvokedCallback;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.view.AppearanceRegion;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
@@ -80,6 +86,17 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
public static boolean IS_U_ANIMATION_ENABLED =
SystemProperties.getInt("persist.wm.debug.predictive_back_anim",
SETTING_VALUE_ON) == SETTING_VALUE_ON;
+
+ public static final float FLING_MAX_LENGTH_SECONDS = 0.1f; // 100ms
+ public static final float FLING_SPEED_UP_FACTOR = 0.6f;
+
+ /**
+ * The maximum additional progress in case of fling gesture.
+ * The end animation starts after the user lifts the finger from the screen, we continue to
+ * fire {@link BackEvent}s until the velocity reaches 0.
+ */
+ private static final float MAX_FLING_PROGRESS = 0.3f; /* 30% of the screen */
+
/** Predictive back animation developer option */
private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
/**
@@ -96,6 +113,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private boolean mShouldStartOnNextMoveEvent = false;
/** @see #setTriggerBack(boolean) */
private boolean mTriggerBack;
+ private FlingAnimationUtils mFlingAnimationUtils;
@Nullable
private BackNavigationInfo mBackNavigationInfo;
@@ -174,6 +192,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mBgHandler = bgHandler;
shellInit.addInitCallback(this::onInit, this);
mAnimationBackground = backAnimationBackground;
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ mFlingAnimationUtils = new FlingAnimationUtils.Builder(displayMetrics)
+ .setMaxLengthSeconds(FLING_MAX_LENGTH_SECONDS)
+ .setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
+ .build();
}
@VisibleForTesting
@@ -465,6 +488,78 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
}
+
+ /**
+ * Allows us to manage the fling gesture, it smoothly animates the current progress value to
+ * the final position, calculated based on the current velocity.
+ *
+ * @param callback the callback to be invoked when the animation ends.
+ */
+ private void dispatchOrAnimateOnBackInvoked(IOnBackInvokedCallback callback) {
+ if (callback == null) {
+ return;
+ }
+
+ boolean animationStarted = false;
+
+ if (mBackNavigationInfo != null && mBackNavigationInfo.isAnimationCallback()) {
+
+ final BackMotionEvent backMotionEvent = mTouchTracker.createProgressEvent();
+ if (backMotionEvent != null) {
+ // Constraints - absolute values
+ float minVelocity = mFlingAnimationUtils.getMinVelocityPxPerSecond();
+ float maxVelocity = mFlingAnimationUtils.getHighVelocityPxPerSecond();
+ float maxX = mTouchTracker.getMaxX(); // px
+ float maxFlingDistance = maxX * MAX_FLING_PROGRESS; // px
+
+ // Current state
+ float currentX = backMotionEvent.getTouchX();
+ float velocity = MathUtils.constrain(backMotionEvent.getVelocityX(),
+ -maxVelocity, maxVelocity);
+
+ // Target state
+ float animationFaction = velocity / maxVelocity; // value between -1 and 1
+ float flingDistance = animationFaction * maxFlingDistance; // px
+ float endX = MathUtils.constrain(currentX + flingDistance, 0f, maxX);
+
+ if (!Float.isNaN(endX)
+ && currentX != endX
+ && Math.abs(velocity) >= minVelocity) {
+ ValueAnimator animator = ValueAnimator.ofFloat(currentX, endX);
+
+ mFlingAnimationUtils.apply(
+ /* animator = */ animator,
+ /* currValue = */ currentX,
+ /* endValue = */ endX,
+ /* velocity = */ velocity,
+ /* maxDistance = */ maxFlingDistance
+ );
+
+ animator.addUpdateListener(animation -> {
+ Float animatedValue = (Float) animation.getAnimatedValue();
+ float progress = mTouchTracker.getProgress(animatedValue);
+ final BackMotionEvent backEvent = mTouchTracker
+ .createProgressEvent(progress);
+ dispatchOnBackProgressed(mActiveCallback, backEvent);
+ });
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ dispatchOnBackInvoked(callback);
+ }
+ });
+ animator.start();
+ animationStarted = true;
+ }
+ }
+ }
+
+ if (!animationStarted) {
+ dispatchOnBackInvoked(callback);
+ }
+ }
+
private void dispatchOnBackInvoked(IOnBackInvokedCallback callback) {
if (callback == null) {
return;
@@ -530,7 +625,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (mBackNavigationInfo != null) {
final IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
if (mTriggerBack) {
- dispatchOnBackInvoked(callback);
+ dispatchOrAnimateOnBackInvoked(callback);
} else {
dispatchOnBackCancelled(callback);
}
@@ -605,7 +700,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
// The next callback should be {@link #onBackAnimationFinished}.
if (mTriggerBack) {
- dispatchOnBackInvoked(mActiveCallback);
+ dispatchOrAnimateOnBackInvoked(mActiveCallback);
} else {
dispatchOnBackCancelled(mActiveCallback);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 904574b08562..7a00f5b9bab4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -16,7 +16,10 @@
package com.android.wm.shell.back;
+import android.annotation.FloatRange;
import android.os.SystemProperties;
+import android.util.MathUtils;
+import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.window.BackEvent;
import android.window.BackMotionEvent;
@@ -99,28 +102,42 @@ class TouchTracker {
}
BackMotionEvent createProgressEvent() {
- float progressThreshold = PROGRESS_THRESHOLD >= 0
- ? PROGRESS_THRESHOLD : mProgressThreshold;
- progressThreshold = progressThreshold == 0 ? 1 : progressThreshold;
float progress = 0;
// Progress is always 0 when back is cancelled and not restarted.
if (!mCancelled) {
- // If back is committed, progress is the distance between the last and first touch
- // point, divided by the max drag distance. Otherwise, it's the distance between
- // the last touch point and the starting threshold, divided by max drag distance.
- // The starting threshold is initially the first touch location, and updated to
- // the location everytime back is restarted after being cancelled.
- float startX = mTriggerBack ? mInitTouchX : mStartThresholdX;
- float deltaX = Math.max(
- mSwipeEdge == BackEvent.EDGE_LEFT
- ? mLatestTouchX - startX
- : startX - mLatestTouchX,
- 0);
- progress = Math.min(Math.max(deltaX / progressThreshold, 0), 1);
+ progress = getProgress(mLatestTouchX);
}
return createProgressEvent(progress);
}
+ /**
+ * Progress value computed from the touch position.
+ *
+ * @param touchX the X touch position of the {@link MotionEvent}.
+ * @return progress value
+ */
+ @FloatRange(from = 0.0, to = 1.0)
+ float getProgress(float touchX) {
+ // If back is committed, progress is the distance between the last and first touch
+ // point, divided by the max drag distance. Otherwise, it's the distance between
+ // the last touch point and the starting threshold, divided by max drag distance.
+ // The starting threshold is initially the first touch location, and updated to
+ // the location everytime back is restarted after being cancelled.
+ float startX = mTriggerBack ? mInitTouchX : mStartThresholdX;
+ float deltaX = Math.abs(startX - touchX);
+ float maxX = getMaxX();
+ maxX = maxX == 0 ? 1 : maxX;
+ return MathUtils.constrain(deltaX / maxX, 0, 1);
+ }
+
+ /**
+ * Maximum X value (in pixels).
+ * Progress is considered to be completed (1f) when this limit is exceeded.
+ */
+ float getMaxX() {
+ return PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
+ }
+
BackMotionEvent createProgressEvent(float progress) {
return new BackMotionEvent(
/* touchX = */ mLatestTouchX,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index c8062bcf8519..b6216b340b38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1532,6 +1532,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (snapshotSurface != null) {
mSyncTransactionQueue.queue(wct);
mSyncTransactionQueue.runInSync(t -> {
+ // reset the pinch gesture
+ maybePerformFinishResizeCallback();
+
// Scale the snapshot from its pre-resize bounds to the post-resize bounds.
mSurfaceTransactionHelper.scale(t, snapshotSurface, preResizeBounds,
snapshotDest);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
index 222307fba8c2..5f6b3fe1e250 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
@@ -31,6 +31,12 @@ import java.util.Objects;
abstract class TvPipAction {
+ /**
+ * Extras key for adding a boolean to the {@link Notification.Action} to differentiate custom
+ * from system actions, most importantly to identify custom close actions.
+ **/
+ public static final String EXTRA_IS_PIP_CUSTOM_ACTION = "EXTRA_IS_PIP_CUSTOM_ACTION";
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"ACTION_"}, value = {
ACTION_FULLSCREEN,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
index bca27a5c6636..977aad4a898a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
@@ -86,7 +86,7 @@ public class TvPipCustomAction extends TvPipAction {
Bundle extras = new Bundle();
extras.putCharSequence(Notification.EXTRA_PICTURE_CONTENT_DESCRIPTION,
mRemoteAction.getContentDescription());
- extras.putBoolean(Notification.EXTRA_CONTAINS_CUSTOM_VIEW, true);
+ extras.putBoolean(TvPipAction.EXTRA_IS_PIP_CUSTOM_ACTION, true);
builder.addExtras(extras);
builder.setSemanticAction(isCloseAction()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index c9b3a1af6507..c4a0e9cf5a74 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -32,6 +32,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM_SHELL),
WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
+ WM_SHELL_RECENTS_TRANSITION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+ Consts.TAG_WM_SHELL),
WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM_SHELL),
WM_SHELL_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index a8b209fc7da6..b55487258220 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -47,7 +47,9 @@ import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.util.TransitionUtil;
@@ -96,6 +98,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
void startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options,
IApplicationThread appThread, IRecentsAnimationRunner listener) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsTransitionHandler.startRecentsTransition");
// only care about latest one.
mAnimApp = appThread;
WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -116,7 +120,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
mixer.setRecentsTransition(transition);
}
if (transition == null) {
- controller.cancel();
+ controller.cancel("startRecentsTransition");
return;
}
controller.setTransition(transition);
@@ -127,6 +131,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
public WindowContainerTransaction handleRequest(IBinder transition,
TransitionRequestInfo request) {
// do not directly handle requests. Only entry point should be via startRecentsTransition
+ Slog.e(TAG, "RecentsTransitionHandler.handleRequest: Unexpected transition request");
return null;
}
@@ -143,11 +148,17 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
SurfaceControl.Transaction finishTransaction,
Transitions.TransitionFinishCallback finishCallback) {
final int controllerIdx = findController(transition);
- if (controllerIdx < 0) return false;
+ if (controllerIdx < 0) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsTransitionHandler.startAnimation: no controller found");
+ return false;
+ }
final RecentsController controller = mControllers.get(controllerIdx);
Transitions.setRunningRemoteTransitionDelegate(mAnimApp);
mAnimApp = null;
if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsTransitionHandler.startAnimation: failed to start animation");
return false;
}
return true;
@@ -168,7 +179,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
SurfaceControl.Transaction finishTransaction) {
final int idx = findController(transition);
if (idx < 0) return;
- mControllers.get(idx).cancel();
+ mControllers.get(idx).cancel("onTransitionConsumed");
}
/** There is only one of these and it gets reset on finish. */
@@ -213,27 +224,38 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
RecentsController(IRecentsAnimationRunner listener) {
mListener = listener;
- mDeathHandler = () -> finish(mWillFinishToHome, false /* leaveHint */);
+ mDeathHandler = () -> {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.DeathRecipient: binder died");
+ finish(mWillFinishToHome, false /* leaveHint */);
+ };
try {
mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */);
} catch (RemoteException e) {
+ Slog.e(TAG, "RecentsController: failed to link to death", e);
mListener = null;
}
}
void setTransition(IBinder transition) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.setTransition: id=%s", transition);
mTransition = transition;
}
- void cancel() {
+ void cancel(String reason) {
// restoring (to-home = false) involves submitting more WM changes, so by default, use
// toHome = true when canceling.
- cancel(true /* toHome */);
+ cancel(true /* toHome */, reason);
}
- void cancel(boolean toHome) {
+ void cancel(boolean toHome, String reason) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.cancel: toHome=%b reason=%s", toHome, reason);
if (mListener != null) {
try {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.cancel: calling onAnimationCanceled");
mListener.onAnimationCanceled(null, null);
} catch (RemoteException e) {
Slog.e(TAG, "Error canceling recents animation", e);
@@ -267,6 +289,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
}
}
try {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.cancel: calling onAnimationCanceled with snapshots");
mListener.onAnimationCanceled(taskIds, snapshots);
} catch (RemoteException e) {
Slog.e(TAG, "Error canceling recents animation", e);
@@ -276,6 +300,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
}
void cleanUp() {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.cleanup");
if (mListener != null && mDeathHandler != null) {
mListener.asBinder().unlinkToDeath(mDeathHandler, 0 /* flags */);
mDeathHandler = null;
@@ -299,6 +324,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
boolean start(TransitionInfo info, SurfaceControl.Transaction t,
SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.start");
if (mListener == null || mTransition == null) {
cleanUp();
return false;
@@ -358,6 +384,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
info.getChanges().size() - i, info, t, mLeashMap);
apps.add(target);
if (TransitionUtil.isClosingType(change.getMode())) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " adding pausing taskId=%d", taskInfo.taskId);
// raise closing (pausing) task to "above" layer so it isn't covered
t.setLayer(target.leash, info.getChanges().size() * 3 - i);
mPausingTasks.add(new TaskState(change, target.leash));
@@ -372,19 +400,23 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
} else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
// do nothing
} else if (TransitionUtil.isOpeningType(change.getMode())) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " adding opening taskId=%d", taskInfo.taskId);
mOpeningTasks.add(new TaskState(change, target.leash));
}
}
}
t.apply();
try {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.start: calling onAnimationStart");
mListener.onAnimationStart(this,
apps.toArray(new RemoteAnimationTarget[apps.size()]),
wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]),
new Rect(0, 0, 0, 0), new Rect());
} catch (RemoteException e) {
Slog.e(TAG, "Error starting recents animation", e);
- cancel();
+ cancel("onAnimationStart() failed");
}
return true;
}
@@ -393,14 +425,19 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
void merge(TransitionInfo info, SurfaceControl.Transaction t,
Transitions.TransitionFinishCallback finishCallback) {
if (mFinishCB == null) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.merge: skip, no finish callback");
// This was no-op'd (likely a repeated start) and we've already sent finish.
return;
}
if (info.getType() == TRANSIT_SLEEP) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.merge: transit_sleep");
// A sleep event means we need to stop animations immediately, so cancel here.
- cancel();
+ cancel("transit_sleep");
return;
}
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.merge");
ArrayList<TransitionInfo.Change> openingTasks = null;
ArrayList<TransitionInfo.Change> closingTasks = null;
mOpeningSeparateHome = false;
@@ -417,7 +454,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
&& taskInfo.configuration.windowConfiguration.isAlwaysOnTop()) {
// Tasks that are always on top (e.g. bubbles), will handle their own transition
// as they are on top of everything else. So cancel the merge here.
- cancel();
+ cancel("task #" + taskInfo.taskId + " is always_on_top");
return;
}
hasTaskChange = hasTaskChange || taskInfo != null;
@@ -448,7 +485,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
// Finish recents animation if the display is changed, so the default
// transition handler can play the animation such as rotation effect.
if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) {
- cancel(mWillFinishToHome);
+ cancel(mWillFinishToHome, "display change");
return;
}
// Don't consider order-only changes as changing apps.
@@ -492,7 +529,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
+ " something unexpected: " + change.getTaskInfo().taskId);
continue;
}
- mPausingTasks.add(mOpeningTasks.remove(openingIdx));
+ final TaskState openingTask = mOpeningTasks.remove(openingIdx);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " pausing opening taskId=%d", openingTask.mTaskInfo.taskId);
+ mPausingTasks.add(openingTask);
didMergeThings = true;
}
}
@@ -509,7 +549,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
// Something is showing/opening a previously-pausing app.
appearedTargets[i] = TransitionUtil.newTarget(
change, layer, mPausingTasks.get(pausingIdx).mLeash);
- mOpeningTasks.add(mPausingTasks.remove(pausingIdx));
+ final TaskState pausingTask = mPausingTasks.remove(pausingIdx);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " opening pausing taskId=%d", pausingTask.mTaskInfo.taskId);
+ mOpeningTasks.add(pausingTask);
// Setup hides opening tasks initially, so make it visible again (since we
// are already showing it).
t.show(change.getLeash());
@@ -522,6 +565,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
final int rootIdx = TransitionUtil.rootIndexFor(change, mInfo);
t.reparent(appearedTargets[i].leash, mInfo.getRoot(rootIdx).getLeash());
t.setLayer(appearedTargets[i].leash, layer);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ " opening new taskId=%d", appearedTargets[i].taskId);
mOpeningTasks.add(new TaskState(change, appearedTargets[i].leash));
}
}
@@ -539,7 +584,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
+ foundRecentsClosing);
if (foundRecentsClosing) {
mWillFinishToHome = false;
- cancel(false /* toHome */);
+ cancel(false /* toHome */, "didn't merge");
}
return;
}
@@ -549,6 +594,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
info.releaseAnimSurfaces();
if (appearedTargets == null) return;
try {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.merge: calling onTasksAppeared");
mListener.onTasksAppeared(appearedTargets);
} catch (RemoteException e) {
Slog.e(TAG, "Error sending appeared tasks to recents animation", e);
@@ -572,6 +619,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
@Override
public TaskSnapshot screenshotTask(int taskId) {
try {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.screenshotTask: taskId=%d", taskId);
return ActivityTaskManager.getService().takeTaskSnapshot(taskId);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to screenshot task", e);
@@ -582,12 +631,19 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
@Override
public void setInputConsumerEnabled(boolean enabled) {
mExecutor.execute(() -> {
- if (mFinishCB == null || !enabled) return;
+ if (mFinishCB == null || !enabled) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.setInputConsumerEnabled: skip, cb?=%b enabled?=%b",
+ mFinishCB != null, enabled);
+ return;
+ }
// transient launches don't receive focus automatically. Since we are taking over
// the gesture now, take focus explicitly.
// This also moves recents back to top if the user gestured before a switch
// animation finished.
try {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.setInputConsumerEnabled: set focus to recents");
ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to set focused task", e);
@@ -602,6 +658,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
@Override
public void setFinishTaskTransaction(int taskId,
PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.setFinishTaskTransaction: taskId=%d", taskId);
mExecutor.execute(() -> {
if (mFinishCB == null) return;
mPipTransaction = finishTransaction;
@@ -619,6 +677,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
Slog.e(TAG, "Duplicate call to finish");
return;
}
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.finishInner: toHome=%b userLeaveHint=%b willFinishToHome=%b",
+ toHome, sendUserLeaveHint, mWillFinishToHome);
final Transitions.TransitionFinishCallback finishCB = mFinishCB;
mFinishCB = null;
@@ -630,6 +691,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
else wct.restoreTransientOrder(mRecentsTask);
}
if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " returning to app");
// The gesture is returning to the pausing-task(s) rather than continuing with
// recents, so end the transition by moving the app back to the top (and also
// re-showing it's task).
@@ -642,6 +704,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
wct.restoreTransientOrder(mRecentsTask);
}
} else if (toHome && mOpeningSeparateHome && mPausingTasks != null) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " 3p launching home");
// Special situation where 3p launcher was changed during recents (this happens
// during tapltests...). Here we get both "return to home" AND "home opening".
// This is basically going home, but we have to restore the recents and home order.
@@ -660,6 +723,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
wct.restoreTransientOrder(mRecentsTask);
}
} else {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " normal finish");
// The general case: committing to recents, going home, or switching tasks.
for (int i = 0; i < mOpeningTasks.size(); ++i) {
t.show(mOpeningTasks.get(i).mTaskSurface);
@@ -716,6 +780,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
*/
@Override
public void detachNavigationBarFromApp(boolean moveHomeToTop) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+ "RecentsController.detachNavigationBarFromApp");
mExecutor.execute(() -> {
if (mTransition == null) return;
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index bdb7d44bad32..08b0bf74f413 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -429,6 +429,7 @@ public class Transitions implements RemoteCallable<Transitions> {
&& (change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) {
t.setAlpha(leash, 0.f);
}
+ finishT.show(leash);
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
finishT.hide(leash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index d95c7a488ea1..3d8bd3854a45 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -135,12 +135,15 @@ public class BackAnimationControllerTest extends ShellTestCase {
mShellExecutor.flushAll();
}
- private void createNavigationInfo(int backType, boolean enableAnimation) {
+ private void createNavigationInfo(int backType,
+ boolean enableAnimation,
+ boolean isAnimationCallback) {
BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder()
.setType(backType)
.setOnBackNavigationDone(new RemoteCallback((bundle) -> {}))
.setOnBackInvokedCallback(mAppCallback)
- .setPrepareRemoteAnimation(enableAnimation);
+ .setPrepareRemoteAnimation(enableAnimation)
+ .setAnimationCallback(isAnimationCallback);
createNavigationInfo(builder);
}
@@ -218,7 +221,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
@Test
public void backToHome_dispatchesEvents() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
@@ -240,6 +245,32 @@ public class BackAnimationControllerTest extends ShellTestCase {
}
@Test
+ public void backToHomeWithAnimationCallback_dispatchesEvents() throws RemoteException {
+ registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ true);
+
+ doMotionEvent(MotionEvent.ACTION_DOWN, 0);
+
+ // Check that back start and progress is dispatched when first move.
+ doMotionEvent(MotionEvent.ACTION_MOVE, 100, 3000);
+
+ simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+
+ verify(mAnimatorCallback).onBackStarted(any(BackMotionEvent.class));
+ verify(mBackAnimationRunner).onAnimationStart(anyInt(), any(), any(), any(), any());
+ ArgumentCaptor<BackMotionEvent> backEventCaptor =
+ ArgumentCaptor.forClass(BackMotionEvent.class);
+ verify(mAnimatorCallback, atLeastOnce()).onBackProgressed(backEventCaptor.capture());
+
+ // Check that back invocation is dispatched.
+ mController.setTriggerBack(true); // Fake trigger back
+ doMotionEvent(MotionEvent.ACTION_UP, 0);
+ verify(mAnimatorCallback).onBackInvoked();
+ }
+
+ @Test
public void animationDisabledFromSettings() throws RemoteException {
// Toggle the setting off
Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, "0");
@@ -254,7 +285,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
ArgumentCaptor<BackMotionEvent> backEventCaptor =
ArgumentCaptor.forClass(BackMotionEvent.class);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, false);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ false,
+ /* isAnimationCallback = */ false);
triggerBackGesture();
releaseBackGesture();
@@ -271,7 +304,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
@Test
public void ignoresGesture_transitionInProgress() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
triggerBackGesture();
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
@@ -309,7 +344,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
@Test
public void acceptsGesture_transitionTimeout() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
// In case it is still running in animation.
doNothing().when(mAnimatorCallback).onBackInvoked();
@@ -334,7 +371,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
public void cancelBackInvokeWhenLostFocus() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
// Check that back start and progress is dispatched when first move.
@@ -454,7 +493,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
mController.registerAnimation(type, animationRunner);
- createNavigationInfo(type, true);
+ createNavigationInfo(type,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
@@ -473,11 +514,15 @@ public class BackAnimationControllerTest extends ShellTestCase {
}
private void doMotionEvent(int actionDown, int coordinate) {
+ doMotionEvent(actionDown, coordinate, 0);
+ }
+
+ private void doMotionEvent(int actionDown, int coordinate, float velocity) {
mController.onMotionEvent(
/* touchX */ coordinate,
/* touchY */ coordinate,
- /* velocityX = */ 0,
- /* velocityY = */ 0,
+ /* velocityX = */ velocity,
+ /* velocityY = */ velocity,
/* keyAction */ actionDown,
/* swipeEdge */ BackEvent.EDGE_LEFT);
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index 4d2bb4c6016a..8b74d766a152 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -18,6 +18,7 @@ package com.android.credentialmanager
import android.app.Activity
import android.os.IBinder
+import android.text.TextUtils
import android.util.Log
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult
@@ -67,9 +68,9 @@ class CredentialSelectorViewModel(
var uiMetrics: UIMetrics = UIMetrics()
- init{
+ init {
uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_INIT,
- credManRepo.requestInfo?.appPackageName)
+ credManRepo.requestInfo?.appPackageName)
}
/**************************************************************************/
@@ -100,7 +101,7 @@ class CredentialSelectorViewModel(
if (this.credManRepo.requestInfo?.token != credManRepo.requestInfo?.token) {
this.uiMetrics.resetInstanceId()
this.uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_NEW_REQUEST,
- credManRepo.requestInfo?.appPackageName)
+ credManRepo.requestInfo?.appPackageName)
}
}
@@ -174,7 +175,7 @@ class CredentialSelectorViewModel(
private fun onInternalError() {
Log.w(Constants.LOG_TAG, "UI closed due to illegal internal state")
this.uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_INTERNAL_ERROR,
- credManRepo.requestInfo?.appPackageName)
+ credManRepo.requestInfo?.appPackageName)
credManRepo.onParsingFailureCancel()
uiState = uiState.copy(dialogState = DialogState.COMPLETE)
}
@@ -314,10 +315,11 @@ class CredentialSelectorViewModel(
uiState = uiState.copy(
createCredentialUiState = uiState.createCredentialUiState?.copy(
currentScreenState =
- if (activeEntry.activeProvider.id ==
- userConfigRepo.getDefaultProviderId())
+ if (activeEntry.activeProvider.id == userConfigRepo.getDefaultProviderId() ||
+ !TextUtils.isEmpty(uiState.createCredentialUiState?.requestDisplayInfo
+ ?.appPreferredDefaultProviderId))
CreateScreenState.CREATION_OPTION_SELECTION
- else CreateScreenState.MORE_OPTIONS_ROW_INTRO,
+ else CreateScreenState.DEFAULT_PROVIDER_CONFIRMATION,
activeEntry = activeEntry
)
)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 96010cc66821..9d871ed75494 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -139,12 +139,12 @@ fun CreateCredentialScreen(
onRemoteEntrySelected = viewModel::createFlowOnEntrySelected,
onLog = { viewModel.logUiEvent(it) },
)
- CreateScreenState.MORE_OPTIONS_ROW_INTRO -> {
+ CreateScreenState.DEFAULT_PROVIDER_CONFIRMATION -> {
if (createCredentialUiState.activeEntry == null) {
viewModel.onIllegalUiState("Expect active entry to be non-null" +
" upon default provider dialog.")
} else {
- MoreOptionsRowIntroCard(
+ DefaultProviderConfirmationCard(
selectedEntry = createCredentialUiState.activeEntry,
onIllegalScreenState = viewModel::onIllegalUiState,
onChangeDefaultSelected =
@@ -420,7 +420,7 @@ fun MoreOptionsSelectionCard(
}
@Composable
-fun MoreOptionsRowIntroCard(
+fun DefaultProviderConfirmationCard(
selectedEntry: ActiveEntry,
onIllegalScreenState: (String) -> Unit,
onChangeDefaultSelected: () -> Unit,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 12bb6298b282..225dbf2b744f 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -126,6 +126,6 @@ enum class CreateScreenState {
PROVIDER_SELECTION,
CREATION_OPTION_SELECTION,
MORE_OPTIONS_SELECTION,
- MORE_OPTIONS_ROW_INTRO,
+ DEFAULT_PROVIDER_CONFIRMATION,
EXTERNAL_ONLY_SELECTION,
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 96ea5b45282b..27aade5e6bf8 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -19,6 +19,7 @@ package com.android.systemui.accessibility.accessibilitymenu;
import android.Manifest;
import android.accessibilityservice.AccessibilityButtonController;
import android.accessibilityservice.AccessibilityService;
+import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -82,6 +83,9 @@ public class AccessibilityMenuService extends AccessibilityService
// TODO(b/136716947): Support multi-display once a11y framework side is ready.
private DisplayManager mDisplayManager;
+
+ private KeyguardManager mKeyguardManager;
+
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
int mRotation;
@@ -114,7 +118,7 @@ public class AccessibilityMenuService extends AccessibilityService
private final BroadcastReceiver mToggleMenuReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mA11yMenuLayout.toggleVisibility();
+ toggleVisibility();
}
};
@@ -159,10 +163,7 @@ public class AccessibilityMenuService extends AccessibilityService
*/
@Override
public void onClicked(AccessibilityButtonController controller) {
- if (SystemClock.uptimeMillis() - mLastTimeTouchedOutside
- > BUTTON_CLICK_TIMEOUT) {
- mA11yMenuLayout.toggleVisibility();
- }
+ toggleVisibility();
}
/**
@@ -209,6 +210,7 @@ public class AccessibilityMenuService extends AccessibilityService
mDisplayManager = getSystemService(DisplayManager.class);
mDisplayManager.registerDisplayListener(mDisplayListener, null);
mAudioManager = getSystemService(AudioManager.class);
+ mKeyguardManager = getSystemService(KeyguardManager.class);
sInitialized = true;
}
@@ -379,4 +381,12 @@ public class AccessibilityMenuService extends AccessibilityService
}
return false;
}
+
+ private void toggleVisibility() {
+ boolean locked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+ if (!locked && SystemClock.uptimeMillis() - mLastTimeTouchedOutside
+ > BUTTON_CLICK_TIMEOUT) {
+ mA11yMenuLayout.toggleVisibility();
+ }
+ }
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
index 7277392f1841..9d1af0e2375a 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
@@ -33,6 +33,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Instrumentation;
+import android.app.KeyguardManager;
import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -44,6 +45,7 @@ import android.media.AudioManager;
import android.os.PowerManager;
import android.provider.Settings;
import android.util.Log;
+import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -69,15 +71,19 @@ public class AccessibilityMenuServiceTest {
private static final int CLICK_ID = AccessibilityNodeInfo.ACTION_CLICK;
private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5;
- private static final int TIMEOUT_UI_CHANGE_S = 10;
+ private static final int TIMEOUT_UI_CHANGE_S = 5;
private static final int NO_GLOBAL_ACTION = -1;
private static final String INPUT_KEYEVENT_KEYCODE_BACK = "input keyevent KEYCODE_BACK";
+ private static final String TEST_PIN = "1234";
private static Instrumentation sInstrumentation;
private static UiAutomation sUiAutomation;
private static AtomicInteger sLastGlobalAction;
private static AccessibilityManager sAccessibilityManager;
+ private static PowerManager sPowerManager;
+ private static KeyguardManager sKeyguardManager;
+ private static DisplayManager sDisplayManager;
@BeforeClass
public static void classSetup() throws Throwable {
@@ -85,8 +91,14 @@ public class AccessibilityMenuServiceTest {
sInstrumentation = InstrumentationRegistry.getInstrumentation();
sUiAutomation = sInstrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+ sUiAutomation.adoptShellPermissionIdentity(
+ UiAutomation.ALL_PERMISSIONS.toArray(new String[0]));
+
final Context context = sInstrumentation.getTargetContext();
sAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ sPowerManager = context.getSystemService(PowerManager.class);
+ sKeyguardManager = context.getSystemService(KeyguardManager.class);
+ sDisplayManager = context.getSystemService(DisplayManager.class);
// Disable all a11yServices if any are active.
if (!sAccessibilityManager.getEnabledAccessibilityServiceList(
@@ -123,12 +135,16 @@ public class AccessibilityMenuServiceTest {
@AfterClass
public static void classTeardown() throws Throwable {
+ clearPin();
Settings.Secure.putString(sInstrumentation.getTargetContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
}
@Before
public void setup() throws Throwable {
+ clearPin();
+ wakeUpScreen();
+ sUiAutomation.executeShellCommand("input keyevent KEYCODE_MENU");
openMenu();
}
@@ -138,11 +154,43 @@ public class AccessibilityMenuServiceTest {
sLastGlobalAction.set(NO_GLOBAL_ACTION);
}
+ private static void clearPin() throws Throwable {
+ sUiAutomation.executeShellCommand("locksettings clear --old " + TEST_PIN);
+ TestUtils.waitUntil("Device did not register as unlocked & insecure.",
+ TIMEOUT_SERVICE_STATUS_CHANGE_S,
+ () -> !sKeyguardManager.isDeviceSecure());
+ }
+
+ private static void setPin() throws Throwable {
+ sUiAutomation.executeShellCommand("locksettings set-pin " + TEST_PIN);
+ TestUtils.waitUntil("Device did not recognize as locked & secure.",
+ TIMEOUT_SERVICE_STATUS_CHANGE_S,
+ () -> sKeyguardManager.isDeviceSecure());
+ }
+
private static boolean isMenuVisible() {
AccessibilityNodeInfo root = sUiAutomation.getRootInActiveWindow();
return root != null && root.getPackageName().toString().equals(PACKAGE_NAME);
}
+ private static void wakeUpScreen() throws Throwable {
+ sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ TestUtils.waitUntil("Screen did not wake up.",
+ TIMEOUT_UI_CHANGE_S,
+ () -> sPowerManager.isInteractive());
+ }
+
+ private static void closeScreen() throws Throwable {
+ Display display = sDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ setPin();
+ sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN);
+ TestUtils.waitUntil("Screen did not close.",
+ TIMEOUT_UI_CHANGE_S,
+ () -> !sPowerManager.isInteractive()
+ && display.getState() == Display.STATE_OFF
+ );
+ }
+
private static void openMenu() throws Throwable {
Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU);
sInstrumentation.getContext().sendBroadcast(intent);
@@ -381,23 +429,24 @@ public class AccessibilityMenuServiceTest {
@Test
public void testOnScreenLock_closesMenu() throws Throwable {
- openMenu();
- Context context = sInstrumentation.getTargetContext();
- PowerManager powerManager = context.getSystemService(PowerManager.class);
-
- assertThat(powerManager).isNotNull();
- assertThat(powerManager.isInteractive()).isTrue();
+ closeScreen();
+ wakeUpScreen();
- sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN);
- TestUtils.waitUntil("Screen did not become locked",
- TIMEOUT_UI_CHANGE_S,
- () -> !powerManager.isInteractive());
+ assertThat(isMenuVisible()).isFalse();
+ }
- sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
- TestUtils.waitUntil("Screen did not wake up",
- TIMEOUT_UI_CHANGE_S,
- () -> powerManager.isInteractive());
+ @Test
+ public void testOnScreenLock_cannotOpenMenu() throws Throwable {
+ closeScreen();
+ wakeUpScreen();
- assertThat(isMenuVisible()).isFalse();
+ boolean timedOut = false;
+ try {
+ openMenu();
+ } catch (AssertionError e) {
+ // Expected
+ timedOut = true;
+ }
+ assertThat(timedOut).isTrue();
}
}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 204bac88bc0d..450c6166905c 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -316,9 +316,9 @@ enum class Style(internal val coreSpec: CoreSpec) {
),
CLOCK_VIBRANT(
CoreSpec(
- a1 = TonalSpec(HueSource(), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
- a2 = TonalSpec(HueAdd(20.0), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
- a3 = TonalSpec(HueAdd(60.0), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
+ a1 = TonalSpec(HueSource(), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
+ a2 = TonalSpec(HueAdd(20.0), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
+ a3 = TonalSpec(HueAdd(60.0), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
// Not Used
n1 = TonalSpec(HueSource(), ChromaConstant(0.0)),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 76e051ea25f3..693268d730a4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -178,6 +178,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
@Override
public void onUserInput() {
+ mKeyguardFaceAuthInteractor.onPrimaryBouncerUserInput();
mUpdateMonitor.cancelFaceAuth();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e0af5ceedb2f..7a2013e2c612 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1957,11 +1957,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
if (mShowing && mKeyguardStateController.isShowing()) {
if (mPM.isInteractive() && !mHiding) {
// It's already showing, and we're not trying to show it while the screen is off.
- // We can simply reset all of the views.
+ // We can simply reset all of the views, but don't hide the bouncer in case the user
+ // is currently interacting with it.
if (DEBUG) Log.d(TAG, "doKeyguard: not showing (instead, resetting) because it is "
+ "already showing, we're interactive, and we were not previously hiding. "
+ "It should be safe to short-circuit here.");
- resetStateLocked();
+ resetStateLocked(/* hideBouncer= */ false);
return;
} else {
// We are trying to show the keyguard while the screen is off or while we were in
@@ -2035,8 +2036,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
* @see #handleReset
*/
private void resetStateLocked() {
+ resetStateLocked(/* hideBouncer= */ true);
+ }
+
+ private void resetStateLocked(boolean hideBouncer) {
if (DEBUG) Log.e(TAG, "resetStateLocked");
- Message msg = mHandler.obtainMessage(RESET);
+ Message msg = mHandler.obtainMessage(RESET, hideBouncer ? 1 : 0, 0);
mHandler.sendMessage(msg);
}
@@ -2226,7 +2231,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
handleHide();
break;
case RESET:
- handleReset();
+ handleReset(msg.arg1 != 0);
break;
case VERIFY_UNLOCK:
Trace.beginSection("KeyguardViewMediator#handleMessage VERIFY_UNLOCK");
@@ -3008,10 +3013,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
* Handle message sent by {@link #resetStateLocked}
* @see #RESET
*/
- private void handleReset() {
+ private void handleReset(boolean hideBouncer) {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleReset");
- mKeyguardViewControllerLazy.get().reset(true /* hideBouncerWhenShowing */);
+ mKeyguardViewControllerLazy.get().reset(hideBouncer);
}
scheduleNonStrongBiometricIdleTimeout();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index dc5ac88472e4..5f2178df4346 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -225,10 +225,17 @@ constructor(
}
private fun observeFaceAuthResettingConditions() {
- // Clear auth status when keyguard is going away or when the user is switching.
- merge(keyguardRepository.isKeyguardGoingAway, userRepository.userSwitchingInProgress)
- .onEach { goingAwayOrUserSwitchingInProgress ->
- if (goingAwayOrUserSwitchingInProgress) {
+ // Clear auth status when keyguard is going away or when the user is switching or device
+ // starts going to sleep.
+ merge(
+ keyguardRepository.wakefulness.map {
+ WakefulnessModel.isSleepingOrStartingToSleep(it)
+ },
+ keyguardRepository.isKeyguardGoingAway,
+ userRepository.userSwitchingInProgress
+ )
+ .onEach { anyOfThemIsTrue ->
+ if (anyOfThemIsTrue) {
_isAuthenticated.value = false
retryCount = 0
halErrorRetryJob?.cancel()
@@ -248,8 +255,8 @@ constructor(
"nonStrongBiometricIsNotAllowed",
faceDetectLog
),
- // We don't want to run face detect if it's not possible to authenticate with FP
- // from the bouncer. UDFPS is the only fp sensor type that won't support this.
+ // We don't want to run face detect if fingerprint can be used to unlock the device
+ // but it's not possible to authenticate with FP from the bouncer (UDFPS)
logAndObserve(
and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning).isFalse(),
"udfpsAuthIsNotPossibleAnymore",
@@ -306,7 +313,7 @@ constructor(
logAndObserve(
combine(
keyguardInteractor.isSecureCameraActive,
- alternateBouncerInteractor.isVisible,
+ alternateBouncerInteractor.isVisible
) { a, b ->
!a || b
},
@@ -334,12 +341,12 @@ constructor(
logAndObserve(isLockedOut.isFalse(), "isNotInLockOutState", faceAuthLog),
logAndObserve(
deviceEntryFingerprintAuthRepository.isLockedOut.isFalse(),
- "fpLockedOut",
+ "fpIsNotLockedOut",
faceAuthLog
),
logAndObserve(
trustRepository.isCurrentUserTrusted.isFalse(),
- "currentUserTrusted",
+ "currentUserIsNotTrusted",
faceAuthLog
),
logAndObserve(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
index 06ae11fe810c..74ef7a50fd44 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
@@ -59,6 +59,7 @@ interface KeyguardFaceAuthInteractor {
fun onQsExpansionStared()
fun onNotificationPanelClicked()
fun onSwipeUpOnBouncer()
+ fun onPrimaryBouncerUserInput()
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
index cad40aac00d3..5005b6c7f0df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
@@ -59,4 +59,5 @@ class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInt
override fun onNotificationPanelClicked() {}
override fun onSwipeUpOnBouncer() {}
+ override fun onPrimaryBouncerUserInput() {}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index 20ebb711c42d..6b515dab79f6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -151,6 +151,10 @@ constructor(
return featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)
}
+ override fun onPrimaryBouncerUserInput() {
+ repository.cancel()
+ }
+
/** Provide the status of face authentication */
override val authenticationStatus = repository.authenticationStatus
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 7edb37832c4f..077ee027d764 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -136,6 +136,14 @@ public class LogModule {
return factory.create("NotifRemoteInputLog", 50 /* maxSize */, false /* systrace */);
}
+ /** Provides a logging buffer for all logs related to unseen notifications. */
+ @Provides
+ @SysUISingleton
+ @UnseenNotificationLog
+ public static LogBuffer provideUnseenNotificationLogBuffer(LogBufferFactory factory) {
+ return factory.create("UnseenNotifLog", 20 /* maxSize */, false /* systrace */);
+ }
+
/** Provides a logging buffer for all logs related to the data layer of notifications. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
new file mode 100644
index 000000000000..5c2321be4388
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.plugins.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for unseen notification related messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface UnseenNotificationLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 9e204e48da8e..11c8c503899e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2809,6 +2809,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
@Override
public void setBouncerShowing(boolean bouncerShowing) {
mBouncerShowing = bouncerShowing;
+ mNotificationStackScrollLayoutController.updateShowEmptyShadeView();
updateVisibility();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 4cbbefe1cd73..2fa070ca20b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -21,8 +21,10 @@ package com.android.systemui.statusbar.notification.collection.coordinator
import android.os.UserHandle
import android.provider.Settings
import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -42,8 +44,14 @@ import com.android.systemui.statusbar.notification.collection.provider.SeenNotif
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.headsUpEvents
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.indentIfPossible
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -57,13 +65,11 @@ import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
-import javax.inject.Inject
-import kotlin.time.Duration
-import kotlin.time.Duration.Companion.seconds
/**
* Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section
@@ -74,17 +80,19 @@ class KeyguardCoordinator
@Inject
constructor(
@Background private val bgDispatcher: CoroutineDispatcher,
+ private val dumpManager: DumpManager,
private val headsUpManager: HeadsUpManager,
private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider,
private val keyguardRepository: KeyguardRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
+ private val logger: KeyguardCoordinatorLogger,
private val notifPipelineFlags: NotifPipelineFlags,
@Application private val scope: CoroutineScope,
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
private val secureSettings: SecureSettings,
private val seenNotifsProvider: SeenNotificationsProviderImpl,
private val statusBarStateController: StatusBarStateController,
-) : Coordinator {
+) : Coordinator, Dumpable {
private val unseenNotifications = mutableSetOf<NotificationEntry>()
private var unseenFilterEnabled = false
@@ -103,6 +111,7 @@ constructor(
pipeline.addCollectionListener(collectionListener)
scope.launch { trackUnseenNotificationsWhileUnlocked() }
scope.launch { invalidateWhenUnseenSettingChanges() }
+ dumpManager.registerDumpable(this)
}
private suspend fun trackUnseenNotificationsWhileUnlocked() {
@@ -122,14 +131,16 @@ constructor(
// If the screen is turning off, stop tracking, but if that transition is
// cancelled, then start again.
emitAll(
- keyguardTransitionRepository.transitions
- .map { step -> !step.isScreenTurningOff }
+ keyguardTransitionRepository.transitions.map { step ->
+ !step.isScreenTurningOff
+ }
)
}
}
// Prevent double emit of `false` caused by transition to AOD, followed by keyguard
// showing
.distinctUntilChanged()
+ .onEach { trackingUnseen -> logger.logTrackingUnseen(trackingUnseen) }
// Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is
// showing again
@@ -140,9 +151,11 @@ constructor(
// set when unlocked
awaitTimeSpentNotDozing(SEEN_TIMEOUT)
clearUnseenOnBeginTracking = true
+ logger.logSeenOnLockscreen()
} else {
if (clearUnseenOnBeginTracking) {
clearUnseenOnBeginTracking = false
+ logger.logAllMarkedSeenOnUnlock()
unseenNotifications.clear()
}
unseenNotifFilter.invalidateList("keyguard no longer showing")
@@ -166,6 +179,8 @@ constructor(
.first()
}
+ // Track "unseen" notifications, marking them as seen when either shade is expanded or the
+ // notification becomes heads up.
private suspend fun trackUnseenNotifications() {
coroutineScope {
launch { clearUnseenNotificationsWhenShadeIsExpanded() }
@@ -179,6 +194,7 @@ constructor(
// keyguard transition and not the user expanding the shade
yield()
if (isExpanded) {
+ logger.logShadeExpanded()
unseenNotifications.clear()
}
}
@@ -190,6 +206,7 @@ constructor(
.forEach { unseenNotifications.remove(it) }
headsUpManager.headsUpEvents.collect { (entry, isHun) ->
if (isHun) {
+ logger.logUnseenHun(entry.key)
unseenNotifications.remove(entry)
}
}
@@ -231,6 +248,7 @@ constructor(
if (
keyguardRepository.isKeyguardShowing() || !statusBarStateController.isExpanded
) {
+ logger.logUnseenAdded(entry.key)
unseenNotifications.add(entry)
}
}
@@ -239,12 +257,15 @@ constructor(
if (
keyguardRepository.isKeyguardShowing() || !statusBarStateController.isExpanded
) {
+ logger.logUnseenUpdated(entry.key)
unseenNotifications.add(entry)
}
}
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
- unseenNotifications.remove(entry)
+ if (unseenNotifications.remove(entry)) {
+ logger.logUnseenRemoved(entry.key)
+ }
}
}
@@ -272,6 +293,7 @@ constructor(
}.also { hasFiltered -> hasFilteredAnyNotifs = hasFilteredAnyNotifs || hasFiltered }
override fun onCleanup() {
+ logger.logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs)
seenNotifsProvider.hasFilteredOutSeenNotifications = hasFilteredAnyNotifs
hasFilteredAnyNotifs = false
}
@@ -306,11 +328,25 @@ constructor(
sectionHeaderVisibilityProvider.sectionHeadersVisible = showSections
}
+ override fun dump(pw: PrintWriter, args: Array<out String>) =
+ with(pw.asIndenting()) {
+ println(
+ "seenNotifsProvider.hasFilteredOutSeenNotifications=" +
+ seenNotifsProvider.hasFilteredOutSeenNotifications
+ )
+ println("unseen notifications:")
+ indentIfPossible {
+ for (notification in unseenNotifications) {
+ println(notification.key)
+ }
+ }
+ }
+
companion object {
private const val TAG = "KeyguardCoordinator"
private val SEEN_TIMEOUT = 5.seconds
}
}
-private val TransitionStep.isScreenTurningOff: Boolean get() =
- transitionState == TransitionState.STARTED && to != KeyguardState.GONE \ No newline at end of file
+private val TransitionStep.isScreenTurningOff: Boolean
+ get() = transitionState == TransitionState.STARTED && to != KeyguardState.GONE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
new file mode 100644
index 000000000000..6503a6403eaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 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.notification.collection.coordinator
+
+import com.android.systemui.log.dagger.UnseenNotificationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import javax.inject.Inject
+
+private const val TAG = "KeyguardCoordinator"
+
+class KeyguardCoordinatorLogger
+@Inject
+constructor(
+ @UnseenNotificationLog private val buffer: LogBuffer,
+) {
+ fun logSeenOnLockscreen() =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ "Notifications on lockscreen will be marked as seen when unlocked."
+ )
+
+ fun logTrackingUnseen(trackingUnseen: Boolean) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { bool1 = trackingUnseen },
+ messagePrinter = { "${if (bool1) "Start" else "Stop"} tracking unseen notifications." },
+ )
+
+ fun logAllMarkedSeenOnUnlock() =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ "Notifications have been marked as seen now that device is unlocked."
+ )
+
+ fun logShadeExpanded() =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ "Notifications have been marked as seen due to shade expansion."
+ )
+
+ fun logUnseenAdded(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = key },
+ messagePrinter = { "Unseen notif added: $str1" },
+ )
+
+ fun logUnseenUpdated(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = key },
+ messagePrinter = { "Unseen notif updated: $str1" },
+ )
+
+ fun logUnseenRemoved(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = key },
+ messagePrinter = { "Unseen notif removed: $str1" },
+ )
+
+ fun logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs: Boolean) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { bool1 = hasFilteredAnyNotifs },
+ messagePrinter = { "UI showing unseen filter treatment: $bool1" },
+ )
+
+ fun logUnseenHun(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = key },
+ messagePrinter = { "Unseen notif has become heads up: $str1" },
+ )
+}
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 e2f93ce62e46..4177263efbd0 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
@@ -1235,7 +1235,8 @@ public class NotificationStackScrollLayoutController {
// Hide empty shade view when in transition to Keyguard.
// That avoids "No Notifications" to blink when transitioning to AOD.
// For more details, see: b/228790482
- && !isInTransitionToKeyguard();
+ && !isInTransitionToKeyguard()
+ && !mCentralSurfaces.isBouncerShowing();
mView.updateEmptyShadeView(shouldShow, mZenModeController.areNotificationsHiddenInShade());
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 0de9608b906f..8f58140bce43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -502,7 +502,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages();
assertTrue(mViewMediator.isShowingAndNotOccluded());
- verify(mStatusBarKeyguardViewManager).reset(anyBoolean());
+ verify(mStatusBarKeyguardViewManager).reset(false);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index ffc6ee2a5a31..fa40fc431b5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -644,6 +644,58 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
}
@Test
+ fun isAuthenticatedIsResetToFalseWhenDeviceStartsGoingToSleep() =
+ testScope.runTest {
+ initCollectors()
+ allPreconditionsToRunFaceAuthAreTrue()
+
+ triggerFaceAuth(false)
+
+ authenticationCallback.value.onAuthenticationSucceeded(
+ mock(FaceManager.AuthenticationResult::class.java)
+ )
+
+ assertThat(authenticated()).isTrue()
+
+ keyguardRepository.setWakefulnessModel(
+ WakefulnessModel(
+ WakefulnessState.STARTING_TO_SLEEP,
+ isWakingUpOrAwake = false,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.POWER_BUTTON
+ )
+ )
+
+ assertThat(authenticated()).isFalse()
+ }
+
+ @Test
+ fun isAuthenticatedIsResetToFalseWhenDeviceGoesToSleep() =
+ testScope.runTest {
+ initCollectors()
+ allPreconditionsToRunFaceAuthAreTrue()
+
+ triggerFaceAuth(false)
+
+ authenticationCallback.value.onAuthenticationSucceeded(
+ mock(FaceManager.AuthenticationResult::class.java)
+ )
+
+ assertThat(authenticated()).isTrue()
+
+ keyguardRepository.setWakefulnessModel(
+ WakefulnessModel(
+ WakefulnessState.ASLEEP,
+ isWakingUpOrAwake = false,
+ lastWakeReason = WakeSleepReason.POWER_BUTTON,
+ lastSleepReason = WakeSleepReason.POWER_BUTTON
+ )
+ )
+
+ assertThat(authenticated()).isFalse()
+ }
+
+ @Test
fun isAuthenticatedIsResetToFalseWhenUserIsSwitching() =
testScope.runTest {
initCollectors()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 3d1d2f46a65e..5da1a846fbfd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -279,6 +279,23 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
}
@Test
+ fun faceAuthIsCancelledWhenUserInputOnPrimaryBouncer() =
+ testScope.runTest {
+ underTest.start()
+
+ underTest.onSwipeUpOnBouncer()
+
+ runCurrent()
+ assertThat(faceAuthRepository.isAuthRunning.value).isTrue()
+
+ underTest.onPrimaryBouncerUserInput()
+
+ runCurrent()
+
+ assertThat(faceAuthRepository.isAuthRunning.value).isFalse()
+ }
+
+ @Test
fun faceAuthIsRequestedWhenSwipeUpOnBouncer() =
testScope.runTest {
underTest.start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index 8f07f8d1a099..c3f51233f59a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -24,6 +24,7 @@ import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.advanceTimeBy
+import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -380,10 +381,12 @@ class KeyguardCoordinatorTest : SysuiTestCase() {
val keyguardCoordinator =
KeyguardCoordinator(
testDispatcher,
+ mock<DumpManager>(),
headsUpManager,
keyguardNotifVisibilityProvider,
keyguardRepository,
keyguardTransitionRepository,
+ mock<KeyguardCoordinatorLogger>(),
notifPipelineFlags,
testScope.backgroundScope,
sectionHeaderVisibilityProvider,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0bdb0c80d219..a3b4a0f51c75 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -194,7 +194,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
AccessibilityUserState.ServiceInfoChangeListener,
AccessibilityWindowManager.AccessibilityEventSender,
AccessibilitySecurityPolicy.AccessibilityUserManager,
- SystemActionPerformer.SystemActionsChangedListener, ProxyManager.SystemSupport{
+ SystemActionPerformer.SystemActionsChangedListener,
+ SystemActionPerformer.DisplayUpdateCallBack, ProxyManager.SystemSupport {
private static final boolean DEBUG = false;
@@ -1219,7 +1220,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private SystemActionPerformer getSystemActionPerformer() {
if (mSystemActionPerformer == null) {
mSystemActionPerformer =
- new SystemActionPerformer(mContext, mWindowManagerService, null, this);
+ new SystemActionPerformer(mContext, mWindowManagerService, null, this, this);
}
return mSystemActionPerformer;
}
@@ -1443,17 +1444,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return;
}
if (!mVisibleBgUserIds.get(userId)) {
- Slogf.wtf(LOG_TAG, "Cannot change current user to %d as it's not visible "
- + "(mVisibleUsers=%s)", userId, mVisibleBgUserIds);
+ Slogf.wtf(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): cannot change "
+ + "current user to %d as it's not visible (mVisibleUsers=%s)",
+ userId, mVisibleBgUserIds);
return;
}
if (mCurrentUserId == userId) {
- Slogf.w(LOG_TAG, "NOT changing current user for test automation purposes as it is "
- + "already %d", mCurrentUserId);
+ Slogf.d(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): NOT changing "
+ + "current user for test automation purposes as it is already %d",
+ mCurrentUserId);
return;
}
- Slogf.i(LOG_TAG, "Changing current user from %d to %d for test automation purposes",
- mCurrentUserId, userId);
+ Slogf.i(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): changing current user"
+ + " from %d to %d for test automation purposes", mCurrentUserId, userId);
mRealCurrentUserId = mCurrentUserId;
switchUser(userId);
}
@@ -1466,7 +1469,13 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
+ "because device doesn't support visible background users");
return;
}
- Slogf.i(LOG_TAG, "Restoring current user to %d after using %d for test automation purposes",
+ if (mRealCurrentUserId == UserHandle.USER_CURRENT) {
+ Slogf.d(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): ignoring "
+ + "because mRealCurrentUserId is already USER_CURRENT");
+ return;
+ }
+ Slogf.i(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): restoring current "
+ + "user to %d after using %d for test automation purposes",
mRealCurrentUserId, mCurrentUserId);
int currentUserId = mRealCurrentUserId;
mRealCurrentUserId = UserHandle.USER_CURRENT;
@@ -1611,6 +1620,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
+ @Override
+ // TODO(b/276459590): Remove when this is resolved at the virtual device/input level.
+ public void moveNonProxyTopFocusedDisplayToTopIfNeeded() {
+ mA11yWindowManager.moveNonProxyTopFocusedDisplayToTopIfNeeded();
+ }
+
+ @Override
+ // TODO(b/276459590): Remove when this is resolved at the virtual device/input level.
+ public int getLastNonProxyTopFocusedDisplayId() {
+ return mA11yWindowManager.getLastNonProxyTopFocusedDisplayId();
+ }
+
@VisibleForTesting
void notifySystemActionsChangedLocked(AccessibilityUserState userState) {
for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index a8a536590004..78f07e4f2692 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -103,6 +103,9 @@ public class AccessibilityWindowManager {
// The top focused display and window token updated with the callback of window lists change.
private int mTopFocusedDisplayId;
private IBinder mTopFocusedWindowToken;
+
+ // The non-proxy display that most recently had top focus.
+ private int mLastNonProxyTopFocusedDisplayId;
// The display has the accessibility focused window currently.
private int mAccessibilityFocusedDisplayId = Display.INVALID_DISPLAY;
@@ -451,6 +454,9 @@ public class AccessibilityWindowManager {
}
if (shouldUpdateWindowsLocked(forceSend, windows)) {
mTopFocusedDisplayId = topFocusedDisplayId;
+ if (!isProxyed(topFocusedDisplayId)) {
+ mLastNonProxyTopFocusedDisplayId = topFocusedDisplayId;
+ }
mTopFocusedWindowToken = topFocusedWindowToken;
if (DEBUG) {
Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): updating windows for "
@@ -1141,6 +1147,21 @@ public class AccessibilityWindowManager {
return false;
}
+ private boolean isProxyed(int displayId) {
+ final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId);
+ return (observer != null && observer.mIsProxy);
+ }
+
+ void moveNonProxyTopFocusedDisplayToTopIfNeeded() {
+ if (mHasProxy
+ && (mLastNonProxyTopFocusedDisplayId != mTopFocusedDisplayId)) {
+ mWindowManagerInternal.moveDisplayToTopIfAllowed(mLastNonProxyTopFocusedDisplayId);
+ }
+ }
+ int getLastNonProxyTopFocusedDisplayId() {
+ return mLastNonProxyTopFocusedDisplayId;
+ }
+
/**
* Checks if we are tracking windows on specified display.
*
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index c89b9b851742..a13df475d25d 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -72,6 +72,13 @@ public class SystemActionPerformer {
}
private final SystemActionsChangedListener mListener;
+ interface DisplayUpdateCallBack {
+ void moveNonProxyTopFocusedDisplayToTopIfNeeded();
+
+ int getLastNonProxyTopFocusedDisplayId();
+ }
+ private final DisplayUpdateCallBack mDisplayUpdateCallBack;
+
private final Object mSystemActionLock = new Object();
// Resource id based ActionId -> RemoteAction
@GuardedBy("mSystemActionLock")
@@ -94,7 +101,7 @@ public class SystemActionPerformer {
public SystemActionPerformer(
Context context,
WindowManagerInternal windowManagerInternal) {
- this(context, windowManagerInternal, null, null);
+ this(context, windowManagerInternal, null, null, null);
}
// Used to mock ScreenshotHelper
@@ -103,17 +110,19 @@ public class SystemActionPerformer {
Context context,
WindowManagerInternal windowManagerInternal,
Supplier<ScreenshotHelper> screenshotHelperSupplier) {
- this(context, windowManagerInternal, screenshotHelperSupplier, null);
+ this(context, windowManagerInternal, screenshotHelperSupplier, null, null);
}
public SystemActionPerformer(
Context context,
WindowManagerInternal windowManagerInternal,
Supplier<ScreenshotHelper> screenshotHelperSupplier,
- SystemActionsChangedListener listener) {
+ SystemActionsChangedListener listener,
+ DisplayUpdateCallBack callback) {
mContext = context;
mWindowManagerService = windowManagerInternal;
mListener = listener;
+ mDisplayUpdateCallBack = callback;
mScreenshotHelperSupplier = screenshotHelperSupplier;
mLegacyHomeAction = new AccessibilityAction(
@@ -245,6 +254,7 @@ public class SystemActionPerformer {
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mSystemActionLock) {
+ mDisplayUpdateCallBack.moveNonProxyTopFocusedDisplayToTopIfNeeded();
// If a system action is registered with the given actionId, call the corresponding
// RemoteAction.
RemoteAction registeredAction = mRegisteredSystemActions.get(actionId);
@@ -341,7 +351,7 @@ public class SystemActionPerformer {
int source) {
KeyEvent event = KeyEvent.obtain(downTime, time, action, keyCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
- source, null);
+ source, mDisplayUpdateCallBack.getLastNonProxyTopFocusedDisplayId(), null);
mContext.getSystemService(InputManager.class)
.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
event.recycle();
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index eb718853a6ce..d9e25ef7dcdc 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -199,6 +199,9 @@ public class TouchState {
case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
mLastTouchedWindowId = event.getWindowId();
break;
+ case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
+ mAms.moveNonProxyTopFocusedDisplayToTopIfNeeded();
+ break;
}
}
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 2d3928ca5721..8f416082374e 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -2237,7 +2237,14 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
clearAllResourcesAndClientMapping(getClientProfile(clientId));
mClientProfiles.remove(clientId);
- mListeners.remove(clientId);
+
+ // it may be called by unregisterClientProfileInternal under test
+ synchronized (mLock) {
+ ResourcesReclaimListenerRecord record = mListeners.remove(clientId);
+ if (record != null) {
+ record.getListener().asBinder().unlinkToDeath(record, 0);
+ }
+ }
}
private void clearFrontendAndClientMapping(ClientProfile profile) {
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 184293e11002..5626aa7f075f 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -681,6 +681,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final StartingWindowRemovalInfo removalInfo = new StartingWindowRemovalInfo();
removalInfo.taskId = task.mTaskId;
removalInfo.playRevealAnimation = prepareAnimation
+ && task.getDisplayContent() != null
&& task.getDisplayInfo().state == Display.STATE_ON;
final boolean playShiftUpAnimation = !task.inMultiWindowMode();
final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 492252314356..792ec2e92083 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -444,6 +444,11 @@ public abstract class WindowManagerInternal {
public abstract IBinder getFocusedWindowTokenFromWindowStates();
/**
+ * Moves the given display to the top.
+ */
+ public abstract void moveDisplayToTopIfAllowed(int displayId);
+
+ /**
* @return Whether the keyguard is engaged.
*/
public abstract boolean isKeyguardLocked();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 62b3c7cd1daf..8822193ab522 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7716,6 +7716,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public void moveDisplayToTopIfAllowed(int displayId) {
+ WindowManagerService.this.moveDisplayToTopIfAllowed(displayId);
+ }
+
+ @Override
public boolean isKeyguardLocked() {
return WindowManagerService.this.isKeyguardLocked();
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
index d9461aada4d3..b62dbcd526cb 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/SystemActionPerformerTest.java
@@ -108,6 +108,7 @@ public class SystemActionPerformerTest {
@Mock private StatusBarManager mMockStatusBarManager;
@Mock private ScreenshotHelper mMockScreenshotHelper;
@Mock private SystemActionPerformer.SystemActionsChangedListener mMockListener;
+ @Mock private SystemActionPerformer.DisplayUpdateCallBack mMockCallback;
@Before
public void setup() {
@@ -125,7 +126,7 @@ public class SystemActionPerformerTest {
mMockContext,
mMockWindowManagerInternal,
() -> mMockScreenshotHelper,
- mMockListener);
+ mMockListener, mMockCallback);
}
private void setupWithRealContext() {
@@ -133,7 +134,7 @@ public class SystemActionPerformerTest {
InstrumentationRegistry.getContext(),
mMockWindowManagerInternal,
() -> mMockScreenshotHelper,
- mMockListener);
+ mMockListener, mMockCallback);
}
// We need below two help functions because AccessbilityAction.equals function only compares
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index aca96ad20385..aad373fdaf95 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -445,14 +445,14 @@ public class SystemConfigTest {
+ " <library \n"
+ " name=\"foo\"\n"
+ " file=\"" + mFooJar + "\"\n"
- + " on-bootclasspath-before=\"Q\"\n"
+ + " on-bootclasspath-before=\"A\"\n"
+ " on-bootclasspath-since=\"W\"\n"
+ " />\n\n"
+ " </permissions>";
parseSharedLibraries(contents);
assertFooIsOnlySharedLibrary();
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
- assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
+ assertThat(entry.onBootclasspathBefore).isEqualTo("A");
assertThat(entry.onBootclasspathSince).isEqualTo("W");
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9cfdaa7cad0c..dd9f3cb3d343 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5447,6 +5447,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testVisitUris_callStyle() {
+ Icon personIcon = Icon.createWithContentUri("content://media/person");
+ Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
+ Person callingPerson = new Person.Builder().setName("Someone")
+ .setIcon(personIcon)
+ .build();
+ PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
+ Notification n = new Notification.Builder(mContext, "a")
+ .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent)
+ .setVerificationIcon(verificationIcon))
+ .setContentTitle("Calling...")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .build();
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ n.visitUris(visitor);
+
+ verify(visitor, times(1)).accept(eq(personIcon.getUri()));
+ verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
+ }
+
+ @Test
public void testVisitUris_audioContentsString() throws Exception {
final Uri audioContents = Uri.parse("content://com.example/audio");
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 25373f9e9e2f..554f64e73b74 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -15,7 +15,7 @@ package {
cc_binary_host {
name: "validatekeymaps",
-
+ cpp_std: "c++20",
srcs: ["Main.cpp"],
cflags: [