diff options
98 files changed, 1488 insertions, 371 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 2eb6ca758970..8d2394b20438 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2833,12 +2833,14 @@ public class Notification implements Parcelable } /** - * Note all {@link Uri} that are referenced internally, with the expectation - * that Uri permission grants will need to be issued to ensure the recipient - * of this object is able to render its contents. - * - * @hide - */ + * Note all {@link Uri} that are referenced internally, with the expectation that Uri permission + * grants will need to be issued to ensure the recipient of this object is able to render its + * contents. + * See b/281044385 for more context and examples about what happens when this isn't done + * correctly. + * + * @hide + */ public void visitUris(@NonNull Consumer<Uri> visitor) { if (publicVersion != null) { publicVersion.visitUris(visitor); @@ -2882,13 +2884,13 @@ public class Notification implements Parcelable ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST, android.app.Person.class); if (people != null && !people.isEmpty()) { for (Person p : people) { - visitor.accept(p.getIconUri()); + p.visitUris(visitor); } } final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class); if (person != null) { - visitor.accept(person.getIconUri()); + person.visitUris(visitor); } final RemoteInputHistoryItem[] history = extras.getParcelableArray( @@ -2910,12 +2912,7 @@ public class Notification implements Parcelable if (!ArrayUtils.isEmpty(messages)) { for (MessagingStyle.Message message : MessagingStyle.Message .getMessagesFromBundleArray(messages)) { - visitor.accept(message.getDataUri()); - - Person senderPerson = message.getSenderPerson(); - if (senderPerson != null) { - visitor.accept(senderPerson.getIconUri()); - } + message.visitUris(visitor); } } @@ -2924,12 +2921,7 @@ public class Notification implements Parcelable if (!ArrayUtils.isEmpty(historic)) { for (MessagingStyle.Message message : MessagingStyle.Message .getMessagesFromBundleArray(historic)) { - visitor.accept(message.getDataUri()); - - Person senderPerson = message.getSenderPerson(); - if (senderPerson != null) { - visitor.accept(senderPerson.getIconUri()); - } + message.visitUris(visitor); } } @@ -2939,7 +2931,7 @@ public class Notification implements Parcelable if (isStyle(CallStyle.class) & extras != null) { Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class); if (callPerson != null) { - visitor.accept(callPerson.getIconUri()); + callPerson.visitUris(visitor); } visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON, Icon.class)); } @@ -8833,6 +8825,18 @@ public class Notification implements Parcelable } /** + * See {@link Notification#visitUris(Consumer)}. + * + * @hide + */ + public void visitUris(@NonNull Consumer<Uri> visitor) { + visitor.accept(getDataUri()); + if (mSender != null) { + mSender.visitUris(visitor); + } + } + + /** * Returns a list of messages read from the given bundle list, e.g. * {@link #EXTRA_MESSAGES} or {@link #EXTRA_HISTORIC_MESSAGES}. */ diff --git a/core/java/android/app/Person.java b/core/java/android/app/Person.java index 97a794d4e4ea..18fc0ce6af15 100644 --- a/core/java/android/app/Person.java +++ b/core/java/android/app/Person.java @@ -24,6 +24,7 @@ import android.os.Parcel; import android.os.Parcelable; import java.util.Objects; +import java.util.function.Consumer; /** * Provides an immutable reference to an entity that appears repeatedly on different surfaces of the @@ -177,6 +178,19 @@ public final class Person implements Parcelable { dest.writeBoolean(mIsBot); } + /** + * Note all {@link Uri} that are referenced internally, with the expectation that Uri permission + * grants will need to be issued to ensure the recipient of this object is able to render its + * contents. + * See b/281044385 for more context and examples about what happens when this isn't done + * correctly. + * + * @hide + */ + public void visitUris(@NonNull Consumer<Uri> visitor) { + visitor.accept(getIconUri()); + } + /** Builder for the immutable {@link Person} class. */ public static class Builder { @Nullable private CharSequence mName; diff --git a/core/java/android/app/ServiceStartArgs.java b/core/java/android/app/ServiceStartArgs.java index 0b000af56400..9c52367392a5 100644 --- a/core/java/android/app/ServiceStartArgs.java +++ b/core/java/android/app/ServiceStartArgs.java @@ -49,7 +49,7 @@ public class ServiceStartArgs implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(taskRemoved ? 1 : 0); out.writeInt(startId); - out.writeInt(flags); + out.writeInt(this.flags); if (args != null) { out.writeInt(1); args.writeToParcel(out, 0); diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java index 99d406446dae..b29e73a717f4 100644 --- a/core/java/android/app/WallpaperInfo.java +++ b/core/java/android/app/WallpaperInfo.java @@ -292,12 +292,12 @@ public final class WallpaperInfo implements Parcelable { packageName = mService.serviceInfo.packageName; applicationInfo = mService.serviceInfo.applicationInfo; } - String contextUriString = pm.getText( - packageName, mContextUriResource, applicationInfo).toString(); - if (contextUriString == null) { + CharSequence contextUriCharSequence = pm.getText( + packageName, mContextUriResource, applicationInfo); + if (contextUriCharSequence == null) { return null; } - return Uri.parse(contextUriString); + return Uri.parse(contextUriCharSequence.toString()); } /** diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java index 1df9b75f0b09..18d0b09faa14 100644 --- a/core/java/android/hardware/lights/Light.java +++ b/core/java/android/hardware/lights/Light.java @@ -110,6 +110,8 @@ public final class Light implements Parcelable { private final int mOrdinal; private final int mType; private final int mCapabilities; + @Nullable + private final int[] mPreferredBrightnessLevels; /** * Creates a new light with the given data. @@ -117,7 +119,7 @@ public final class Light implements Parcelable { * @hide */ public Light(int id, int ordinal, int type) { - this(id, "Light", ordinal, type, 0); + this(id, "Light", ordinal, type, 0, null); } /** @@ -126,11 +128,22 @@ public final class Light implements Parcelable { * @hide */ public Light(int id, String name, int ordinal, int type, int capabilities) { + this(id, name, ordinal, type, capabilities, null); + } + + /** + * Creates a new light with the given data. + * + * @hide + */ + public Light(int id, String name, int ordinal, int type, int capabilities, + @Nullable int[] preferredBrightnessLevels) { mId = id; mName = name; mOrdinal = ordinal; mType = type; mCapabilities = capabilities; + mPreferredBrightnessLevels = preferredBrightnessLevels; } private Light(@NonNull Parcel in) { @@ -139,6 +152,7 @@ public final class Light implements Parcelable { mOrdinal = in.readInt(); mType = in.readInt(); mCapabilities = in.readInt(); + mPreferredBrightnessLevels = in.createIntArray(); } /** Implement the Parcelable interface */ @@ -149,6 +163,7 @@ public final class Light implements Parcelable { dest.writeInt(mOrdinal); dest.writeInt(mType); dest.writeInt(mCapabilities); + dest.writeIntArray(mPreferredBrightnessLevels); } /** Implement the Parcelable interface */ @@ -252,4 +267,17 @@ public final class Light implements Parcelable { return (mCapabilities & LIGHT_CAPABILITY_COLOR_RGB) == LIGHT_CAPABILITY_COLOR_RGB; } + /** + * Returns preferred brightness levels for the light which will be used when user + * increase/decrease brightness levels for the light (currently only used for Keyboard + * backlight control using backlight up/down keys). + * + * The values in the preferred brightness level array are in the range [0, 255]. + * + * @hide + */ + @Nullable + public int[] getPreferredBrightnessLevels() { + return mPreferredBrightnessLevels; + } } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index ddaa71c6b1b5..c11f4975149d 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -786,7 +786,11 @@ public final class SurfaceControl implements Parcelable { mReleaseStack = null; } setUnreleasedWarningCallSite(callsite); - addToRegistry(); + if (nativeObject != 0) { + // Only add valid surface controls to the registry. This is called at the end of this + // method since its information is dumped if the process threshold is reached. + addToRegistry(); + } } /** @@ -893,6 +897,10 @@ public final class SurfaceControl implements Parcelable { "Only buffer layers can set a valid buffer size."); } + if (mName == null) { + Log.w(TAG, "Missing name for SurfaceControl", new Throwable()); + } + if ((mFlags & FX_SURFACE_MASK) == FX_SURFACE_NORMAL) { setBLASTLayer(); } @@ -1254,6 +1262,9 @@ public final class SurfaceControl implements Parcelable { } /** + * Note: Most callers should use {@link SurfaceControl.Builder} or one of the other constructors + * to build an instance of a SurfaceControl. This constructor is mainly used for + * unparceling and passing into an AIDL call as an out parameter. * @hide */ public SurfaceControl() { @@ -2495,6 +2506,7 @@ public final class SurfaceControl implements Parcelable { public static SurfaceControl mirrorSurface(SurfaceControl mirrorOf) { long nativeObj = nativeMirrorSurface(mirrorOf.mNativeObject); SurfaceControl sc = new SurfaceControl(); + sc.mName = mirrorOf.mName + " (mirror)"; sc.assignNativeObject(nativeObj, "mirrorSurface"); return sc; } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index d9872174f9be..c8cf7d9a5194 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -171,8 +171,7 @@ public class SurfaceControlViewHost { public SurfacePackage(@NonNull SurfacePackage other) { SurfaceControl otherSurfaceControl = other.mSurfaceControl; if (otherSurfaceControl != null && otherSurfaceControl.isValid()) { - mSurfaceControl = new SurfaceControl(); - mSurfaceControl.copyFrom(otherSurfaceControl, "SurfacePackage"); + mSurfaceControl = new SurfaceControl(otherSurfaceControl, "SurfacePackage"); } mAccessibilityEmbeddedConnection = other.mAccessibilityEmbeddedConnection; mInputToken = other.mInputToken; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 0e72ea8622e2..d40c032eb21c 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -555,6 +555,13 @@ public interface WindowManager extends ViewManager { int TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT = (1 << 9); // 0x200 /** + * Transition flag: The transition is prepared when nothing is visible on screen, e.g. screen + * is off. The animation handlers can decide whether to skip animations. + * @hide + */ + int TRANSIT_FLAG_INVISIBLE = (1 << 10); // 0x400 + + /** * @hide */ @IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = { @@ -567,7 +574,8 @@ public interface WindowManager extends ViewManager { TRANSIT_FLAG_KEYGUARD_LOCKED, TRANSIT_FLAG_IS_RECENTS, TRANSIT_FLAG_KEYGUARD_GOING_AWAY, - TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT + TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT, + TRANSIT_FLAG_INVISIBLE, }) @Retention(RetentionPolicy.SOURCE) @interface TransitionFlags {} diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java index e530aec2119a..869b69611eba 100644 --- a/core/java/com/android/internal/jank/InteractionJankMonitor.java +++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java @@ -28,6 +28,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_ALL_APPS_SCROLL; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME; +import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_PIP; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_ICON; import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_LAUNCH_FROM_RECENTS; @@ -258,8 +259,16 @@ public class InteractionJankMonitor { public static final int CUJ_IME_INSETS_ANIMATION = 69; public static final int CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION = 70; public static final int CUJ_LAUNCHER_OPEN_SEARCH_RESULT = 71; + // 72 - 77 are reserved for b/281564325. - private static final int LAST_CUJ = CUJ_LAUNCHER_OPEN_SEARCH_RESULT; + /** + * In some cases when we do not have any end-target, we play a simple slide-down animation. + * eg: Open an app from Overview/Task switcher such that there is no home-screen icon. + * eg: Exit the app using back gesture. + */ + public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78; + + private static final int LAST_CUJ = CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK; private static final int NO_STATSD_LOGGING = -1; // Used to convert CujType to InteractionType enum value for statsd logging. @@ -340,6 +349,14 @@ public class InteractionJankMonitor { CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_ANIMATION; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LOCKSCREEN_CLOCK_MOVE_ANIMATION; CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_OPEN_SEARCH_RESULT] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_OPEN_SEARCH_RESULT; + // 72 - 77 are reserved for b/281564325. + CUJ_TO_STATSD_INTERACTION_TYPE[72] = NO_STATSD_LOGGING; + CUJ_TO_STATSD_INTERACTION_TYPE[73] = NO_STATSD_LOGGING; + CUJ_TO_STATSD_INTERACTION_TYPE[74] = NO_STATSD_LOGGING; + CUJ_TO_STATSD_INTERACTION_TYPE[75] = NO_STATSD_LOGGING; + CUJ_TO_STATSD_INTERACTION_TYPE[76] = NO_STATSD_LOGGING; + CUJ_TO_STATSD_INTERACTION_TYPE[77] = NO_STATSD_LOGGING; + CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK; } private static class InstanceHolder { @@ -439,6 +456,7 @@ public class InteractionJankMonitor { CUJ_IME_INSETS_ANIMATION, CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION, CUJ_LAUNCHER_OPEN_SEARCH_RESULT, + CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK, }) @Retention(RetentionPolicy.SOURCE) public @interface CujType { @@ -1050,6 +1068,8 @@ public class InteractionJankMonitor { return "LOCKSCREEN_CLOCK_MOVE_ANIMATION"; case CUJ_LAUNCHER_OPEN_SEARCH_RESULT: return "LAUNCHER_OPEN_SEARCH_RESULT"; + case CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK: + return "LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK"; } return "UNKNOWN"; } diff --git a/core/proto/android/input/keyboard_configured.proto b/core/proto/android/input/keyboard_configured.proto new file mode 100644 index 000000000000..16990087b319 --- /dev/null +++ b/core/proto/android/input/keyboard_configured.proto @@ -0,0 +1,50 @@ +/* + * Copyright 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. + */ + +syntax = "proto2"; + +package com.android.internal.os; + +option java_outer_classname = "KeyboardConfiguredProto"; + +/** + * RepeatedKeyboardLayout proto from input_extension_atoms.proto, + * duplicated here so that it's accessible in the build. + * Must be kept in sync with the version in input_extension_atoms.proto. + */ + +// Message containing the repeated field for KeyboardLayoutConfig +message RepeatedKeyboardLayoutConfig { + repeated KeyboardLayoutConfig keyboard_layout_config = 1; +} + +// Keyboard layout configured when the device is connected +// used in KeyboardConfigured atom +message KeyboardLayoutConfig { + // Keyboard configuration details + // Layout type mappings found at: + // frameworks/base/core/res/res/values/attrs.xml + optional int32 keyboard_layout_type = 1; + // PK language language tag (e.g. en-US, ru-Cyrl, etc). This will follow + // BCP-47 language tag standards. + optional string keyboard_language_tag = 2; + // Selected keyboard layout name (e.g. English(US), English(Dvorak), etc.) + optional string keyboard_layout_name = 3; + // Criteria for layout selection (such as user, device, virtual keyboard based) + // IntDef annotation at: + // services/core/java/com/android/server/input/KeyboardMetricsCollector.java + optional int32 layout_selection_criteria = 4; +} diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java index 6e8e93a8c86b..b2e42ba90152 100644 --- a/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java +++ b/core/tests/coretests/src/android/content/res/FontScaleConverterActivityTest.java @@ -26,6 +26,7 @@ import android.app.Activity; import android.compat.testing.PlatformCompatChangeRule; import android.os.Bundle; import android.platform.test.annotations.IwTest; +import android.platform.test.annotations.PlatinumTest; import android.platform.test.annotations.Presubmit; import android.provider.Settings; import android.util.PollingCheck; @@ -72,6 +73,7 @@ public class FontScaleConverterActivityTest { restoreSystemFontScaleToDefault(); } + @PlatinumTest(focusArea = "accessibility") @IwTest(focusArea = "accessibility") @Test public void testFontsScaleNonLinearly() { @@ -103,6 +105,7 @@ public class FontScaleConverterActivityTest { ))); } + @PlatinumTest(focusArea = "accessibility") @IwTest(focusArea = "accessibility") @Test public void testOnConfigurationChanged_doesNotCrash() { @@ -117,6 +120,7 @@ public class FontScaleConverterActivityTest { }); } + @PlatinumTest(focusArea = "accessibility") @IwTest(focusArea = "accessibility") @Test public void testUpdateConfiguration_doesNotCrash() { diff --git a/core/tests/coretests/src/android/view/SurfaceControlRegistryTests.java b/core/tests/coretests/src/android/view/SurfaceControlRegistryTests.java index d10ba7ccbac4..e117051ba9de 100644 --- a/core/tests/coretests/src/android/view/SurfaceControlRegistryTests.java +++ b/core/tests/coretests/src/android/view/SurfaceControlRegistryTests.java @@ -104,6 +104,18 @@ public class SurfaceControlRegistryTests { } @Test + public void testInvalidSurfaceControlNotAddedToRegistry() { + int hash0 = SurfaceControlRegistry.getProcessInstance().hashCode(); + // Verify no changes to the registry when dealing with invalid surface controls + SurfaceControl sc0 = new SurfaceControl(); + SurfaceControl sc1 = new SurfaceControl(sc0, "test"); + assertEquals(hash0, SurfaceControlRegistry.getProcessInstance().hashCode()); + sc0.release(); + sc1.release(); + assertEquals(hash0, SurfaceControlRegistry.getProcessInstance().hashCode()); + } + + @Test public void testThresholds() { SurfaceControlRegistry registry = SurfaceControlRegistry.getProcessInstance(); TestReporter reporter = new TestReporter(); diff --git a/graphics/java/android/graphics/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java index f9113a21405c..6705b25ab0ec 100644 --- a/graphics/java/android/graphics/GraphicBuffer.java +++ b/graphics/java/android/graphics/GraphicBuffer.java @@ -57,7 +57,7 @@ public class GraphicBuffer implements Parcelable { private final int mUsage; // Note: do not rename, this field is used by native code @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private final long mNativeObject; + private long mNativeObject; // These two fields are only used by lock/unlockCanvas() private Canvas mCanvas; @@ -219,6 +219,7 @@ public class GraphicBuffer implements Parcelable { if (!mDestroyed) { mDestroyed = true; nDestroyGraphicBuffer(mNativeObject); + mNativeObject = 0; } } @@ -239,7 +240,7 @@ public class GraphicBuffer implements Parcelable { @Override protected void finalize() throws Throwable { try { - if (!mDestroyed) nDestroyGraphicBuffer(mNativeObject); + destroy(); } finally { super.finalize(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index bc0b71c97346..2dbccaceeddc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -542,9 +542,12 @@ public abstract class WMShellModule { Optional<PipTouchHandler> pipTouchHandlerOptional, Optional<RecentsTransitionHandler> recentsTransitionHandler, KeyguardTransitionHandler keyguardTransitionHandler, + Optional<DesktopModeController> desktopModeController, + Optional<DesktopTasksController> desktopTasksController, Transitions transitions) { return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional, - pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler); + pipTouchHandlerOptional, recentsTransitionHandler, keyguardTransitionHandler, + desktopModeController, desktopTasksController); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java index 1169af9306b0..705b35235193 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java @@ -33,6 +33,7 @@ import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DE import android.app.ActivityManager.RunningTaskInfo; import android.app.WindowConfiguration; import android.content.Context; +import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.Region; import android.net.Uri; @@ -414,6 +415,25 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll } /** + * Applies the proper surface states (rounded corners) to tasks when desktop mode is active. + * This is intended to be used when desktop mode is part of another animation but isn't, itself, + * animating. + */ + public void syncSurfaceState(@NonNull TransitionInfo info, + SurfaceControl.Transaction finishTransaction) { + // Add rounded corners to freeform windows + final TypedArray ta = mContext.obtainStyledAttributes( + new int[]{android.R.attr.dialogCornerRadius}); + final int cornerRadius = ta.getDimensionPixelSize(0, 0); + ta.recycle(); + for (TransitionInfo.Change change: info.getChanges()) { + if (change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FREEFORM) { + finishTransaction.setCornerRadius(change.getLeash(), cornerRadius); + } + } + } + + /** * A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE} */ private final class SettingsObserver extends ContentObserver { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index b551e6b9fb55..6ca9facc8110 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.desktopmode +import android.R import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD @@ -24,6 +25,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.app.WindowConfiguration.WindowingMode import android.content.Context +import android.content.res.TypedArray import android.graphics.Point import android.graphics.Rect import android.graphics.Region @@ -460,6 +462,25 @@ class DesktopTasksController( } } + /** + * Applies the proper surface states (rounded corners) to tasks when desktop mode is active. + * This is intended to be used when desktop mode is part of another animation but isn't, itself, + * animating. + */ + fun syncSurfaceState( + info: TransitionInfo, + finishTransaction: SurfaceControl.Transaction + ) { + // Add rounded corners to freeform windows + val ta: TypedArray = context.obtainStyledAttributes( + intArrayOf(R.attr.dialogCornerRadius)) + val cornerRadius = ta.getDimensionPixelSize(0, 0).toFloat() + ta.recycle() + info.changes + .filter { it.taskInfo.windowingMode == WINDOWING_MODE_FREEFORM } + .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) } + } + private fun handleFreeformTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId) if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index e0ffffffa727..256d48c5618c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -192,6 +192,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private final SplitScreenTransitions mSplitTransitions; private final SplitscreenEventLogger mLogger; private final ShellExecutor mMainExecutor; + // Cache live tile tasks while entering recents, evict them from stages in finish transaction + // if user is opening another task(s). + private final ArrayList<Integer> mPausingTasks = new ArrayList<>(); private final Optional<RecentTasksController> mRecentTasks; private final Rect mTempRect1 = new Rect(); @@ -658,6 +661,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // Add task launch requests wct.startTask(mainTaskId, mainOptions); + // leave recents animation by re-start pausing tasks + if (mPausingTasks.contains(mainTaskId)) { + mPausingTasks.clear(); + } mSplitTransitions.startEnterTransition( TRANSIT_TO_FRONT, wct, remoteTransition, this, null, null, TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false); @@ -1630,7 +1637,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } private void updateRecentTasksSplitPair() { - if (!mShouldUpdateRecents) { + // Preventing from single task update while processing recents. + if (!mShouldUpdateRecents || !mPausingTasks.isEmpty()) { return; } mRecentTasks.ifPresent(recentTasks -> { @@ -2582,6 +2590,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final TransitionInfo.Change change = info.getChanges().get(iC); final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo(); if (taskInfo == null || !taskInfo.hasParentTask()) continue; + if (mPausingTasks.contains(taskInfo.taskId)) { + continue; + } final @StageType int stageType = getStageType(getStageOfTask(taskInfo)); if (stageType == STAGE_TYPE_MAIN && (isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE)) { @@ -2654,6 +2665,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mShowDecorImmediately = true; mSplitLayout.flingDividerToCenter(); } + mPausingTasks.clear(); }); finishEnterSplitScreen(finishT); @@ -2811,12 +2823,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, /** Call this when starting the open-recents animation while split-screen is active. */ public void onRecentsInSplitAnimationStart(TransitionInfo info) { + if (isSplitScreenVisible()) { + // Cache tasks on live tile. + for (int i = 0; i < info.getChanges().size(); ++i) { + final TransitionInfo.Change change = info.getChanges().get(i); + if (TransitionUtil.isClosingType(change.getMode()) + && change.getTaskInfo() != null) { + final int taskId = change.getTaskInfo().taskId; + if (mMainStage.getTopVisibleChildTaskId() == taskId + || mSideStage.getTopVisibleChildTaskId() == taskId) { + mPausingTasks.add(taskId); + } + } + } + } + addDividerBarToTransition(info, false /* show */); } + /** Call this when the recents animation canceled during split-screen. */ + public void onRecentsInSplitAnimationCanceled() { + mPausingTasks.clear(); + } + /** Call this when the recents animation during split-screen finishes. */ public void onRecentsInSplitAnimationFinish(WindowContainerTransaction finishWct, - SurfaceControl.Transaction finishT, TransitionInfo info) { + SurfaceControl.Transaction finishT) { + mPausingTasks.clear(); // Check if the recent transition is finished by returning to the current // split, so we can restore the divider bar. for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) { @@ -2840,6 +2873,27 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, logExit(EXIT_REASON_UNKNOWN); } + /** Call this when the recents animation finishes by doing pair-to-pair switch. */ + public void onRecentsPairToPairAnimationFinish(WindowContainerTransaction finishWct) { + // Pair-to-pair switch happened so here should evict the live tile from its stage. + // Otherwise, the task will remain in stage, and occluding the new task when next time + // user entering recents. + for (int i = mPausingTasks.size() - 1; i >= 0; --i) { + final int taskId = mPausingTasks.get(i); + if (mMainStage.containsTask(taskId)) { + mMainStage.evictChildren(finishWct, taskId); + } else if (mSideStage.containsTask(taskId)) { + mSideStage.evictChildren(finishWct, taskId); + } + } + // If pending enter hasn't consumed, the mix handler will invoke start pending + // animation within following transition. + if (mSplitTransitions.mPendingEnter == null) { + mPausingTasks.clear(); + updateRecentTasksSplitPair(); + } + } + private void addDividerBarToTransition(@NonNull TransitionInfo info, boolean show) { final SurfaceControl leash = mSplitLayout.getDividerLeash(); if (leash == null || !leash.isValid()) { @@ -2892,6 +2946,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, pw.println(innerPrefix + "SplitLayout"); mSplitLayout.dump(pw, childPrefix); } + if (!mPausingTasks.isEmpty()) { + pw.println(childPrefix + "mPausingTasks=" + mPausingTasks); + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index da7d18641a97..92ff5fed4584 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -377,6 +377,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } } + void evictChildren(WindowContainerTransaction wct, int taskId) { + final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.get(taskId); + if (taskInfo != null) { + wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + } + } + void reparentTopTask(WindowContainerTransaction wct) { wct.reparentTasks(null /* currentParent */, mRootTaskInfo.token, CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index 863b5ab73a7d..5ee5324f8758 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -40,6 +40,9 @@ import android.window.WindowContainerTransaction; import android.window.WindowContainerTransactionCallback; import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.desktopmode.DesktopModeController; +import com.android.wm.shell.desktopmode.DesktopModeStatus; +import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.keyguard.KeyguardTransitionHandler; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip.phone.PipTouchHandler; @@ -65,6 +68,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, private RecentsTransitionHandler mRecentsHandler; private StageCoordinator mSplitHandler; private final KeyguardTransitionHandler mKeyguardHandler; + private DesktopModeController mDesktopModeController; + private DesktopTasksController mDesktopTasksController; private static class MixedTransition { static final int TYPE_ENTER_PIP_FROM_SPLIT = 1; @@ -81,6 +86,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, /** Keyguard exit/occlude/unocclude transition. */ static final int TYPE_KEYGUARD = 5; + /** Recents Transition while in desktop mode. */ + static final int TYPE_RECENTS_DURING_DESKTOP = 6; + /** The default animation for this mixed transition. */ static final int ANIM_TYPE_DEFAULT = 0; @@ -132,7 +140,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, Optional<SplitScreenController> splitScreenControllerOptional, Optional<PipTouchHandler> pipTouchHandlerOptional, Optional<RecentsTransitionHandler> recentsHandlerOptional, - KeyguardTransitionHandler keyguardHandler) { + KeyguardTransitionHandler keyguardHandler, + Optional<DesktopModeController> desktopModeControllerOptional, + Optional<DesktopTasksController> desktopTasksControllerOptional) { mPlayer = player; mKeyguardHandler = keyguardHandler; if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent() @@ -149,6 +159,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, if (mRecentsHandler != null) { mRecentsHandler.addMixer(this); } + mDesktopModeController = desktopModeControllerOptional.orElse(null); + mDesktopTasksController = desktopTasksControllerOptional.orElse(null); }, this); } } @@ -218,7 +230,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, @Override public Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT) { - if (mRecentsHandler != null && mSplitHandler.isSplitScreenVisible()) { + if (mRecentsHandler != null && (mSplitHandler.isSplitScreenVisible() + || DesktopModeStatus.isActive(mPlayer.getContext()))) { return this; } return null; @@ -233,6 +246,13 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition); mixed.mLeftoversHandler = mRecentsHandler; mActiveTransitions.add(mixed); + } else if (DesktopModeStatus.isActive(mPlayer.getContext())) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + + "desktop mode is active, so treat it as Mixed."); + final MixedTransition mixed = new MixedTransition( + MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition); + mixed.mLeftoversHandler = mRecentsHandler; + mActiveTransitions.add(mixed); } else { throw new IllegalStateException("Accepted a recents transition but don't know how to" + " handle it"); @@ -306,6 +326,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, } else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) { return animateKeyguard(mixed, info, startTransaction, finishTransaction, finishCallback); + } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) { + return animateRecentsDuringDesktop(mixed, info, startTransaction, finishTransaction, + finishCallback); } else { mActiveTransitions.remove(mixed); throw new IllegalStateException("Starting mixed animation without a known mixed type? " @@ -540,9 +563,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, mixed.mInFlightSubAnimations = 0; mActiveTransitions.remove(mixed); // If pair-to-pair switching, the post-recents clean-up isn't needed. + wct = wct != null ? wct : new WindowContainerTransaction(); if (mixed.mAnimType != MixedTransition.ANIM_TYPE_PAIR_TO_PAIR) { - wct = wct != null ? wct : new WindowContainerTransaction(); - mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction, info); + mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction); + } else { + // notify pair-to-pair recents animation finish + mSplitHandler.onRecentsPairToPairAnimationFinish(wct); } mSplitHandler.onTransitionAnimationComplete(); finishCallback.onTransitionFinished(wct, wctCB); @@ -552,6 +578,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, final boolean handled = mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info, startTransaction, finishTransaction, finishCB); if (!handled) { + mSplitHandler.onRecentsInSplitAnimationCanceled(); mActiveTransitions.remove(mixed); } return handled; @@ -578,6 +605,30 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, return true; } + private boolean animateRecentsDuringDesktop(@NonNull final MixedTransition mixed, + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + boolean consumed = mRecentsHandler.startAnimation( + mixed.mTransition, info, startTransaction, finishTransaction, finishCallback); + if (!consumed) { + return false; + } + //Sync desktop mode state (proto 1) + if (mDesktopModeController != null) { + mDesktopModeController.syncSurfaceState(info, finishTransaction); + return true; + } + //Sync desktop mode state (proto 2) + if (mDesktopTasksController != null) { + mDesktopTasksController.syncSurfaceState(info, finishTransaction); + return true; + } + + return false; + } + @Override public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, @@ -621,6 +672,9 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, finishCallback); } else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) { mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); + } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) { + mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, + finishCallback); } else { throw new IllegalStateException("Playing a mixed transition with unknown type? " + mixed.mType); @@ -646,6 +700,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT); } else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) { mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT); + } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) { + mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index 6a2468a7eaa2..dc8a25842969 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -299,7 +299,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } // Early check if the transition doesn't warrant an animation. - if (Transitions.isAllNoAnimation(info) || Transitions.isAllOrderOnly(info)) { + if (Transitions.isAllNoAnimation(info) || Transitions.isAllOrderOnly(info) + || (info.getFlags() & WindowManager.TRANSIT_FLAG_INVISIBLE) != 0) { startTransaction.apply(); finishTransaction.apply(); finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java index 19d8384ace41..fc301b6993c0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java @@ -23,6 +23,7 @@ import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.transitTypeToString; +import static android.window.TransitionInfo.FLAGS_IS_NON_APP_WINDOW; import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT; import static android.window.TransitionInfo.FLAG_TRANSLUCENT; @@ -150,6 +151,10 @@ public class TransitionAnimationHelper { .loadAnimationAttr(options.getPackageName(), options.getAnimations(), animAttr, translucent); } + } else if (translucent && !isTask && ((changeFlags & FLAGS_IS_NON_APP_WINDOW) == 0)) { + // Un-styled translucent activities technically have undefined animations; however, + // as is always the case, some apps now rely on this being no-animation, so skip + // loading animations here. } else { a = transitionAnimation.loadDefaultAnimationAttr(animAttr, translucent); } 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 3b306e793640..e6d4603db10d 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 @@ -16,9 +16,12 @@ package com.android.wm.shell.transition; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM; +import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_SLEEP; import static android.view.WindowManager.TRANSIT_TO_BACK; @@ -1081,6 +1084,16 @@ public class Transitions implements RemoteCallable<Transitions>, } } } + if (request.getType() == TRANSIT_KEYGUARD_OCCLUDE && request.getTriggerTask() != null + && request.getTriggerTask().getWindowingMode() == WINDOWING_MODE_FREEFORM) { + // This freeform task is on top of keyguard, so its windowing mode should be changed to + // fullscreen. + if (wct == null) { + wct = new WindowContainerTransaction(); + } + wct.setWindowingMode(request.getTriggerTask().token, WINDOWING_MODE_FULLSCREEN); + wct.setBounds(request.getTriggerTask().token, null); + } mOrganizer.startTransition(transitionToken, wct != null && wct.isEmpty() ? null : wct); active.mToken = transitionToken; // Currently, WMCore only does one transition at a time. If it makes a requestStart, it diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt index b7e73ad11c9f..72f25f36c9d9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt @@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.traces.component.ComponentNameMatcher import android.tools.common.traces.component.EdgeExtensionComponentMatcher @@ -60,6 +61,7 @@ class CopyContentInSplit(override val flicker: FlickerTest) : thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt index 0b0a3dad320b..ed3df9ced3b0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt @@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder @@ -58,6 +59,7 @@ class DragDividerToResize(override val flicker: FlickerTest) : thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt index 8cf871f88314..b4c6afd14a90 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.tools.common.NavBar @@ -59,6 +60,7 @@ class SwitchAppByDoubleTapDivider(override val flicker: FlickerTest) : thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt index 3b2da8dbcf9f..2cedc3570cfd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt @@ -18,6 +18,7 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder @@ -62,6 +63,7 @@ class SwitchBetweenSplitPairs(override val flicker: FlickerTest) : thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt index a189a3f67eca..a5ad97d8ad65 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -62,6 +63,7 @@ open class CopyContentInSplitBenchmark(override val flicker: FlickerTest) : thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt index 55ab7b3a30e4..fa6a4bfbcda6 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder @@ -68,6 +69,7 @@ open class DismissSplitScreenByDividerBenchmark(flicker: FlickerTest) : SplitScr thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt index c4cfd1add25c..d2beb678a4d5 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder @@ -55,6 +56,7 @@ open class DismissSplitScreenByGoHomeBenchmark(override val flicker: FlickerTest thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt index 146287c21c75..e95fd947ebde 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder @@ -58,6 +59,7 @@ open class DragDividerToResizeBenchmark(override val flicker: FlickerTest) : Assume.assumeTrue(tapl.isTablet || !flicker.scenario.isLandscapeOrSeascapeAtStart) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt index cc715021adf4..63b74e29c39c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -70,6 +71,7 @@ open class EnterSplitScreenByDragFromAllAppsBenchmark(override val flicker: Flic Assume.assumeTrue(tapl.isTablet) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt index de78f09d3ef4..e94da8713b43 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -67,6 +68,7 @@ open class EnterSplitScreenByDragFromNotificationBenchmark(override val flicker: thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt index a29eb4085e54..f41117f0d54e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -70,6 +71,7 @@ open class EnterSplitScreenByDragFromShortcutBenchmark(flicker: FlickerTest) : thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt index b2395cafafc1..12f610b73e13 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -65,6 +66,7 @@ open class EnterSplitScreenByDragFromTaskbarBenchmark(override val flicker: Flic thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt index e1d85d0a4371..77818d380053 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder @@ -64,6 +65,7 @@ open class EnterSplitScreenFromOverviewBenchmark(override val flicker: FlickerTe thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt index ba8c46091808..6ff22902667c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.common.Rotation @@ -134,6 +135,7 @@ open class SwitchAppByDoubleTapDividerBenchmark(override val flicker: FlickerTes return displayBounds.width > displayBounds.height } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt index bbb2edc621e2..400adea8880d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -63,6 +64,7 @@ open class SwitchBackToSplitFromAnotherAppBenchmark(override val flicker: Flicke thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt index fa382932eb88..1ec43405ee44 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -61,6 +62,7 @@ open class SwitchBackToSplitFromHomeBenchmark(override val flicker: FlickerTest) thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt index 1064bd93e3c1..9757153929ca 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.NavBar import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -61,6 +62,7 @@ open class SwitchBackToSplitFromRecentBenchmark(override val flicker: FlickerTes thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt index 8f4393f8d20d..c19a38dc9daf 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.device.flicker.junit.FlickerParametersRunnerFactory import android.tools.device.flicker.legacy.FlickerBuilder @@ -64,6 +65,7 @@ open class SwitchBetweenSplitPairsBenchmark(override val flicker: FlickerTest) : thisTransition(this) } + @PlatinumTest(focusArea = "sysui") @IwTest(focusArea = "sysui") @Presubmit @Test open fun cujCompleted() {} companion object { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java index 60c0e5535568..5f705d743601 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java @@ -283,7 +283,7 @@ public class SplitTransitionTests extends ShellTestCase { // Make sure it cleans-up if recents doesn't restore WindowContainerTransaction commitWCT = new WindowContainerTransaction(); mStageCoordinator.onRecentsInSplitAnimationFinish(commitWCT, - mock(SurfaceControl.Transaction.class), mock(TransitionInfo.class)); + mock(SurfaceControl.Transaction.class)); assertFalse(mStageCoordinator.isSplitScreenVisible()); } @@ -322,7 +322,7 @@ public class SplitTransitionTests extends ShellTestCase { mMainStage.onTaskAppeared(mMainChild, mock(SurfaceControl.class)); mSideStage.onTaskAppeared(mSideChild, mock(SurfaceControl.class)); mStageCoordinator.onRecentsInSplitAnimationFinish(restoreWCT, - mock(SurfaceControl.Transaction.class), mock(TransitionInfo.class)); + mock(SurfaceControl.Transaction.class)); assertTrue(mStageCoordinator.isSplitScreenVisible()); } diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index ca1bb3e97815..da2e56f5b6fa 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -768,6 +768,7 @@ static void ImageReader_unlockGraphicBuffer(JNIEnv* env, jobject /*thiz*/, android_graphics_GraphicBuffer_getNativeGraphicsBuffer(env, buffer); if (graphicBuffer.get() == NULL) { jniThrowRuntimeException(env, "Invalid graphic buffer!"); + return; } status_t res = graphicBuffer->unlock(); diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt index 2b38b4cefe3e..8e0cf894bb28 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt @@ -34,11 +34,11 @@ import kotlinx.coroutines.runBlocking /** * The repository to load the App List data. */ -internal interface AppListRepository { +interface AppListRepository { /** Loads the list of [ApplicationInfo]. */ suspend fun loadApps( userId: Int, - showInstantApps: Boolean = false, + loadInstantApps: Boolean = false, matchAnyUserForAdmin: Boolean = false, ): List<ApplicationInfo> @@ -50,6 +50,9 @@ internal interface AppListRepository { /** Gets the system app package names. */ fun getSystemPackageNamesBlocking(userId: Int): Set<String> + + /** Loads the list of [ApplicationInfo], and filter base on `isSystemApp`. */ + suspend fun loadAndFilterApps(userId: Int, isSystemApp: Boolean): List<ApplicationInfo> } /** @@ -62,13 +65,13 @@ object AppListRepositoryUtil { AppListRepositoryImpl(context).getSystemPackageNamesBlocking(userId) } -internal class AppListRepositoryImpl(private val context: Context) : AppListRepository { +class AppListRepositoryImpl(private val context: Context) : AppListRepository { private val packageManager = context.packageManager private val userManager = context.userManager override suspend fun loadApps( userId: Int, - showInstantApps: Boolean, + loadInstantApps: Boolean, matchAnyUserForAdmin: Boolean, ): List<ApplicationInfo> = coroutineScope { val hiddenSystemModulesDeferred = async { @@ -86,7 +89,7 @@ internal class AppListRepositoryImpl(private val context: Context) : AppListRepo val hiddenSystemModules = hiddenSystemModulesDeferred.await() val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await() installedApplicationsAsUser.filter { app -> - app.isInAppList(showInstantApps, hiddenSystemModules, hideWhenDisabledPackages) + app.isInAppList(loadInstantApps, hiddenSystemModules, hideWhenDisabledPackages) } } @@ -136,17 +139,17 @@ internal class AppListRepositoryImpl(private val context: Context) : AppListRepo ): Flow<(app: ApplicationInfo) -> Boolean> = userIdFlow.combine(showSystemFlow, ::showSystemPredicate) - override fun getSystemPackageNamesBlocking(userId: Int) = - runBlocking { getSystemPackageNames(userId) } + override fun getSystemPackageNamesBlocking(userId: Int) = runBlocking { + loadAndFilterApps(userId = userId, isSystemApp = true).map { it.packageName }.toSet() + } - private suspend fun getSystemPackageNames(userId: Int): Set<String> = - coroutineScope { - val loadAppsDeferred = async { loadApps(userId) } - val homeOrLauncherPackages = loadHomeOrLauncherPackages(userId) - val showSystemPredicate = - { app: ApplicationInfo -> isSystemApp(app, homeOrLauncherPackages) } - loadAppsDeferred.await().filter(showSystemPredicate).map { it.packageName }.toSet() + override suspend fun loadAndFilterApps(userId: Int, isSystemApp: Boolean) = coroutineScope { + val loadAppsDeferred = async { loadApps(userId) } + val homeOrLauncherPackages = loadHomeOrLauncherPackages(userId) + loadAppsDeferred.await().filter { app -> + isSystemApp(app, homeOrLauncherPackages) == isSystemApp } + } private suspend fun showSystemPredicate( userId: Int, diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt index e3ea2e78756f..a0ff216875a2 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt @@ -76,7 +76,7 @@ class AppInfoProvider(private val packageInfo: PackageInfo) { private fun AppVersion() { if (packageInfo.versionName == null) return Spacer(modifier = Modifier.height(4.dp)) - SettingsBody(packageInfo.versionName) + SettingsBody(packageInfo.versionNameBidiWrapped) } @Composable @@ -84,10 +84,15 @@ class AppInfoProvider(private val packageInfo: PackageInfo) { if (packageInfo.versionName == null) return Divider() Box(modifier = Modifier.padding(SettingsDimension.itemPadding)) { - val versionName = BidiFormatter.getInstance().unicodeWrap(packageInfo.versionName) - SettingsBody(stringResource(R.string.version_text, versionName)) + SettingsBody(stringResource(R.string.version_text, packageInfo.versionNameBidiWrapped)) } } + + private companion object { + /** Wrapped the version name, so its directionality still keep same when RTL. */ + val PackageInfo.versionNameBidiWrapped: String + get() = BidiFormatter.getInstance().unicodeWrap(versionName) + } } @Composable diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt index 302f78081626..375ed60e17cf 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt @@ -108,7 +108,7 @@ class AppListRepositoryTest { val appList = repository.loadApps( userId = ADMIN_USER_ID, - showInstantApps = false, + loadInstantApps = false, ) assertThat(appList).containsExactly(NORMAL_APP) @@ -120,7 +120,7 @@ class AppListRepositoryTest { val appList = repository.loadApps( userId = ADMIN_USER_ID, - showInstantApps = true, + loadInstantApps = true, ) assertThat(appList).containsExactly(NORMAL_APP, INSTANT_APP) @@ -325,6 +325,21 @@ class AppListRepositoryTest { assertThat(systemPackageNames).containsExactly(SYSTEM_APP.packageName) } + @Test + fun loadAndFilterApps_loadNonSystemApp_returnExpectedValues() = runTest { + mockInstalledApplications( + apps = listOf( + NORMAL_APP, INSTANT_APP, SYSTEM_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUNCHER_APP + ), + userId = ADMIN_USER_ID, + ) + + val appList = repository.loadAndFilterApps(userId = ADMIN_USER_ID, isSystemApp = false) + + assertThat(appList) + .containsExactly(NORMAL_APP, UPDATED_SYSTEM_APP, HOME_APP, IN_LAUNCHER_APP) + } + private suspend fun getShowSystemPredicate(showSystem: Boolean) = repository.showSystemPredicate( userIdFlow = flowOf(ADMIN_USER_ID), diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt index 6889e5d21ac0..9b224976e080 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt @@ -87,7 +87,7 @@ class AppListViewModelTest { private object FakeAppListRepository : AppListRepository { override suspend fun loadApps( userId: Int, - showInstantApps: Boolean, + loadInstantApps: Boolean, matchAnyUserForAdmin: Boolean, ) = listOf(APP) @@ -97,6 +97,9 @@ class AppListViewModelTest { ): Flow<(app: ApplicationInfo) -> Boolean> = flowOf { true } override fun getSystemPackageNamesBlocking(userId: Int): Set<String> = emptySet() + + override suspend fun loadAndFilterApps(userId: Int, isSystemApp: Boolean) = + emptyList<ApplicationInfo>() } private object FakeAppRepository : AppRepository { diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml index 0d86e0a40b6d..ab522a388735 100644 --- a/packages/SystemUI/res/layout/screen_share_dialog.xml +++ b/packages/SystemUI/res/layout/screen_share_dialog.xml @@ -36,7 +36,7 @@ android:layout_width="@dimen/screenrecord_logo_size" android:layout_height="@dimen/screenrecord_logo_size" android:src="@drawable/ic_media_projection_permission" - android:tint="?androidprv:attr/colorAccentPrimary" + android:tint="?androidprv:attr/colorAccentPrimaryVariant" android:importantForAccessibility="no"/> <TextView android:id="@+id/screen_share_dialog_title" diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index afc25909ca91..99b5d52f8322 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -158,15 +158,18 @@ public class KeyguardPatternView extends KeyguardInputView public void startAppearAnimation() { enableClipping(false); - setAlpha(1f); + setAlpha(0f); setTranslationY(mAppearAnimationUtils.getStartTranslation()); AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */, 0, mAppearAnimationUtils.getInterpolator(), getAnimationListener(InteractionJankMonitor.CUJ_LOCKSCREEN_PATTERN_APPEAR)); - mAppearAnimationUtils.startAnimation2d( - mLockPatternView.getCellStates(), - () -> enableClipping(true), - this); + mLockPatternView.post(() -> { + setAlpha(1f); + mAppearAnimationUtils.startAnimation2d( + mLockPatternView.getCellStates(), + () -> enableClipping(true), + KeyguardPatternView.this); + }); if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) { mAppearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0, AppearAnimationUtils.DEFAULT_APPEAR_DURATION, diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 0f0ebed01e82..894158c1b092 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -246,6 +246,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private static final int MSG_TIME_FORMAT_UPDATE = 344; private static final int MSG_REQUIRE_NFC_UNLOCK = 345; private static final int MSG_KEYGUARD_DISMISS_ANIMATION_FINISHED = 346; + private static final int MSG_SERVICE_PROVIDERS_UPDATED = 347; /** Biometric authentication state: Not listening. */ private static final int BIOMETRIC_STATE_STOPPED = 0; @@ -1818,6 +1819,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) { String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE); mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state)); + } else if (TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED.equals(action)) { + mHandler.obtainMessage(MSG_SERVICE_PROVIDERS_UPDATED, intent).sendToTarget(); } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED); } else if (Intent.ACTION_SERVICE_STATE.equals(action)) { @@ -2387,6 +2390,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab case MSG_SERVICE_STATE_CHANGE: handleServiceStateChange(msg.arg1, (ServiceState) msg.obj); break; + case MSG_SERVICE_PROVIDERS_UPDATED: + handleServiceProvidersUpdated((Intent) msg.obj); + break; case MSG_SCREEN_TURNED_OFF: Trace.beginSection("KeyguardUpdateMonitor#handler MSG_SCREEN_TURNED_OFF"); handleScreenTurnedOff(); @@ -2457,6 +2463,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab filter.addAction(Intent.ACTION_SERVICE_STATE); filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); + filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED); filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); filter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED); mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter, mHandler); @@ -3712,6 +3719,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } /** + * Handle {@link #MSG_SERVICE_PROVIDERS_UPDATED} + */ + private void handleServiceProvidersUpdated(Intent intent) { + mLogger.logServiceProvidersUpdated(intent); + callbacksRefreshCarrierInfo(); + } + + /** * Whether the keyguard is showing and not occluded. */ public boolean isKeyguardVisible() { diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index 17cc23632d94..4923ab0fab18 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -16,11 +16,15 @@ package com.android.keyguard.logging +import android.content.Intent import android.hardware.biometrics.BiometricConstants.LockoutMode import android.os.PowerManager import android.os.PowerManager.WakeReason import android.telephony.ServiceState import android.telephony.SubscriptionInfo +import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX +import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID +import android.telephony.TelephonyManager import com.android.keyguard.ActiveUnlockConfig import com.android.keyguard.FaceAuthUiEvent import com.android.keyguard.KeyguardListenModel @@ -363,6 +367,21 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { ) } + fun logServiceProvidersUpdated(intent: Intent) { + logBuffer.log( + TAG, + VERBOSE, + { + int1 = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID) + str1 = intent.getStringExtra(TelephonyManager.EXTRA_SPN) + str2 = intent.getStringExtra(TelephonyManager.EXTRA_PLMN) + }, + { + "action SERVICE_PROVIDERS_UPDATED subId=$int1 spn=$str1 plmn=$str2" + } + ) + } + fun logSimState(subId: Int, slotId: Int, state: Int) { logBuffer.log( TAG, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java index 757afb616fd1..67c85bd94bd7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardLifecyclesDispatcher.java @@ -16,11 +16,19 @@ package com.android.systemui.keyguard; +import android.annotation.IntDef; import android.os.Handler; +import android.os.Looper; import android.os.Message; -import android.os.Trace; +import android.os.TraceNameSupplier; + +import androidx.annotation.NonNull; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Main; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import javax.inject.Inject; @@ -29,7 +37,6 @@ import javax.inject.Inject; */ @SysUISingleton public class KeyguardLifecyclesDispatcher { - static final int SCREEN_TURNING_ON = 0; static final int SCREEN_TURNED_ON = 1; static final int SCREEN_TURNING_OFF = 2; @@ -39,19 +46,46 @@ public class KeyguardLifecyclesDispatcher { static final int FINISHED_WAKING_UP = 5; static final int STARTED_GOING_TO_SLEEP = 6; static final int FINISHED_GOING_TO_SLEEP = 7; - private static final String TAG = "KeyguardLifecyclesDispatcher"; - private final ScreenLifecycle mScreenLifecycle; - private final WakefulnessLifecycle mWakefulnessLifecycle; + @IntDef({ + SCREEN_TURNING_ON, + SCREEN_TURNED_ON, + SCREEN_TURNING_OFF, + SCREEN_TURNED_OFF, + STARTED_WAKING_UP, + FINISHED_WAKING_UP, + STARTED_GOING_TO_SLEEP, + FINISHED_GOING_TO_SLEEP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface KeyguardLifecycleMessageType { + } + + private static String getNameOfMessage(@KeyguardLifecycleMessageType int what) { + return switch (what) { + case SCREEN_TURNING_ON -> "SCREEN_TURNING_ON"; + case SCREEN_TURNED_ON -> "SCREEN_TURNED_ON"; + case SCREEN_TURNING_OFF -> "SCREEN_TURNING_OFF"; + case SCREEN_TURNED_OFF -> "SCREEN_TURNED_OFF"; + case STARTED_WAKING_UP -> "STARTED_WAKING_UP"; + case FINISHED_WAKING_UP -> "FINISHED_WAKING_UP"; + case STARTED_GOING_TO_SLEEP -> "STARTED_GOING_TO_SLEEP"; + case FINISHED_GOING_TO_SLEEP -> "FINISHED_GOING_TO_SLEEP"; + default -> "UNKNOWN"; + }; + } + + private final Handler mHandler; @Inject - public KeyguardLifecyclesDispatcher(ScreenLifecycle screenLifecycle, + public KeyguardLifecyclesDispatcher( + @Main Looper mainLooper, + ScreenLifecycle screenLifecycle, WakefulnessLifecycle wakefulnessLifecycle) { - mScreenLifecycle = screenLifecycle; - mWakefulnessLifecycle = wakefulnessLifecycle; + mHandler = new KeyguardLifecycleHandler(mainLooper, screenLifecycle, wakefulnessLifecycle); } - void dispatch(int what) { + void dispatch(@KeyguardLifecycleMessageType int what) { mHandler.obtainMessage(what).sendToTarget(); } @@ -60,7 +94,7 @@ public class KeyguardLifecyclesDispatcher { * @param pmReason Reason this message was triggered - this should be a value from either * {@link PowerManager.WakeReason} or {@link PowerManager.GoToSleepReason}. */ - void dispatch(int what, int pmReason) { + void dispatch(@KeyguardLifecycleMessageType int what, int pmReason) { final Message message = mHandler.obtainMessage(what); message.arg1 = pmReason; message.sendToTarget(); @@ -70,44 +104,48 @@ public class KeyguardLifecyclesDispatcher { * @param what Message to send. * @param object Object to send with the message */ - void dispatch(int what, Object object) { + void dispatch(@KeyguardLifecycleMessageType int what, Object object) { mHandler.obtainMessage(what, object).sendToTarget(); } - private Handler mHandler = new Handler() { + private static class KeyguardLifecycleHandler extends Handler { + private static final String TAG = "KeyguardLifecycleHandler"; + private final ScreenLifecycle mScreenLifecycle; + private final WakefulnessLifecycle mWakefulnessLifecycle; + + public KeyguardLifecycleHandler(Looper looper, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle) { + super(looper); + mScreenLifecycle = screenLifecycle; + mWakefulnessLifecycle = wakefulnessLifecycle; + } + + @NonNull @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case SCREEN_TURNING_ON: - Trace.beginSection("KeyguardLifecyclesDispatcher#SCREEN_TURNING_ON"); - mScreenLifecycle.dispatchScreenTurningOn(); - Trace.endSection(); - break; - case SCREEN_TURNED_ON: - mScreenLifecycle.dispatchScreenTurnedOn(); - break; - case SCREEN_TURNING_OFF: - mScreenLifecycle.dispatchScreenTurningOff(); - break; - case SCREEN_TURNED_OFF: - mScreenLifecycle.dispatchScreenTurnedOff(); - break; - case STARTED_WAKING_UP: - mWakefulnessLifecycle.dispatchStartedWakingUp(msg.arg1 /* pmReason */); - break; - case FINISHED_WAKING_UP: - mWakefulnessLifecycle.dispatchFinishedWakingUp(); - break; - case STARTED_GOING_TO_SLEEP: - mWakefulnessLifecycle.dispatchStartedGoingToSleep(msg.arg1 /* pmReason */); - break; - case FINISHED_GOING_TO_SLEEP: - mWakefulnessLifecycle.dispatchFinishedGoingToSleep(); - break; - default: - throw new IllegalArgumentException("Unknown message: " + msg); + public String getTraceName(@NonNull Message msg) { + if (msg.getCallback() instanceof TraceNameSupplier || msg.getCallback() != null) { + return super.getTraceName(msg); } + return TAG + "#" + getNameOfMessage(msg.what); } - }; + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case SCREEN_TURNING_ON -> mScreenLifecycle.dispatchScreenTurningOn(); + case SCREEN_TURNED_ON -> mScreenLifecycle.dispatchScreenTurnedOn(); + case SCREEN_TURNING_OFF -> mScreenLifecycle.dispatchScreenTurningOff(); + case SCREEN_TURNED_OFF -> mScreenLifecycle.dispatchScreenTurnedOff(); + case STARTED_WAKING_UP -> + mWakefulnessLifecycle.dispatchStartedWakingUp(msg.arg1 /* pmReason */); + case FINISHED_WAKING_UP -> mWakefulnessLifecycle.dispatchFinishedWakingUp(); + case STARTED_GOING_TO_SLEEP -> + mWakefulnessLifecycle.dispatchStartedGoingToSleep(msg.arg1 /* pmReason */); + case FINISHED_GOING_TO_SLEEP -> + mWakefulnessLifecycle.dispatchFinishedGoingToSleep(); + default -> throw new IllegalArgumentException("Unknown message: " + msg); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java index d2526dffcc52..a8d22c48e709 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java @@ -122,6 +122,10 @@ public class KeyguardService extends Service { } } + // Avoid wrapping non-task and non-wallpaper changes as they don't need to animate + // for keyguard unlock animation. + if (taskId < 0 && !wallpapers) continue; + final RemoteAnimationTarget target = TransitionUtil.newTarget(change, // wallpapers go into the "below" layer space info.getChanges().size() - i, @@ -303,46 +307,6 @@ public class KeyguardService extends Service { } } - final IRemoteTransition mOccludeAnimation = new IRemoteTransition.Stub() { - @Override - public void startAnimation(IBinder transition, TransitionInfo info, - SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback) - throws RemoteException { - t.apply(); - mBinder.setOccluded(true /* isOccluded */, true /* animate */); - finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */); - info.releaseAllSurfaces(); - } - - @Override - public void mergeAnimation(IBinder transition, TransitionInfo info, - SurfaceControl.Transaction t, IBinder mergeTarget, - IRemoteTransitionFinishedCallback finishCallback) { - t.close(); - info.releaseAllSurfaces(); - } - }; - - final IRemoteTransition mUnoccludeAnimation = new IRemoteTransition.Stub() { - @Override - public void startAnimation(IBinder transition, TransitionInfo info, - SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback) - throws RemoteException { - t.apply(); - mBinder.setOccluded(false /* isOccluded */, true /* animate */); - finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */); - info.releaseAllSurfaces(); - } - - @Override - public void mergeAnimation(IBinder transition, TransitionInfo info, - SurfaceControl.Transaction t, IBinder mergeTarget, - IRemoteTransitionFinishedCallback finishCallback) { - t.close(); - info.releaseAllSurfaces(); - } - }; - private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() { private static final String TRACK_NAME = "IKeyguardService"; diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt index 1a158c89dee7..29a7fe7d061a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt @@ -668,8 +668,24 @@ class KeyguardUnlockAnimationController @Inject constructor( lockscreenSmartspace?.visibility = View.INVISIBLE } - // Start an animation for the wallpaper, which will finish keyguard exit when it completes. - fadeInWallpaper() + // As soon as the shade has animated out of the way, start the canned unlock animation, + // which will finish keyguard exit when it completes. The in-window animations in the + // Launcher window will end on their own. + handler.postDelayed({ + if (keyguardViewMediator.get().isShowingAndNotOccluded && + !keyguardStateController.isKeyguardGoingAway) { + Log.e(TAG, "Finish keyguard exit animation delayed Runnable ran, but we are " + + "showing and not going away.") + return@postDelayed + } + + if (wallpaperTargets != null) { + fadeInWallpaper() + } else { + keyguardViewMediator.get().exitKeyguardAndFinishSurfaceBehindRemoteAnimation( + false /* cancelled */) + } + }, CANNED_UNLOCK_START_DELAY) } /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 45e4623c7e27..81f325f53f1b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -17,6 +17,8 @@ package com.android.systemui.keyguard; import static android.app.StatusBarManager.SESSION_KEYGUARD; +import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT; +import static android.provider.Settings.System.LOCKSCREEN_SOUNDS_ENABLED; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT; @@ -70,7 +72,6 @@ import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; @@ -93,7 +94,6 @@ import android.view.WindowManager; import android.view.WindowManagerPolicyConstants; import android.view.animation.Animation; import android.view.animation.AnimationUtils; -import android.window.IRemoteTransition; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -154,6 +154,9 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.util.settings.SecureSettings; +import com.android.systemui.util.settings.SystemSettings; +import com.android.systemui.util.time.SystemClock; import com.android.wm.shell.keyguard.KeyguardTransitions; import dagger.Lazy; @@ -161,7 +164,6 @@ import dagger.Lazy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; -import java.util.Optional; import java.util.concurrent.Executor; /** @@ -215,7 +217,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private final static String TAG = "KeyguardViewMediator"; - private static final String DELAYED_KEYGUARD_ACTION = + public static final String DELAYED_KEYGUARD_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD"; private static final String DELAYED_LOCK_PROFILE_ACTION = "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_LOCK"; @@ -250,7 +252,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, * turning on the keyguard (i.e, the user has this much time to turn * the screen back on without having to face the keyguard). */ - private static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000; + public static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000; /** * How long we'll wait for the {@link ViewMediatorCallback#keyguardDoneDrawing()} @@ -306,6 +308,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, /** UserSwitcherController for creating guest user on boot complete */ private final UserSwitcherController mUserSwitcherController; + private final SecureSettings mSecureSettings; + private final SystemSettings mSystemSettings; + private final SystemClock mSystemClock; /** * Used to keep the device awake while to ensure the keyguard finishes opening before @@ -1253,7 +1258,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy, Lazy<ActivityLaunchAnimator> activityLaunchAnimator, Lazy<ScrimController> scrimControllerLazy, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + SecureSettings secureSettings, + SystemSettings systemSettings, + SystemClock systemClock) { mContext = context; mUserTracker = userTracker; mFalsingCollector = falsingCollector; @@ -1267,6 +1275,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mPM = powerManager; mTrustManager = trustManager; mUserSwitcherController = userSwitcherController; + mSecureSettings = secureSettings; + mSystemSettings = systemSettings; + mSystemClock = systemClock; mStatusBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mKeyguardDisplayManager = keyguardDisplayManager; @@ -1316,7 +1327,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } public void userActivity() { - mPM.userActivity(SystemClock.uptimeMillis(), false); + mPM.userActivity(mSystemClock.uptimeMillis(), false); } private void setupLocked() { @@ -1502,7 +1513,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, if (cameraGestureTriggered) { // Just to make sure, make sure the device is awake. - mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(), + mContext.getSystemService(PowerManager.class).wakeUp(mSystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH, "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK"); setPendingLock(false); @@ -1599,12 +1610,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // to enable it a bit later (i.e, give the user a chance // to turn the screen back on within a certain window without // having to unlock the screen) - final ContentResolver cr = mContext.getContentResolver(); // From SecuritySettings - final long lockAfterTimeout = Settings.Secure.getInt(cr, - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, - KEYGUARD_LOCK_AFTER_DELAY_DEFAULT); + final long lockAfterTimeout = mSecureSettings.getIntForUser(LOCK_SCREEN_LOCK_AFTER_TIMEOUT, + KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, + userId); // From DevicePolicyAdmin final long policyTimeout = mLockPatternUtils.getDevicePolicyManager() @@ -1616,8 +1626,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, timeout = lockAfterTimeout; } else { // From DisplaySettings - long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT, - KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT); + long displayTimeout = mSystemSettings.getIntForUser(SCREEN_OFF_TIMEOUT, + KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT, + userId); // policy in effect. Make sure we don't go beyond policy limit. displayTimeout = Math.max(displayTimeout, 0); // ignore negative values @@ -1638,7 +1649,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private void doKeyguardLaterLocked(long timeout) { // Lock in the future - long when = SystemClock.elapsedRealtime() + timeout; + long when = mSystemClock.elapsedRealtime() + timeout; Intent intent = new Intent(DELAYED_KEYGUARD_ACTION); intent.setPackage(mContext.getPackageName()); intent.putExtra("seq", mDelayedShowingSequence); @@ -1660,7 +1671,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, if (userTimeout == 0) { doKeyguardForChildProfilesLocked(); } else { - long userWhen = SystemClock.elapsedRealtime() + userTimeout; + long userWhen = mSystemClock.elapsedRealtime() + userTimeout; Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION); lockIntent.setPackage(mContext.getPackageName()); lockIntent.putExtra("seq", mDelayedProfileShowingSequence); @@ -2468,8 +2479,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, private void playSound(int soundId) { if (soundId == 0) return; - final ContentResolver cr = mContext.getContentResolver(); - if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) { + int lockscreenSoundsEnabled = mSystemSettings.getIntForUser(LOCKSCREEN_SOUNDS_ENABLED, 1, + KeyguardUpdateMonitor.getCurrentUser()); + if (lockscreenSoundsEnabled == 1) { mLockSounds.stop(mLockSoundStreamId); // Init mAudioManager @@ -2644,7 +2656,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // It's possible that the device was unlocked (via BOUNCER) while dozing. It's time to // wake up. if (mAodShowing) { - mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, + mPM.wakeUp(mSystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:BOUNCER_DOZING"); } @@ -2659,7 +2671,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // TODO(bc-unlock): Fill parameters mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams(() -> { handleStartKeyguardExitAnimation( - SystemClock.uptimeMillis() + mHideAnimation.getStartOffset(), + mSystemClock.uptimeMillis() + mHideAnimation.getStartOffset(), mHideAnimation.getDuration(), null /* apps */, null /* wallpapers */, null /* nonApps */, null /* finishedCallback */); }); @@ -2668,7 +2680,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // It's possible that the device was unlocked (via BOUNCER or Fingerprint) while // dreaming. It's time to wake up. if (mDreamOverlayShowing) { - mPM.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, + mPM.wakeUp(mSystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:UNLOCK_DREAMING"); } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index d7c039d9b519..1c5bb5f4efaf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -64,6 +64,9 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.util.settings.SecureSettings; +import com.android.systemui.util.settings.SystemSettings; +import com.android.systemui.util.time.SystemClock; import com.android.wm.shell.keyguard.KeyguardTransitions; import dagger.Lazy; @@ -128,7 +131,10 @@ public class KeyguardModule { Lazy<NotificationShadeWindowController> notificationShadeWindowController, Lazy<ActivityLaunchAnimator> activityLaunchAnimator, Lazy<ScrimController> scrimControllerLazy, - FeatureFlags featureFlags) { + FeatureFlags featureFlags, + SecureSettings secureSettings, + SystemSettings systemSettings, + SystemClock systemClock) { return new KeyguardViewMediator( context, uiEventLogger, @@ -162,7 +168,10 @@ public class KeyguardModule { notificationShadeWindowController, activityLaunchAnimator, scrimControllerLazy, - featureFlags); + featureFlags, + secureSettings, + systemSettings, + systemClock); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt index c8d37a165a0e..a8d662c96284 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt @@ -406,19 +406,21 @@ object KeyguardBottomAreaViewBinder { view.isClickable = viewModel.isClickable if (viewModel.isClickable) { if (viewModel.useLongPress) { - view.setOnTouchListener( - KeyguardQuickAffordanceOnTouchListener( - view, - viewModel, - messageDisplayer, - vibratorHelper, - falsingManager, - ) + val onTouchListener = KeyguardQuickAffordanceOnTouchListener( + view, + viewModel, + messageDisplayer, + vibratorHelper, + falsingManager, ) + view.setOnTouchListener(onTouchListener) + view.onLongClickListener = + OnLongClickListener(falsingManager, viewModel, vibratorHelper, onTouchListener) } else { view.setOnClickListener(OnClickListener(viewModel, checkNotNull(falsingManager))) } } else { + view.onLongClickListener = null view.setOnClickListener(null) view.setOnTouchListener(null) } @@ -454,6 +456,42 @@ object KeyguardBottomAreaViewBinder { .start() } + private class OnLongClickListener( + private val falsingManager: FalsingManager?, + private val viewModel: KeyguardQuickAffordanceViewModel, + private val vibratorHelper: VibratorHelper?, + private val onTouchListener: KeyguardQuickAffordanceOnTouchListener + ) : View.OnLongClickListener { + override fun onLongClick(view: View): Boolean { + if (falsingManager?.isFalseLongTap(FalsingManager.MODERATE_PENALTY) == true) { + return true + } + + if (viewModel.configKey != null) { + viewModel.onClicked( + KeyguardQuickAffordanceViewModel.OnClickedParameters( + configKey = viewModel.configKey, + expandable = Expandable.fromView(view), + slotId = viewModel.slotId, + ) + ) + vibratorHelper?.vibrate( + if (viewModel.isActivated) { + KeyguardBottomAreaVibrations.Activated + } else { + KeyguardBottomAreaVibrations.Deactivated + } + ) + } + + onTouchListener.cancel() + return true + } + + override fun onLongClickUseDefaultHapticFeedback(view: View?) = false + + } + private class OnClickListener( private val viewModel: KeyguardQuickAffordanceViewModel, private val falsingManager: FalsingManager, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceOnTouchListener.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceOnTouchListener.kt index 5745d6ae077e..7685345805f4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceOnTouchListener.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceOnTouchListener.kt @@ -46,7 +46,7 @@ class KeyguardQuickAffordanceOnTouchListener( @SuppressLint("ClickableViewAccessibility") override fun onTouch(v: View, event: MotionEvent): Boolean { return when (event.actionMasked) { - MotionEvent.ACTION_DOWN -> + MotionEvent.ACTION_DOWN -> { if (viewModel.configKey != null) { downDisplayCoords.set(event.rawX, event.rawY) if (isUsingAccurateTool(event)) { @@ -62,21 +62,10 @@ class KeyguardQuickAffordanceOnTouchListener( .scaleX(PRESSED_SCALE) .scaleY(PRESSED_SCALE) .setDuration(longPressDurationMs) - .withEndAction { - if ( - falsingManager?.isFalseLongTap( - FalsingManager.MODERATE_PENALTY - ) == false - ) { - dispatchClick(viewModel.configKey) - } - cancel() - } } - true - } else { - false } + false + } MotionEvent.ACTION_MOVE -> { if (!isUsingAccurateTool(event)) { // Moving too far while performing a long-press gesture cancels that @@ -91,7 +80,7 @@ class KeyguardQuickAffordanceOnTouchListener( cancel() } } - true + false } MotionEvent.ACTION_UP -> { if (isUsingAccurateTool(event)) { @@ -146,7 +135,7 @@ class KeyguardQuickAffordanceOnTouchListener( } ) } - true + false } MotionEvent.ACTION_CANCEL -> { cancel() @@ -179,7 +168,7 @@ class KeyguardQuickAffordanceOnTouchListener( view.setOnClickListener(null) } - private fun cancel(onAnimationEnd: Runnable? = null) { + fun cancel(onAnimationEnd: Runnable? = null) { longPressAnimator?.cancel() longPressAnimator = null view.animate().scaleX(1f).scaleY(1f).withEndAction(onAnimationEnd) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt index bce334610f28..6b993ce9e7bf 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt @@ -53,6 +53,7 @@ import android.text.TextUtils import android.util.Log import android.util.Pair as APair import androidx.media.utils.MediaConstants +import com.android.internal.annotations.Keep import com.android.internal.logging.InstanceId import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.Dumpable @@ -219,7 +220,7 @@ class MediaDataManager( private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() // There should ONLY be at most one Smartspace media recommendation. var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA - private var smartspaceSession: SmartspaceSession? = null + @Keep private var smartspaceSession: SmartspaceSession? = null private var allowMediaRecommendations = allowMediaRecommendations(context) private val artworkWidth = @@ -381,6 +382,8 @@ class MediaDataManager( fun destroy() { smartspaceMediaDataProvider.unregisterListener(this) + smartspaceSession?.close() + smartspaceSession = null context.unregisterReceiver(appChangeReceiver) } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 2f72cb95db98..419d045885a8 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -654,6 +654,24 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void serviceProvidersUpdated_broadcastTriggersInfoRefresh() { + // The callback is invoked once on init + verify(mTestCallback, times(1)).onRefreshCarrierInfo(); + + // WHEN the SERVICE_PROVIDERS_UPDATED broadcast is sent + Intent intent = new Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED); + intent.putExtra(TelephonyManager.EXTRA_SPN, "spn"); + intent.putExtra(TelephonyManager.EXTRA_PLMN, "plmn"); + mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(), + putPhoneInfo(intent, null, true)); + mTestableLooper.processAllMessages(); + + // THEN verify keyguardUpdateMonitorCallback receives a refresh callback + // Note that we have times(2) here because it's been called once already + verify(mTestCallback, times(2)).onRefreshCarrierInfo(); + } + + @Test public void testTriesToAuthenticateFingerprint_whenKeyguard() { mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */); mTestableLooper.processAllMessages(); 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 f31ac00051f6..c4a0e7c6b7ab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -16,11 +16,16 @@ package com.android.systemui.keyguard; +import static android.os.PowerManager.WAKE_REASON_WAKE_MOTION; +import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT; import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; +import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_TIMEOUT; import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT; +import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION; +import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -35,9 +40,12 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.AlarmManager; import android.app.IActivityManager; +import android.app.PendingIntent; import android.app.admin.DevicePolicyManager; import android.app.trust.TrustManager; +import android.content.Context; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.telephony.TelephonyManager; @@ -94,9 +102,12 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.settings.SecureSettings; +import com.android.systemui.util.settings.SystemSettings; import com.android.systemui.util.time.FakeSystemClock; import com.android.wm.shell.keyguard.KeyguardTransitions; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -156,18 +167,24 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock CentralSurfaces mCentralSurfaces; private @Mock UiEventLogger mUiEventLogger; private @Mock SessionTracker mSessionTracker; + private @Mock SystemSettings mSystemSettings; + private @Mock SecureSettings mSecureSettings; + private @Mock AlarmManager mAlarmManager; + private FakeSystemClock mSystemClock; private FakeFeatureFlags mFeatureFlags; + private int mInitialUserId; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mFalsingCollector = new FalsingCollectorFake(); - + mSystemClock = new FakeSystemClock(); when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager); when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class)); when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true); when(mInteractionJankMonitor.end(anyInt())).thenReturn(true); + mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager); final ViewRootImpl testViewRoot = mock(ViewRootImpl.class); when(testViewRoot.getView()).thenReturn(mock(View.class)); when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot); @@ -183,6 +200,12 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { DejankUtils.setImmediate(true); createAndStartViewMediator(); + mInitialUserId = KeyguardUpdateMonitor.getCurrentUser(); + } + + @After + public void teardown() { + KeyguardUpdateMonitor.setCurrentUser(mInitialUserId); } @Test @@ -369,6 +392,49 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { } @Test + public void lockAfterScreenTimeoutUsesValueFromSettings() { + int currentUserId = 99; + int userSpecificTimeout = 5999; + KeyguardUpdateMonitor.setCurrentUser(currentUserId); + + when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false); + when(mDevicePolicyManager.getMaximumTimeToLock(null, currentUserId)).thenReturn(0L); + when(mSecureSettings.getIntForUser(LOCK_SCREEN_LOCK_AFTER_TIMEOUT, + KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, currentUserId)).thenReturn(userSpecificTimeout); + mSystemClock.setElapsedRealtime(0L); + ArgumentCaptor<PendingIntent> pendingIntent = ArgumentCaptor.forClass(PendingIntent.class); + + mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_TIMEOUT); + + verify(mAlarmManager).setExactAndAllowWhileIdle(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), + eq(Long.valueOf(userSpecificTimeout)), pendingIntent.capture()); + assertEquals(DELAYED_KEYGUARD_ACTION, pendingIntent.getValue().getIntent().getAction()); + } + + @Test + public void lockAfterSpecifiedAfterDreamStarted() { + int currentUserId = 99; + int userSpecificTimeout = 5999; + KeyguardUpdateMonitor.setCurrentUser(currentUserId); + + // set mDeviceInteractive to true + mViewMediator.onStartedWakingUp(WAKE_REASON_WAKE_MOTION, false); + mFeatureFlags.set(Flags.LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING, false); + when(mLockPatternUtils.isSecure(currentUserId)).thenReturn(true); + when(mDevicePolicyManager.getMaximumTimeToLock(null, currentUserId)).thenReturn(0L); + when(mSecureSettings.getIntForUser(LOCK_SCREEN_LOCK_AFTER_TIMEOUT, + KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, currentUserId)).thenReturn(userSpecificTimeout); + mSystemClock.setElapsedRealtime(0L); + ArgumentCaptor<PendingIntent> pendingIntent = ArgumentCaptor.forClass(PendingIntent.class); + + mViewMediator.onDreamingStarted(); + + verify(mAlarmManager).setExactAndAllowWhileIdle(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), + eq(Long.valueOf(userSpecificTimeout)), pendingIntent.capture()); + assertEquals(DELAYED_KEYGUARD_ACTION, pendingIntent.getValue().getIntent().getAction()); + } + + @Test public void testHideSurfaceBehindKeyguardMarksKeyguardNotGoingAway() { mViewMediator.hideSurfaceBehindKeyguard(); @@ -629,7 +695,10 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { () -> mNotificationShadeWindowController, () -> mActivityLaunchAnimator, () -> mScrimController, - mFeatureFlags); + mFeatureFlags, + mSecureSettings, + mSystemSettings, + mSystemClock); mViewMediator.start(); mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null); diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java index f31ca8178eb6..c2ebddf00fb4 100644 --- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java +++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java @@ -2057,7 +2057,11 @@ public class CameraExtensionsProxyService extends Service { mIsImageValid = false; if (mGraphicBuffer != null) { - ImageReader.unlockGraphicBuffer(mGraphicBuffer); + try { + ImageReader.unlockGraphicBuffer(mGraphicBuffer); + } catch (RuntimeException e) { + e.printStackTrace(); + } mGraphicBuffer.destroy(); mGraphicBuffer = null; } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index d2d99b1a0a5e..44c50334649f 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -225,6 +225,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private static final String EXTRA_REQUEST_ID = "android.service.autofill.extra.REQUEST_ID"; private static final String PCC_HINTS_DELIMITER = ","; + public static final String EXTRA_KEY_DETECTIONS = "detections"; final Object mLock; @@ -3653,6 +3654,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final ArrayList<FillContext> contexts = mergePreviousSessionLocked( /* forSave= */ true); + FieldClassificationResponse fieldClassificationResponse = + mClassificationState.mLastFieldClassificationResponse; + if (mService.isPccClassificationEnabled() + && fieldClassificationResponse != null + && !fieldClassificationResponse.getClassifications().isEmpty()) { + if (mClientState == null) { + mClientState = new Bundle(); + } + mClientState.putParcelableArrayList(EXTRA_KEY_DETECTIONS, new ArrayList<>( + fieldClassificationResponse.getClassifications())); + } final SaveRequest saveRequest = new SaveRequest(contexts, mClientState, mSelectedDatasetIds); mRemoteFillService.onSaveRequest(saveRequest); diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 12bb5d23e4cf..76a994ec63e9 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -151,6 +151,8 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -1707,7 +1709,8 @@ class UserController implements Handler.Callback { mInjector.getWindowManager().setSwitchingUser(true); // Only lock if the user has a secure keyguard PIN/Pattern/Pwd if (mInjector.getKeyguardManager().isDeviceSecure(userId)) { - mInjector.getWindowManager().lockNow(null); + // Make sure the device is locked before moving on with the user switch + mInjector.lockDeviceNowAndWaitForKeyguardShown(); } } @@ -3444,6 +3447,11 @@ class UserController implements Handler.Callback { WindowManagerService getWindowManager() { return mService.mWindowManager; } + + ActivityTaskManagerInternal getActivityTaskManagerInternal() { + return mService.mAtmInternal; + } + void activityManagerOnUserStopped(@UserIdInt int userId) { LocalServices.getService(ActivityTaskManagerInternal.class).onUserStopped(userId); } @@ -3667,5 +3675,43 @@ class UserController implements Handler.Callback { void onSystemUserVisibilityChanged(boolean visible) { getUserManagerInternal().onSystemUserVisibilityChanged(visible); } + + void lockDeviceNowAndWaitForKeyguardShown() { + if (getWindowManager().isKeyguardLocked()) { + return; + } + + final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); + t.traceBegin("lockDeviceNowAndWaitForKeyguardShown"); + + final CountDownLatch latch = new CountDownLatch(1); + ActivityTaskManagerInternal.ScreenObserver screenObserver = + new ActivityTaskManagerInternal.ScreenObserver() { + @Override + public void onAwakeStateChanged(boolean isAwake) { + + } + + @Override + public void onKeyguardStateChanged(boolean isShowing) { + if (isShowing) { + latch.countDown(); + } + } + }; + + getActivityTaskManagerInternal().registerScreenObserver(screenObserver); + getWindowManager().lockDeviceNow(); + try { + if (!latch.await(20, TimeUnit.SECONDS)) { + throw new RuntimeException("Keyguard is not shown in 20 seconds"); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + getActivityTaskManagerInternal().unregisterScreenObserver(screenObserver); + t.traceEnd(); + } + } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 05ca6e4554fb..6ac163121d8c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -266,8 +266,12 @@ public abstract class AuthenticationClient<T, O extends AuthenticateOptions> } } else { if (isBackgroundAuth) { - Slog.e(TAG, "cancelling due to background auth"); - cancel(); + Slog.e(TAG, "Sending cancel to client(Due to background auth)"); + if (mTaskStackListener != null) { + mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener); + } + sendCancelOnly(getListener()); + mCallback.onClientFinished(this, false); } else { // Allow system-defined limit of number of attempts before giving up if (mShouldUseLockoutTracker) { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 4208a12f91d4..d4bb445d66ac 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -3828,10 +3828,27 @@ public class Vpn { }, retryDelayMs, TimeUnit.MILLISECONDS); } + private boolean significantCapsChange(@Nullable final NetworkCapabilities left, + @Nullable final NetworkCapabilities right) { + if (left == right) return false; + return null == left + || null == right + || !Arrays.equals(left.getTransportTypes(), right.getTransportTypes()) + || !Arrays.equals(left.getCapabilities(), right.getCapabilities()) + || !Arrays.equals(left.getEnterpriseIds(), right.getEnterpriseIds()) + || !Objects.equals(left.getTransportInfo(), right.getTransportInfo()) + || !Objects.equals(left.getAllowedUids(), right.getAllowedUids()) + || !Objects.equals(left.getUnderlyingNetworks(), right.getUnderlyingNetworks()) + || !Objects.equals(left.getNetworkSpecifier(), right.getNetworkSpecifier()); + } + /** Called when the NetworkCapabilities of underlying network is changed */ public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) { - mEventChanges.log("[UnderlyingNW] Cap changed from " - + mUnderlyingNetworkCapabilities + " to " + nc); + if (significantCapsChange(mUnderlyingNetworkCapabilities, nc)) { + // TODO : make this log terser + mEventChanges.log("[UnderlyingNW] Cap changed from " + + mUnderlyingNetworkCapabilities + " to " + nc); + } final NetworkCapabilities oldNc = mUnderlyingNetworkCapabilities; mUnderlyingNetworkCapabilities = nc; if (oldNc == null || !nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds())) { diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index be9df4aecf43..2c54e1cea3fa 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -4725,13 +4725,11 @@ public class HdmiControlService extends SystemService { Slog.w(TAG, "Tried to update eARC status on a port that doesn't support eARC."); return; } - // If eARC is disabled, the local device is null. In this case, the HAL shouldn't have - // reported connection state changes, but even if it did, it won't take effect. if (mEarcLocalDevice != null) { mEarcLocalDevice.handleEarcStateChange(status); } else if (status == HDMI_EARC_STATUS_ARC_PENDING) { - // If the local device is null we notify the Audio Service that eARC connection - // is disabled. + // If eARC is disabled, the local device is null. This is why we notify + // AudioService here that the eARC connection is terminated. notifyEarcStatusToAudioService(false, new ArrayList<>()); startArcAction(true, null); } diff --git a/services/core/java/com/android/server/input/InputFeatureFlagProvider.java b/services/core/java/com/android/server/input/InputFeatureFlagProvider.java index 3854adad9cd8..7c7f1513bd96 100644 --- a/services/core/java/com/android/server/input/InputFeatureFlagProvider.java +++ b/services/core/java/com/android/server/input/InputFeatureFlagProvider.java @@ -38,8 +38,15 @@ public final class InputFeatureFlagProvider { private static final boolean KEYBOARD_BACKLIGHT_ANIMATION_ENABLED = InputProperties.enable_keyboard_backlight_animation().orElse(false); + // To disable Custom keyboard backlight levels support via IDC files run: + // adb shell setprop persist.input.keyboard_backlight_custom_levels.enabled false (requires + // restart) + private static final boolean KEYBOARD_BACKLIGHT_CUSTOM_LEVELS_ENABLED = + InputProperties.enable_keyboard_backlight_custom_levels().orElse(true); + private static Optional<Boolean> sKeyboardBacklightControlOverride = Optional.empty(); private static Optional<Boolean> sKeyboardBacklightAnimationOverride = Optional.empty(); + private static Optional<Boolean> sKeyboardBacklightCustomLevelsOverride = Optional.empty(); public static boolean isKeyboardBacklightControlEnabled() { return sKeyboardBacklightControlOverride.orElse(KEYBOARD_BACKLIGHT_CONTROL_ENABLED); @@ -49,6 +56,11 @@ public final class InputFeatureFlagProvider { return sKeyboardBacklightAnimationOverride.orElse(KEYBOARD_BACKLIGHT_ANIMATION_ENABLED); } + public static boolean isKeyboardBacklightCustomLevelsEnabled() { + return sKeyboardBacklightCustomLevelsOverride.orElse( + KEYBOARD_BACKLIGHT_CUSTOM_LEVELS_ENABLED); + } + public static void setKeyboardBacklightControlEnabled(boolean enabled) { sKeyboardBacklightControlOverride = Optional.of(enabled); } @@ -57,11 +69,16 @@ public final class InputFeatureFlagProvider { sKeyboardBacklightAnimationOverride = Optional.of(enabled); } + public static void setKeyboardBacklightCustomLevelsEnabled(boolean enabled) { + sKeyboardBacklightCustomLevelsOverride = Optional.of(enabled); + } + /** * Clears all input feature flag overrides. */ public static void clearOverrides() { sKeyboardBacklightControlOverride = Optional.empty(); sKeyboardBacklightAnimationOverride = Optional.empty(); + sKeyboardBacklightCustomLevelsOverride = Optional.empty(); } } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 9f3ab885bf16..c7b80af27d79 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -493,8 +493,6 @@ public class InputManagerService extends IInputManager.Stub // Add ourselves to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); - - mSettingsObserver.registerAndUpdate(); } // TODO(BT) Pass in parameter for bluetooth system @@ -505,6 +503,8 @@ public class InputManagerService extends IInputManager.Stub mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); + mSettingsObserver.registerAndUpdate(); + synchronized (mLidSwitchLock) { mSystemReady = true; diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java index 61ca0cbff7bf..36238a8cfd23 100644 --- a/services/core/java/com/android/server/input/KeyboardBacklightController.java +++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java @@ -46,6 +46,7 @@ import java.time.Duration; import java.util.Arrays; import java.util.Objects; import java.util.OptionalInt; +import java.util.TreeSet; /** * A thread-safe component of {@link InputManagerService} responsible for managing the keyboard @@ -70,7 +71,9 @@ final class KeyboardBacklightController implements private static final int MSG_NOTIFY_USER_INACTIVITY = 5; private static final int MSG_INTERACTIVE_STATE_CHANGED = 6; private static final int MAX_BRIGHTNESS = 255; - private static final int NUM_BRIGHTNESS_CHANGE_STEPS = 10; + private static final int DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS = 10; + @VisibleForTesting + static final int MAX_BRIGHTNESS_CHANGE_STEPS = 10; private static final long TRANSITION_ANIMATION_DURATION_MILLIS = Duration.ofSeconds(1).toMillis(); @@ -80,7 +83,8 @@ final class KeyboardBacklightController implements static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis(); @VisibleForTesting - static final int[] BRIGHTNESS_VALUE_FOR_LEVEL = new int[NUM_BRIGHTNESS_CHANGE_STEPS + 1]; + static final int[] DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL = + new int[DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS + 1]; private final Context mContext; private final NativeInputManagerService mNative; @@ -104,10 +108,10 @@ final class KeyboardBacklightController implements static { // Fixed brightness levels to avoid issues when converting back and forth from the // device brightness range to [0-255] - // Levels are: 0, 25, 51, ..., 255 - for (int i = 0; i <= NUM_BRIGHTNESS_CHANGE_STEPS; i++) { - BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor( - ((float) i * MAX_BRIGHTNESS) / NUM_BRIGHTNESS_CHANGE_STEPS); + // Levels are: 0, 51, ..., 255 + for (int i = 0; i <= DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS; i++) { + DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor( + ((float) i * MAX_BRIGHTNESS) / DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS); } } @@ -184,7 +188,8 @@ final class KeyboardBacklightController implements final int currBrightnessLevel = state.mBrightnessLevel; final int newBrightnessLevel; if (direction == Direction.DIRECTION_UP) { - newBrightnessLevel = Math.min(currBrightnessLevel + 1, NUM_BRIGHTNESS_CHANGE_STEPS); + newBrightnessLevel = Math.min(currBrightnessLevel + 1, + state.getNumBrightnessChangeSteps()); } else { newBrightnessLevel = Math.max(currBrightnessLevel - 1, 0); } @@ -194,7 +199,7 @@ final class KeyboardBacklightController implements try { mDataStore.setKeyboardBacklightBrightness(inputDevice.getDescriptor(), keyboardBacklight.getId(), - BRIGHTNESS_VALUE_FOR_LEVEL[newBrightnessLevel]); + state.mBrightnessValueForLevel[newBrightnessLevel]); } finally { mDataStore.saveIfNeeded(); } @@ -202,6 +207,7 @@ final class KeyboardBacklightController implements } private void restoreBacklightBrightness(InputDevice inputDevice, Light keyboardBacklight) { + KeyboardBacklightState state = mKeyboardBacklights.get(inputDevice.getId()); OptionalInt brightness; synchronized (mDataStore) { brightness = mDataStore.getKeyboardBacklightBrightness( @@ -209,9 +215,9 @@ final class KeyboardBacklightController implements } if (brightness.isPresent()) { int brightnessValue = Math.max(0, Math.min(MAX_BRIGHTNESS, brightness.getAsInt())); - int index = Arrays.binarySearch(BRIGHTNESS_VALUE_FOR_LEVEL, brightnessValue); + int index = Arrays.binarySearch(state.mBrightnessValueForLevel, brightnessValue); if (index < 0) { - index = Math.min(NUM_BRIGHTNESS_CHANGE_STEPS, -(index + 1)); + index = Math.min(state.getNumBrightnessChangeSteps(), -(index + 1)); } updateBacklightState(inputDevice.getId(), index, false /* isTriggeredByKeyPress */); if (DEBUG) { @@ -386,7 +392,7 @@ final class KeyboardBacklightController implements for (int i = 0; i < mKeyboardBacklightListenerRecords.size(); i++) { IKeyboardBacklightState callbackState = new IKeyboardBacklightState(); callbackState.brightnessLevel = brightnessLevel; - callbackState.maxBrightnessLevel = NUM_BRIGHTNESS_CHANGE_STEPS; + callbackState.maxBrightnessLevel = state.getNumBrightnessChangeSteps(); mKeyboardBacklightListenerRecords.valueAt(i).notifyKeyboardBacklightChanged( deviceId, callbackState, isTriggeredByKeyPress); } @@ -443,10 +449,6 @@ final class KeyboardBacklightController implements ipw.decreaseIndent(); } - private static boolean isAnimationEnabled() { - return InputFeatureFlagProvider.isKeyboardBacklightAnimationEnabled(); - } - // A record of a registered Keyboard backlight listener from one process. private class KeyboardBacklightListenerRecord implements IBinder.DeathRecipient { public final int mPid; @@ -482,18 +484,52 @@ final class KeyboardBacklightController implements private final Light mLight; private int mBrightnessLevel; private ValueAnimator mAnimator; + private final int[] mBrightnessValueForLevel; KeyboardBacklightState(int deviceId, Light light) { mDeviceId = deviceId; mLight = light; + mBrightnessValueForLevel = setupBrightnessLevels(); + } + + private int[] setupBrightnessLevels() { + if (!InputFeatureFlagProvider.isKeyboardBacklightCustomLevelsEnabled()) { + return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL; + } + int[] customLevels = mLight.getPreferredBrightnessLevels(); + if (customLevels == null || customLevels.length == 0) { + return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL; + } + TreeSet<Integer> brightnessLevels = new TreeSet<>(); + brightnessLevels.add(0); + for (int level : customLevels) { + if (level > 0 && level < MAX_BRIGHTNESS) { + brightnessLevels.add(level); + } + } + brightnessLevels.add(MAX_BRIGHTNESS); + int brightnessChangeSteps = brightnessLevels.size() - 1; + if (brightnessChangeSteps > MAX_BRIGHTNESS_CHANGE_STEPS) { + return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL; + } + int[] result = new int[brightnessLevels.size()]; + int index = 0; + for (int val : brightnessLevels) { + result[index++] = val; + } + return result; + } + + private int getNumBrightnessChangeSteps() { + return mBrightnessValueForLevel.length - 1; } private void onBacklightStateChanged() { - setBacklightValue(mIsBacklightOn ? BRIGHTNESS_VALUE_FOR_LEVEL[mBrightnessLevel] : 0); + setBacklightValue(mIsBacklightOn ? mBrightnessValueForLevel[mBrightnessLevel] : 0); } private void setBrightnessLevel(int brightnessLevel) { if (mIsBacklightOn) { - setBacklightValue(BRIGHTNESS_VALUE_FOR_LEVEL[brightnessLevel]); + setBacklightValue(mBrightnessValueForLevel[brightnessLevel]); } mBrightnessLevel = brightnessLevel; } @@ -509,7 +545,7 @@ final class KeyboardBacklightController implements if (fromValue == toValue) { return; } - if (isAnimationEnabled()) { + if (InputFeatureFlagProvider.isKeyboardBacklightAnimationEnabled()) { startAnimation(fromValue, toValue); } else { mNative.setLightColor(mDeviceId, mLight.getId(), Color.argb(toValue, 0, 0, 0)); diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java index 6ec4022fe15a..611a61a2e272 100644 --- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java +++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java @@ -252,6 +252,8 @@ final class KeyboardLayoutManager implements InputManager.InputDeviceListener { if (needToShowNotification) { maybeUpdateNotification(); } + // TODO (b/280421650): Implement logging statements using KeyboardMetricsCollector + // for KeyboardConfigured atom } private String getDefaultKeyboardLayout(final InputDevice inputDevice) { diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java index a9ae3121ce9f..b8f57f555c0e 100644 --- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java +++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java @@ -16,10 +16,20 @@ package com.android.server.input; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.hardware.input.KeyboardLayout; +import android.util.proto.ProtoOutputStream; import android.view.InputDevice; +import com.android.internal.os.KeyboardConfiguredProto.KeyboardLayoutConfig; +import com.android.internal.os.KeyboardConfiguredProto.RepeatedKeyboardLayoutConfig; import com.android.internal.util.FrameworkStatsLog; +import java.lang.annotation.Retention; +import java.util.List; + /** * Collect Keyboard metrics */ @@ -38,4 +48,115 @@ public final class KeyboardMetricsCollector { FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED, vendor_id, product_id, keyboardSystemEvent, keyCode, modifierState); } + + /** + * Function to log the KeyboardConfigured + * {@link com.android.os.input.KeyboardConfigured} atom + * + * @param inputDevice Input device + * @param keyboardLayoutConfigurations List of keyboard configurations + * @param isFirstTimeConfiguration Whether keyboard is configured for the first time + */ + public static void logKeyboardConfiguredAtom(InputDevice inputDevice, + List<KeyboardLayoutConfiguration> keyboardLayoutConfigurations, + boolean isFirstTimeConfiguration) { + int vendor_id = inputDevice.getVendorId(); + int product_id = inputDevice.getProductId(); + + // Creating proto to log nested field KeyboardLayoutConfig in atom + ProtoOutputStream proto = new ProtoOutputStream(); + + for (KeyboardLayoutConfiguration keyboardLayoutConfiguration : + keyboardLayoutConfigurations) { + addKeyboardLayoutConfigurationToProto(proto, keyboardLayoutConfiguration); + } + // Push the atom to Statsd + FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_CONFIGURED, + isFirstTimeConfiguration, vendor_id, product_id, proto.getBytes()); + } + + /** + * Populate the KeyboardLayoutConfig proto which is a repeated proto + * in the RepeatedKeyboardLayoutConfig proto with values from the + * {@link KeyboardLayoutConfiguration} class + * The proto definitions can be found at: + * "frameworks/proto_logging/stats/atoms/input/input_extension_atoms.proto" + * + * @param proto Representing the nested proto RepeatedKeyboardLayoutConfig + * @param keyboardLayoutConfiguration Class containing the fields for populating the + * KeyboardLayoutConfig proto + */ + private static void addKeyboardLayoutConfigurationToProto(ProtoOutputStream proto, + KeyboardLayoutConfiguration keyboardLayoutConfiguration) { + // Start a new KeyboardLayoutConfig proto. + long keyboardLayoutConfigToken = proto.start( + RepeatedKeyboardLayoutConfig.KEYBOARD_LAYOUT_CONFIG); + proto.write(KeyboardLayoutConfig.KEYBOARD_LANGUAGE_TAG, + keyboardLayoutConfiguration.getKeyboardLanguageTag()); + proto.write(KeyboardLayoutConfig.KEYBOARD_LAYOUT_TYPE, + keyboardLayoutConfiguration.getKeyboardLayoutType()); + proto.write(KeyboardLayoutConfig.KEYBOARD_LAYOUT_NAME, + keyboardLayoutConfiguration.getKeyboardLayoutName()); + proto.write(KeyboardLayoutConfig.LAYOUT_SELECTION_CRITERIA, + keyboardLayoutConfiguration.getLayoutSelectionCriteria()); + proto.end(keyboardLayoutConfigToken); + } + + /** + * Java class representing the proto KeyboardLayoutConfig defined in + * "frameworks/proto_logging/stats/atoms/input/input_extension_atoms.proto" + * + * @see com.android.os.input.KeyboardConfigured + */ + public static class KeyboardLayoutConfiguration { + // KeyboardLayoutType in "frameworks/base/core/res/res/values/attrs.xml" + // contains mapping for enums to int + int mKeyboardLayoutType; + String mKeyboardLanguageTag; + KeyboardLayout mKeyboardLayout; + @LayoutSelectionCriteria int mLayoutSelectionCriteria; + + @Retention(SOURCE) + @IntDef(prefix = { "LAYOUT_SELECTION_CRITERIA_" }, value = { + LAYOUT_SELECTION_CRITERIA_USER, + LAYOUT_SELECTION_CRITERIA_DEVICE, + LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD + }) + public @interface LayoutSelectionCriteria {} + + /** Manual selection by user */ + public static final int LAYOUT_SELECTION_CRITERIA_USER = 0; + + /** Auto-detection based on device provided language tag and layout type */ + public static final int LAYOUT_SELECTION_CRITERIA_DEVICE = 1; + + /** Auto-detection based on IME provided language tag and layout type */ + public static final int LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD = 2; + + KeyboardLayoutConfiguration(int keyboardLayoutType, + String keyboardLanguageTag, + KeyboardLayout keyboardLayout, + @LayoutSelectionCriteria int layoutSelectionCriteria) { + mKeyboardLayoutType = keyboardLayoutType; + mKeyboardLanguageTag = keyboardLanguageTag; + mKeyboardLayout = keyboardLayout; + mLayoutSelectionCriteria = layoutSelectionCriteria; + } + int getKeyboardLayoutType() { + return mKeyboardLayoutType; + } + + String getKeyboardLanguageTag() { + return mKeyboardLanguageTag; + } + + String getKeyboardLayoutName() { + return mKeyboardLayout.getLabel(); + } + + @LayoutSelectionCriteria int getLayoutSelectionCriteria() { + return mLayoutSelectionCriteria; + } + } } + diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 952678408343..b1a289f046bd 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1095,6 +1095,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal(); if (dreamManagerInternal == null || !dreamManagerInternal.canStartDreaming(isScreenOn)) { + Slog.d(TAG, "Can't start dreaming when attempting to dream from short power" + + " press (isScreenOn=" + isScreenOn + ")"); noDreamAction.run(); return; } @@ -6051,6 +6053,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override + @WindowManagerFuncs.LidState + public int getLidState() { + return mDefaultDisplayPolicy.getLidState(); + } + + @Override public void dumpDebug(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(ROTATION_MODE, mDefaultDisplayRotation.getUserRotationMode()); diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 887f9461bdce..3da78123016b 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -218,6 +218,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * between it and the policy. */ public interface WindowManagerFuncs { + @IntDef(prefix = { "LID_" }, value = { + LID_ABSENT, + LID_CLOSED, + LID_OPEN, + }) + @Retention(RetentionPolicy.SOURCE) + @interface LidState{} + public static final int LID_ABSENT = -1; public static final int LID_CLOSED = 0; public static final int LID_OPEN = 1; @@ -231,8 +239,9 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { public static final int CAMERA_LENS_COVERED = 1; /** - * Returns a code that describes the current state of the lid switch. + * Returns a {@link LidState} that describes the current state of the lid switch. */ + @LidState public int getLidState(); /** @@ -282,7 +291,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** * Convert the lid state to a human readable format. */ - static String lidStateToString(int lid) { + static String lidStateToString(@LidState int lid) { switch (lid) { case LID_ABSENT: return "LID_ABSENT"; @@ -1241,4 +1250,11 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @return {@code true} if the key will be handled globally. */ boolean isGlobalKey(int keyCode); + + /** + * Returns a {@link WindowManagerFuncs.LidState} that describes the current state of + * the lid switch. + */ + @WindowManagerFuncs.LidState + int getLidState(); } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index b8c5b3f5524a..712be36e51c6 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -33,6 +33,7 @@ import static android.os.PowerManagerInternal.isInteractive; import static android.os.PowerManagerInternal.wakefulnessToString; import static com.android.internal.util.LatencyTracker.ACTION_TURN_ON_SCREEN; +import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED; import android.annotation.IntDef; import android.annotation.NonNull; @@ -5733,6 +5734,11 @@ public final class PowerManagerService extends SystemService @Override // Binder call public void wakeUp(long eventTime, @WakeReason int reason, String details, String opPackageName) { + if (mPolicy.getLidState() == LID_CLOSED) { + Slog.d(TAG, "Ignoring wake up call due to the lid being closed"); + return; + } + final long now = mClock.uptimeMillis(); if (eventTime > now) { Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now); diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 3e3eb570d0e3..7f9352b32ac5 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2925,15 +2925,6 @@ class ActivityStarter { } } - // If the matching task is already in the adjacent task of the launch target. Adjust to use - // the adjacent task as its launch target. So the existing task will be launched into the - // closer one and won't be reparent redundantly. - final Task adjacentTargetTask = mTargetRootTask.getAdjacentTask(); - if (adjacentTargetTask != null && intentActivity.isDescendantOf(adjacentTargetTask) - && intentTask.isOnTop()) { - mTargetRootTask = adjacentTargetTask; - } - // If the target task is not in the front, then we need to bring it to the front... // except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have // the same behavior as if a new instance was being started, which means not bringing it diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index e07c65426278..32f1f42aacb9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -262,9 +262,17 @@ public abstract class ActivityTaskManagerInternal { */ public abstract void setVr2dDisplayId(int vr2dDisplayId); + /** + * Registers a {@link ScreenObserver}. + */ public abstract void registerScreenObserver(ScreenObserver observer); /** + * Unregisters the given {@link ScreenObserver}. + */ + public abstract void unregisterScreenObserver(ScreenObserver observer); + + /** * Returns is the caller has the same uid as the Recents component */ public abstract boolean isCallerRecents(int callingUid); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 89862918744c..4d4ffbafdcad 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -296,6 +296,7 @@ import java.text.DateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -652,7 +653,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { */ float mMinPercentageMultiWindowSupportWidth; - final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = new ArrayList<>(); + final List<ActivityTaskManagerInternal.ScreenObserver> mScreenObservers = + Collections.synchronizedList(new ArrayList<>()); // VR Vr2d Display Id. int mVr2dDisplayId = INVALID_DISPLAY; @@ -5869,6 +5871,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public void unregisterScreenObserver(ScreenObserver observer) { + mScreenObservers.remove(observer); + } + + @Override public boolean isCallerRecents(int callingUid) { return ActivityTaskManagerService.this.isCallerRecents(callingUid); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index e44d27911262..6aec96988a77 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -6511,6 +6511,22 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp .getKeyguardController().isDisplayOccluded(mDisplayId); } + /** + * @return the task that is occluding the keyguard + */ + @Nullable + Task getTaskOccludingKeyguard() { + final KeyguardController keyguardController = mRootWindowContainer.mTaskSupervisor + .getKeyguardController(); + if (keyguardController.getTopOccludingActivity(mDisplayId) != null) { + return keyguardController.getTopOccludingActivity(mDisplayId).getRootTask(); + } + if (keyguardController.getDismissKeyguardActivity(mDisplayId) != null) { + return keyguardController.getDismissKeyguardActivity(mDisplayId).getRootTask(); + } + return null; + } + @VisibleForTesting void removeAllTasks() { forAllTasks((t) -> { t.getRootTask().removeChild(t, "removeAllTasks"); }); diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 35e891ce8bbe..812d2a5d3217 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -225,6 +225,7 @@ public class DisplayPolicy { /** Currently it can only be non-null when physical display switch happens. */ private DecorInsets.Cache mCachedDecorInsets; + @WindowManagerFuncs.LidState private volatile int mLidState = LID_ABSENT; private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; private volatile boolean mHdmiPlugged; @@ -752,10 +753,11 @@ public class DisplayPolicy { return mNavigationBarCanMove; } - public void setLidState(int lidState) { + public void setLidState(@WindowManagerFuncs.LidState int lidState) { mLidState = lidState; } + @WindowManagerFuncs.LidState public int getLidState() { return mLidState; } diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 87de0f6e4aa0..bc1ddf8f66bc 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -513,6 +513,7 @@ public class DisplayRotation { } if (mDisplayContent.inTransition() + && mDisplayContent.getDisplayPolicy().isScreenOnFully() && !mDisplayContent.mTransitionController.useShellTransitionsRotation()) { // Rotation updates cannot be performed while the previous rotation change animation // is still in progress. Skip this update. We will try updating again after the diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index ff2985c98421..e8a4c1c5c3d3 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -91,6 +91,21 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { } @Override + void setClientVisible(boolean clientVisible) { + final boolean wasClientVisible = isClientVisible(); + super.setClientVisible(clientVisible); + // The layer of ImePlaceholder needs to be updated on a higher z-order for + // non-activity window (For activity window, IME is already on top of it). + if (!wasClientVisible && isClientVisible()) { + final InsetsControlTarget imeControlTarget = getControlTarget(); + if (imeControlTarget != null && imeControlTarget.getWindow() != null + && imeControlTarget.getWindow().mActivityRecord == null) { + mDisplayContent.assignWindowLayers(false /* setLayoutNeeded */); + } + } + } + + @Override void setServerVisible(boolean serverVisible) { mServerVisible = serverVisible; if (!mFrozen) { diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 5f6d66011768..99878a3d0ffe 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -17,7 +17,6 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; @@ -411,19 +410,20 @@ class KeyguardController { if (waitAppTransition) { mService.deferWindowLayout(); try { - mRootWindowContainer.getDefaultDisplay() - .requestTransitionAndLegacyPrepare( - isDisplayOccluded(DEFAULT_DISPLAY) - ? TRANSIT_KEYGUARD_OCCLUDE - : TRANSIT_KEYGUARD_UNOCCLUDE, 0 /* flags */); + if (isDisplayOccluded(DEFAULT_DISPLAY)) { + mRootWindowContainer.getDefaultDisplay().requestTransitionAndLegacyPrepare( + TRANSIT_KEYGUARD_OCCLUDE, + topActivity != null ? topActivity.getRootTask() : null); + } else { + mRootWindowContainer.getDefaultDisplay().requestTransitionAndLegacyPrepare( + TRANSIT_KEYGUARD_UNOCCLUDE, 0 /* flags */); + } updateKeyguardSleepToken(DEFAULT_DISPLAY); mWindowManager.executeAppTransition(); } finally { mService.continueWindowLayout(); } } - dismissMultiWindowModeForTaskIfNeeded(displayId, topActivity != null - ? topActivity.getRootTask() : null); } /** @@ -473,6 +473,14 @@ class KeyguardController { return getDisplayState(displayId).mOccluded; } + ActivityRecord getTopOccludingActivity(int displayId) { + return getDisplayState(displayId).mTopOccludesActivity; + } + + ActivityRecord getDismissKeyguardActivity(int displayId) { + return getDisplayState(displayId).mDismissingKeyguardActivity; + } + /** * @return true if Keyguard can be currently dismissed without entering credentials. */ @@ -488,22 +496,6 @@ class KeyguardController { return getDisplayState(DEFAULT_DISPLAY).mShowingDream; } - private void dismissMultiWindowModeForTaskIfNeeded(int displayId, - @Nullable Task currentTaskControllingOcclusion) { - // TODO(b/113840485): Handle docked stack for individual display. - if (!getDisplayState(displayId).mKeyguardShowing || !isDisplayOccluded(DEFAULT_DISPLAY)) { - return; - } - - // Dismiss freeform windowing mode - if (currentTaskControllingOcclusion == null) { - return; - } - if (currentTaskControllingOcclusion.inFreeformWindowingMode()) { - currentTaskControllingOcclusion.setWindowingMode(WINDOWING_MODE_FULLSCREEN); - } - } - private void updateKeyguardSleepToken() { for (int displayNdx = mRootWindowContainer.getChildCount() - 1; displayNdx >= 0; displayNdx--) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 536915929e88..7e839596c59b 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2376,6 +2376,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> if (!displayShouldSleep && display.mTransitionController.isShellTransitionsEnabled() && !display.mTransitionController.isCollecting()) { int transit = TRANSIT_NONE; + Task startTask = null; if (!display.getDisplayPolicy().isAwake()) { // Note that currently this only happens on default display because non-default // display is always awake. @@ -2383,12 +2384,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } else if (display.isKeyguardOccluded()) { // The display was awake so this is resuming activity for occluding keyguard. transit = WindowManager.TRANSIT_KEYGUARD_OCCLUDE; + startTask = display.getTaskOccludingKeyguard(); } if (transit != TRANSIT_NONE) { display.mTransitionController.requestStartTransition( display.mTransitionController.createTransition(transit), - null /* startTask */, null /* remoteTransition */, - null /* displayChange */); + startTask, null /* remoteTransition */, null /* displayChange */); } } // Set the sleeping state of the root tasks on the display. diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 663db861b79e..b938b9e4ec51 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -687,7 +687,11 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // All windows are synced already. return; } - if (!isInTransition(wc)) return; + if (wc.mDisplayContent == null || !isInTransition(wc)) return; + if (!wc.mDisplayContent.getDisplayPolicy().isScreenOnFully() + || wc.mDisplayContent.getDisplayInfo().state == Display.STATE_OFF) { + mFlags |= WindowManager.TRANSIT_FLAG_INVISIBLE; + } if (mContainerFreezer == null) { mContainerFreezer = new ScreenshotFreezer(); @@ -2245,8 +2249,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { while (leashReference.getParent() != ancestor) { leashReference = leashReference.getParent(); } + final SurfaceControl rootLeash = leashReference.makeAnimationLeash().setName( "Transition Root: " + leashReference.getName()).build(); + rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots"); startT.setLayer(rootLeash, leashReference.getLastLayer()); outInfo.addRootLeash(endDisplayId, rootLeash, ancestor.getBounds().left, ancestor.getBounds().top); diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 2f1bf35a5ca8..8587270dd187 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -2214,13 +2214,25 @@ static jobject nativeGetLights(JNIEnv* env, jobject nativeImplObj, jint deviceId jCapability |= env->GetStaticIntField(gLightClassInfo.clazz, gLightClassInfo.lightCapabilityColorRgb); } + + ScopedLocalRef<jintArray> jPreferredBrightnessLevels{env}; + if (!lightInfo.preferredBrightnessLevels.empty()) { + std::vector<int32_t> vec; + for (auto it : lightInfo.preferredBrightnessLevels) { + vec.push_back(ftl::to_underlying(it)); + } + jPreferredBrightnessLevels.reset(env->NewIntArray(vec.size())); + env->SetIntArrayRegion(jPreferredBrightnessLevels.get(), 0, vec.size(), vec.data()); + } + ScopedLocalRef<jobject> lightObj(env, env->NewObject(gLightClassInfo.clazz, gLightClassInfo.constructor, static_cast<jint>(lightInfo.id), env->NewStringUTF(lightInfo.name.c_str()), static_cast<jint>(lightInfo.ordinal), - jTypeId, jCapability)); + jTypeId, jCapability, + jPreferredBrightnessLevels.get())); // Add light object to list env->CallBooleanMethod(jLights, gArrayListClassInfo.add, lightObj.get()); } @@ -2846,7 +2858,7 @@ int register_android_server_InputManager(JNIEnv* env) { FIND_CLASS(gLightClassInfo.clazz, "android/hardware/lights/Light"); gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz)); GET_METHOD_ID(gLightClassInfo.constructor, gLightClassInfo.clazz, "<init>", - "(ILjava/lang/String;III)V"); + "(ILjava/lang/String;III[I)V"); gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz)); gLightClassInfo.lightTypeInput = diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java index 317fd58e0c76..dccacb4d301a 100644 --- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java @@ -58,6 +58,7 @@ import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -103,11 +104,13 @@ import com.android.server.am.UserState.KeyEvictedCallback; import com.android.server.pm.UserJourneyLogger; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.UserManagerService; +import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.WindowManagerService; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.Arrays; @@ -187,6 +190,7 @@ public class UserControllerTest { doNothing().when(mInjector).activityManagerOnUserStopped(anyInt()); doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt()); doNothing().when(mInjector).taskSupervisorRemoveUser(anyInt()); + doNothing().when(mInjector).lockDeviceNowAndWaitForKeyguardShown(); mockIsUsersOnSecondaryDisplaysEnabled(false); // All UserController params are set to default. @@ -951,6 +955,45 @@ public class UserControllerTest { .systemServiceManagerOnUserCompletedEvent(eq(user2), eq(event2a)); } + @Test + public void testStallUserSwitchUntilTheKeyguardIsShown() throws Exception { + // enable user switch ui, because keyguard is only shown then + mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true, + /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false); + + // mock the device to be secure in order to expect the keyguard to be shown + when(mInjector.mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true); + + // call real lockDeviceNowAndWaitForKeyguardShown method for this test + doCallRealMethod().when(mInjector).lockDeviceNowAndWaitForKeyguardShown(); + + // call startUser on a thread because we're expecting it to be blocked + Thread threadStartUser = new Thread(()-> { + mUserController.startUser(TEST_USER_ID, USER_START_MODE_FOREGROUND); + }); + threadStartUser.start(); + + // make sure the switch is stalled... + Thread.sleep(2000); + // by checking REPORT_USER_SWITCH_MSG is not sent yet + assertNull(mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG)); + // and the thread is still alive + assertTrue(threadStartUser.isAlive()); + + // mock send the keyguard shown event + ArgumentCaptor<ActivityTaskManagerInternal.ScreenObserver> captor = ArgumentCaptor.forClass( + ActivityTaskManagerInternal.ScreenObserver.class); + verify(mInjector.mActivityTaskManagerInternal).registerScreenObserver(captor.capture()); + captor.getValue().onKeyguardStateChanged(true); + + // verify the switch now moves on... + Thread.sleep(1000); + // by checking REPORT_USER_SWITCH_MSG is sent + assertNotNull(mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG)); + // and the thread is finished + assertFalse(threadStartUser.isAlive()); + } + private void setUpAndStartUserInBackground(int userId) throws Exception { setUpUser(userId, 0); mUserController.startUser(userId, USER_START_MODE_BACKGROUND); @@ -1092,6 +1135,7 @@ public class UserControllerTest { private final IStorageManager mStorageManagerMock; private final UserManagerInternal mUserManagerInternalMock; private final WindowManagerService mWindowManagerMock; + private final ActivityTaskManagerInternal mActivityTaskManagerInternal; private final KeyguardManager mKeyguardManagerMock; private final LockPatternUtils mLockPatternUtilsMock; @@ -1111,6 +1155,7 @@ public class UserControllerTest { mUserManagerMock = mock(UserManagerService.class); mUserManagerInternalMock = mock(UserManagerInternal.class); mWindowManagerMock = mock(WindowManagerService.class); + mActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class); mStorageManagerMock = mock(IStorageManager.class); mKeyguardManagerMock = mock(KeyguardManager.class); when(mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(true); @@ -1172,6 +1217,11 @@ public class UserControllerTest { } @Override + ActivityTaskManagerInternal getActivityTaskManagerInternal() { + return mActivityTaskManagerInternal; + } + + @Override KeyguardManager getKeyguardManager() { return mKeyguardManagerMock; } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java index d5d06d3b4eb8..046b01c831b5 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java @@ -16,8 +16,10 @@ package com.android.server.biometrics.sensors.face.aidl; +import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -205,7 +207,9 @@ public class FaceAuthenticationClientTest { client.onAuthenticated(new Face("friendly", 1 /* faceId */, 2 /* deviceId */), true /* authenticated */, new ArrayList<>()); - verify(mCancellationSignal).cancel(); + verify(mCancellationSignal, never()).cancel(); + verify(mClientMonitorCallbackConverter) + .onError(anyInt(), anyInt(), eq(BIOMETRIC_ERROR_CANCELED), anyInt()); } private FaceAuthenticationClient createClient() throws RemoteException { diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java index f8f40fe44457..c383a96d5de3 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java @@ -16,6 +16,8 @@ package com.android.server.biometrics.sensors.fingerprint.aidl; +import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -399,7 +401,9 @@ public class FingerprintAuthenticationClientTest { mLooper.moveTimeForward(10); mLooper.dispatchAll(); - verify(mCancellationSignal).cancel(); + verify(mCancellationSignal, never()).cancel(); + verify(mClientMonitorCallbackConverter) + .onError(anyInt(), anyInt(), eq(BIOMETRIC_ERROR_CANCELED), anyInt()); } private FingerprintAuthenticationClient createClient() throws RemoteException { diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt index 272679280a62..ef15ccba4c74 100644 --- a/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt +++ b/services/tests/servicestests/src/com/android/server/input/KeyboardBacklightControllerTests.kt @@ -32,7 +32,8 @@ import android.platform.test.annotations.Presubmit import android.view.InputDevice import androidx.test.annotation.UiThreadTest import androidx.test.core.app.ApplicationProvider -import com.android.server.input.KeyboardBacklightController.BRIGHTNESS_VALUE_FOR_LEVEL +import com.android.server.input.KeyboardBacklightController.DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL +import com.android.server.input.KeyboardBacklightController.MAX_BRIGHTNESS_CHANGE_STEPS import com.android.server.input.KeyboardBacklightController.USER_INACTIVITY_THRESHOLD_MILLIS import org.junit.After import org.junit.Assert.assertEquals @@ -65,12 +66,20 @@ private fun createKeyboard(deviceId: Int): InputDevice = .build() private fun createLight(lightId: Int, lightType: Int): Light = + createLight( + lightId, + lightType, + null + ) + +private fun createLight(lightId: Int, lightType: Int, suggestedBrightnessLevels: IntArray?): Light = Light( lightId, "Light $lightId", 1, lightType, - Light.LIGHT_CAPABILITY_BRIGHTNESS + Light.LIGHT_CAPABILITY_BRIGHTNESS, + suggestedBrightnessLevels ) /** * Tests for {@link KeyboardBacklightController}. @@ -98,7 +107,6 @@ class KeyboardBacklightControllerTests { private lateinit var context: Context private lateinit var dataStore: PersistentDataStore private lateinit var testLooper: TestLooper - private val totalLevels = BRIGHTNESS_VALUE_FOR_LEVEL.size private var lightColorMap: HashMap<Int, Int> = HashMap() private var lastBacklightState: KeyboardBacklightState? = null private var sysfsNodeChanges = 0 @@ -146,84 +154,21 @@ class KeyboardBacklightControllerTests { @Test fun testKeyboardBacklightIncrementDecrement() { - BacklightAnimationFlag(false).use { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use { val keyboardWithBacklight = createKeyboard(DEVICE_ID) val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT) `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight)) keyboardBacklightController.onInputDeviceAdded(DEVICE_ID) - for (level in 1 until totalLevels) { - incrementKeyboardBacklight(DEVICE_ID) - assertEquals( - "Light value for level $level mismatched", - Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0), - lightColorMap[LIGHT_ID] - ) - assertEquals( - "Light value for level $level must be correctly stored in the datastore", - BRIGHTNESS_VALUE_FOR_LEVEL[level], - dataStore.getKeyboardBacklightBrightness( - keyboardWithBacklight.descriptor, - LIGHT_ID - ).asInt - ) - } - - // Increment above max level - incrementKeyboardBacklight(DEVICE_ID) - assertEquals( - "Light value for max level mismatched", - Color.argb(MAX_BRIGHTNESS, 0, 0, 0), - lightColorMap[LIGHT_ID] - ) - assertEquals( - "Light value for max level must be correctly stored in the datastore", - MAX_BRIGHTNESS, - dataStore.getKeyboardBacklightBrightness( - keyboardWithBacklight.descriptor, - LIGHT_ID - ).asInt - ) - - for (level in totalLevels - 2 downTo 0) { - decrementKeyboardBacklight(DEVICE_ID) - assertEquals( - "Light value for level $level mismatched", - Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0), - lightColorMap[LIGHT_ID] - ) - assertEquals( - "Light value for level $level must be correctly stored in the datastore", - BRIGHTNESS_VALUE_FOR_LEVEL[level], - dataStore.getKeyboardBacklightBrightness( - keyboardWithBacklight.descriptor, - LIGHT_ID - ).asInt - ) - } - - // Decrement below min level - decrementKeyboardBacklight(DEVICE_ID) - assertEquals( - "Light value for min level mismatched", - Color.argb(0, 0, 0, 0), - lightColorMap[LIGHT_ID] - ) - assertEquals( - "Light value for min level must be correctly stored in the datastore", - 0, - dataStore.getKeyboardBacklightBrightness( - keyboardWithBacklight.descriptor, - LIGHT_ID - ).asInt - ) + assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight, + DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL) } } @Test fun testKeyboardWithoutBacklight() { - BacklightAnimationFlag(false).use { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use { val keyboardWithoutBacklight = createKeyboard(DEVICE_ID) val keyboardInputLight = createLight(LIGHT_ID, Light.LIGHT_TYPE_INPUT) `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithoutBacklight) @@ -237,7 +182,7 @@ class KeyboardBacklightControllerTests { @Test fun testKeyboardWithMultipleLight() { - BacklightAnimationFlag(false).use { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use { val keyboardWithBacklight = createKeyboard(DEVICE_ID) val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT) val keyboardInputLight = createLight(SECOND_LIGHT_ID, Light.LIGHT_TYPE_INPUT) @@ -259,17 +204,17 @@ class KeyboardBacklightControllerTests { @Test fun testRestoreBacklightOnInputDeviceAdded() { - BacklightAnimationFlag(false).use { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use { val keyboardWithBacklight = createKeyboard(DEVICE_ID) val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT) `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight)) - for (level in 1 until totalLevels) { + for (level in 1 until DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL.size) { dataStore.setKeyboardBacklightBrightness( keyboardWithBacklight.descriptor, LIGHT_ID, - BRIGHTNESS_VALUE_FOR_LEVEL[level] - 1 + DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[level] - 1 ) keyboardBacklightController.onInputDeviceAdded(DEVICE_ID) @@ -278,7 +223,7 @@ class KeyboardBacklightControllerTests { assertEquals( "Keyboard backlight level should be restored to the level saved in the " + "data store", - Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0), + Color.argb(DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0), lightColorMap[LIGHT_ID] ) keyboardBacklightController.onInputDeviceRemoved(DEVICE_ID) @@ -288,7 +233,7 @@ class KeyboardBacklightControllerTests { @Test fun testRestoreBacklightOnInputDeviceChanged() { - BacklightAnimationFlag(false).use { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use { val keyboardWithBacklight = createKeyboard(DEVICE_ID) val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT) `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) @@ -320,9 +265,10 @@ class KeyboardBacklightControllerTests { @Test fun testKeyboardBacklight_registerUnregisterListener() { - BacklightAnimationFlag(false).use { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use { val keyboardWithBacklight = createKeyboard(DEVICE_ID) val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT) + val maxLevel = DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL.size - 1 `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight)) keyboardBacklightController.onInputDeviceAdded(DEVICE_ID) @@ -341,13 +287,13 @@ class KeyboardBacklightControllerTests { lastBacklightState!!.deviceId ) assertEquals( - "Backlight state brightnessLevel should be " + 1, + "Backlight state brightnessLevel should be 1", 1, lastBacklightState!!.brightnessLevel ) assertEquals( - "Backlight state maxBrightnessLevel should be " + (totalLevels - 1), - (totalLevels - 1), + "Backlight state maxBrightnessLevel should be $maxLevel", + maxLevel, lastBacklightState!!.maxBrightnessLevel ) assertEquals( @@ -368,7 +314,7 @@ class KeyboardBacklightControllerTests { @Test fun testKeyboardBacklight_userActivity() { - BacklightAnimationFlag(false).use { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use { val keyboardWithBacklight = createKeyboard(DEVICE_ID) val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT) `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) @@ -400,7 +346,7 @@ class KeyboardBacklightControllerTests { @Test fun testKeyboardBacklight_displayOnOff() { - BacklightAnimationFlag(false).use { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use { val keyboardWithBacklight = createKeyboard(DEVICE_ID) val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT) `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) @@ -490,7 +436,7 @@ class KeyboardBacklightControllerTests { @Test @UiThreadTest fun testKeyboardBacklightAnimation_onChangeLevels() { - BacklightAnimationFlag(true).use { + KeyboardBacklightFlags(animationEnabled = true, customLevelsEnabled = false).use { val keyboardWithBacklight = createKeyboard(DEVICE_ID) val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT) `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) @@ -500,17 +446,145 @@ class KeyboardBacklightControllerTests { incrementKeyboardBacklight(DEVICE_ID) assertEquals( "Should start animation from level 0", - BRIGHTNESS_VALUE_FOR_LEVEL[0], + DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[0], lastAnimationValues[0] ) assertEquals( "Should start animation to level 1", - BRIGHTNESS_VALUE_FOR_LEVEL[1], + DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[1], lastAnimationValues[1] ) } } + @Test + fun testKeyboardBacklightPreferredLevels() { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use { + val keyboardWithBacklight = createKeyboard(DEVICE_ID) + val suggestedLevels = intArrayOf(0, 22, 63, 135, 196, 255) + val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT, + suggestedLevels) + `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) + `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight)) + keyboardBacklightController.onInputDeviceAdded(DEVICE_ID) + + assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight, + suggestedLevels) + } + } + + @Test + fun testKeyboardBacklightPreferredLevels_moreThanMax_shouldUseDefault() { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use { + val keyboardWithBacklight = createKeyboard(DEVICE_ID) + val suggestedLevels = IntArray(MAX_BRIGHTNESS_CHANGE_STEPS + 1) { 10 * (it + 1) } + val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT, + suggestedLevels) + `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) + `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight)) + keyboardBacklightController.onInputDeviceAdded(DEVICE_ID) + + assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight, + DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL) + } + } + + @Test + fun testKeyboardBacklightPreferredLevels_mustHaveZeroAndMaxBrightnessAsBounds() { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use { + val keyboardWithBacklight = createKeyboard(DEVICE_ID) + val suggestedLevels = intArrayOf(22, 63, 135, 196) + val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT, + suggestedLevels) + `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) + `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight)) + keyboardBacklightController.onInputDeviceAdded(DEVICE_ID) + + // Framework will add the lowest and maximum levels if not provided via config + assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight, + intArrayOf(0, 22, 63, 135, 196, 255)) + } + } + + @Test + fun testKeyboardBacklightPreferredLevels_dropsOutOfBoundsLevels() { + KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use { + val keyboardWithBacklight = createKeyboard(DEVICE_ID) + val suggestedLevels = intArrayOf(22, 63, 135, 400, 196, 1000) + val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT, + suggestedLevels) + `when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight) + `when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight)) + keyboardBacklightController.onInputDeviceAdded(DEVICE_ID) + + // Framework will drop out of bound levels in the config + assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight, + intArrayOf(0, 22, 63, 135, 196, 255)) + } + } + + private fun assertIncrementDecrementForLevels( + device: InputDevice, + light: Light, + expectedLevels: IntArray + ) { + val deviceId = device.id + val lightId = light.id + for (level in 1 until expectedLevels.size) { + incrementKeyboardBacklight(deviceId) + assertEquals( + "Light value for level $level mismatched", + Color.argb(expectedLevels[level], 0, 0, 0), + lightColorMap[lightId] + ) + assertEquals( + "Light value for level $level must be correctly stored in the datastore", + expectedLevels[level], + dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt + ) + } + + // Increment above max level + incrementKeyboardBacklight(deviceId) + assertEquals( + "Light value for max level mismatched", + Color.argb(MAX_BRIGHTNESS, 0, 0, 0), + lightColorMap[lightId] + ) + assertEquals( + "Light value for max level must be correctly stored in the datastore", + MAX_BRIGHTNESS, + dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt + ) + + for (level in expectedLevels.size - 2 downTo 0) { + decrementKeyboardBacklight(deviceId) + assertEquals( + "Light value for level $level mismatched", + Color.argb(expectedLevels[level], 0, 0, 0), + lightColorMap[lightId] + ) + assertEquals( + "Light value for level $level must be correctly stored in the datastore", + expectedLevels[level], + dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt + ) + } + + // Decrement below min level + decrementKeyboardBacklight(deviceId) + assertEquals( + "Light value for min level mismatched", + Color.argb(0, 0, 0, 0), + lightColorMap[lightId] + ) + assertEquals( + "Light value for min level must be correctly stored in the datastore", + 0, + dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt + ) + } + inner class KeyboardBacklightListener : IKeyboardBacklightListener.Stub() { override fun onBrightnessChanged( deviceId: Int, @@ -545,9 +619,13 @@ class KeyboardBacklightControllerTests { val isTriggeredByKeyPress: Boolean ) - private inner class BacklightAnimationFlag constructor(enabled: Boolean) : AutoCloseable { + private inner class KeyboardBacklightFlags constructor( + animationEnabled: Boolean, + customLevelsEnabled: Boolean + ) : AutoCloseable { init { - InputFeatureFlagProvider.setKeyboardBacklightAnimationEnabled(enabled) + InputFeatureFlagProvider.setKeyboardBacklightAnimationEnabled(animationEnabled) + InputFeatureFlagProvider.setKeyboardBacklightCustomLevelsEnabled(customLevelsEnabled) } override fun close() { diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 933f00231313..7aec04568e0f 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -26,6 +26,9 @@ import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING; import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING; +import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; +import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED; + import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertFalse; @@ -145,6 +148,7 @@ public class PowerManagerServiceTest { @Mock private ActivityManagerInternal mActivityManagerInternalMock; @Mock private AttentionManagerInternal mAttentionManagerInternalMock; @Mock private DreamManagerInternal mDreamManagerInternalMock; + @Mock private WindowManagerPolicy mPolicyMock; @Mock private PowerManagerService.NativeWrapper mNativeWrapperMock; @Mock private Notifier mNotifierMock; @Mock private WirelessChargerDetector mWirelessChargerDetectorMock; @@ -205,6 +209,7 @@ public class PowerManagerServiceTest { .thenReturn(true); when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn(""); when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true); + when(mPolicyMock.getLidState()).thenReturn(LID_ABSENT); addLocalServiceMock(LightsManager.class, mLightsManagerMock); addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock); @@ -212,6 +217,7 @@ public class PowerManagerServiceTest { addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock); addLocalServiceMock(AttentionManagerInternal.class, mAttentionManagerInternalMock); addLocalServiceMock(DreamManagerInternal.class, mDreamManagerInternalMock); + addLocalServiceMock(WindowManagerPolicy.class, mPolicyMock); mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); mResourcesSpy = spy(mContextSpy.getResources()); @@ -678,6 +684,20 @@ public class PowerManagerServiceTest { assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); } + @Test + public void testWakefulnessAwake_ShouldNotWakeUpWhenLidClosed() { + when(mPolicyMock.getLidState()).thenReturn(LID_CLOSED); + createService(); + startSystem(); + forceSleep(); + + mService.getBinderServiceInstance().wakeUp(mClock.now(), + PowerManager.WAKE_REASON_POWER_BUTTON, + "testing IPowerManager.wakeUp()", "pkg.name"); + + assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); + } + /** * Tests a series of variants that control whether a device wakes-up when it is plugged in * or docked. diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 866260757df9..114796d17ef1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -25,6 +25,7 @@ import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; @@ -38,6 +39,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.spy; @@ -419,10 +421,10 @@ public class InsetsStateControllerTest extends WindowTestsBase { @Test public void testUpdateAboveInsetsState_zOrderChanged() { - final WindowState ime = createTestWindow("ime"); - final WindowState app = createTestWindow("app"); - final WindowState statusBar = createTestWindow("statusBar"); - final WindowState navBar = createTestWindow("navBar"); + final WindowState ime = createNonAppWindow("ime"); + final WindowState app = createNonAppWindow("app"); + final WindowState statusBar = createNonAppWindow("statusBar"); + final WindowState navBar = createNonAppWindow("navBar"); final InsetsSourceProvider imeSourceProvider = getController().getOrCreateSourceProvider(ID_IME, ime()); @@ -430,7 +432,9 @@ public class InsetsStateControllerTest extends WindowTestsBase { waitUntilHandlersIdle(); clearInvocations(mDisplayContent); + imeSourceProvider.updateControlForTarget(app, false /* force */); imeSourceProvider.setClientVisible(true); + verify(mDisplayContent).assignWindowLayers(anyBoolean()); waitUntilHandlersIdle(); // The visibility change should trigger a traversal to notify the change. verify(mDisplayContent).notifyInsetsChanged(any()); @@ -546,6 +550,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { control2.getInsetsHint().bottom); } + /** Creates a window which is associated with ActivityRecord. */ private WindowState createTestWindow(String name) { final WindowState win = createWindow(null, TYPE_APPLICATION, name); win.setHasSurface(true); @@ -553,6 +558,14 @@ public class InsetsStateControllerTest extends WindowTestsBase { return win; } + /** Creates a non-activity window. */ + private WindowState createNonAppWindow(String name) { + final WindowState win = createWindow(null, LAST_APPLICATION_WINDOW + 1, name); + win.setHasSurface(true); + spyOn(win); + return win; + } + private InsetsStateController getController() { return mDisplayContent.getInsetsStateController(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index adf3f3976f38..192632ce0277 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; +import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; + import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; @@ -354,4 +356,9 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { public boolean isGlobalKey(int keyCode) { return false; } + + @Override + public int getLidState() { + return LID_ABSENT; + } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt index 7f496d828996..122a6cbbb98f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt @@ -17,6 +17,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation import android.tools.common.traces.component.ComponentNameMatcher @@ -102,6 +103,7 @@ open class CloseImeOnGoHomeTest(flicker: FlickerTest) : BaseTest(flicker) { @Presubmit @Test + @PlatinumTest(focusArea = "ime") @IwTest(focusArea = "ime") override fun cujCompleted() { super.cujCompleted() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt index c693ca759bdd..5aa43820e5cb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt @@ -17,6 +17,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -103,6 +104,7 @@ open class CloseImeToAppOnPressBackTest(flicker: FlickerTest) : BaseTest(flicker @Presubmit @Test + @PlatinumTest(focusArea = "ime") @IwTest(focusArea = "ime") override fun cujCompleted() { super.cujCompleted() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt index d5208e060883..6731089f8903 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt @@ -18,6 +18,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -71,6 +72,7 @@ open class CloseImeToHomeOnFinishActivityTest(flicker: FlickerTest) : BaseTest(f @Presubmit @Test + @PlatinumTest(focusArea = "ime") @IwTest(focusArea = "ime") override fun cujCompleted() { runAndIgnoreAssumptionViolation { entireScreenCovered() } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt index d1335294f629..c70e3cb773d4 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt @@ -17,6 +17,7 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.Rotation import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -52,6 +53,7 @@ open class ShowImeWhenFocusingOnInputFieldTest(flicker: FlickerTest) : BaseTest( @Presubmit @Test + @PlatinumTest(focusArea = "ime") @IwTest(focusArea = "ime") override fun cujCompleted() { super.cujCompleted() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index 855ea3e38b3e..7fbcfec40121 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -17,6 +17,7 @@ package com.android.server.wm.flicker.rotation import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.flicker.junit.FlickerParametersRunnerFactory @@ -129,6 +130,7 @@ open class ChangeAppRotationTest(flicker: FlickerTest) : RotationTransition(flic } @Test + @PlatinumTest(focusArea = "framework") @IwTest(focusArea = "framework") override fun cujCompleted() { super.cujCompleted() diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index 0cbbb83b48ee..44ae14a8e4bb 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -17,6 +17,7 @@ package com.android.server.wm.flicker.rotation import android.platform.test.annotations.IwTest +import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit import android.tools.common.ScenarioBuilder import android.tools.common.traces.component.ComponentNameMatcher @@ -213,6 +214,7 @@ open class SeamlessAppRotationTest(flicker: FlickerTest) : RotationTransition(fl } @Test + @PlatinumTest(focusArea = "framework") @IwTest(focusArea = "framework") override fun cujCompleted() { appWindowFullScreen() |