diff options
218 files changed, 3205 insertions, 956 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 26c64bd7adbc..e0fc9590f9f7 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -33468,7 +33468,7 @@ package android.os { public static class Build.VERSION_CODES { ctor public Build.VERSION_CODES(); - field @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static final int BAKLAVA = 10000; // 0x2710 + field @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static final int BAKLAVA = 36; // 0x24 field public static final int BASE = 1; // 0x1 field public static final int BASE_1_1 = 2; // 0x2 field public static final int CUPCAKE = 3; // 0x3 @@ -33508,7 +33508,7 @@ package android.os { } @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static class Build.VERSION_CODES_FULL { - field public static final int BAKLAVA = 1000000000; // 0x3b9aca00 + field public static final int BAKLAVA = 3600000; // 0x36ee80 field public static final int BASE = 100000; // 0x186a0 field public static final int BASE_1_1 = 200000; // 0x30d40 field public static final int CUPCAKE = 300000; // 0x493e0 diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2cfba4b8468f..7b9ec4a7821e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -7061,7 +7061,7 @@ public final class ActivityThread extends ClientTransactionHandler Slog.w(TAG, "Low overhead tracing feature is not enabled"); break; } - VMDebug.startLowOverheadTrace(); + VMDebug.startLowOverheadTraceForAllMethods(); break; default: try { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index c50452157d74..08719fc549f8 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4051,10 +4051,13 @@ public class DevicePolicyManager { public static final int EXEMPT_FROM_HIBERNATION = 3; /** - * Exempt an app from all power-related restrictions, including app standby and doze. + * Exempt an app from all power-related restrictions, including app standby. * In addition, the app will be able to start foreground services from the background, * and the user will not be able to stop foreground services run by the app. * + * <p><strong>Note:</strong> This option does NOT exempt apps from Doze mode. In fact, + * DPC apps themselves are not automatically exempted from Doze mode either. + * * @hide */ @SystemApi diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java index 1d2f133ee759..b39bd8c10022 100644 --- a/core/java/android/hardware/display/DisplayTopology.java +++ b/core/java/android/hardware/display/DisplayTopology.java @@ -108,7 +108,6 @@ public final class DisplayTopology implements Parcelable { public DisplayTopology() {} - @VisibleForTesting public DisplayTopology(TreeNode root, int primaryDisplayId) { mRoot = root; if (mRoot != null) { @@ -275,7 +274,7 @@ public final class DisplayTopology implements Parcelable { float offset; int pos; - if (Math.abs(xOverlap) > Math.abs(yOverlap)) { + if (xOverlap > yOverlap) { // Deviation in each dimension is a penalty in the potential parenting. To // get the X deviation, overlap is subtracted from the lesser width so that // a maximum overlap results in a deviation of zero. @@ -541,6 +540,19 @@ public final class DisplayTopology implements Parcelable { } @Override + public boolean equals(Object obj) { + if (!(obj instanceof DisplayTopology)) { + return false; + } + return obj.toString().equals(toString()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + @Override public String toString() { StringWriter out = new StringWriter(); PrintWriter writer = new PrintWriter(out); @@ -610,7 +622,7 @@ public final class DisplayTopology implements Parcelable { } @Nullable - private static TreeNode findDisplay(int displayId, @Nullable TreeNode startingNode) { + public static TreeNode findDisplay(int displayId, @Nullable TreeNode startingNode) { if (startingNode == null) { return null; } @@ -775,16 +787,22 @@ public final class DisplayTopology implements Parcelable { */ private float mOffset; - private final List<TreeNode> mChildren = new ArrayList<>(); + private final List<TreeNode> mChildren; @VisibleForTesting public TreeNode(int displayId, float width, float height, @Position int position, float offset) { + this(displayId, width, height, position, offset, List.of()); + } + + public TreeNode(int displayId, float width, float height, int position, + float offset, List<TreeNode> children) { mDisplayId = displayId; mWidth = width; mHeight = height; mPosition = position; mOffset = offset; + mChildren = new ArrayList<>(children); } public TreeNode(Parcel source) { diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index c51ad9e986ef..1e6469c57fa9 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1271,7 +1271,7 @@ public class Build { * Baklava. */ @FlaggedApi(Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME) - public static final int BAKLAVA = CUR_DEVELOPMENT; + public static final int BAKLAVA = 36; } /** @hide */ diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 06eb0428bfcf..f58baffb1367 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -1145,4 +1145,9 @@ interface IWindowManager * @param deviceId The id of the {@link InputDevice} that will handle the shortcut. */ KeyboardShortcutGroup getApplicationLaunchKeyboardShortcuts(int deviceId); + + /** + * Returns whether the display with {@code displayId} ignores orientation request. + */ + boolean getIgnoreOrientationRequest(int displayId); } diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt index 008db5ef114e..6d6b56754000 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt +++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt @@ -635,8 +635,7 @@ class DisplayTopologyTest { // 222 RectF(0f, 0f, 30f, 30f), RectF(40f, 10f, 70f, 40f), - RectF(80.5f, 50f, 110f, 80f), // left+=0.5 to cause a preference for - // TOP/BOTTOM attach + RectF(80.5f, 50f, 110f, 80f), ) verifyDisplay(root, id = 0, width = 30f, height = 30f, noOfChildren = 1) @@ -644,7 +643,7 @@ class DisplayTopologyTest { root.children[0], id = 1, width = 30f, height = 30f, POSITION_RIGHT, offset = 10f, noOfChildren = 1) verifyDisplay( - root.children[0].children[0], id = 2, width = 29.5f, height = 30f, POSITION_BOTTOM, + root.children[0].children[0], id = 2, width = 29.5f, height = 30f, POSITION_RIGHT, offset = 30f, noOfChildren = 0) } @@ -702,6 +701,76 @@ class DisplayTopologyTest { } @Test + fun rearrange_preferLongHorizontalShiftOverAttachToCorner() { + // An earlier implementation decided vertical or horizontal clamp direction based on the abs + // value of the overlap in each dimension, rather than the raw overlap. + + // This horizontal span is twice the height of displays, making abs(xOverlap) > yOverlap, + // i.e. abs(-60) > 30 + // | + // |----| + // 000 111 + // 000 111 + // 000 111 + + // Before fix: + // 000 + // 000 + // 000 + // 111 + // 111 + // 111 + + // After fix: + // 000111 + // 000111 + // 000111 + + val root = rearrangeRects( + RectF(0f, 0f, 30f, 30f), + RectF(90f, 0f, 120f, 30f), + ) + + verifyDisplay(root, id = 0, width = 30f, height = 30f, noOfChildren = 1) + verifyDisplay( + root.children[0], id = 1, width = 30f, height = 30f, POSITION_RIGHT, + offset = 0f, noOfChildren = 0) + } + + @Test + fun rearrange_preferLongVerticalShiftOverAttachToCorner() { + // Before: + // 111 + // 111 + // 111 + // | + // |- This vertical span is 40dp + // | + // | + // 000 + // 000 + // 000 + + // After: + // 111 + // 111 + // 111 + // 000 + // 000 + // 000 + + val root = rearrangeRects( + RectF(20f, 70f, 50f, 100f), + RectF(00f, 0f, 30f, 30f), + ) + + verifyDisplay(root, id = 0, width = 30f, height = 30f, noOfChildren = 1) + verifyDisplay( + root.children[0], id = 1, width = 30f, height = 30f, POSITION_TOP, + offset = -20f, noOfChildren = 0) + } + + @Test fun copy() { val display1 = DisplayTopology.TreeNode(/* displayId= */ 1, /* width= */ 200f, /* height= */ 600f, /* position= */ 0, /* offset= */ 0f) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/EventLogTags.logtags b/libs/WindowManager/Shell/src/com/android/wm/shell/EventLogTags.logtags index db960d15c526..b716e9e574fa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/EventLogTags.logtags +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/EventLogTags.logtags @@ -8,4 +8,4 @@ option java_package com.android.wm.shell 38500 wm_shell_enter_desktop_mode (EnterReason|1|5),(SessionId|1|5) 38501 wm_shell_exit_desktop_mode (ExitReason|1|5),(SessionId|1|5) -38502 wm_shell_desktop_mode_task_update (TaskEvent|1|5),(InstanceId|1|5),(uid|1|5),(TaskHeight|1),(TaskWidth|1),(TaskX|1),(TaskY|1),(SessionId|1|5),(MinimiseReason|1|5),(UnminimiseReason|1|5),(VisibleTaskCount|1) +38502 wm_shell_desktop_mode_task_update (TaskEvent|1|5),(InstanceId|1|5),(uid|1|5),(TaskHeight|1),(TaskWidth|1),(TaskX|1),(TaskY|1),(SessionId|1|5),(MinimiseReason|1|5),(UnminimiseReason|1|5),(VisibleTaskCount|1),(FocusReason|1|5) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 30d679006c98..4f9028e8aaf3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -477,24 +477,23 @@ public class BubbleController implements ConfigurationChangeListener, @Override public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { - for (Bubble b : mBubbleData.getBubbles()) { - if (task.taskId == b.getTaskId()) { - ProtoLog.d(WM_SHELL_BUBBLES, - "onActivityRestartAttempt - taskId=%d selecting matching bubble=%s", - task.taskId, b.getKey()); - mBubbleData.setSelectedBubbleAndExpandStack(b); - return; - } + final int taskId = task.taskId; + Bubble bubble = mBubbleData.getBubbleInStackWithTaskId(taskId); + if (bubble != null) { + ProtoLog.d(WM_SHELL_BUBBLES, + "onActivityRestartAttempt - taskId=%d selecting matching bubble=%s", + taskId, bubble.getKey()); + mBubbleData.setSelectedBubbleAndExpandStack(bubble); + return; } - for (Bubble b : mBubbleData.getOverflowBubbles()) { - if (task.taskId == b.getTaskId()) { - ProtoLog.d(WM_SHELL_BUBBLES, "onActivityRestartAttempt - taskId=%d " - + "selecting matching overflow bubble=%s", - task.taskId, b.getKey()); - promoteBubbleFromOverflow(b); - mBubbleData.setExpanded(true); - return; - } + + bubble = mBubbleData.getOverflowBubbleWithTaskId(taskId); + if (bubble != null) { + ProtoLog.d(WM_SHELL_BUBBLES, "onActivityRestartAttempt - taskId=%d " + + "selecting matching overflow bubble=%s", + taskId, bubble.getKey()); + promoteBubbleFromOverflow(bubble); + mBubbleData.setExpanded(true); } } }); @@ -1296,8 +1295,8 @@ public class BubbleController implements ConfigurationChangeListener, * @param timestamp the timestamp of the removal */ public void dragBubbleToDismiss(String bubbleKey, long timestamp) { - String selectedBubbleKey = mBubbleData.getSelectedBubbleKey(); - Bubble bubbleToDismiss = mBubbleData.getAnyBubbleWithkey(bubbleKey); + final String selectedBubbleKey = mBubbleData.getSelectedBubbleKey(); + final Bubble bubbleToDismiss = mBubbleData.getAnyBubbleWithKey(bubbleKey); if (bubbleToDismiss != null) { mBubbleData.dismissBubbleWithKey( bubbleKey, Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER, timestamp); @@ -1330,11 +1329,11 @@ public class BubbleController implements ConfigurationChangeListener, @VisibleForTesting public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) { - boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key) - && !mBubbleData.getAnyBubbleWithkey(key).showInShade()); + final boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key) + && !mBubbleData.getAnyBubbleWithKey(key).showInShade()); - boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey); - boolean isSummary = key.equals(mBubbleData.getSummaryKey(groupKey)); + final boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey); + final boolean isSummary = key.equals(mBubbleData.getSummaryKey(groupKey)); return (isSummary && isSuppressedSummary) || isSuppressedBubble; } @@ -1362,8 +1361,6 @@ public class BubbleController implements ConfigurationChangeListener, public void expandStackAndSelectBubbleFromLauncher(String key, int topOnScreen) { mBubblePositioner.setBubbleBarTopOnScreen(topOnScreen); - boolean wasExpanded = (mLayerView != null && mLayerView.isExpanded()); - if (BubbleOverflow.KEY.equals(key)) { mBubbleData.setSelectedBubbleFromLauncher(mBubbleData.getOverflow()); mLayerView.showExpandedView(mBubbleData.getOverflow()); @@ -1371,10 +1368,11 @@ public class BubbleController implements ConfigurationChangeListener, return; } - Bubble b = mBubbleData.getAnyBubbleWithkey(key); + final Bubble b = mBubbleData.getAnyBubbleWithKey(key); if (b == null) { return; } + final boolean wasExpanded = (mLayerView != null && mLayerView.isExpanded()); if (mBubbleData.hasBubbleInStackWithKey(b.getKey())) { // already in the stack mBubbleData.setSelectedBubbleFromLauncher(b); @@ -1748,31 +1746,32 @@ public class BubbleController implements ConfigurationChangeListener, public void updateBubble(BubbleEntry notif, boolean suppressFlyout, boolean showInShade) { // If this is an interruptive notif, mark that it's interrupted mSysuiProxy.setNotificationInterruption(notif.getKey()); - boolean isNonInterruptiveNotExpanding = !notif.getRanking().isTextChanged() + final boolean isNonInterruptiveNotExpanding = !notif.getRanking().isTextChanged() && (notif.getBubbleMetadata() != null && !notif.getBubbleMetadata().getAutoExpandBubble()); + final Bubble bubble; if (isNonInterruptiveNotExpanding && mBubbleData.hasOverflowBubbleWithKey(notif.getKey())) { // Update the bubble but don't promote it out of overflow - Bubble b = mBubbleData.getOverflowBubbleWithKey(notif.getKey()); + bubble = mBubbleData.getOverflowBubbleWithKey(notif.getKey()); if (notif.isBubble()) { notif.setFlagBubble(false); } - updateNotNotifyingEntry(b, notif, showInShade); + updateNotNotifyingEntry(bubble, notif, showInShade); } else if (mBubbleData.hasAnyBubbleWithKey(notif.getKey()) && isNonInterruptiveNotExpanding) { - Bubble b = mBubbleData.getAnyBubbleWithkey(notif.getKey()); - if (b != null) { - updateNotNotifyingEntry(b, notif, showInShade); + bubble = mBubbleData.getAnyBubbleWithKey(notif.getKey()); + if (bubble != null) { + updateNotNotifyingEntry(bubble, notif, showInShade); } } else if (mBubbleData.isSuppressedWithLocusId(notif.getLocusId())) { // Update the bubble but don't promote it out of overflow - Bubble b = mBubbleData.getSuppressedBubbleWithKey(notif.getKey()); - if (b != null) { - updateNotNotifyingEntry(b, notif, showInShade); + bubble = mBubbleData.getSuppressedBubbleWithKey(notif.getKey()); + if (bubble != null) { + updateNotNotifyingEntry(bubble, notif, showInShade); } } else { - Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */); + bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */); if (notif.shouldSuppressNotificationList()) { // If we're suppressing notifs for DND, we don't want the bubbles to randomly // expand when DND turns off so flip the flag. @@ -2323,12 +2322,12 @@ public class BubbleController implements ConfigurationChangeListener, BubbleEntry summary, @Nullable List<BubbleEntry> children, IntConsumer removeCallback) { if (children != null) { for (int i = 0; i < children.size(); i++) { - BubbleEntry child = children.get(i); + final BubbleEntry child = children.get(i); if (mBubbleData.hasAnyBubbleWithKey(child.getKey())) { // Suppress the bubbled child // As far as group manager is concerned, once a child is no longer shown // in the shade, it is essentially removed. - Bubble bubbleChild = mBubbleData.getAnyBubbleWithkey(child.getKey()); + final Bubble bubbleChild = mBubbleData.getAnyBubbleWithKey(child.getKey()); if (bubbleChild != null) { bubbleChild.setSuppressNotification(true); bubbleChild.setShowDot(false /* show */); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java index 76d91ede7aa3..74302094a296 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java @@ -27,7 +27,6 @@ import android.content.Intent; import android.content.LocusId; import android.content.pm.ShortcutInfo; import android.os.UserHandle; -import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -48,6 +47,7 @@ import com.android.wm.shell.shared.bubbles.RemovedBubble; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -667,7 +667,7 @@ public class BubbleData { /** Removes all bubbles for the given user. */ public void removeBubblesForUser(int userId) { - List<Bubble> removedBubbles = filterAllBubbles(bubble -> + final List<Bubble> removedBubbles = filterAllBubbles(bubble -> userId == bubble.getUser().getIdentifier()); for (Bubble b : removedBubbles) { doRemove(b.getKey(), Bubbles.DISMISS_USER_ACCOUNT_REMOVED); @@ -1162,7 +1162,7 @@ public class BubbleData { @VisibleForTesting(visibility = PRIVATE) @Nullable - Bubble getAnyBubbleWithkey(String key) { + Bubble getAnyBubbleWithKey(String key) { Bubble b = getBubbleInStackWithKey(key); if (b == null) { b = getOverflowBubbleWithKey(key); @@ -1173,77 +1173,45 @@ public class BubbleData { return b; } - /** @return any bubble (in the stack or the overflow) that matches the provided shortcutId. */ + /** @return the bubble in the stack that matches the provided taskId. */ @Nullable - Bubble getAnyBubbleWithShortcutId(String shortcutId) { - if (TextUtils.isEmpty(shortcutId)) { - return null; - } - for (int i = 0; i < mBubbles.size(); i++) { - Bubble bubble = mBubbles.get(i); - String bubbleShortcutId = bubble.getShortcutInfo() != null - ? bubble.getShortcutInfo().getId() - : bubble.getMetadataShortcutId(); - if (shortcutId.equals(bubbleShortcutId)) { - return bubble; - } - } - - for (int i = 0; i < mOverflowBubbles.size(); i++) { - Bubble bubble = mOverflowBubbles.get(i); - String bubbleShortcutId = bubble.getShortcutInfo() != null - ? bubble.getShortcutInfo().getId() - : bubble.getMetadataShortcutId(); - if (shortcutId.equals(bubbleShortcutId)) { - return bubble; - } - } - return null; + Bubble getBubbleInStackWithTaskId(int taskId) { + return getBubbleWithPredicate(mBubbles, b -> b.getTaskId() == taskId); } - @VisibleForTesting(visibility = PRIVATE) + /** @return the bubble in the stack that matches the provided key. */ @Nullable + @VisibleForTesting(visibility = PRIVATE) public Bubble getBubbleInStackWithKey(String key) { - for (int i = 0; i < mBubbles.size(); i++) { - Bubble bubble = mBubbles.get(i); - if (bubble.getKey().equals(key)) { - return bubble; - } - } - return null; + return getBubbleWithPredicate(mBubbles, b -> b.getKey().equals(key)); } + /** @return the bubble in the stack that matches the provided locusId. */ @Nullable - private Bubble getBubbleInStackWithLocusId(LocusId locusId) { - if (locusId == null) return null; - for (int i = 0; i < mBubbles.size(); i++) { - Bubble bubble = mBubbles.get(i); - if (locusId.equals(bubble.getLocusId())) { - return bubble; - } + private Bubble getBubbleInStackWithLocusId(@Nullable LocusId locusId) { + if (locusId == null) { + return null; } - return null; + return getBubbleWithPredicate(mBubbles, b -> locusId.equals(b.getLocusId())); } + /** @return the bubble in the stack that matches the provided icon view. */ @Nullable - Bubble getBubbleWithView(View view) { - for (int i = 0; i < mBubbles.size(); i++) { - Bubble bubble = mBubbles.get(i); - if (bubble.getIconView() != null && bubble.getIconView().equals(view)) { - return bubble; - } - } - return null; + Bubble getBubbleInStackWithView(View view) { + return getBubbleWithPredicate(mBubbles, b -> + b.getIconView() != null && b.getIconView().equals(view)); + } + + /** @return the overflow bubble that matches the provided taskId. */ + @Nullable + Bubble getOverflowBubbleWithTaskId(int taskId) { + return getBubbleWithPredicate(mOverflowBubbles, b -> b.getTaskId() == taskId); } + /** @return the overflow bubble that matches the provided key. */ + @Nullable public Bubble getOverflowBubbleWithKey(String key) { - for (int i = 0; i < mOverflowBubbles.size(); i++) { - Bubble bubble = mOverflowBubbles.get(i); - if (bubble.getKey().equals(key)) { - return bubble; - } - } - return null; + return getBubbleWithPredicate(mOverflowBubbles, b -> b.getKey().equals(key)); } /** @@ -1255,12 +1223,7 @@ public class BubbleData { @Nullable @VisibleForTesting(visibility = PRIVATE) public Bubble getSuppressedBubbleWithKey(String key) { - for (Bubble b : mSuppressedBubbles.values()) { - if (b.getKey().equals(key)) { - return b; - } - } - return null; + return getBubbleWithPredicate(mSuppressedBubbles.values(), b -> b.getKey().equals(key)); } /** @@ -1269,11 +1232,32 @@ public class BubbleData { * @param key notification key * @return bubble that matches or null */ + @Nullable @VisibleForTesting(visibility = PRIVATE) public Bubble getPendingBubbleWithKey(String key) { - for (Bubble b : mPendingBubbles.values()) { - if (b.getKey().equals(key)) { - return b; + return getBubbleWithPredicate(mPendingBubbles.values(), b -> b.getKey().equals(key)); + } + + @Nullable + private static Bubble getBubbleWithPredicate(@NonNull final List<Bubble> bubbles, + @NonNull final Predicate<Bubble> predicate) { + // Uses an indexed for loop for optimized performance when iterating over ArrayLists. + for (int i = 0; i < bubbles.size(); i++) { + final Bubble bubble = bubbles.get(i); + if (predicate.test(bubble)) { + return bubble; + } + } + return null; + } + + @Nullable + private static Bubble getBubbleWithPredicate(@NonNull final Collection<Bubble> bubbles, + @NonNull final Predicate<Bubble> predicate) { + // Uses an enhanced for loop for general collections, which may not support indexed access. + for (final Bubble bubble : bubbles) { + if (predicate.test(bubble)) { + return bubble; } } return null; @@ -1284,7 +1268,7 @@ public class BubbleData { * bubbles (i.e. pending, suppressed, active, and overflowed). */ private List<Bubble> filterAllBubbles(Predicate<Bubble> predicate) { - ArrayList<Bubble> matchingBubbles = new ArrayList<>(); + final ArrayList<Bubble> matchingBubbles = new ArrayList<>(); for (Bubble b : mPendingBubbles.values()) { if (predicate.test(b)) { matchingBubbles.add(b); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 1094c290df06..4e7f87c48a86 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -497,7 +497,7 @@ public class BubbleStackView extends FrameLayout view /* bubble */, mDismissView.getHeight() /* translationYBy */, () -> dismissBubbleIfExists( - mBubbleData.getBubbleWithView(view)) /* after */); + mBubbleData.getBubbleInStackWithView(view)) /* after */); } mDismissView.hide(); @@ -558,7 +558,7 @@ public class BubbleStackView extends FrameLayout return; } - final Bubble clickedBubble = mBubbleData.getBubbleWithView(view); + final Bubble clickedBubble = mBubbleData.getBubbleInStackWithView(view); // If the bubble has since left us, ignore the click. if (clickedBubble == null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java index c1f704ab455d..1f3b1b6718f7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesTransitionObserver.java @@ -33,11 +33,13 @@ import com.android.wm.shell.transition.Transitions; */ public class BubblesTransitionObserver implements Transitions.TransitionObserver { - private BubbleController mBubbleController; - private BubbleData mBubbleData; + @NonNull + private final BubbleController mBubbleController; + @NonNull + private final BubbleData mBubbleData; - public BubblesTransitionObserver(BubbleController controller, - BubbleData bubbleData) { + public BubblesTransitionObserver(@NonNull BubbleController controller, + @NonNull BubbleData bubbleData) { mBubbleController = controller; mBubbleData = bubbleData; } @@ -57,7 +59,7 @@ public class BubblesTransitionObserver implements Transitions.TransitionObserver || mBubbleData.getSelectedBubble() == null) { continue; } - int expandedId = mBubbleData.getSelectedBubble().getTaskId(); + final int expandedId = mBubbleData.getSelectedBubble().getTaskId(); // If the task id that's opening is the same as the expanded bubble, skip collapsing // because it is our bubble that is opening. if (expandedId != INVALID_TASK_ID && expandedId != taskInfo.taskId) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index c9890a5b4963..94e629a6887f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -661,7 +661,9 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged if (android.view.inputmethod.Flags.refactorInsetsController()) { setVisibleDirectly(false /* visible */, statsToken); } - ImeTracker.forLogging().onHidden(mStatsToken); + if (!android.view.inputmethod.Flags.refactorInsetsController()) { + ImeTracker.forLogging().onHidden(mStatsToken); + } } else if (mAnimationDirection == DIRECTION_SHOW && !mCancelled) { ImeTracker.forLogging().onShown(mStatsToken); } else if (mCancelled) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt index 702c67473db2..7897c0aa35bc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt @@ -342,6 +342,7 @@ class DesktopModeEventLogger { taskUpdate.unminimizeReason?.reason ?: UNSET_UNMINIMIZE_REASON, /* visible_task_count */ taskUpdate.visibleTaskCount, + taskUpdate.focusReason?.reason ?: UNSET_FOCUS_REASON, ) EventLogTags.writeWmShellDesktopModeTaskUpdate( /* task_event */ @@ -364,6 +365,7 @@ class DesktopModeEventLogger { taskUpdate.unminimizeReason?.reason ?: UNSET_UNMINIMIZE_REASON, /* visible_task_count */ taskUpdate.visibleTaskCount, + taskUpdate.focusReason?.reason ?: UNSET_FOCUS_REASON, ) } @@ -408,6 +410,8 @@ class DesktopModeEventLogger { * @property taskY y-coordinate of the top-left corner * @property minimizeReason the reason the task was minimized * @property unminimizeReason the reason the task was unminimized + * @property visibleTaskCount the number of visible tasks after this update + * @property focusReason the reason the task was focused */ data class TaskUpdate( val instanceId: Int, @@ -419,6 +423,7 @@ class DesktopModeEventLogger { val minimizeReason: MinimizeReason? = null, val unminimizeReason: UnminimizeReason? = null, val visibleTaskCount: Int, + val focusReason: FocusReason? = null, ) /** @@ -509,6 +514,16 @@ class DesktopModeEventLogger { ), } + // Default value used when the task was not unminimized. + @VisibleForTesting + const val UNSET_FOCUS_REASON = + FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__FOCUS_REASON__UNSET_FOCUS + + /** The reason a task was unminimized. */ + enum class FocusReason(val reason: Int) { + UNKNOWN(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__FOCUS_REASON__FOCUS_UNKNOWN) + } + /** * Enum EnterReason mapped to the EnterReason definition in * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt index df4b1c4a66ec..a43358603bc3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt @@ -27,7 +27,9 @@ import android.os.Trace import android.util.SparseArray import android.view.SurfaceControl import android.view.WindowManager +import android.view.WindowManager.TRANSIT_OPEN import android.window.TransitionInfo +import android.window.TransitionInfo.FLAG_MOVED_TO_TOP import androidx.annotation.VisibleForTesting import androidx.core.util.containsKey import androidx.core.util.forEach @@ -39,6 +41,7 @@ import com.android.internal.protolog.ProtoLog import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.FocusReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason @@ -91,6 +94,8 @@ class DesktopModeLoggerTransitionObserver( // following enter reason could be Screen On private var wasPreviousTransitionExitByScreenOff: Boolean = false + private var focusedFreeformTask: TaskInfo? = null + @VisibleForTesting var isSessionActive: Boolean = false fun onInit() { @@ -151,6 +156,7 @@ class DesktopModeLoggerTransitionObserver( transitionInfo = info, preTransitionVisibleFreeformTasks = visibleFreeformTaskInfos, postTransitionVisibleFreeformTasks = postTransitionVisibleFreeformTasks, + newFocusedFreeformTask = getNewFocusedFreeformTask(info), ) wasPreviousTransitionExitToOverview = info.isExitToRecentsTransition() } @@ -161,6 +167,19 @@ class DesktopModeLoggerTransitionObserver( override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {} + // Returns null if there was no change in focused task + private fun getNewFocusedFreeformTask(info: TransitionInfo): TaskInfo? { + val freeformWindowChanges = + info.changes + .filter { it.taskInfo != null && it.requireTaskInfo().taskId != INVALID_TASK_ID } + .filter { it.requireTaskInfo().isFreeformWindow() } + return freeformWindowChanges + .findLast { change -> + change.hasFlags(FLAG_MOVED_TO_TOP) || change.mode == TRANSIT_OPEN + } + ?.taskInfo + } + private fun getPostTransitionVisibleFreeformTaskInfos( info: TransitionInfo ): SparseArray<TaskInfo> { @@ -238,6 +257,7 @@ class DesktopModeLoggerTransitionObserver( transitionInfo: TransitionInfo, preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, postTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, + newFocusedFreeformTask: TaskInfo?, ) { if ( postTransitionVisibleFreeformTasks.isEmpty() && @@ -250,6 +270,7 @@ class DesktopModeLoggerTransitionObserver( transitionInfo, preTransitionVisibleFreeformTasks, postTransitionVisibleFreeformTasks, + newFocusedFreeformTask, ) desktopModeEventLogger.logSessionExit(getExitReason(transitionInfo)) @@ -268,6 +289,7 @@ class DesktopModeLoggerTransitionObserver( transitionInfo, preTransitionVisibleFreeformTasks, postTransitionVisibleFreeformTasks, + newFocusedFreeformTask, ) } else if (isSessionActive) { // Session is neither starting, nor finishing, log task updates if there are any @@ -276,12 +298,14 @@ class DesktopModeLoggerTransitionObserver( transitionInfo, preTransitionVisibleFreeformTasks, postTransitionVisibleFreeformTasks, + newFocusedFreeformTask, ) } // update the state to the new version visibleFreeformTaskInfos.clear() visibleFreeformTaskInfos.putAll(postTransitionVisibleFreeformTasks) + focusedFreeformTask = newFocusedFreeformTask } /** Compare the old and new state of taskInfos and identify and log the changes */ @@ -290,10 +314,16 @@ class DesktopModeLoggerTransitionObserver( transitionInfo: TransitionInfo, preTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, postTransitionVisibleFreeformTasks: SparseArray<TaskInfo>, + newFocusedFreeformTask: TaskInfo?, ) { postTransitionVisibleFreeformTasks.forEach { taskId, taskInfo -> + val focusChangedReason = getFocusChangedReason(taskId, newFocusedFreeformTask) val currentTaskUpdate = - buildTaskUpdateForTask(taskInfo, postTransitionVisibleFreeformTasks.size()) + buildTaskUpdateForTask( + taskInfo, + postTransitionVisibleFreeformTasks.size(), + focusChangedReason = focusChangedReason, + ) val previousTaskInfo = preTransitionVisibleFreeformTasks[taskId] when { // new tasks added @@ -314,11 +344,14 @@ class DesktopModeLoggerTransitionObserver( postTransitionVisibleFreeformTasks.size().toString(), ) } + focusChangedReason != null -> + desktopModeEventLogger.logTaskInfoChanged(currentTaskUpdate) // old tasks that were resized or repositioned // TODO(b/347935387): Log changes only once they are stable. buildTaskUpdateForTask( previousTaskInfo, postTransitionVisibleFreeformTasks.size(), + focusChangedReason = focusChangedReason, ) != currentTaskUpdate -> desktopModeEventLogger.logTaskInfoChanged(currentTaskUpdate) } @@ -373,11 +406,21 @@ class DesktopModeLoggerTransitionObserver( return null } + private fun getFocusChangedReason( + taskId: Int, + newFocusedFreeformTask: TaskInfo?, + ): FocusReason? { + val newFocusedTask = newFocusedFreeformTask ?: return null + if (taskId != newFocusedTask.taskId) return null + return if (newFocusedTask != focusedFreeformTask) FocusReason.UNKNOWN else null + } + private fun buildTaskUpdateForTask( taskInfo: TaskInfo, visibleTasks: Int, minimizeReason: MinimizeReason? = null, unminimizeReason: UnminimizeReason? = null, + focusChangedReason: FocusReason? = null, ): TaskUpdate { val screenBounds = taskInfo.configuration.windowConfiguration.bounds val positionInParent = taskInfo.positionInParent @@ -393,6 +436,7 @@ class DesktopModeLoggerTransitionObserver( visibleTaskCount = visibleTasks, minimizeReason = minimizeReason, unminimizeReason = unminimizeReason, + focusReason = focusChangedReason, ) } @@ -475,6 +519,12 @@ class DesktopModeLoggerTransitionObserver( visibleFreeformTaskInfos.set(taskInfo.taskId, taskInfo) } + /** Sets the focused task - only used for testing. */ + @VisibleForTesting + fun setFocusedTaskForTesting(taskInfo: TaskInfo) { + focusedFreeformTask = taskInfo + } + private fun TransitionInfo.Change.requireTaskInfo(): RunningTaskInfo = this.taskInfo ?: throw IllegalStateException("Expected TaskInfo in the Change") diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt index 45d1281ba0e0..5757c6afd196 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt @@ -33,7 +33,6 @@ import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource import com.android.wm.shell.windowdecor.common.DecorThemeUtil -import com.android.wm.shell.windowdecor.common.Theme import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.TooltipColorScheme import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.TooltipEducationViewConfig diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java index 08211ab5df9c..cc962acf1182 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java @@ -370,7 +370,8 @@ class SplashscreenWindowCreator extends AbsSplashWindowCreator { private void removeWindowInner(@NonNull View decorView, boolean hideView) { requestTopUi(false); - if (!decorView.isAttachedToWindow()) { + if (decorView.getParent() == null) { + Slog.w(TAG, "This root view has no parent, never been added to a ViewRootImpl?"); return; } if (hideView) { diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppFromAllAppsTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppFromAllAppsTest.kt new file mode 100644 index 000000000000..61af4a5f82d4 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppFromAllAppsTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.functional + +import android.platform.test.annotations.Postsubmit +import com.android.wm.shell.scenarios.OpenAppFromAllApps +import org.junit.runner.RunWith +import org.junit.runners.BlockJUnit4ClassRunner + +/* Functional test for [OpenAppsInDesktopMode]. */ +@RunWith(BlockJUnit4ClassRunner::class) +@Postsubmit +class OpenAppFromAllAppsTest : OpenAppFromAllApps()
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppFromTaskbarTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppFromTaskbarTest.kt new file mode 100644 index 000000000000..bb5697e6ddfc --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/OpenAppFromTaskbarTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.functional + +import android.platform.test.annotations.Postsubmit +import com.android.wm.shell.scenarios.OpenAppFromTaskbar +import org.junit.runner.RunWith +import org.junit.runners.BlockJUnit4ClassRunner + +/* Functional test for [OpenAppsInDesktopMode]. */ +@RunWith(BlockJUnit4ClassRunner::class) +@Postsubmit +class OpenAppFromTaskbarTest : OpenAppFromTaskbar()
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnminimizeAppFromAllAppsTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnminimizeAppFromAllAppsTest.kt new file mode 100644 index 000000000000..0c681f94d7ef --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnminimizeAppFromAllAppsTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.functional + +import android.platform.test.annotations.Postsubmit +import com.android.wm.shell.scenarios.UnminimizeAppFromAllApps +import org.junit.runner.RunWith +import org.junit.runners.BlockJUnit4ClassRunner + +/* Functional test for [OpenAppsInDesktopMode]. */ +@RunWith(BlockJUnit4ClassRunner::class) +@Postsubmit +class UnminimizeAppFromAllAppsTest : UnminimizeAppFromAllApps()
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnminimizeAppFromTaskbarTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnminimizeAppFromTaskbarTest.kt new file mode 100644 index 000000000000..4e65ad092881 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/UnminimizeAppFromTaskbarTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.functional + +import android.platform.test.annotations.Postsubmit +import com.android.wm.shell.scenarios.UnminimizeAppFromTaskbar +import org.junit.runner.RunWith +import org.junit.runners.BlockJUnit4ClassRunner + +/* Functional test for [OpenAppsInDesktopMode]. */ +@RunWith(BlockJUnit4ClassRunner::class) +@Postsubmit +class UnminimizeAppFromTaskbarTest : UnminimizeAppFromTaskbar()
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppFromAllApps.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppFromAllApps.kt new file mode 100644 index 000000000000..36cdd5b26992 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppFromAllApps.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.scenarios + +import android.app.Instrumentation +import android.tools.NavBar +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.Rotation +import android.tools.traces.parsers.WindowManagerStateHelper +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.server.wm.flicker.helpers.DesktopModeAppHelper +import com.android.server.wm.flicker.helpers.MailAppHelper +import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.window.flags.Flags +import com.android.wm.shell.Utils +import org.junit.After +import org.junit.Assume +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test + +@Ignore("Test Base Class") +abstract class OpenAppFromAllApps(val rotation: Rotation = Rotation.ROTATION_0) { + + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val tapl = LauncherInstrumentation() + private val wmHelper = WindowManagerStateHelper(instrumentation) + private val device = UiDevice.getInstance(instrumentation) + private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation)) + private val mailApp = MailAppHelper(instrumentation) + + @Rule + @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) + + @Before + fun setup() { + Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) + tapl.enableTransientTaskbar(false) + ChangeDisplayOrientationRule.setRotation(rotation) + testApp.enterDesktopMode(wmHelper, device) + tapl.showTaskbarIfHidden() + } + + @Test + open fun openApp() { + tapl.launchedAppState.taskbar + .openAllApps() + .getAppIcon(mailApp.appName) + .launch(mailApp.packageName) + } + + @After + fun teardown() { + mailApp.exit(wmHelper) + testApp.exit(wmHelper) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppFromTaskbar.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppFromTaskbar.kt new file mode 100644 index 000000000000..2b456beff58f --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppFromTaskbar.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.scenarios + +import android.app.Instrumentation +import android.tools.NavBar +import android.tools.Rotation +import android.tools.device.apphelpers.BrowserAppHelper +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.server.wm.flicker.helpers.DesktopModeAppHelper +import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.window.flags.Flags +import com.android.wm.shell.Utils +import org.junit.After +import org.junit.Assume +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test + +@Ignore("Test Base Class") +abstract class OpenAppFromTaskbar(val rotation: Rotation = Rotation.ROTATION_0) { + + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val tapl = LauncherInstrumentation() + private val wmHelper = WindowManagerStateHelper(instrumentation) + private val device = UiDevice.getInstance(instrumentation) + private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation)) + private val browserApp = BrowserAppHelper(instrumentation) + + @Rule + @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) + + @Before + fun setup() { + Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) + tapl.enableTransientTaskbar(false) + ChangeDisplayOrientationRule.setRotation(rotation) + testApp.enterDesktopMode(wmHelper, device) + tapl.showTaskbarIfHidden() + } + + @Test + open fun openApp() { + tapl.launchedAppState.taskbar + .getAppIcon(browserApp.appName) + .launch(browserApp.packageName) + } + + @After + fun teardown() { + browserApp.exit(wmHelper) + testApp.exit(wmHelper) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromAllApps.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromAllApps.kt new file mode 100644 index 000000000000..234b984a6cff --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromAllApps.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.scenarios + +import android.app.Instrumentation +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.server.wm.flicker.helpers.DesktopModeAppHelper +import com.android.server.wm.flicker.helpers.MailAppHelper +import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.window.flags.Flags +import com.android.wm.shell.Utils +import org.junit.After +import org.junit.Assume +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test + +@Ignore("Test Base Class") +abstract class UnminimizeAppFromAllApps(val rotation: Rotation = Rotation.ROTATION_0) { + + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val tapl = LauncherInstrumentation() + private val wmHelper = WindowManagerStateHelper(instrumentation) + private val device = UiDevice.getInstance(instrumentation) + private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation)) + private val mailHelper = MailAppHelper(instrumentation) + private val mailApp = DesktopModeAppHelper(mailHelper) + + @Rule + @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) + + @Before + fun setup() { + Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) + tapl.enableTransientTaskbar(false) + ChangeDisplayOrientationRule.setRotation(rotation) + testApp.enterDesktopMode(wmHelper, device) + tapl.showTaskbarIfHidden() + mailApp.launchViaIntent(wmHelper) + mailApp.minimizeDesktopApp(wmHelper, device) + } + + @Test + open fun unminimizeApp() { + tapl.launchedAppState.taskbar + .openAllApps() + .getAppIcon(mailHelper.appName) + .launch(mailApp.packageName) + } + + @After + fun teardown() { + testApp.exit(wmHelper) + mailApp.exit(wmHelper) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromTaskbar.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromTaskbar.kt new file mode 100644 index 000000000000..3e98e4342b3f --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/UnminimizeAppFromTaskbar.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.scenarios + +import android.app.Instrumentation +import android.tools.NavBar +import android.tools.Rotation +import android.tools.device.apphelpers.BrowserAppHelper +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.server.wm.flicker.helpers.DesktopModeAppHelper +import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.window.flags.Flags +import com.android.wm.shell.Utils +import org.junit.After +import org.junit.Assume +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test + +@Ignore("Test Base Class") +abstract class UnminimizeAppFromTaskbar(val rotation: Rotation = Rotation.ROTATION_0) { + + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val tapl = LauncherInstrumentation() + private val wmHelper = WindowManagerStateHelper(instrumentation) + private val device = UiDevice.getInstance(instrumentation) + private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation)) + private val browserHelper = BrowserAppHelper(instrumentation) + private val browserApp = DesktopModeAppHelper(browserHelper) + + @Rule + @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) + + @Before + fun setup() { + Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) + tapl.enableTransientTaskbar(false) + ChangeDisplayOrientationRule.setRotation(rotation) + testApp.enterDesktopMode(wmHelper, device) + tapl.showTaskbarIfHidden() + browserApp.launchViaIntent(wmHelper) + browserApp.minimizeDesktopApp(wmHelper, device) + } + + @Test + open fun unminimizeApp() { + tapl.launchedAppState.taskbar + .getAppIcon(browserHelper.appName) + .launch(browserHelper.packageName) + } + + @After + fun teardown() { + testApp.exit(wmHelper) + browserApp.exit(wmHelper) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index a6f8150ffc55..e51fa45c3010 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt @@ -27,6 +27,7 @@ import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.helpers.WindowUtils import android.tools.traces.component.ComponentNameMatcher +import android.view.WindowManagerGlobal import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper @@ -38,13 +39,12 @@ import com.android.wm.shell.flicker.pip.common.PipTransition import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized +import java.lang.AssertionError /** * Test entering pip while changing orientation (from app in landscape to pip window in portrait) @@ -75,7 +75,15 @@ import org.junit.runners.Parameterized open class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) { override val pipApp: PipAppHelper = PipAppHelper(instrumentation) internal val testApp = FixedOrientationAppHelper(instrumentation) - internal val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) + internal val ignoreOrientationRequest = WindowManagerGlobal.getWindowManagerService() + ?.getIgnoreOrientationRequest(WindowUtils.defaultDisplayId) + ?: throw AssertionError("WMS must not be null.") + internal val startingBounds = if (ignoreOrientationRequest) { + // If the device chooses to ignore orientation request, use the current display bounds. + WindowUtils.getDisplayBounds(Rotation.ROTATION_0) + } else { + WindowUtils.getDisplayBounds(Rotation.ROTATION_90) + } private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) override val thisTransition: FlickerBuilder.() -> Unit = { @@ -167,20 +175,14 @@ open class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransitio @Presubmit @Test open fun pipAppLayerCoversFullScreenOnStart() { - assumeFalse(tapl.isTablet) - flicker.assertLayersStart { visibleRegion(pipApp).coversExactly(startingBounds) } - } - - /** - * Checks that the visible region of [pipApp] covers the full display area at the start of the - * transition - */ - @Ignore("TODO(b/356277166): enable the tablet test") - @Test - open fun pipAppLayerPlusLetterboxCoversFullScreenOnStartTablet() { - assumeTrue(tapl.isTablet) flicker.assertLayersStart { - visibleRegion(pipApp.or(ComponentNameMatcher.LETTERBOX)).coversExactly(startingBounds) + visibleRegion( + if (ignoreOrientationRequest) { + pipApp.or(ComponentNameMatcher.LETTERBOX) + } else { + pipApp + } + ).coversExactly(startingBounds) } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipToOtherOrientation.kt index d65f158e00d6..676c9a4c7d8f 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipToOtherOrientation.kt @@ -26,10 +26,7 @@ import com.android.server.wm.flicker.helpers.BottomHalfPipAppHelper import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.EnterPipToOtherOrientation -import org.junit.Assume.assumeFalse -import org.junit.Assume.assumeTrue import org.junit.FixMethodOrder -import org.junit.Ignore import org.junit.Test import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -71,19 +68,14 @@ class BottomHalfEnterPipToOtherOrientation(flicker: LegacyFlickerTest) : @Test override fun pipAppLayerCoversFullScreenOnStart() { // Test app and pip app should covers the entire screen on start. - assumeFalse(tapl.isTablet) flicker.assertLayersStart { - visibleRegion(pipApp.or(testApp)).coversExactly(startingBounds) - } - } - - @Ignore("TODO(b/356277166): enable the tablet test") - @Test - override fun pipAppLayerPlusLetterboxCoversFullScreenOnStartTablet() { - // Test app and pip app should covers the entire screen on start. - assumeTrue(tapl.isTablet) - flicker.assertLayersStart { - visibleRegion(pipApp.or(ComponentNameMatcher.LETTERBOX)).coversExactly(startingBounds) + visibleRegion( + if (ignoreOrientationRequest) { + pipApp.or(testApp).or(ComponentNameMatcher.LETTERBOX) + } else { + pipApp.or(testApp) + } + ).coversExactly(startingBounds) } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt index eb6f1d75e6ca..bddc06204a52 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt @@ -35,12 +35,14 @@ import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.FocusReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.NO_SESSION_ID import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskSizeUpdate import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UNSET_FOCUS_REASON import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UNSET_MINIMIZE_REASON import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UNSET_UNMINIMIZE_REASON import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason @@ -188,6 +190,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { UNSET_MINIMIZE_REASON, UNSET_UNMINIMIZE_REASON, TASK_COUNT, + UNSET_FOCUS_REASON, ) verify { EventLogTags.writeWmShellDesktopModeTaskUpdate( @@ -202,6 +205,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { eq(UNSET_MINIMIZE_REASON), eq(UNSET_UNMINIMIZE_REASON), eq(TASK_COUNT), + eq(UNSET_FOCUS_REASON), ) } verifyZeroInteractions(staticMockMarker(EventLogTags::class.java)) @@ -233,6 +237,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { UNSET_MINIMIZE_REASON, UNSET_UNMINIMIZE_REASON, TASK_COUNT, + UNSET_FOCUS_REASON, ) verify { EventLogTags.writeWmShellDesktopModeTaskUpdate( @@ -247,6 +252,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { eq(UNSET_MINIMIZE_REASON), eq(UNSET_UNMINIMIZE_REASON), eq(TASK_COUNT), + eq(UNSET_FOCUS_REASON), ) } verifyZeroInteractions(staticMockMarker(EventLogTags::class.java)) @@ -278,6 +284,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { UNSET_MINIMIZE_REASON, UNSET_UNMINIMIZE_REASON, TASK_COUNT, + UNSET_FOCUS_REASON, ) verify { EventLogTags.writeWmShellDesktopModeTaskUpdate( @@ -295,6 +302,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { eq(UNSET_MINIMIZE_REASON), eq(UNSET_UNMINIMIZE_REASON), eq(TASK_COUNT), + eq(UNSET_FOCUS_REASON), ) } verifyZeroInteractions(staticMockMarker(EventLogTags::class.java)) @@ -320,6 +328,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { MinimizeReason.TASK_LIMIT.reason, UNSET_UNMINIMIZE_REASON, TASK_COUNT, + UNSET_FOCUS_REASON, ) verify { EventLogTags.writeWmShellDesktopModeTaskUpdate( @@ -337,6 +346,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { eq(MinimizeReason.TASK_LIMIT.reason), eq(UNSET_UNMINIMIZE_REASON), eq(TASK_COUNT), + eq(UNSET_FOCUS_REASON), ) } verifyZeroInteractions(staticMockMarker(EventLogTags::class.java)) @@ -362,6 +372,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { UNSET_MINIMIZE_REASON, UnminimizeReason.TASKBAR_TAP.reason, TASK_COUNT, + UNSET_FOCUS_REASON, ) verify { EventLogTags.writeWmShellDesktopModeTaskUpdate( @@ -379,6 +390,51 @@ class DesktopModeEventLoggerTest : ShellTestCase() { eq(UNSET_MINIMIZE_REASON), eq(UnminimizeReason.TASKBAR_TAP.reason), eq(TASK_COUNT), + eq(UNSET_FOCUS_REASON), + ) + } + verifyZeroInteractions(staticMockMarker(EventLogTags::class.java)) + } + + @Test + fun logTaskInfoChanged_logsTaskUpdateWithFocusReason() { + val sessionId = startDesktopModeSession() + + desktopModeEventLogger.logTaskInfoChanged( + createTaskUpdate(focusChangesReason = FocusReason.UNKNOWN) + ) + + verifyOnlyOneTaskUpdateLogging( + FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED, + TASK_UPDATE.instanceId, + TASK_UPDATE.uid, + TASK_UPDATE.taskHeight, + TASK_UPDATE.taskWidth, + TASK_UPDATE.taskX, + TASK_UPDATE.taskY, + sessionId, + UNSET_MINIMIZE_REASON, + UNSET_UNMINIMIZE_REASON, + TASK_COUNT, + FocusReason.UNKNOWN.reason, + ) + verify { + EventLogTags.writeWmShellDesktopModeTaskUpdate( + eq( + FrameworkStatsLog + .DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED + ), + eq(TASK_UPDATE.instanceId), + eq(TASK_UPDATE.uid), + eq(TASK_UPDATE.taskHeight), + eq(TASK_UPDATE.taskWidth), + eq(TASK_UPDATE.taskX), + eq(TASK_UPDATE.taskY), + eq(sessionId), + eq(UNSET_MINIMIZE_REASON), + eq(UNSET_UNMINIMIZE_REASON), + eq(TASK_COUNT), + eq(FocusReason.UNKNOWN.reason), ) } verifyZeroInteractions(staticMockMarker(EventLogTags::class.java)) @@ -497,6 +553,8 @@ class DesktopModeEventLoggerTest : ShellTestCase() { eq(UNSET_UNMINIMIZE_REASON), /* visible_task_count */ eq(0), + /* focus_reason */ + eq(UNSET_FOCUS_REASON), ) } } @@ -536,6 +594,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { anyInt(), anyInt(), anyInt(), + anyInt(), ) }, never(), @@ -597,6 +656,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { minimizeReason: Int, unminimizeReason: Int, visibleTaskCount: Int, + focusChangedReason: Int, ) { verify({ FrameworkStatsLog.write( @@ -612,6 +672,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { eq(minimizeReason), eq(unminimizeReason), eq(visibleTaskCount), + eq(focusChangedReason), ) }) verify({ @@ -628,6 +689,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { anyInt(), anyInt(), anyInt(), + anyInt(), ) }) } @@ -710,6 +772,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { private fun createTaskUpdate( minimizeReason: MinimizeReason? = null, unminimizeReason: UnminimizeReason? = null, + focusChangesReason: FocusReason? = null, ) = TaskUpdate( TASK_ID, @@ -721,6 +784,7 @@ class DesktopModeEventLoggerTest : ShellTestCase() { minimizeReason, unminimizeReason, TASK_COUNT, + focusChangesReason, ) } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt index 2e9d6d95eebb..b7d25b5255f8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserverTest.kt @@ -38,6 +38,7 @@ import android.view.WindowManager.TRANSIT_WAKE import android.window.IWindowContainerToken import android.window.TransitionInfo import android.window.TransitionInfo.Change +import android.window.TransitionInfo.FLAG_MOVED_TO_TOP import android.window.WindowContainerToken import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito @@ -47,6 +48,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.FocusReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.MinimizeReason import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason @@ -175,7 +177,7 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() { verifyTaskAddedAndEnterLogging( EnterReason.APP_FREEFORM_INTENT, - DEFAULT_TASK_UPDATE.copy(visibleTaskCount = 1), + DEFAULT_TASK_UPDATE.copy(visibleTaskCount = 1, focusReason = FocusReason.UNKNOWN), ) } @@ -635,7 +637,15 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() { callOnTransitionReady(transitionInfo) verify(desktopModeEventLogger, times(1)) - .logTaskAdded(eq(DEFAULT_TASK_UPDATE.copy(instanceId = 2, visibleTaskCount = 2))) + .logTaskAdded( + eq( + DEFAULT_TASK_UPDATE.copy( + instanceId = 2, + visibleTaskCount = 2, + focusReason = FocusReason.UNKNOWN, + ) + ) + ) verify(desktopModeEventLogger, never()).logSessionEnter(any()) } @@ -695,6 +705,34 @@ class DesktopModeLoggerTransitionObserverTest : ShellTestCase() { } @Test + fun sessionAlreadyStarted_taskFocusChanged_logsTaskUpdate() { + val taskInfo1 = createTaskInfo(WINDOWING_MODE_FREEFORM, id = 1) + val taskInfo2 = createTaskInfo(WINDOWING_MODE_FREEFORM, id = 2) + transitionObserver.addTaskInfosToCachedMap(taskInfo1) + transitionObserver.addTaskInfosToCachedMap(taskInfo2) + transitionObserver.isSessionActive = true + transitionObserver.setFocusedTaskForTesting(taskInfo1) + + val task2FocusedChange = createChange(TRANSIT_CHANGE, taskInfo2) + task2FocusedChange.flags = FLAG_MOVED_TO_TOP + val transitionInfo = + TransitionInfoBuilder(TRANSIT_CHANGE, 0).addChange(task2FocusedChange).build() + callOnTransitionReady(transitionInfo) + + verify(desktopModeEventLogger, times(1)) + .logTaskInfoChanged( + eq( + DEFAULT_TASK_UPDATE.copy( + instanceId = 2, + visibleTaskCount = 2, + focusReason = FocusReason.UNKNOWN, + ) + ) + ) + verifyZeroInteractions(desktopModeEventLogger) + } + + @Test fun sessionAlreadyStarted_multipleTasksUpdated_logsTaskUpdateForCorrectTask() { // add 2 existing freeform task val taskInfo1 = createTaskInfo(WINDOWING_MODE_FREEFORM) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java index 6d18e3696f84..b11715b669f4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java @@ -16,12 +16,16 @@ package com.android.wm.shell.pip.phone; +import static com.android.wm.shell.Flags.FLAG_ENABLE_PIP2; + import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.graphics.Rect; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Size; @@ -45,6 +49,7 @@ import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.sysui.ShellInit; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -63,6 +68,8 @@ import java.util.Optional; @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) public class PipTouchHandlerTest extends ShellTestCase { + @Rule + public SetFlagsRule setFlagsRule = new SetFlagsRule(); private static final int INSET = 10; private static final int PIP_LENGTH = 100; @@ -150,6 +157,7 @@ public class PipTouchHandlerTest extends ShellTestCase { } @Test + @DisableFlags(FLAG_ENABLE_PIP2) public void instantiate_addInitCallback() { verify(mShellInit, times(1)).addInitCallback(any(), any()); } diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java index 73728bcd1ff7..7bd4b3f771ab 100644 --- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java +++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java @@ -240,6 +240,11 @@ public class MainSwitchBar extends LinearLayout implements OnCheckedChangeListen } } + /** Removes all [OnCheckedChangeListener]s. */ + public void removeAllOnSwitchChangeListeners() { + mSwitchChangeListeners.clear(); + } + /** * Remove a listener for switch changes */ diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java index 83858d9c9c54..d883fb0594e6 100644 --- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java +++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java @@ -17,12 +17,13 @@ package com.android.settingslib.widget; import android.content.Context; -import android.content.res.TypedArray; import android.os.Build; import android.util.AttributeSet; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.preference.PreferenceViewHolder; import androidx.preference.TwoStatePreference; @@ -34,124 +35,67 @@ import java.util.List; /** * MainSwitchPreference is a Preference with a customized Switch. * This component is used as the main switch of the page - * to enable or disable the prefereces on the page. + * to enable or disable the preferences on the page. */ -public class MainSwitchPreference extends TwoStatePreference - implements OnCheckedChangeListener, GroupSectionDividerMixin { +public class MainSwitchPreference extends TwoStatePreference implements OnCheckedChangeListener, + GroupSectionDividerMixin { private final List<OnCheckedChangeListener> mSwitchChangeListeners = new ArrayList<>(); - private MainSwitchBar mMainSwitchBar; - - public MainSwitchPreference(Context context) { - super(context); - init(context, null); + public MainSwitchPreference(@NonNull Context context) { + this(context, null); } - public MainSwitchPreference(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs); + public MainSwitchPreference(@NonNull Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); } - public MainSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs); + public MainSwitchPreference(@NonNull Context context, @Nullable AttributeSet attrs, + int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); } - public MainSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, - int defStyleRes) { + public MainSwitchPreference(@NonNull Context context, @Nullable AttributeSet attrs, + int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - init(context, attrs); + boolean isExpressive = SettingsThemeHelper.isExpressiveTheme(context); + int resId = isExpressive ? R.layout.settingslib_expressive_main_switch_layout + : R.layout.settingslib_main_switch_layout; + setLayoutResource(resId); } @Override - public void onBindViewHolder(PreferenceViewHolder holder) { + public void onBindViewHolder(@NonNull PreferenceViewHolder holder) { super.onBindViewHolder(holder); holder.setDividerAllowedAbove(false); holder.setDividerAllowedBelow(false); - mMainSwitchBar = (MainSwitchBar) holder.findViewById(R.id.settingslib_main_switch_bar); + MainSwitchBar mainSwitchBar = holder.itemView.requireViewById( + R.id.settingslib_main_switch_bar); + mainSwitchBar.setTitle(getTitle()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + mainSwitchBar.setSummary(getSummary()); + } + mainSwitchBar.setIconSpaceReserved(isIconSpaceReserved()); // To support onPreferenceChange callback, it needs to call callChangeListener() when // MainSwitchBar is clicked. - mMainSwitchBar.setOnClickListener((view) -> callChangeListener(isChecked())); - setIconSpaceReserved(isIconSpaceReserved()); - updateStatus(isChecked()); - registerListenerToSwitchBar(); - } + mainSwitchBar.setOnClickListener(view -> callChangeListener(isChecked())); - private void init(Context context, AttributeSet attrs) { - boolean isExpressive = SettingsThemeHelper.isExpressiveTheme(context); - int resId = isExpressive - ? R.layout.settingslib_expressive_main_switch_layout - : R.layout.settingslib_main_switch_layout; - setLayoutResource(resId); - mSwitchChangeListeners.add(this); - if (attrs != null) { - final TypedArray a = context.obtainStyledAttributes(attrs, - androidx.preference.R.styleable.Preference, 0 /*defStyleAttr*/, - 0 /*defStyleRes*/); - final CharSequence title = a.getText( - androidx.preference.R.styleable.Preference_android_title); - setTitle(title); - - CharSequence summary = a.getText( - androidx.preference.R.styleable.Preference_android_summary); - setSummary(summary); - - final boolean bIconSpaceReserved = a.getBoolean( - androidx.preference.R.styleable.Preference_android_iconSpaceReserved, true); - setIconSpaceReserved(bIconSpaceReserved); - a.recycle(); - } - } + // Remove all listeners to 1. avoid triggering listener when update UI 2. prevent potential + // listener leaking when the view holder is reused by RecyclerView + mainSwitchBar.removeAllOnSwitchChangeListeners(); + mainSwitchBar.setChecked(isChecked()); + mainSwitchBar.addOnSwitchChangeListener(this); - @Override - public void setChecked(boolean checked) { - super.setChecked(checked); - if (mMainSwitchBar != null && mMainSwitchBar.isChecked() != checked) { - mMainSwitchBar.setChecked(checked); - } - } - - @Override - public void setTitle(CharSequence title) { - super.setTitle(title); - if (mMainSwitchBar != null) { - mMainSwitchBar.setTitle(title); - } - } - - @Override - public void setSummary(CharSequence summary) { - super.setSummary(summary); - if (mMainSwitchBar != null - && Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { - mMainSwitchBar.setSummary(summary); - } - } - - @Override - public void setIconSpaceReserved(boolean iconSpaceReserved) { - super.setIconSpaceReserved(iconSpaceReserved); - if (mMainSwitchBar != null) { - mMainSwitchBar.setIconSpaceReserved(iconSpaceReserved); - } + mainSwitchBar.show(); } @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { super.setChecked(isChecked); - } - - /** - * Update the switch status of preference - */ - public void updateStatus(boolean checked) { - setChecked(checked); - if (mMainSwitchBar != null) { - mMainSwitchBar.setTitle(getTitle()); - mMainSwitchBar.show(); + for (OnCheckedChangeListener listener : mSwitchChangeListeners) { + listener.onCheckedChanged(buttonView, isChecked); } } @@ -162,10 +106,6 @@ public class MainSwitchPreference extends TwoStatePreference if (!mSwitchChangeListeners.contains(listener)) { mSwitchChangeListeners.add(listener); } - - if (mMainSwitchBar != null) { - mMainSwitchBar.addOnSwitchChangeListener(listener); - } } /** @@ -173,14 +113,5 @@ public class MainSwitchPreference extends TwoStatePreference */ public void removeOnSwitchChangeListener(OnCheckedChangeListener listener) { mSwitchChangeListeners.remove(listener); - if (mMainSwitchBar != null) { - mMainSwitchBar.removeOnSwitchChangeListener(listener); - } - } - - private void registerListenerToSwitchBar() { - for (OnCheckedChangeListener listener : mSwitchChangeListeners) { - mMainSwitchBar.addOnSwitchChangeListener(listener); - } } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt index 2078b363f434..1deb62510daf 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt @@ -67,7 +67,7 @@ class SatelliteDialogUtilsTest { @Test @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) - fun mayStartSatelliteWarningDialog_satelliteIsOn_showWarningDialog() = runBlocking { + fun mayStartSatelliteWarningDialog_satelliteIsOn_showWarningDialog(): Unit = runBlocking { `when`(satelliteManager.registerForModemStateChanged(any(), any())) .thenAnswer { invocation -> val callback = invocation diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java index c2e81bd7d54c..a47b4d5c354f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java @@ -23,6 +23,7 @@ import android.view.View; import android.widget.TextView; import androidx.preference.PreferenceViewHolder; +import androidx.test.core.app.ApplicationProvider; import com.android.settingslib.widget.mainswitch.R; @@ -30,19 +31,17 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class MainSwitchPreferenceTest { - private Context mContext; + private final Context mContext = ApplicationProvider.getApplicationContext(); private View mRootView; private PreferenceViewHolder mHolder; private MainSwitchPreference mPreference; @Before public void setUp() { - mContext = RuntimeEnvironment.application; mRootView = View.inflate(mContext, R.layout.settingslib_main_switch_layout, null /* parent */); mHolder = PreferenceViewHolder.createInstanceForTests(mRootView); @@ -50,23 +49,22 @@ public class MainSwitchPreferenceTest { } @Test - public void setTitle_shouldUpdateTitle() { + public void onBindViewHolder_title() { final String defaultOnText = "Test title"; - mPreference.onBindViewHolder(mHolder); mPreference.setTitle(defaultOnText); - mPreference.updateStatus(true /* checked */); + mPreference.onBindViewHolder(mHolder); - assertThat(((TextView) mRootView.findViewById(R.id.switch_text)).getText()) - .isEqualTo(defaultOnText); + assertThat(mRootView.<TextView>requireViewById( + R.id.switch_text).getText().toString()).isEqualTo(defaultOnText); } @Test - public void updateStatus_shouldMatchTheStatus() { + public void onBindViewHolder_checked() { + mPreference.setChecked(true); mPreference.onBindViewHolder(mHolder); - mPreference.updateStatus(true); - assertThat(mPreference.isChecked()).isTrue(); + assertThat(mRootView.<MainSwitchBar>requireViewById( + R.id.settingslib_main_switch_bar).isChecked()).isTrue(); } - } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index c1c3e04d46fd..14b2dfe414a4 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -214,6 +214,17 @@ public class SettingsBackupAgent extends BackupAgentHelper { "failed_to_restore_softap_config"; private static final String ERROR_FAILED_TO_RESTORE_WIFI_CONFIG = "failed_to_restore_wifi_config"; + private static final String ERROR_FAILED_TO_RESTORE_SIM_SPECIFIC_SETTINGS = + "failed_to_restore_sim_specific_settings"; + private static final String ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES = + "failed_to_convert_network_policies"; + private static final String ERROR_UNKNOWN_BACKUP_SERIALIZATION_VERSION = + "unknown_backup_serialization_version"; + private static final String INTERRUPTED_EXCEPTION = "interrupted_exception"; + private static final String ERROR_FAILED_TO_RETRIEVE_WIFI_SETTINGS_BACKUP_DATA = + "failed_to_retrieve_wifi_settings_backup_data"; + private static final String ERROR_FAILED_TO_RESTORE_WIFI_SETTINGS_BACKUP_DATA = + "failed_to_restore_wifi_settings_backup_data"; // Name of the temporary file we use during full backup/restore. This is @@ -1436,6 +1447,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { try { out.writeInt(NETWORK_POLICIES_BACKUP_VERSION); out.writeInt(policies.length); + int numberOfPoliciesBackedUp = 0; for (NetworkPolicy policy : policies) { // We purposefully only backup policies that the user has // defined; any inferred policies might include @@ -1445,13 +1457,25 @@ public class SettingsBackupAgent extends BackupAgentHelper { out.writeByte(BackupUtils.NOT_NULL); out.writeInt(marshaledPolicy.length); out.write(marshaledPolicy); + if (areAgentMetricsEnabled) { + numberOfPoliciesBackedUp++; + } } else { out.writeByte(BackupUtils.NULL); } } + if (areAgentMetricsEnabled) { + numberOfSettingsPerKey.put(KEY_NETWORK_POLICIES, numberOfPoliciesBackedUp); + } } catch (IOException ioe) { Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage()); baos.reset(); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsBackupFailed( + KEY_NETWORK_POLICIES, + policies.length, + ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES); + } } } return baos.toByteArray(); @@ -1502,6 +1526,12 @@ public class SettingsBackupAgent extends BackupAgentHelper { try { int version = in.readInt(); if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) { + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + KEY_NETWORK_POLICIES, + /* count= */ 1, + ERROR_UNKNOWN_BACKUP_SERIALIZATION_VERSION); + } throw new BackupUtils.BadVersionException( "Unknown Backup Serialization Version"); } @@ -1518,10 +1548,20 @@ public class SettingsBackupAgent extends BackupAgentHelper { } // Only set the policies if there was no error in the restore operation networkPolicyManager.setNetworkPolicies(policies); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger + .logItemsRestored(KEY_NETWORK_POLICIES, policies.length); + } } catch (NullPointerException | IOException | BackupUtils.BadVersionException | DateTimeException e) { // NPE can be thrown when trying to instantiate a NetworkPolicy Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage()); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + KEY_NETWORK_POLICIES, + /* count= */ 1, + ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES); + } } } } @@ -1592,7 +1632,8 @@ public class SettingsBackupAgent extends BackupAgentHelper { return true; } - private byte[] getSimSpecificSettingsData() { + @VisibleForTesting + byte[] getSimSpecificSettingsData() { byte[] simSpecificData = new byte[0]; PackageManager packageManager = getBaseContext().getPackageManager(); if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { @@ -1600,17 +1641,36 @@ public class SettingsBackupAgent extends BackupAgentHelper { simSpecificData = subManager.getAllSimSpecificSettingsForBackup(); Log.i(TAG, "sim specific data of length + " + simSpecificData.length + " successfully retrieved"); + if (areAgentMetricsEnabled) { + // We're unable to determine how many settings this includes, so we'll just log 1. + numberOfSettingsPerKey.put(KEY_SIM_SPECIFIC_SETTINGS_2, 1); + } } return simSpecificData; } - private void restoreSimSpecificSettings(byte[] data) { + @VisibleForTesting + void restoreSimSpecificSettings(byte[] data) { PackageManager packageManager = getBaseContext().getPackageManager(); boolean hasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); if (hasTelephony) { SubscriptionManager subManager = SubscriptionManager.from(getBaseContext()); - subManager.restoreAllSimSpecificSettingsFromBackup(data); + if (areAgentMetricsEnabled) { + try { + subManager.restoreAllSimSpecificSettingsFromBackup(data); + mBackupRestoreEventLogger + .logItemsRestored(KEY_SIM_SPECIFIC_SETTINGS_2, /* count= */ 1); + } catch (Exception e) { + mBackupRestoreEventLogger + .logItemsRestoreFailed( + KEY_SIM_SPECIFIC_SETTINGS_2, + /* count= */ 1, + ERROR_FAILED_TO_RESTORE_SIM_SPECIFIC_SETTINGS); + } + } else { + subManager.restoreAllSimSpecificSettingsFromBackup(data); + } } } @@ -1637,20 +1697,49 @@ public class SettingsBackupAgent extends BackupAgentHelper { }); // cts requires B&R with 10 seconds if (latch.await(10, TimeUnit.SECONDS) && backupWifiData.value != null) { + if (areAgentMetricsEnabled) { + numberOfSettingsPerKey.put(KEY_WIFI_SETTINGS_BACKUP_DATA, 1); + } return backupWifiData.value; } } catch (InterruptedException ie) { Log.e(TAG, "fail to retrieveWifiBackupData, " + ie); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsBackupFailed( + KEY_WIFI_SETTINGS_BACKUP_DATA, + /* count= */ 1, + INTERRUPTED_EXCEPTION); + } } Log.e(TAG, "fail to retrieveWifiBackupData"); + if (areAgentMetricsEnabled) { + mBackupRestoreEventLogger.logItemsBackupFailed( + KEY_WIFI_SETTINGS_BACKUP_DATA, + /* count= */ 1, + ERROR_FAILED_TO_RETRIEVE_WIFI_SETTINGS_BACKUP_DATA); + } return new byte[0]; } - private void restoreWifiData(byte[] data) { + @VisibleForTesting + void restoreWifiData(byte[] data) { if (DEBUG_BACKUP) { Log.v(TAG, "Applying restored all wifi data"); } - mWifiManager.restoreWifiBackupData(data); + if (areAgentMetricsEnabled) { + try { + mWifiManager.restoreWifiBackupData(data); + mBackupRestoreEventLogger.logItemsRestored( + KEY_WIFI_SETTINGS_BACKUP_DATA, /* count= */ 1); + } catch (Exception e) { + mBackupRestoreEventLogger.logItemsRestoreFailed( + KEY_WIFI_SETTINGS_BACKUP_DATA, + /* count= */ 1, + ERROR_FAILED_TO_RESTORE_WIFI_SETTINGS_BACKUP_DATA); + } + } else { + mWifiManager.restoreWifiBackupData(data); + } } private void updateWindowManagerIfNeeded(Integer previousDensity) { diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java index 6e5b602c02c5..48c360b635ea 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java @@ -18,6 +18,8 @@ package com.android.providers.settings; import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_WIFI_NEW_CONFIG; import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SOFTAP_CONFIG; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_SIM_SPECIFIC_SETTINGS_2; +import static com.android.providers.settings.SettingsBackupRestoreKeys.KEY_WIFI_SETTINGS_BACKUP_DATA; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; @@ -59,6 +61,7 @@ import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.provider.settings.validators.SettingsValidators; import android.provider.settings.validators.Validator; +import android.telephony.SubscriptionManager; import android.test.mock.MockContentProvider; import android.test.mock.MockContentResolver; @@ -136,6 +139,7 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { @Mock private BackupDataInput mBackupDataInput; @Mock private BackupDataOutput mBackupDataOutput; @Mock private static WifiManager mWifiManager; + @Mock private static SubscriptionManager mSubscriptionManager; private TestFriendlySettingsBackupAgent mAgentUnderTest; private Context mContext; @@ -906,6 +910,110 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { assertNull(getLoggingResultForDatatype(KEY_WIFI_NEW_CONFIG, mAgentUnderTest)); } + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + getSimSpecificSettingsData_agentMetricsAreEnabled_numberOfSettingsInKeyAreRecorded() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.BACKUP); + when(mSubscriptionManager.getAllSimSpecificSettingsForBackup()).thenReturn(new byte[0]); + + mAgentUnderTest.getSimSpecificSettingsData(); + + assertEquals(mAgentUnderTest.getNumberOfSettingsPerKey(KEY_SIM_SPECIFIC_SETTINGS_2), 1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreSimSpecificSettings_agentMetricsAreEnabled_restoreIsSuccessful_successMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doNothing().when(mSubscriptionManager).restoreAllSimSpecificSettingsFromBackup(any()); + + mAgentUnderTest.restoreSimSpecificSettings(new byte[0]); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_SIM_SPECIFIC_SETTINGS_2, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreSimSpecificSettings_agentMetricsAreEnabled_restoreIsNotSuccessful_failureMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doThrow(new RuntimeException()) + .when(mSubscriptionManager) + .restoreAllSimSpecificSettingsFromBackup(any()); + + mAgentUnderTest.restoreSimSpecificSettings(new byte[0]); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_SIM_SPECIFIC_SETTINGS_2, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + } + + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreSimSpecificSettings_agentMetricsAreNotEnabled_metricsAreNotLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doNothing().when(mSubscriptionManager).restoreAllSimSpecificSettingsFromBackup(any()); + + mAgentUnderTest.restoreSimSpecificSettings(new byte[0]); + + assertNull(getLoggingResultForDatatype(KEY_SIM_SPECIFIC_SETTINGS_2, mAgentUnderTest)); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreWifiData_agentMetricsAreEnabled_restoreIsSuccessful_successMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doNothing().when(mWifiManager).restoreWifiBackupData(any()); + + mAgentUnderTest.restoreWifiData(new byte[0]); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_WIFI_SETTINGS_BACKUP_DATA, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getSuccessCount(), 1); + } + + @Test + @EnableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void + restoreWifiData_agentMetricsAreEnabled_restoreIsNotSuccessful_failureMetricsAreLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doThrow(new RuntimeException()).when(mWifiManager).restoreWifiBackupData(any()); + + mAgentUnderTest.restoreWifiData(new byte[0]); + + DataTypeResult loggingResult = + getLoggingResultForDatatype(KEY_WIFI_SETTINGS_BACKUP_DATA, mAgentUnderTest); + assertNotNull(loggingResult); + assertEquals(loggingResult.getFailCount(), 1); + } + + @Test + @DisableFlags(com.android.server.backup.Flags.FLAG_ENABLE_METRICS_SETTINGS_BACKUP_AGENTS) + public void restoreWifiData_agentMetricsAreDisabled_metricsAreNotLogged() { + mAgentUnderTest.onCreate( + UserHandle.SYSTEM, BackupDestination.CLOUD, OperationType.RESTORE); + doNothing().when(mWifiManager).restoreWifiBackupData(any()); + + mAgentUnderTest.restoreWifiData(new byte[0]); + + assertNull(getLoggingResultForDatatype(KEY_WIFI_SETTINGS_BACKUP_DATA, mAgentUnderTest)); + } + private byte[] generateBackupData(Map<String, String> keyValueData) { int totalBytes = 0; for (String key : keyValueData.keySet()) { @@ -1106,10 +1214,14 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest { @Override public Object getSystemService(String name) { - if (name.equals(Context.WIFI_SERVICE)) { - return mWifiManager; + switch (name) { + case Context.WIFI_SERVICE: + return mWifiManager; + case Context.TELEPHONY_SUBSCRIPTION_SERVICE: + return mSubscriptionManager; + default: + return super.getSystemService(name); } - return super.getSystemService(name); } } diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index f753316cb67a..d1a0d582d4d7 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1946,4 +1946,14 @@ flag { namespace: "systemui" description: "Show a rich ongoing notification on the always-on display (depends on ui_rich_ongoing)" bug: "369151941" +} + +flag { + name: "stabilize_heads_up_group_v2" + namespace: "systemui" + description: "Stabilize heads up groups in VisualStabilityCoordinator" + bug: "357753857" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt index 215a43382b06..6e9e8efea894 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt @@ -41,8 +41,8 @@ object MediaContentPicker : StaticElementContentPicker { override fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey { return when { transition.isTransitioningBetween(Scenes.Lockscreen, Scenes.Shade) -> { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt index 019639da48c5..b4c60037b426 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt @@ -17,8 +17,11 @@ package com.android.systemui.scene.ui.composable.transitions import androidx.compose.animation.core.tween +import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.TransitionBuilder +import com.android.compose.animation.scene.UserActionDistance +import com.android.compose.animation.scene.UserActionDistanceScope import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.notifications.ui.composable.NotificationsShade @@ -28,6 +31,10 @@ import kotlin.time.Duration.Companion.milliseconds fun TransitionBuilder.toNotificationsShadeTransition(durationScale: Double = 1.0) { spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt()) + distance = UserActionDistance { _, shadeContentKey, _ -> + calculateShadePanelTargetPositionY(shadeContentKey) + } + // Ensure the clock isn't clipped by the shade outline during the transition from lockscreen. sharedElement( ClockElementKeys.smallClockElementKey, @@ -43,4 +50,12 @@ fun TransitionBuilder.toNotificationsShadeTransition(durationScale: Double = 1.0 fractionRange(start = .5f) { fade(Notifications.Elements.NotificationScrim) } } +/** Returns the Y position of the bottom of the shade container panel within [shadeOverlayKey]. */ +fun UserActionDistanceScope.calculateShadePanelTargetPositionY(shadeOverlayKey: ContentKey): Float { + val marginTop = OverlayShade.Elements.Panel.targetOffset(shadeOverlayKey)?.y ?: 0f + val panelHeight = + OverlayShade.Elements.Panel.targetSize(shadeOverlayKey)?.height?.toFloat() ?: 0f + return marginTop + panelHeight +} + private val DefaultDuration = 300.milliseconds diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt index faccf14767b5..c9fbb4da9ffb 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt @@ -25,9 +25,8 @@ import kotlin.time.Duration.Companion.milliseconds fun TransitionBuilder.toQuickSettingsShadeTransition(durationScale: Double = 1.0) { spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt()) - distance = UserActionDistance { fromContent, _, _ -> - val fromContentSize = checkNotNull(fromContent.targetSize()) - fromContentSize.height.toFloat() * 2 / 3f + distance = UserActionDistance { _, shadeContentKey, _ -> + calculateShadePanelTargetPositionY(shadeContentKey) } translate(OverlayShade.Elements.Panel, Edge.Top) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt index 916d85a80e77..ab3f6396e5c0 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt @@ -92,6 +92,10 @@ internal class DraggableHandler( else -> null } ?: return NoOpDragController + if (result is UserActionResult.ShowOverlay) { + layoutImpl.hideOverlays(result.hideCurrentOverlays) + } + val swipeAnimation = createSwipeAnimation(swipes, result) return updateDragController(swipes, swipeAnimation) } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt index 8865a079733a..a5dba0f64583 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt @@ -60,7 +60,6 @@ import com.android.compose.animation.scene.transformation.PropertyTransformation import com.android.compose.animation.scene.transformation.TransformationWithRange import com.android.compose.modifiers.thenIf import com.android.compose.ui.graphics.drawInContainer -import com.android.compose.ui.util.IntIndexedMap import com.android.compose.ui.util.lerp import kotlin.math.roundToInt import kotlinx.coroutines.launch @@ -74,14 +73,6 @@ internal class Element(val key: ElementKey) { val stateByContent = SnapshotStateMap<ContentKey, State>() /** - * A sorted map of nesting depth (key) to content key (value). For shared elements it is used to - * determine which content this element should be rendered by. The nesting depth refers to the - * number of STLs nested within each other, starting at 0 for the parent STL and increasing by - * one for each nested [NestedSceneTransitionLayout]. - */ - val renderAuthority = IntIndexedMap<ContentKey>() - - /** * The last transition that was used when computing the state (size, position and alpha) of this * element in any content, or `null` if it was last laid out when idle. */ @@ -285,7 +276,6 @@ internal class ElementNode( val element = layoutImpl.elements[key] ?: Element(key).also { layoutImpl.elements[key] = it } _element = element - addToRenderAuthority(element) if (!element.stateByContent.contains(content.key)) { val contents = buildList { layoutImpl.ancestors.fastForEach { add(it.inContent) } @@ -318,22 +308,9 @@ internal class ElementNode( removeNodeFromContentState() maybePruneMaps(layoutImpl, element, stateInContent) - removeFromRenderAuthority() _element = null } - private fun addToRenderAuthority(element: Element) { - val nestingDepth = layoutImpl.ancestors.size - element.renderAuthority[nestingDepth] = content.key - } - - private fun removeFromRenderAuthority() { - val nestingDepth = layoutImpl.ancestors.size - if (element.renderAuthority[nestingDepth] == content.key) { - element.renderAuthority.remove(nestingDepth) - } - } - private fun removeNodeFromContentState() { stateInContent.nodes.remove(this) } @@ -677,12 +654,8 @@ internal inline fun elementState( // Check if any ancestor runs a transition that has a transformation for the element states.fastForEachReversed { state -> if ( - state is TransitionState.Transition && - (state.transformationSpec.hasTransformation( - elementKey, - state.fromContent, - ) || - state.transformationSpec.hasTransformation(elementKey, state.toContent)) + isSharedElement(state, isInContent) || + hasTransformationForElement(state, elementKey) ) { return state } @@ -710,6 +683,21 @@ internal inline fun elementState( return null } +private inline fun isSharedElement( + state: TransitionState, + isInContent: (ContentKey) -> Boolean, +): Boolean { + return state is TransitionState.Transition && + isInContent(state.fromContent) && + isInContent(state.toContent) +} + +private fun hasTransformationForElement(state: TransitionState, elementKey: ElementKey): Boolean { + return state is TransitionState.Transition && + (state.transformationSpec.hasTransformation(elementKey, state.fromContent) || + state.transformationSpec.hasTransformation(elementKey, state.toContent)) +} + internal inline fun elementContentWhenIdle( layoutImpl: SceneTransitionLayoutImpl, currentState: TransitionState, @@ -964,13 +952,12 @@ private fun shouldPlaceElement( val transition = when (elementState) { is TransitionState.Idle -> { - return element.shouldBeRenderedBy(content) && - content == - elementContentWhenIdle( - layoutImpl, - elementState, - isInContent = { it in element.stateByContent }, - ) + return content == + elementContentWhenIdle( + layoutImpl, + elementState, + isInContent = { it in element.stateByContent }, + ) } is TransitionState.Transition -> elementState } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt index c10a48567b22..f4af5f055935 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt @@ -212,8 +212,8 @@ private fun shouldComposeMoveableElement( scenePicker.contentDuringTransition( element = elementKey, transition = transition, - fromContentZIndex = layoutImpl.content(transition.fromContent).zIndex, - toContentZIndex = layoutImpl.content(transition.toContent).zIndex, + fromContentZIndex = layoutImpl.content(transition.fromContent).globalZIndex, + toContentZIndex = layoutImpl.content(transition.toContent).globalZIndex, ) return pickedScene == content diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt index 621166e1823a..96d68ff03acd 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PredictiveBackHandler.kt @@ -44,6 +44,10 @@ internal fun PredictiveBackHandler( return@PredictiveBackHandler } + if (result is ShowOverlay) { + layoutImpl.hideOverlays(result.hideCurrentOverlays) + } + val animation = createSwipeAnimation( layoutImpl, diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index 431a376d8eaf..184c2a28727b 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -62,7 +62,7 @@ fun SceneTransitionLayout( swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector, swipeDetector: SwipeDetector = DefaultSwipeDetector, @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0.05f, - builder: SceneTransitionLayoutScope.() -> Unit, + builder: SceneTransitionLayoutScope<ContentScope>.() -> Unit, ) { SceneTransitionLayoutForTesting( state, @@ -75,7 +75,7 @@ fun SceneTransitionLayout( ) } -interface SceneTransitionLayoutScope { +interface SceneTransitionLayoutScope<out CS : ContentScope> { /** * Add a scene to this layout, identified by [key]. * @@ -88,7 +88,7 @@ interface SceneTransitionLayoutScope { fun scene( key: SceneKey, userActions: Map<UserAction, UserActionResult> = emptyMap(), - content: @Composable ContentScope.() -> Unit, + content: @Composable CS.() -> Unit, ) /** @@ -118,7 +118,7 @@ interface SceneTransitionLayoutScope { mapOf(Back to UserActionResult.HideOverlay(key)), alignment: Alignment = Alignment.Center, isModal: Boolean = true, - content: @Composable ContentScope.() -> Unit, + content: @Composable CS.() -> Unit, ) } @@ -253,18 +253,6 @@ interface BaseContentScope : ElementStateScope { fun Modifier.disableSwipesWhenScrolling( bounds: NestedScrollableBound = NestedScrollableBound.Any ): Modifier - - /** - * A [NestedSceneTransitionLayout] will share its elements with its ancestor STLs therefore - * enabling sharedElement transitions between them. - */ - // TODO(b/380070506): Add more parameters when default params are supported in Kotlin 2.0.21 - @Composable - fun NestedSceneTransitionLayout( - state: SceneTransitionLayoutState, - modifier: Modifier, - builder: SceneTransitionLayoutScope.() -> Unit, - ) } @Stable @@ -337,6 +325,29 @@ interface ContentScope : BaseContentScope { type: SharedValueType<T, *>, canOverflow: Boolean, ): AnimatedState<T> + + /** + * A [NestedSceneTransitionLayout] will share its elements with its ancestor STLs therefore + * enabling sharedElement transitions between them. + */ + // TODO(b/380070506): Add more parameters when default params are supported in Kotlin 2.0.21 + @Composable + fun NestedSceneTransitionLayout( + state: SceneTransitionLayoutState, + modifier: Modifier, + builder: SceneTransitionLayoutScope<ContentScope>.() -> Unit, + ) +} + +internal interface InternalContentScope : ContentScope { + + @Composable + fun NestedSceneTransitionLayoutForTesting( + state: SceneTransitionLayoutState, + modifier: Modifier, + onLayoutImpl: ((SceneTransitionLayoutImpl) -> Unit)?, + builder: SceneTransitionLayoutScope<InternalContentScope>.() -> Unit, + ) } /** @@ -607,8 +618,24 @@ sealed class UserActionResult( val overlay: OverlayKey, override val transitionKey: TransitionKey? = null, override val requiresFullDistanceSwipe: Boolean = false, + + /** Specify which overlays (if any) should be hidden when this user action is started. */ + val hideCurrentOverlays: HideCurrentOverlays = HideCurrentOverlays.None, ) : UserActionResult(transitionKey, requiresFullDistanceSwipe) { override fun toContent(currentScene: SceneKey): ContentKey = overlay + + sealed class HideCurrentOverlays { + /** Hide none of the current overlays. */ + object None : HideCurrentOverlays() + + /** Hide all current overlays. */ + object All : HideCurrentOverlays() + + /** Hide [overlays], for those in that set that are currently shown. */ + class Some(val overlays: Set<OverlayKey>) : HideCurrentOverlays() { + constructor(vararg overlays: OverlayKey) : this(overlays.toSet()) + } + } } /** A [UserActionResult] that hides [overlay]. */ @@ -714,7 +741,7 @@ internal fun SceneTransitionLayoutForTesting( sharedElementMap: MutableMap<ElementKey, Element> = remember { mutableMapOf() }, ancestors: List<Ancestor> = remember { emptyList() }, lookaheadScope: LookaheadScope? = null, - builder: SceneTransitionLayoutScope.() -> Unit, + builder: SceneTransitionLayoutScope<InternalContentScope>.() -> Unit, ) { val density = LocalDensity.current val directionChangeSlop = LocalViewConfiguration.current.touchSlop diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index 38ad0a80fd00..16fd5b1e78e6 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -45,9 +45,12 @@ import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.util.fastAny +import androidx.compose.ui.util.fastFirstOrNull import androidx.compose.ui.util.fastForEach import androidx.compose.ui.util.fastForEachReversed import androidx.compose.ui.zIndex +import com.android.compose.animation.scene.UserActionResult.ShowOverlay.HideCurrentOverlays import com.android.compose.animation.scene.content.Content import com.android.compose.animation.scene.content.Overlay import com.android.compose.animation.scene.content.Scene @@ -78,7 +81,7 @@ internal class SceneTransitionLayoutImpl( internal var swipeSourceDetector: SwipeSourceDetector, internal var swipeDetector: SwipeDetector, internal var transitionInterceptionThreshold: Float, - builder: SceneTransitionLayoutScope.() -> Unit, + builder: SceneTransitionLayoutScope<InternalContentScope>.() -> Unit, /** * The scope that should be used by *animations started by this layout only*, i.e. animations @@ -221,19 +224,30 @@ internal class SceneTransitionLayoutImpl( state.checkThread() } - internal fun scene(key: SceneKey): Scene { - return scenes[key] ?: error("Scene $key is not configured") + private fun sceneOrNull(key: SceneKey): Scene? { + return scenes[key] + ?: ancestors + .fastFirstOrNull { it.layoutImpl.scenes[key] != null } + ?.layoutImpl + ?.scenes + ?.get(key) } - internal fun contentOrNull(key: ContentKey): Content? { - return when (key) { - is SceneKey -> scenes[key] - is OverlayKey -> overlays[key] - } + private fun overlayOrNull(key: OverlayKey): Overlay? { + return overlays[key] + ?: ancestors + .fastFirstOrNull { it.layoutImpl.overlays[key] != null } + ?.layoutImpl + ?.overlays + ?.get(key) + } + + internal fun scene(key: SceneKey): Scene { + return sceneOrNull(key) ?: error("Scene $key is not configured") } internal fun overlay(key: OverlayKey): Overlay { - return overlays[key] ?: error("Overlay $key is not configured") + return overlayOrNull(key) ?: error("Overlay $key is not configured") } internal fun content(key: ContentKey): Content { @@ -243,6 +257,10 @@ internal class SceneTransitionLayoutImpl( } } + internal fun isAncestorContent(content: ContentKey): Boolean { + return ancestors.fastAny { it.inContent == content } + } + internal fun contentForUserActions(): Content { return findOverlayWithHighestZIndex() ?: scene(state.transitionState.currentScene) } @@ -266,7 +284,7 @@ internal class SceneTransitionLayoutImpl( } internal fun updateContents( - builder: SceneTransitionLayoutScope.() -> Unit, + builder: SceneTransitionLayoutScope<InternalContentScope>.() -> Unit, layoutDirection: LayoutDirection, ) { // Keep a reference of the current contents. After processing [builder], the contents that @@ -275,15 +293,17 @@ internal class SceneTransitionLayoutImpl( val overlaysToRemove = if (_overlays == null) mutableSetOf() else overlays.keys.toMutableSet() + val parentZIndex = + if (ancestors.isEmpty()) 0L else content(ancestors.last().inContent).globalZIndex // The incrementing zIndex of each scene. - var zIndex = 0f + var zIndex = 0 var overlaysDefined = false - object : SceneTransitionLayoutScope { + object : SceneTransitionLayoutScope<InternalContentScope> { override fun scene( key: SceneKey, userActions: Map<UserAction, UserActionResult>, - content: @Composable ContentScope.() -> Unit, + content: @Composable InternalContentScope.() -> Unit, ) { require(!overlaysDefined) { "all scenes must be defined before overlays" } @@ -291,11 +311,14 @@ internal class SceneTransitionLayoutImpl( val resolvedUserActions = resolveUserActions(key, userActions, layoutDirection) val scene = scenes[key] + val globalZIndex = + Content.calculateGlobalZIndex(parentZIndex, ++zIndex, ancestors.size) if (scene != null) { // Update an existing scene. scene.content = content scene.userActions = resolvedUserActions - scene.zIndex = zIndex + scene.zIndex = zIndex.toFloat() + scene.globalZIndex = globalZIndex } else { // New scene. scenes[key] = @@ -304,11 +327,10 @@ internal class SceneTransitionLayoutImpl( this@SceneTransitionLayoutImpl, content, resolvedUserActions, - zIndex, + zIndex.toFloat(), + globalZIndex, ) } - - zIndex++ } override fun overlay( @@ -316,17 +338,20 @@ internal class SceneTransitionLayoutImpl( userActions: Map<UserAction, UserActionResult>, alignment: Alignment, isModal: Boolean, - content: @Composable (ContentScope.() -> Unit), + content: @Composable (InternalContentScope.() -> Unit), ) { overlaysDefined = true overlaysToRemove.remove(key) val overlay = overlays[key] val resolvedUserActions = resolveUserActions(key, userActions, layoutDirection) + val globalZIndex = + Content.calculateGlobalZIndex(parentZIndex, ++zIndex, ancestors.size) if (overlay != null) { // Update an existing overlay. overlay.content = content - overlay.zIndex = zIndex + overlay.zIndex = zIndex.toFloat() + overlay.globalZIndex = globalZIndex overlay.userActions = resolvedUserActions overlay.alignment = alignment overlay.isModal = isModal @@ -338,13 +363,12 @@ internal class SceneTransitionLayoutImpl( this@SceneTransitionLayoutImpl, content, resolvedUserActions, - zIndex, + zIndex.toFloat(), + globalZIndex, alignment, isModal, ) } - - zIndex++ } } .builder() @@ -537,13 +561,27 @@ internal class SceneTransitionLayoutImpl( .sortedBy { it.zIndex } } + internal fun hideOverlays(hide: HideCurrentOverlays) { + fun maybeHide(overlay: OverlayKey) { + if (state.canHideOverlay(overlay)) { + state.hideOverlay(overlay, animationScope = this.animationScope) + } + } + + when (hide) { + HideCurrentOverlays.None -> {} + HideCurrentOverlays.All -> HashSet(state.currentOverlays).forEach { maybeHide(it) } + is HideCurrentOverlays.Some -> hide.overlays.forEach { maybeHide(it) } + } + } + @VisibleForTesting internal fun setContentsAndLayoutTargetSizeForTest(size: IntSize) { lastSize = size (scenes.values + overlays.values).forEach { it.targetSize = size } } - internal fun overlaysOrNullForTest(): Map<OverlayKey, Overlay>? = _overlays + @VisibleForTesting internal fun overlaysOrNullForTest(): Map<OverlayKey, Overlay>? = _overlays } private data class LayoutElement(private val layoutImpl: SceneTransitionLayoutImpl) : diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt index ed3a5cac8184..ee3944893ced 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt @@ -20,52 +20,22 @@ import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.transformation.SharedElementTransformation import com.android.compose.animation.scene.transformation.TransformationWithRange -/** - * Whether this element should be rendered by the given [content]. This method returns true only for - * exactly one content at any given time. - */ -internal fun Element.shouldBeRenderedBy(content: ContentKey): Boolean { - // The current strategy is that always the content with the lowest nestingDepth has authority. - // This content is supposed to render the shared element because this is also the level at which - // the transition is running. If the [renderAuthority.size] is 1 it means that that this element - // is currently composed only in one nesting level, which means that the render authority - // is determined by "classic" shared element code. - return renderAuthority.size > 0 && - (renderAuthority.size == 1 || renderAuthority.first() == content) -} - -/** - * Whether this element is currently composed in multiple [SceneTransitionLayout]s. - * - * Note: Shared elements across [NestedSceneTransitionLayout]s side-by-side are not supported. - */ -internal fun Element.isPresentInMultipleStls(): Boolean { - return renderAuthority.size > 1 -} - internal fun shouldPlaceSharedElement( layoutImpl: SceneTransitionLayoutImpl, content: ContentKey, elementKey: ElementKey, transition: TransitionState.Transition, ): Boolean { - val element = layoutImpl.elements.getValue(elementKey) - if (element.isPresentInMultipleStls()) { - // If the element is present in multiple STLs we require the highest STL to render it and - // we don't want contentPicker to potentially return false for the highest STL. - return element.shouldBeRenderedBy(content) - } - - val scenePicker = elementKey.contentPicker - val pickedScene = - scenePicker.contentDuringTransition( + val contentPicker = elementKey.contentPicker + val pickedContent = + contentPicker.contentDuringTransition( element = elementKey, transition = transition, - fromContentZIndex = layoutImpl.content(transition.fromContent).zIndex, - toContentZIndex = layoutImpl.content(transition.toContent).zIndex, + fromContentZIndex = layoutImpl.content(transition.fromContent).globalZIndex, + toContentZIndex = layoutImpl.content(transition.toContent).globalZIndex, ) - return pickedScene == content + return pickedContent == content || layoutImpl.isAncestorContent(pickedContent) } internal fun isSharedElementEnabled( diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt index a29c1bbe0a0c..badb8a80b982 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt @@ -210,8 +210,8 @@ interface ElementContentPicker { fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey /** @@ -279,8 +279,8 @@ object HighestZIndexContentPicker : ElementContentPicker { override fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey { return if (fromContentZIndex > toContentZIndex) { transition.fromContent @@ -300,8 +300,8 @@ object HighestZIndexContentPicker : ElementContentPicker { override fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey { return HighestZIndexContentPicker.contentDuringTransition( element, @@ -321,8 +321,8 @@ object LowestZIndexContentPicker : ElementContentPicker { override fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey { return if (fromContentZIndex < toContentZIndex) { transition.fromContent @@ -342,8 +342,8 @@ object LowestZIndexContentPicker : ElementContentPicker { override fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey { return LowestZIndexContentPicker.contentDuringTransition( element, @@ -375,8 +375,8 @@ class MovableElementContentPicker(override val contents: Set<ContentKey>) : override fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey { return when { transition.toContent in contents -> transition.toContent diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt index 8457481b3e14..fffc7f988acf 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt @@ -36,7 +36,7 @@ internal class ElementStateScopeImpl(private val layoutImpl: SceneTransitionLayo } override fun ContentKey.targetSize(): IntSize? { - return layoutImpl.contentOrNull(this)?.targetSize.takeIf { it != IntSize.Zero } + return layoutImpl.content(this).targetSize.takeIf { it != IntSize.Zero } } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt index 6ccd498f7a04..86201a9c0879 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt @@ -27,6 +27,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -45,6 +46,7 @@ import com.android.compose.animation.scene.ElementContentScope import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.ElementScope import com.android.compose.animation.scene.ElementStateScope +import com.android.compose.animation.scene.InternalContentScope import com.android.compose.animation.scene.MovableElement import com.android.compose.animation.scene.MovableElementContentScope import com.android.compose.animation.scene.MovableElementKey @@ -68,24 +70,78 @@ import com.android.compose.gesture.nestedScrollController import com.android.compose.modifiers.thenIf import com.android.compose.ui.graphics.ContainerState import com.android.compose.ui.graphics.container +import kotlin.math.pow /** A content defined in a [SceneTransitionLayout], i.e. a scene or an overlay. */ @Stable internal sealed class Content( open val key: ContentKey, val layoutImpl: SceneTransitionLayoutImpl, - content: @Composable ContentScope.() -> Unit, + content: @Composable InternalContentScope.() -> Unit, actions: Map<UserAction.Resolved, UserActionResult>, zIndex: Float, + globalZIndex: Long, ) { private val nestedScrollControlState = NestedScrollControlState() internal val scope = ContentScopeImpl(layoutImpl, content = this, nestedScrollControlState) val containerState = ContainerState() var content by mutableStateOf(content) - var zIndex by mutableFloatStateOf(zIndex) var targetSize by mutableStateOf(IntSize.Zero) var userActions by mutableStateOf(actions) + var zIndex by mutableFloatStateOf(zIndex) + + /** + * The globalZIndex is a zIndex that indicates the z order of each content across any nested + * STLs. This is done by dividing the number range of a Long into chunks of three digits. As + * Long.MAX_VALUE is a bit larger than 1e18 we start the first level at 1e15 to give at least + * 1000 contents space. The first level of nesting depth will occupy the 3 highest digits and + * with each level we continue into the next three. Therefore the parent z order will have + * priority and their children have room to order themselves within the "less significant bits". + * + * As an example, imagine the following tree of nested scenes: + * ``` + * / \ + * A01 A02 -- nestingDepth 0 + * / \ | + * B01 B02 C01 -- nestingDepth 1 + * | + * D01 -- nestingDepth 2 + * ``` + * + * The zIndex values would be: + * ``` + * A01: 1e15 (1_000_000_000_000_000) + * A02: 2e15 (2_000_000_000_000_000) + * B01: 1.001e15 (1_001_000_000_000_000) + * B02: 1.002e15 (1_002_000_000_000_000) + * C01: 2.001e15 (2_001_000_000_000_000) + * D01: 1.002001e15 (1_002_001_000_000_000) + * ``` + * + * Therefore the order of zIndexes will correctly be: A01, B01, B02, D01, A02, C01, which + * corresponds to a Pre-order traversal of the tree. + * + * Since composition of the tree does not happen all at once we can't do a Pre-order traversal + * right away without allocating resources to build and manage the tree structure through all + * updates. Using this method we have stable zIndexes at time of composition of each content + * independently with the only drawback that contents per each STL are limited to 999 and + * nesting depth is limited to 6 (18 / 3). + */ + var globalZIndex by mutableLongStateOf(globalZIndex) + + companion object { + fun calculateGlobalZIndex( + parentGlobalZIndex: Long, + localZIndex: Int, + nestingDepth: Int, + ): Long { + require(nestingDepth in 0..5) { "NestingDepth of STLs can be at most 5." } + require(localZIndex in 1..999) { "A scene can have at most 999 contents." } + val offsetForDepth = 10.0.pow((5 - nestingDepth) * 3).toLong() + return parentGlobalZIndex + offsetForDepth * localZIndex + } + } @SuppressLint("NotConstructor") @Composable @@ -118,7 +174,7 @@ internal class ContentScopeImpl( private val layoutImpl: SceneTransitionLayoutImpl, private val content: Content, private val nestedScrollControlState: NestedScrollControlState, -) : ContentScope, ElementStateScope by layoutImpl.elementStateScope { +) : InternalContentScope, ElementStateScope by layoutImpl.elementStateScope { override val contentKey: ContentKey get() = content.key @@ -208,7 +264,17 @@ internal class ContentScopeImpl( override fun NestedSceneTransitionLayout( state: SceneTransitionLayoutState, modifier: Modifier, - builder: SceneTransitionLayoutScope.() -> Unit, + builder: SceneTransitionLayoutScope<ContentScope>.() -> Unit, + ) { + NestedSceneTransitionLayoutForTesting(state, modifier, null, builder) + } + + @Composable + override fun NestedSceneTransitionLayoutForTesting( + state: SceneTransitionLayoutState, + modifier: Modifier, + onLayoutImpl: ((SceneTransitionLayoutImpl) -> Unit)?, + builder: SceneTransitionLayoutScope<InternalContentScope>.() -> Unit, ) { val ancestors = remember(layoutImpl, contentKey, layoutImpl.ancestors) { @@ -217,7 +283,7 @@ internal class ContentScopeImpl( SceneTransitionLayoutForTesting( state, modifier, - onLayoutImpl = null, + onLayoutImpl = onLayoutImpl, builder = builder, sharedElementMap = layoutImpl.elements, ancestors = ancestors, diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt index d4de559cef43..300de3f36b1f 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Overlay.kt @@ -22,7 +22,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment -import com.android.compose.animation.scene.ContentScope +import com.android.compose.animation.scene.InternalContentScope import com.android.compose.animation.scene.OverlayKey import com.android.compose.animation.scene.SceneTransitionLayoutImpl import com.android.compose.animation.scene.UserAction @@ -33,12 +33,13 @@ import com.android.compose.animation.scene.UserActionResult internal class Overlay( override val key: OverlayKey, layoutImpl: SceneTransitionLayoutImpl, - content: @Composable ContentScope.() -> Unit, + content: @Composable InternalContentScope.() -> Unit, actions: Map<UserAction.Resolved, UserActionResult>, zIndex: Float, + globalZIndex: Long, alignment: Alignment, isModal: Boolean, -) : Content(key, layoutImpl, content, actions, zIndex) { +) : Content(key, layoutImpl, content, actions, zIndex, globalZIndex) { var alignment by mutableStateOf(alignment) var isModal by mutableStateOf(isModal) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt index 4a7a94d6e177..275341c7268b 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt @@ -18,7 +18,7 @@ package com.android.compose.animation.scene.content import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable -import com.android.compose.animation.scene.ContentScope +import com.android.compose.animation.scene.InternalContentScope import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneTransitionLayoutImpl import com.android.compose.animation.scene.UserAction @@ -29,10 +29,11 @@ import com.android.compose.animation.scene.UserActionResult internal class Scene( override val key: SceneKey, layoutImpl: SceneTransitionLayoutImpl, - content: @Composable ContentScope.() -> Unit, + content: @Composable InternalContentScope.() -> Unit, actions: Map<UserAction.Resolved, UserActionResult>, zIndex: Float, -) : Content(key, layoutImpl, content, actions, zIndex) { + globalZIndex: Long, +) : Content(key, layoutImpl, content, actions, zIndex, globalZIndex) { override fun toString(): String { return "Scene(key=$key)" } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/IntIndexedMap.kt b/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/IntIndexedMap.kt deleted file mode 100644 index 1b5341b8048a..000000000000 --- a/packages/SystemUI/compose/scene/src/com/android/compose/ui/util/IntIndexedMap.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.compose.ui.util - -/** - * This is a custom implementation that resembles a SortedMap<Int, T> but is based on a simple - * ArrayList to avoid the allocation overhead and boxing. - * - * It can only hold positive keys and 0 and it is only efficient for small keys (0 - ~100), but - * therefore provides fast operations for small keys. - */ -internal class IntIndexedMap<T> { - private val arrayList = ArrayList<T?>() - private var _size = 0 - val size - get() = _size - - /** Returns the value at [key] or null if the key is not present. */ - operator fun get(key: Int): T? { - if (key < 0 || key >= arrayList.size) return null - return arrayList[key] - } - - /** - * Sets the value at [key] to [value]. If [key] is larger than the current size of the map, this - * operation may take up to O(key) time and space. Therefore this data structure is only - * efficient for small [key] sizes. - */ - operator fun set(key: Int, value: T?) { - if (key < 0) - throw UnsupportedOperationException("This map can only hold positive keys and 0.") - if (key < arrayList.size) { - if (arrayList[key] != null && value == null) _size-- - if (arrayList[key] == null && value != null) _size++ - arrayList[key] = value - } else { - if (value == null) return - while (key > arrayList.size) { - arrayList.add(null) - } - _size++ - arrayList.add(value) - } - } - - /** Remove value at [key] */ - fun remove(key: Int) { - if (key >= arrayList.size) return - this[key] = null - } - - /** Get the [value] with the smallest [key] of the map. */ - fun first(): T { - for (i in 0 until arrayList.size) { - return arrayList[i] ?: continue - } - throw NoSuchElementException("The map is empty.") - } -} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt index 35ff0044f4d6..68e85db2c80b 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt @@ -36,6 +36,7 @@ import com.android.compose.animation.scene.TestScenes.SceneA import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.content.state.TransitionState +import com.android.compose.animation.scene.content.state.TransitionState.Companion.DistanceUnspecified import com.android.compose.animation.scene.content.state.TransitionState.Transition import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.gesture.NestedDraggable @@ -84,7 +85,7 @@ class DraggableHandlerTest { layoutImpl.updateContents(scenesBuilder, layoutDirection) } - private val scenesBuilder: SceneTransitionLayoutScope.() -> Unit = { + private val scenesBuilder: SceneTransitionLayoutScope<ContentScope>.() -> Unit = { scene(key = SceneA, userActions = mutableUserActionsA) { Text("SceneA") } scene(key = SceneB, userActions = mutableUserActionsB) { Text("SceneB") } scene( @@ -785,6 +786,29 @@ class DraggableHandlerTest { } @Test + fun animateWhenDistanceUnspecified() = runGestureTest { + layoutState.transitions = transitions { + from(SceneA, to = SceneB) { + distance = UserActionDistance { _, _, _ -> DistanceUnspecified } + } + } + + val controller = onDragStarted(overSlop = up(fractionOfScreen = 0.9f)) + + // The distance is not computed yet, so we don't know the "progress" value yet. + assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.0f) + + controller.onDragStoppedAnimateNow( + // We are animating from SceneA to SceneA, when the distance is still unspecified. + velocity = velocityThreshold, + onAnimationStart = { + assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.0f) + }, + ) + assertIdle(SceneA) + } + + @Test fun showOverlay() = runGestureTest { mutableUserActionsA = mapOf(Swipe.Down to UserActionResult.ShowOverlay(OverlayA)) diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementContentPickerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementContentPickerTest.kt index c8e7e6592e17..fba0aa88ef7a 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementContentPickerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementContentPickerTest.kt @@ -33,8 +33,8 @@ class MovableElementContentPickerTest { picker.contentDuringTransition( TestElements.Foo, transition(from = TestScenes.SceneA, to = TestScenes.SceneB), - fromContentZIndex = 0f, - toContentZIndex = 1f, + fromContentZIndex = 0, + toContentZIndex = 1, ) ) .isEqualTo(TestScenes.SceneB) @@ -47,8 +47,8 @@ class MovableElementContentPickerTest { picker.contentDuringTransition( TestElements.Foo, transition(from = TestScenes.SceneA, to = TestScenes.SceneB), - fromContentZIndex = 0f, - toContentZIndex = 1f, + fromContentZIndex = 0, + toContentZIndex = 1, ) ) .isEqualTo(TestScenes.SceneA) @@ -61,8 +61,8 @@ class MovableElementContentPickerTest { picker.contentDuringTransition( TestElements.Foo, transition(from = TestScenes.SceneA, to = TestScenes.SceneB), - fromContentZIndex = 0f, - toContentZIndex = 1f, + fromContentZIndex = 0, + toContentZIndex = 1, ) } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt index 8d718c1418e0..e023936eb448 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt @@ -166,14 +166,14 @@ class MovableElementTest { override fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey { transition as TransitionState.Transition.ChangeScene assertThat(transition).hasFromScene(SceneA) assertThat(transition).hasToScene(SceneB) - assertThat(fromContentZIndex).isEqualTo(0) - assertThat(toContentZIndex).isEqualTo(1) + assertThat(fromContentZIndex).isEqualTo(1_000_000_000_000_000) + assertThat(toContentZIndex).isEqualTo(2_000_000_000_000_000) // Compose Foo in Scene A if progress < 0.65f, otherwise compose it // in Scene B. @@ -362,8 +362,8 @@ class MovableElementTest { override fun contentDuringTransition( element: ElementKey, transition: TransitionState.Transition, - fromContentZIndex: Float, - toContentZIndex: Float, + fromContentZIndex: Long, + toContentZIndex: Long, ): ContentKey { return SceneA } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt index 50bfbfe6d29c..b4b328b14a78 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt @@ -33,6 +33,7 @@ import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.platform.testTag import androidx.compose.ui.test.SemanticsMatcher import androidx.compose.ui.test.assertIsDisplayed @@ -50,7 +51,10 @@ import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestOverlays.OverlayA import com.android.compose.animation.scene.TestOverlays.OverlayB +import com.android.compose.animation.scene.TestOverlays.OverlayC +import com.android.compose.animation.scene.TestOverlays.OverlayD import com.android.compose.animation.scene.TestScenes.SceneA +import com.android.compose.animation.scene.UserActionResult.ShowOverlay import com.android.compose.animation.scene.subjects.assertThat import com.android.compose.test.assertSizeIsEqualTo import com.android.compose.test.setContentAndCreateMainScope @@ -821,4 +825,63 @@ class OverlayTest { assertThat(state.transitionState).isIdle() assertThat(state.transitionState).hasCurrentOverlays(/* empty */ ) } + + @Test + fun showOverlay_hideAllOverlays() { + val state = + rule.runOnUiThread { + MutableSceneTransitionLayoutStateForTests( + SceneA, + initialOverlays = setOf(OverlayA, OverlayB, OverlayC), + // We don't allow overlay C to be hidden. + canHideOverlay = { it != OverlayC }, + ) + } + + var touchSlop = 0f + rule.setContent { + touchSlop = LocalViewConfiguration.current.touchSlop + SceneTransitionLayout(state) { + scene(SceneA) { Box(Modifier.fillMaxSize()) } + overlay(OverlayA) { Box(Modifier.fillMaxSize()) } + overlay(OverlayB) { Box(Modifier.fillMaxSize()) } + overlay( + OverlayC, + mapOf( + Swipe.Down to + ShowOverlay( + OverlayD, + hideCurrentOverlays = ShowOverlay.HideCurrentOverlays.All, + ) + ), + ) { + Box(Modifier.fillMaxSize()) + } + overlay(OverlayD) { Box(Modifier.fillMaxSize()) } + } + } + + assertThat(state.transitionState).hasCurrentOverlays(OverlayA, OverlayB, OverlayC) + + rule.onRoot().performTouchInput { + down(center) + moveBy(Offset(0f, touchSlop)) + } + + // We closed all overlay, but C can not be hidden. + val transition = assertThat(state.transitionState).isShowOrHideOverlayTransition() + assertThat(transition).hasCurrentScene(SceneA) + assertThat(transition).hasCurrentOverlays(OverlayC) + assertThat(transition).hasProgress(0f) + assertThat(transition).hasOverlay(OverlayD) + + rule.onRoot().performTouchInput { moveBy(Offset(0f, bottom / 2f)) } + assertThat(transition).hasProgress(0.5f) + + rule.onRoot().performTouchInput { up() } + rule.waitForIdle() + assertThat(state.transitionState).isIdle() + assertThat(state.transitionState).hasCurrentScene(SceneA) + assertThat(state.transitionState).hasCurrentOverlays(OverlayC, OverlayD) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt index 9f15ebd69657..2bf235846b32 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt @@ -32,9 +32,11 @@ import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestOverlays.OverlayA import com.android.compose.animation.scene.TestOverlays.OverlayB +import com.android.compose.animation.scene.TestOverlays.OverlayC import com.android.compose.animation.scene.TestScenes.SceneA import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC +import com.android.compose.animation.scene.UserActionResult.ShowOverlay import com.android.compose.animation.scene.subjects.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -273,6 +275,57 @@ class PredictiveBackHandlerTest { rule.onNode(hasTestTag(OverlayB.testTag)).assertDoesNotExist() } + @Test + fun showOverlay_hideSomeOverlays() { + val state = + rule.runOnUiThread { + MutableSceneTransitionLayoutStateForTests( + SceneA, + initialOverlays = setOf(OverlayA, OverlayB), + ) + } + + rule.setContent { + SceneTransitionLayout(state) { + scene(SceneA) { Box(Modifier.fillMaxSize()) } + overlay(OverlayA) { Box(Modifier.fillMaxSize()) } + overlay( + OverlayB, + mapOf( + Back to + ShowOverlay( + OverlayC, + hideCurrentOverlays = ShowOverlay.HideCurrentOverlays.Some(OverlayA), + ) + ), + ) { + Box(Modifier.fillMaxSize()) + } + overlay(OverlayC) { Box(Modifier.fillMaxSize()) } + } + } + + assertThat(state.transitionState).hasCurrentOverlays(OverlayA, OverlayB) + + val dispatcher = rule.activity.onBackPressedDispatcher + rule.runOnUiThread { dispatcher.dispatchOnBackStarted(backEvent()) } + + val transition = assertThat(state.transitionState).isShowOrHideOverlayTransition() + assertThat(transition).hasCurrentScene(SceneA) + assertThat(transition).hasCurrentOverlays(OverlayB) + assertThat(transition).hasProgress(0f) + assertThat(transition).hasOverlay(OverlayC) + + rule.runOnUiThread { dispatcher.dispatchOnBackProgressed(backEvent(progress = 0.5f)) } + assertThat(transition).hasProgress(0.5f) + + rule.runOnUiThread { dispatcher.onBackPressed() } + rule.waitForIdle() + assertThat(state.transitionState).isIdle() + assertThat(state.transitionState).hasCurrentScene(SceneA) + assertThat(state.transitionState).hasCurrentOverlays(OverlayB, OverlayC) + } + private fun backEvent(progress: Float = 0f): BackEventCompat { return BackEventCompat( touchX = 0f, diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt index 8db7dbca2474..0bd51cd9822d 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt @@ -129,22 +129,22 @@ abstract class BaseTransitionSubject<T : TransitionState.Transition>( check("currentOverlays").that(actual.currentOverlays).containsExactlyElementsIn(overlays) } - fun hasProgress(progress: Float, tolerance: Float = 0f) { + fun hasProgress(progress: Float, tolerance: Float = 0.01f) { check("progress").that(actual.progress).isWithin(tolerance).of(progress) } - fun hasProgressVelocity(progressVelocity: Float, tolerance: Float = 0f) { + fun hasProgressVelocity(progressVelocity: Float, tolerance: Float = 0.01f) { check("progressVelocity") .that(actual.progressVelocity) .isWithin(tolerance) .of(progressVelocity) } - fun hasPreviewProgress(progress: Float, tolerance: Float = 0f) { + fun hasPreviewProgress(progress: Float, tolerance: Float = 0.01f) { check("previewProgress").that(actual.previewProgress).isWithin(tolerance).of(progress) } - fun hasPreviewProgressVelocity(progressVelocity: Float, tolerance: Float = 0f) { + fun hasPreviewProgressVelocity(progressVelocity: Float, tolerance: Float = 0.01f) { check("previewProgressVelocity") .that(actual.previewProgressVelocity) .isWithin(tolerance) diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSceneTransitionLayoutTest.kt new file mode 100644 index 000000000000..0042f5018957 --- /dev/null +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSceneTransitionLayoutTest.kt @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene.transformation + +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.compose.animation.scene.MutableSceneTransitionLayoutStateForTests +import com.android.compose.animation.scene.SceneTransitionLayoutForTesting +import com.android.compose.animation.scene.SceneTransitionLayoutImpl +import com.android.compose.animation.scene.TestScenes +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class NestedSceneTransitionLayoutTest { + @get:Rule val rule = createComposeRule() + + @Test + fun nestedStls_testZIndex() { + var nullableLayoutImpl: SceneTransitionLayoutImpl? = null + + rule.setContent { + SceneTransitionLayoutForTesting( + state = MutableSceneTransitionLayoutStateForTests(TestScenes.SceneA) + ) { + scene(TestScenes.SceneA) { + NestedSceneTransitionLayoutForTesting( + MutableSceneTransitionLayoutStateForTests(TestScenes.SceneD), + Modifier, + onLayoutImpl = null, + ) { + scene(TestScenes.SceneC) {} + scene(TestScenes.SceneD) { + NestedSceneTransitionLayoutForTesting( + MutableSceneTransitionLayoutStateForTests(TestScenes.SceneE), + Modifier, + onLayoutImpl = { nullableLayoutImpl = it }, + ) { + scene(TestScenes.SceneE) {} + } + } + } + } + scene(TestScenes.SceneB) {} + } + + assertThat(nullableLayoutImpl?.content(TestScenes.SceneA)?.globalZIndex) + .isEqualTo(1_000_000_000_000_000) + assertThat(nullableLayoutImpl?.content(TestScenes.SceneB)?.globalZIndex) + .isEqualTo(2_000_000_000_000_000) + assertThat(nullableLayoutImpl?.content(TestScenes.SceneC)?.globalZIndex) + .isEqualTo(1_001_000_000_000_000) + assertThat(nullableLayoutImpl?.content(TestScenes.SceneD)?.globalZIndex) + .isEqualTo(1_002_000_000_000_000) + assertThat(nullableLayoutImpl?.content(TestScenes.SceneE)?.globalZIndex) + .isEqualTo(1_002_001_000_000_000) + } + } +} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt index 83dd6d3eec28..f44ae90746d5 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt @@ -38,6 +38,7 @@ import com.android.compose.animation.scene.AutoTransitionTestAssertionScope import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.Default4FrameLinearTransition import com.android.compose.animation.scene.Edge +import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.MutableSceneTransitionLayoutState import com.android.compose.animation.scene.MutableSceneTransitionLayoutStateForTests import com.android.compose.animation.scene.SceneKey @@ -77,11 +78,14 @@ class NestedSharedElementTest { ) @Composable - private fun ContentScope.SharedElement(element: SharedElement) { + private fun ContentScope.SharedElement( + element: SharedElement, + key: ElementKey = TestElements.Foo, + ) { Box(Modifier.fillMaxSize()) { Box( Modifier.offset(element.x, element.y) - .element(TestElements.Foo) + .element(key) .size(element.width, element.height) .background(element.color) .alpha(element.alpha) @@ -165,9 +169,9 @@ class NestedSharedElementTest { ) { before { onElement(TestElements.Foo).assertElementVariant(elementVariant1) } atAllFrames(4) { - onElement(TestElements.Foo, TestScenes.SceneB).assertIsNotDisplayed() + onElement(TestElements.Foo, TestScenes.SceneA).assertIsNotDisplayed() - onElement(TestElements.Foo, TestScenes.SceneA) + onElement(TestElements.Foo, TestScenes.SceneB) .assertBetweenElementVariants(elementVariant1, elementVariant2, this) } after { onElement(TestElements.Foo).assertElementVariant(elementVariant2) } @@ -175,6 +179,29 @@ class NestedSharedElementTest { } @Test + fun fromParentSTLtoNestedSTL_contentPickerLowestZOrder() { + rule.testTransition( + fromSceneContent = { SharedElement(elementVariant1, TestElements.LowZIndex) }, + toSceneContent = { + NestedSceneTransitionLayout(nestedState, modifier = Modifier) { + scene(Scenes.NestedSceneA) { + SharedElement(elementVariant2, TestElements.LowZIndex) + } + } + }, + ) { + before { onElement(TestElements.LowZIndex).assertElementVariant(elementVariant1) } + atAllFrames(4) { + onElement(TestElements.LowZIndex, TestScenes.SceneB).assertIsNotDisplayed() + + onElement(TestElements.LowZIndex, TestScenes.SceneA) + .assertBetweenElementVariants(elementVariant1, elementVariant2, this) + } + after { onElement(TestElements.LowZIndex).assertElementVariant(elementVariant2) } + } + } + + @Test fun nestedSharedElementTransition_fromParentSTLtoNestedNestedSTL() { rule.testTransition( fromSceneContent = contentWithSharedElement, @@ -182,9 +209,9 @@ class NestedSharedElementTest { ) { before { onElement(TestElements.Foo).assertElementVariant(elementVariant1) } atAllFrames(4) { - onElement(TestElements.Foo, TestScenes.SceneB).assertIsNotDisplayed() + onElement(TestElements.Foo, TestScenes.SceneA).assertIsNotDisplayed() - onElement(TestElements.Foo, TestScenes.SceneA) + onElement(TestElements.Foo, TestScenes.SceneB) .assertBetweenElementVariants(elementVariant1, elementVariant4, this) } after { onElement(TestElements.Foo).assertElementVariant(elementVariant4) } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/ui/util/IntIndexMapTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/ui/util/IntIndexMapTest.kt deleted file mode 100644 index d7a9b9007be0..000000000000 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/ui/util/IntIndexMapTest.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.compose.ui.util - -import com.google.common.truth.Truth.assertThat -import org.junit.Test - -class IntIndexMapTest { - - @Test - fun testSetGetFirstAndSize() { - val map = IntIndexedMap<String>() - - // Write first element at 10 - map[10] = "1" - assertThat(map[10]).isEqualTo("1") - assertThat(map.size).isEqualTo(1) - assertThat(map.first()).isEqualTo("1") - - // Write same element to same index - map[10] = "1" - assertThat(map[10]).isEqualTo("1") - assertThat(map.size).isEqualTo(1) - - // Writing into larger index - map[12] = "2" - assertThat(map[12]).isEqualTo("2") - assertThat(map.size).isEqualTo(2) - assertThat(map.first()).isEqualTo("1") - - // Overwriting existing index - map[10] = "3" - assertThat(map[10]).isEqualTo("3") - assertThat(map.size).isEqualTo(2) - assertThat(map.first()).isEqualTo("3") - - // Writing into smaller index - map[0] = "4" - assertThat(map[0]).isEqualTo("4") - assert(map.size == 3) - assertThat(map.first()).isEqualTo("4") - - // Writing null into non-null index - map[0] = null - assertThat(map[0]).isEqualTo(null) - assertThat(map.size).isEqualTo(2) - assertThat(map.first()).isEqualTo("3") - - // Writing null into smaller null index - map[1] = null - assertThat(map[1]).isEqualTo(null) - assertThat(map.size).isEqualTo(2) - - // Writing null into larger null index - map[15] = null - assertThat(map[15]).isEqualTo(null) - assertThat(map.size).isEqualTo(2) - - // Remove existing element - map.remove(12) - assertThat(map[12]).isEqualTo(null) - assertThat(map.size).isEqualTo(1) - - // Remove non-existing element - map.remove(17) - assertThat(map[17]).isEqualTo(null) - assertThat(map.size).isEqualTo(1) - - // Remove all elements - assertThat(map.first()).isEqualTo("3") - map.remove(10) - map.remove(10) - map.remove(0) - assertThat(map.size).isEqualTo(0) - assertThat(map[10]).isEqualTo(null) - assertThat(map.size).isEqualTo(0) - } -} diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestValues.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestValues.kt index 95ef2ce821e1..c6af0d4846e0 100644 --- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestValues.kt +++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestValues.kt @@ -27,18 +27,22 @@ object TestScenes { val SceneB = SceneKey("SceneB") val SceneC = SceneKey("SceneC") val SceneD = SceneKey("SceneD") + val SceneE = SceneKey("SceneE") } /** Overlay keys that can be reused by tests. */ object TestOverlays { val OverlayA = OverlayKey("OverlayA") val OverlayB = OverlayKey("OverlayB") + val OverlayC = OverlayKey("OverlayC") + val OverlayD = OverlayKey("OverlayD") } /** Element keys that can be reused by tests. */ object TestElements { val Foo = ElementKey("Foo") val Bar = ElementKey("Bar") + val LowZIndex = ElementKey("LowZIndex", contentPicker = LowestZIndexContentPicker) } /** Value keys that can be reused by tests. */ diff --git a/packages/SystemUI/res/raw/trackpad_switch_apps_edu.json b/packages/SystemUI/res/raw/trackpad_switch_apps_edu.json new file mode 100644 index 000000000000..1d1d34628a5e --- /dev/null +++ b/packages/SystemUI/res/raw/trackpad_switch_apps_edu.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":60,"ip":37,"op":538,"w":554,"h":564,"nm":"Trackpad-JSON_Quickswitch-EDU","ddd":0,"assets":[{"id":"comp_0","nm":"Trackpad-Quickswitch_toLeft","fr":60,"layers":[{"ddd":0,"ind":2,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","parent":8,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":249,"s":[100]},{"t":255,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[4,0,0],"t":121,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.984,0,0],"t":122,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.922,0,0],"t":123,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.823,0,0],"t":124,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.685,0,0],"t":125,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.507,0,0],"t":126,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.294,0,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.046,0,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[2.768,0,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[2.463,0,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[2.136,0,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[1.788,0,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[1.424,0,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[1.047,0,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0.662,0,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-0.115,0,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-0.5,0,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-1.798,0,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-3.075,0,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-4.319,0,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-5.521,0,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-6.674,0,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-7.774,0,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-8.825,0,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-9.819,0,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-10.761,0,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-11.65,0,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-12.489,0,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-13.282,0,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-14.028,0,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-14.732,0,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-15.397,0,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-16.023,0,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-16.614,0,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-17.171,0,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-17.7,0,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-18.199,0,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-18.672,0,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-19.119,0,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-19.543,0,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-19.945,0,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-20.325,0,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-20.684,0,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-21.025,0,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-21.349,0,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-21.655,0,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-21.945,0,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-22.221,0,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-22.481,0,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-22.728,0,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-22.962,0,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-23.184,0,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-23.393,0,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-23.592,0,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-23.779,0,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-23.956,0,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.124,0,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.283,0,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.433,0,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.574,0,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.706,0,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.831,0,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.947,0,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.055,0,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.158,0,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.253,0,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.341,0,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.423,0,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.497,0,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.566,0,0],"t":191,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.631,0,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.688,0,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.741,0,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.788,0,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.83,0,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.867,0,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.899,0,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.927,0,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.951,0,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.97,0,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.996,0,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[20.5,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Super Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.64],"y":[0.48]},"o":{"x":[0.36],"y":[0]},"t":121,"s":[0]},{"i":{"x":[0.31],"y":[1]},"o":{"x":[0.15],"y":[0.514]},"t":138,"s":[15]},{"t":205,"s":[100]}],"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[82,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[68.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[68.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[82,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"4F","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[36.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[36.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[41,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"3F","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[-41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[-27.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[-27.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[-41,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"1F","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.44,"y":0.44},"t":72,"s":[4.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":247,"s":[4.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[0,0]}],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"2F","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":37,"op":345,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"qs:scale","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[277,197.5,0],"t":37,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5,0],"t":287,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"k":[{"s":[99.903,99.903,100],"t":127,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.828,99.828,100],"t":128,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.731,99.731,100],"t":129,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.615,99.615,100],"t":130,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.479,99.479,100],"t":131,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.327,99.327,100],"t":132,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.16,99.16,100],"t":133,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.979,98.979,100],"t":134,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.789,98.789,100],"t":135,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.591,98.591,100],"t":136,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.388,98.388,100],"t":137,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.183,98.183,100],"t":138,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.978,97.978,100],"t":139,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.774,97.774,100],"t":140,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.574,97.574,100],"t":141,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.729,96.729,100],"t":142,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.95,95.95,100],"t":143,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.256,95.256,100],"t":144,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.657,94.657,100],"t":145,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.158,94.158,100],"t":146,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.758,93.758,100],"t":147,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.452,93.452,100],"t":148,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.233,93.233,100],"t":149,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.091,93.091,100],"t":150,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.085,93.085,100],"t":249,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.929,93.929,100],"t":250,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.014,95.014,100],"t":251,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.985,95.985,100],"t":252,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.803,96.803,100],"t":253,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.48,97.48,100],"t":254,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.039,98.039,100],"t":255,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.498,98.498,100],"t":256,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.874,98.874,100],"t":257,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.179,99.179,100],"t":258,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.424,99.424,100],"t":259,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.617,99.617,100],"t":260,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.765,99.765,100],"t":261,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.872,99.872,100],"t":262,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.946,99.946,100],"t":263,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}],"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Void","np":19,"mn":"Pseudo/250958","ix":1,"en":1,"ef":[{"ty":0,"nm":"Width","mn":"Pseudo/250958-0001","ix":1,"v":{"a":0,"k":100,"ix":1}},{"ty":0,"nm":"Height","mn":"Pseudo/250958-0002","ix":2,"v":{"a":0,"k":100,"ix":2}},{"ty":0,"nm":"Offset X","mn":"Pseudo/250958-0003","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":0,"nm":"Offset Y","mn":"Pseudo/250958-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Roundness","mn":"Pseudo/250958-0005","ix":5,"v":{"a":0,"k":0,"ix":5}},{"ty":6,"nm":"About","mn":"Pseudo/250958-0006","ix":6,"v":0},{"ty":6,"nm":"Plague of null layers.","mn":"Pseudo/250958-0007","ix":7,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0008","ix":8,"v":0},{"ty":6,"nm":"Following projects","mn":"Pseudo/250958-0009","ix":9,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0010","ix":10,"v":0},{"ty":6,"nm":"through time.","mn":"Pseudo/250958-0011","ix":11,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0012","ix":12,"v":0},{"ty":6,"nm":"Be free of the past.","mn":"Pseudo/250958-0013","ix":13,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0014","ix":14,"v":0},{"ty":6,"nm":"Copyright 2023 Battle Axe Inc","mn":"Pseudo/250958-0015","ix":15,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0016","ix":16,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0017","ix":17,"v":0}]}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"screenMatte_app1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[503.5,314.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"QS_App1","parent":3,"tt":1,"tp":4,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[528.828,0,0],"t":125,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[528.311,0,0],"t":126,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[527.45,0,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[526.244,0,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[524.703,0,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[522.835,0,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[520.666,0,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[518.221,0,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[515.526,0,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[512.606,0,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[509.523,0,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[506.294,0,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[502.963,0,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[499.562,0,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[496.143,0,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[492.715,0,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[489.322,0,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[474.472,0,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[459.809,0,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[445.483,0,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[431.585,0,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[418.223,0,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[405.443,0,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[393.278,0,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[381.743,0,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[370.824,0,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[360.508,0,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[350.778,0,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[341.601,0,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[332.958,0,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[324.805,0,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[317.115,0,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[309.865,0,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[303.02,0,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[296.562,0,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[290.467,0,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[284.707,0,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[279.267,0,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[274.119,0,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[269.247,0,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[264.65,0,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[260.286,0,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[256.163,0,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252.263,0,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[248.57,0,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[245.075,0,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[241.76,0,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[238.635,0,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[235.673,0,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[232.866,0,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[230.223,0,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[227.717,0,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[225.358,0,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[223.127,0,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[221.026,0,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[219.045,0,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[217.185,0,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[215.428,0,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[213.792,0,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[212.25,0,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[210.812,0,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[209.468,0,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[208.211,0,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[207.048,0,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[205.972,0,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[204.981,0,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[204.068,0,0],"t":191,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[203.233,0,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[202.466,0,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[201.777,0,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[201.157,0,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[200.606,0,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[200.124,0,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[199.702,0,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[199.34,0,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[199.039,0,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[198.798,0,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[198.608,0,0],"t":202,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[198.479,0,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[198.376,0,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[191.108,0,0],"t":248,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[158.789,0,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[117.772,0,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[88.925,0,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[68.502,0,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.185,0,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.287,0,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[31.832,0,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[24.24,0,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[18.107,0,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[13.165,0,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[9.231,0,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[6.132,0,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.764,0,0],"t":261,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[2.041,0,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0.869,0,0],"t":263,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0.207,0,0],"t":264,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,0,0],"t":265,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"k":[{"s":[252,157.593,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.664,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.755,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.864,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.989,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.128,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.278,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.438,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.604,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.774,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.945,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.115,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.281,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.444,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.601,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.236,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.781,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.236,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.606,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.896,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.117,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.278,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.389,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.419,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.659,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.753,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.407,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.947,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.588,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.309,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.091,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.921,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.791,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.69,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.562,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":504,"h":315,"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"screenMatte_app2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[277,197.5,0],"t":37,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5,0],"t":287,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"k":[{"s":[503.5,314.5],"t":37,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.5,314.5],"t":287,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}}]},"p":{"a":0,"k":[0,0],"ix":3},"r":{"k":[{"s":[28],"t":37,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[28],"t":287,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.208,0.302,0.184,1],"t":37,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.208,0.302,0.184,1],"t":287,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"k":[{"s":[100],"t":37,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":287,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"QS_App2","parent":3,"tt":1,"tp":6,"refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[0,0,0],"t":124,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-0.172,0,0],"t":125,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-0.689,0,0],"t":126,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-1.55,0,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-2.756,0,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-4.297,0,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-6.165,0,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-8.334,0,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-10.779,0,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-13.474,0,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-16.394,0,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-19.477,0,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-22.706,0,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-26.037,0,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-29.438,0,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-32.857,0,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-36.285,0,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-39.678,0,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.528,0,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-69.191,0,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-83.517,0,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-97.415,0,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-110.777,0,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-123.557,0,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-135.722,0,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-147.257,0,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-158.176,0,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-168.492,0,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-178.222,0,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-187.399,0,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-196.042,0,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-204.195,0,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-211.885,0,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-219.135,0,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-225.98,0,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-232.438,0,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-238.533,0,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-244.293,0,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-249.733,0,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-254.881,0,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-259.753,0,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-264.35,0,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-268.714,0,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-272.837,0,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-276.737,0,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-280.43,0,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-283.925,0,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-287.24,0,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-290.365,0,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-293.327,0,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-296.134,0,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-298.777,0,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-301.283,0,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-303.642,0,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-305.873,0,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-307.974,0,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-309.955,0,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-311.815,0,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-313.572,0,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-315.208,0,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-316.75,0,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-318.188,0,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-319.532,0,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-320.789,0,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-321.952,0,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-323.028,0,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-324.019,0,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-324.932,0,0],"t":191,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-325.767,0,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-326.534,0,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-327.223,0,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-327.843,0,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-328.394,0,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-328.876,0,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-329.298,0,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-329.66,0,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-329.961,0,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-330.202,0,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-330.521,0,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-330.624,0,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-337.892,0,0],"t":248,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-370.211,0,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-411.228,0,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-440.075,0,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-460.498,0,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-475.815,0,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-487.713,0,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-497.168,0,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-504.76,0,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-510.893,0,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-515.835,0,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-519.769,0,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-522.868,0,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-525.236,0,0],"t":261,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-526.959,0,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-528.131,0,0],"t":263,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-528.793,0,0],"t":264,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"k":[{"s":[252,157.593,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.664,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.755,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.864,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.989,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.128,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.278,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.438,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.604,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.774,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.945,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.115,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.281,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.444,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.601,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.236,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.781,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.236,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.606,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.896,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.117,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.278,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.389,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.419,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.659,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.753,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.407,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.947,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.588,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.309,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.091,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.921,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.791,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.69,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.562,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":504,"h":315,"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,459,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[200,128],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":18,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843137255,0.301960784314,0.18431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321317559","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[503.5,314.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277.5,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"op","nm":"Stroke align: Outside","a":{"a":0,"k":7,"ix":1},"lj":1,"ml":{"a":0,"k":4,"ix":3},"ix":3,"mn":"ADBE Vector Filter - Offset","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"QS_App1","fr":60,"pfr":1,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[339.937,151.75,0],"ix":2,"l":2},"a":{"a":0,"k":[339.937,151.75,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.021,-1.766],[0,0],[-2.043,0],[0,0],[1.022,1.767]],"o":[[-1.021,-1.766],[0,0],[-1.022,1.767],[0,0],[2.043,0],[0,0]],"v":[[2.297,-7.675],[-2.297,-7.675],[-9.64,5.025],[-7.343,9],[7.343,9],[9.64,5.025]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":0,"k":9,"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Triangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[481.874,21],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Triangle","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,18],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[457.874,21],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[292,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Text field","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[334,279],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Text field","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[109,28],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Sent","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[425.5,208.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Sent","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[160,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":14,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Sent","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[400,158.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Sent","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[126,40],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":14,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Received","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[251,78.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Received","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"roundedMatte 2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","tt":1,"tp":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[334,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[340,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Message","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[82,171.125,0],"ix":2,"l":2},"a":{"a":0,"k":[82,171.125,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[80,177.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 4","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[94,165.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 3","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Avatar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[34,171.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[82.5,140.5,0],"ix":2,"l":2},"a":{"a":0,"k":[82,140.938,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Search","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[82,31.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"header","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[80,257.375],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 6","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[94,245.375],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 5","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Avatar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[34,251.375],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 3","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,64],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Message","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[82,171],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"block","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[80,96.875],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 2","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[94,84.875],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 1","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Avatar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[34,90.875],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"roundedMatte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","tt":1,"tp":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"app only","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]},{"id":"comp_2","nm":"QS_App2","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28,75.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-7,-0.65],[-7,8.5],[-2,8.5],[-2,2.5],[2,2.5],[2,8.5],[7,8.5],[7,-0.65],[9.8,1.5],[11,-0.1],[7,-3.15],[7,-7.5],[4,-7.5],[4,-5.45],[0,-8.5],[-11,-0.1],[-9.8,1.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,-0.533],[0,0],[-0.4,0.333],[-0.533,0],[-0.4,-0.35]],"o":[[0,0],[0,-0.533],[0.4,-0.35],[0.533,0],[0.4,0.333]],"v":[[2,-1.475],[-2,-1.475],[-1.4,-2.775],[0,-3.3],[1.4,-2.775]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 2","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,76,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1.425,6.6],[-4.175,1],[8,1],[8,-1],[-4.175,-1],[1.425,-6.6],[0,-8],[-8,0],[0,8]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[92,76,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8,1],[4.175,1],[-1.425,6.6],[0,8],[8,0],[0,-8],[-1.425,-6.6],[4.175,-1],[-8,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[124,76,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.55,-1.55],[-2.233,0],[-1.433,1.117],[-0.467,1.767],[0,0],[1.033,-0.733],[1.283,0],[1.167,1.167],[0,1.667],[-1.167,1.167],[-1.667,0],[-0.917,-0.533],[-0.533,-0.933],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[1.05,0.467],[1.15,0],[1.55,-1.55],[0,-2.233]],"o":[[1.55,1.55],[1.833,0],[1.433,-1.117],[0,0],[-0.417,1.2],[-1.033,0.733],[-1.667,0],[-1.167,-1.167],[0,-1.667],[1.167,-1.167],[1.083,0],[0.933,0.533],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.75,-0.883],[-1.05,-0.483],[-2.233,0],[-1.55,1.55],[0,2.233]],"v":[[-5.675,5.675],[0,8],[4.9,6.325],[7.75,2],[5.65,2],[3.475,4.9],[0,6],[-4.25,4.25],[-6,0],[-4.25,-4.25],[0,-6],[3,-5.2],[5.2,-3],[1,-3],[1,-1],[8,-1],[8,-8],[6,-8],[6,-5.25],[3.3,-7.275],[0,-8],[-5.675,-5.675],[-8,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[320,76,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[336,24],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":360,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".onTertiaryFixedVariant","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"onTertiaryFixedVariant"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"appView Matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","tt":1,"tp":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,179.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-4.418],[0,0],[0,0],[0,0],[4.418,0]],"o":[[-4.418,0],[0,0],[0,0],[0,0],[0,-4.418],[0,0]],"v":[[-244,-135.5],[-252,-127.5],[-252,135.5],[252,135.5],[252,-127.5],[244,-135.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".onTertiaryFixed","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"onTertiaryFixed"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[158,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-7,1],[-1,1],[-1,7],[1,7],[1,1],[7,1],[7,-1],[1,-1],[1,-7],[-1,-7],[-1,-1],[-7,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[32,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,18],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[124,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-7,5.6],[-5.6,7],[0,1.4],[5.6,7],[7,5.6],[1.4,0],[7,-5.6],[5.6,-7],[0,-1.4],[-5.6,-7],[-7,-5.6],[-1.4,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[78.5,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-6.627],[0,0],[0,0],[0,0],[6.627,0]],"o":[[-6.627,0],[0,0],[0,0],[0,0],[0,-6.627],[0,0]],"v":[[-50.5,-16],[-62.5,-4],[-62.5,20],[62.5,20],[62.5,-4],[50.5,-16]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".onTertiaryFixed","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"onTertiaryFixed"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"background Matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","tt":1,"tp":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".onTertiaryFixedVariant","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"onTertiaryFixedVariant"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0}]},{"id":"comp_3","nm":"Trackpad-Quickswitch_toRight","fr":60,"layers":[{"ddd":0,"ind":2,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","parent":8,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":249,"s":[100]},{"t":255,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[4,0,0],"t":121,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.014,0,0],"t":122,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.067,0,0],"t":123,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.152,0,0],"t":124,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.27,0,0],"t":125,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.423,0,0],"t":126,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.606,0,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.819,0,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[5.06,0,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[5.327,0,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[5.613,0,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[5.916,0,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[6.233,0,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[6.56,0,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[6.893,0,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[7.566,0,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[7.9,0,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[9.025,0,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[10.133,0,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[11.21,0,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[12.251,0,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[13.25,0,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[14.205,0,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[15.115,0,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[15.977,0,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[16.793,0,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[17.564,0,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[18.291,0,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[18.978,0,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[19.624,0,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[20.235,0,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[20.81,0,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[21.353,0,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[21.865,0,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[22.349,0,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[22.807,0,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[23.24,0,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[23.65,0,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[24.038,0,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[24.405,0,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[24.753,0,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[25.082,0,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[25.393,0,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[25.689,0,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[25.969,0,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[26.235,0,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[26.486,0,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[26.725,0,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[26.951,0,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[27.164,0,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[27.367,0,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[27.56,0,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[27.741,0,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[27.913,0,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[28.074,0,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[28.227,0,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[28.372,0,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[28.508,0,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[28.636,0,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[28.758,0,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[28.871,0,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[28.979,0,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.079,0,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.173,0,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.263,0,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.346,0,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.422,0,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.494,0,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.56,0,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.62,0,0],"t":191,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.677,0,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.727,0,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.774,0,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.815,0,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.852,0,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.884,0,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.912,0,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.937,0,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.958,0,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.988,0,0],"t":202,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[20.5,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Super Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.64],"y":[0.48]},"o":{"x":[0.36],"y":[0]},"t":121,"s":[0]},{"i":{"x":[0.31],"y":[1]},"o":{"x":[0.15],"y":[0.514]},"t":138,"s":[15]},{"t":205,"s":[100]}],"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[82,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[68.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[68.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[82,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"4F","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[36.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[36.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[41,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"3F","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[-41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[-27.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[-27.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[-41,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"1F","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.44,"y":0.44},"t":72,"s":[4.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":247,"s":[4.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[0,0]}],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"2F","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":37,"op":345,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"qs:scale","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[277,197.5,0],"t":37,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5,0],"t":286,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"k":[{"s":[99.903,99.903,100],"t":127,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.828,99.828,100],"t":128,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.731,99.731,100],"t":129,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.615,99.615,100],"t":130,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.479,99.479,100],"t":131,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.327,99.327,100],"t":132,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.16,99.16,100],"t":133,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.979,98.979,100],"t":134,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.789,98.789,100],"t":135,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.591,98.591,100],"t":136,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.388,98.388,100],"t":137,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.183,98.183,100],"t":138,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.978,97.978,100],"t":139,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.774,97.774,100],"t":140,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.574,97.574,100],"t":141,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.729,96.729,100],"t":142,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.95,95.95,100],"t":143,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.256,95.256,100],"t":144,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.657,94.657,100],"t":145,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[94.158,94.158,100],"t":146,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.758,93.758,100],"t":147,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.452,93.452,100],"t":148,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.233,93.233,100],"t":149,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.091,93.091,100],"t":150,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.085,93.085,100],"t":249,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.929,93.929,100],"t":250,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.014,95.014,100],"t":251,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.985,95.985,100],"t":252,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.803,96.803,100],"t":253,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.48,97.48,100],"t":254,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.039,98.039,100],"t":255,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.498,98.498,100],"t":256,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.874,98.874,100],"t":257,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.179,99.179,100],"t":258,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.424,99.424,100],"t":259,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.617,99.617,100],"t":260,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.765,99.765,100],"t":261,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.872,99.872,100],"t":262,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.946,99.946,100],"t":263,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}],"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Void","np":19,"mn":"Pseudo/250958","ix":1,"en":1,"ef":[{"ty":0,"nm":"Width","mn":"Pseudo/250958-0001","ix":1,"v":{"a":0,"k":100,"ix":1}},{"ty":0,"nm":"Height","mn":"Pseudo/250958-0002","ix":2,"v":{"a":0,"k":100,"ix":2}},{"ty":0,"nm":"Offset X","mn":"Pseudo/250958-0003","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":0,"nm":"Offset Y","mn":"Pseudo/250958-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Roundness","mn":"Pseudo/250958-0005","ix":5,"v":{"a":0,"k":0,"ix":5}},{"ty":6,"nm":"About","mn":"Pseudo/250958-0006","ix":6,"v":0},{"ty":6,"nm":"Plague of null layers.","mn":"Pseudo/250958-0007","ix":7,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0008","ix":8,"v":0},{"ty":6,"nm":"Following projects","mn":"Pseudo/250958-0009","ix":9,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0010","ix":10,"v":0},{"ty":6,"nm":"through time.","mn":"Pseudo/250958-0011","ix":11,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0012","ix":12,"v":0},{"ty":6,"nm":"Be free of the past.","mn":"Pseudo/250958-0013","ix":13,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0014","ix":14,"v":0},{"ty":6,"nm":"Copyright 2023 Battle Axe Inc","mn":"Pseudo/250958-0015","ix":15,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0016","ix":16,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0017","ix":17,"v":0}]}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"screenMatte_app1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[503.5,314.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"QS_App1","parent":3,"tt":1,"tp":4,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[0,0,0],"t":124,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0.172,0,0],"t":125,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0.689,0,0],"t":126,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[1.55,0,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[2.756,0,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.297,0,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[6.165,0,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[8.334,0,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[10.779,0,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[13.474,0,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[16.394,0,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[19.477,0,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[22.706,0,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[26.037,0,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[29.438,0,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[32.857,0,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.285,0,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[39.678,0,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.528,0,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[69.191,0,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[83.517,0,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[97.415,0,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[110.777,0,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[123.557,0,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[135.722,0,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[147.257,0,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[158.176,0,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[168.492,0,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[178.222,0,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[187.399,0,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[196.042,0,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[204.195,0,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[211.885,0,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[219.135,0,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[225.98,0,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[232.438,0,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[238.533,0,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[244.293,0,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[249.733,0,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[254.881,0,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[259.753,0,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[264.35,0,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[268.714,0,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[272.837,0,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[276.737,0,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[280.43,0,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[283.925,0,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[287.24,0,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[290.365,0,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[293.327,0,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[296.134,0,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[298.777,0,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[301.283,0,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[303.642,0,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[305.873,0,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[307.974,0,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[309.955,0,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[311.815,0,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[313.572,0,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[315.208,0,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[316.75,0,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[318.188,0,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[319.532,0,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[320.789,0,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[321.952,0,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[323.028,0,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[324.019,0,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[324.932,0,0],"t":191,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[325.767,0,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[326.534,0,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[327.223,0,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[327.843,0,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[328.394,0,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[328.876,0,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[329.298,0,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[329.66,0,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[329.961,0,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[330.202,0,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[330.521,0,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[330.624,0,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[337.892,0,0],"t":248,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[370.211,0,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[411.228,0,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[440.075,0,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[460.498,0,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[475.815,0,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[487.713,0,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[497.168,0,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[504.76,0,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[510.893,0,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[515.835,0,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[519.769,0,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[522.868,0,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[525.236,0,0],"t":261,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[526.959,0,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[528.131,0,0],"t":263,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[528.793,0,0],"t":264,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"k":[{"s":[252,157.593,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.664,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.755,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.864,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.989,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.128,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.278,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.438,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.604,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.774,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.945,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.115,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.281,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.444,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.601,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.236,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.781,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.236,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.606,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.896,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.117,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.278,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.389,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.419,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.659,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.753,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.407,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.947,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.588,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.309,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.091,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.921,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.791,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.69,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.562,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":504,"h":315,"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"screenMatte_app2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[277,197.5,0],"t":37,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5,0],"t":286,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"k":[{"s":[503.5,314.5],"t":37,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.5,314.5],"t":286,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}}]},"p":{"a":0,"k":[0,0],"ix":3},"r":{"k":[{"s":[28],"t":37,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[28],"t":286,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.208,0.302,0.184,1],"t":37,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.208,0.302,0.184,1],"t":286,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"k":[{"s":[100],"t":37,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":286,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"QS_App2","parent":3,"tt":1,"tp":6,"refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[-528.828,0,0],"t":125,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-528.311,0,0],"t":126,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-527.45,0,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-526.244,0,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-524.703,0,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-522.835,0,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-520.666,0,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-518.221,0,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-515.526,0,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-512.606,0,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-509.523,0,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-506.294,0,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-502.963,0,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-499.562,0,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-496.143,0,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-492.715,0,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-489.322,0,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-474.472,0,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-459.809,0,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-445.483,0,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-431.585,0,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-418.223,0,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-405.443,0,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-393.278,0,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-381.743,0,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-370.824,0,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-360.508,0,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-350.778,0,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-341.601,0,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-332.958,0,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-324.805,0,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-317.115,0,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-309.865,0,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-303.02,0,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-296.562,0,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-290.467,0,0],"t":160,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-284.707,0,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-279.267,0,0],"t":162,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-274.119,0,0],"t":163,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-269.247,0,0],"t":164,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-264.65,0,0],"t":165,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-260.286,0,0],"t":166,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-256.163,0,0],"t":167,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-252.263,0,0],"t":168,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-248.57,0,0],"t":169,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-245.075,0,0],"t":170,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-241.76,0,0],"t":171,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-238.635,0,0],"t":172,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-235.673,0,0],"t":173,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-232.866,0,0],"t":174,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-230.223,0,0],"t":175,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-227.717,0,0],"t":176,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-225.358,0,0],"t":177,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-223.127,0,0],"t":178,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-221.026,0,0],"t":179,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-219.045,0,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-217.185,0,0],"t":181,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-215.428,0,0],"t":182,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-213.792,0,0],"t":183,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-212.25,0,0],"t":184,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-210.812,0,0],"t":185,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-209.468,0,0],"t":186,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-208.211,0,0],"t":187,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-207.048,0,0],"t":188,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-205.972,0,0],"t":189,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-204.981,0,0],"t":190,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-204.068,0,0],"t":191,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-203.233,0,0],"t":192,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-202.466,0,0],"t":193,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-201.777,0,0],"t":194,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-201.157,0,0],"t":195,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-200.606,0,0],"t":196,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-200.124,0,0],"t":197,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-199.702,0,0],"t":198,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-199.34,0,0],"t":199,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-199.039,0,0],"t":200,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-198.798,0,0],"t":201,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-198.608,0,0],"t":202,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-198.479,0,0],"t":203,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-198.376,0,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-191.108,0,0],"t":248,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-158.789,0,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-117.772,0,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-88.925,0,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.502,0,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.185,0,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-41.287,0,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-31.832,0,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.24,0,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-18.107,0,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-13.165,0,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-9.231,0,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-6.132,0,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-3.764,0,0],"t":261,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-2.041,0,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-0.869,0,0],"t":263,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-0.207,0,0],"t":264,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,0,0],"t":265,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"k":[{"s":[252,157.593,0],"t":127,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.664,0],"t":128,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.755,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.864,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.989,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.128,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.278,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.438,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.604,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.774,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.945,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.115,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.281,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.444,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.601,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.236,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.781,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.236,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.606,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.896,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.117,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.278,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.389,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,162.419,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.659,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.753,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.407,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.947,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.588,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.309,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.091,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.921,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.791,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.69,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.562,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":504,"h":315,"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,459,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[200,128],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":18,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843137255,0.301960784314,0.18431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321317559","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[503.5,314.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277.5,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"op","nm":"Stroke align: Outside","a":{"a":0,"k":7,"ix":1},"lj":1,"ml":{"a":0,"k":4,"ix":3},"ix":3,"mn":"ADBE Vector Filter - Offset","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Trackpad-Quickswitch_toLeft","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,282,0],"ix":2,"l":2},"a":{"a":0,"k":[277,282,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":554,"h":564,"ip":287,"op":707,"st":250,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Trackpad-Quickswitch_toRight","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,282,0],"ix":2,"l":2},"a":{"a":0,"k":[277,282,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":554,"h":564,"ip":0,"op":287,"st":0,"bm":0}],"markers":[{"tm":37,"cm":"","dr":500},{"tm":121,"cm":"gesture to R","dr":84},{"tm":205,"cm":"end of gesture","dr":0},{"tm":247,"cm":"release","dr":0},{"tm":371,"cm":"gesture to L","dr":84},{"tm":455,"cm":"end of L gesture","dr":0},{"tm":497,"cm":"release","dr":0}],"props":{}}
\ No newline at end of file diff --git a/packages/SystemUI/res/raw/trackpad_switch_apps_success.json b/packages/SystemUI/res/raw/trackpad_switch_apps_success.json new file mode 100644 index 000000000000..33925ed9d25e --- /dev/null +++ b/packages/SystemUI/res/raw/trackpad_switch_apps_success.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":60,"ip":0,"op":78,"w":554,"h":564,"nm":"Trackpad-JSON_Quickswitch-Success","ddd":0,"assets":[{"id":"comp_0","nm":"TrackpadBack_Success_Checkmark","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Check Rotate","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.12],"y":[1]},"o":{"x":[0.44],"y":[0]},"t":2,"s":[-16]},{"t":20,"s":[6]}],"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[95.049,95.049,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":228,"st":-72,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Bounce","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.12],"y":[1]},"o":{"x":[0.44],"y":[0]},"t":12,"s":[0]},{"t":36,"s":[-6]}],"ix":10},"p":{"a":0,"k":[81,127,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.263,0.263,0.833],"y":[1.126,1.126,1]},"o":{"x":[0.05,0.05,0.05],"y":[0.958,0.958,0]},"t":1,"s":[80,80,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.45,0.45,0.167],"y":[0.325,0.325,0]},"t":20,"s":[105,105,100]},{"t":36,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-0.289,"ix":10},"p":{"a":0,"k":[14.364,-33.591,0],"ix":2,"l":2},"a":{"a":0,"k":[-0.125,0,0],"ix":1,"l":2},"s":{"a":0,"k":[104.744,104.744,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.401,-0.007],[-10.033,11.235]],"o":[[5.954,7.288],[1.401,0.007],[0,0]],"v":[[-28.591,4.149],[-10.73,26.013],[31.482,-21.255]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":3,"s":[0]},{"i":{"x":[0.22],"y":[1]},"o":{"x":[0.001],"y":[0.149]},"t":10,"s":[29]},{"t":27,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":11,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":5,"op":44,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[95,95,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.275,0.275,0.21],"y":[1.102,1.102,1]},"o":{"x":[0.037,0.037,0.05],"y":[0.476,0.476,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.252,0.252,0.47],"y":[0.159,0.159,0]},"t":16,"s":[120,120,100]},{"t":28,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.32,0.32],"y":[0.11,0.11]},"t":16,"s":[148,148]},{"t":28,"s":[136,136]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":88,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.208,0.302,0.184,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.208,0.302,0.184,1],"t":43,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Checkbox - Widget","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"Trackpad-Quickswitch_toRight","fr":60,"layers":[{"ddd":0,"ind":2,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","parent":8,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":249,"s":[100]},{"t":255,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[30,0,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[30,0,0],"t":282,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[20.5,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Super Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.64],"y":[0.48]},"o":{"x":[0.36],"y":[0]},"t":121,"s":[0]},{"i":{"x":[0.31],"y":[1]},"o":{"x":[0.15],"y":[0.514]},"t":138,"s":[15]},{"t":205,"s":[100]}],"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[82,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[68.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[68.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[82,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"4F","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[36.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[36.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[41,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"3F","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[-41,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.426,"y":0.426},"t":72,"s":[-27.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.657,"y":1},"o":{"x":0.42,"y":0},"t":247,"s":[-27.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[-41,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"1F","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":62,"s":[36,36]},{"i":{"x":[0.56,0.56],"y":[1,1]},"o":{"x":[0.446,0.446],"y":[0,0]},"t":72,"s":[28,28]},{"i":{"x":[0.656,0.656],"y":[1,1]},"o":{"x":[0.44,0.44],"y":[0,0]},"t":247,"s":[28,28]},{"t":257,"s":[36,36]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":62,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":0.56},"o":{"x":0.44,"y":0.44},"t":72,"s":[4.5,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.56,"y":1},"o":{"x":0.44,"y":0},"t":247,"s":[4.5,0],"to":[0,0],"ti":[0,0]},{"t":257,"s":[0,0]}],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"2F","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":37,"op":345,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"qs:scale","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[277,197.5,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5,0],"t":282,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"k":[{"s":[93.085,93.085,100],"t":249,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[93.929,93.929,100],"t":250,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.014,95.014,100],"t":251,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[95.985,95.985,100],"t":252,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[96.803,96.803,100],"t":253,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[97.48,97.48,100],"t":254,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.039,98.039,100],"t":255,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.498,98.498,100],"t":256,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[98.874,98.874,100],"t":257,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.179,99.179,100],"t":258,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.424,99.424,100],"t":259,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.617,99.617,100],"t":260,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.765,99.765,100],"t":261,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.872,99.872,100],"t":262,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}},{"s":[99.946,99.946,100],"t":263,"i":{"x":[1,1,1],"y":[1,1,1]},"o":{"x":[0,0,0],"y":[0,0,0]}}],"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Void","np":19,"mn":"Pseudo/250958","ix":1,"en":1,"ef":[{"ty":0,"nm":"Width","mn":"Pseudo/250958-0001","ix":1,"v":{"a":0,"k":100,"ix":1}},{"ty":0,"nm":"Height","mn":"Pseudo/250958-0002","ix":2,"v":{"a":0,"k":100,"ix":2}},{"ty":0,"nm":"Offset X","mn":"Pseudo/250958-0003","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":0,"nm":"Offset Y","mn":"Pseudo/250958-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Roundness","mn":"Pseudo/250958-0005","ix":5,"v":{"a":0,"k":0,"ix":5}},{"ty":6,"nm":"About","mn":"Pseudo/250958-0006","ix":6,"v":0},{"ty":6,"nm":"Plague of null layers.","mn":"Pseudo/250958-0007","ix":7,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0008","ix":8,"v":0},{"ty":6,"nm":"Following projects","mn":"Pseudo/250958-0009","ix":9,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0010","ix":10,"v":0},{"ty":6,"nm":"through time.","mn":"Pseudo/250958-0011","ix":11,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0012","ix":12,"v":0},{"ty":6,"nm":"Be free of the past.","mn":"Pseudo/250958-0013","ix":13,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0014","ix":14,"v":0},{"ty":6,"nm":"Copyright 2023 Battle Axe Inc","mn":"Pseudo/250958-0015","ix":15,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0016","ix":16,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0017","ix":17,"v":0}]}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"screenMatte_app1","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[503.5,314.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"QS_App1","parent":3,"tt":1,"tp":4,"refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[330.624,0,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[337.892,0,0],"t":248,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[370.211,0,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[411.228,0,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[440.075,0,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[460.498,0,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[475.815,0,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[487.713,0,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[497.168,0,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[504.76,0,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[510.893,0,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[515.835,0,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[519.769,0,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[522.868,0,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[525.236,0,0],"t":261,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[526.959,0,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[528.131,0,0],"t":263,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[528.793,0,0],"t":264,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"k":[{"s":[252,162.419,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.659,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.753,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.407,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.947,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.588,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.309,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.091,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.921,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.791,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.69,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.562,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":504,"h":315,"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"screenMatte_app2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[277,197.5,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5,0],"t":282,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"k":[{"s":[503.5,314.5],"t":247,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"s":[503.5,314.5],"t":282,"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}}]},"p":{"a":0,"k":[0,0],"ix":3},"r":{"k":[{"s":[28],"t":247,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[28],"t":282,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.208,0.302,0.184,1],"t":247,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.208,0.302,0.184,1],"t":282,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"k":[{"s":[100],"t":247,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[100],"t":282,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"QS_App2","parent":3,"tt":1,"tp":6,"refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[-198.376,0,0],"t":247,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-191.108,0,0],"t":248,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-158.789,0,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-117.772,0,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-88.925,0,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-68.502,0,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.185,0,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-41.287,0,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-31.832,0,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-24.24,0,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-18.107,0,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-13.165,0,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-9.231,0,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-6.132,0,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-3.764,0,0],"t":261,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-2.041,0,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-0.869,0,0],"t":263,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-0.207,0,0],"t":264,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[0,0,0],"t":265,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"k":[{"s":[252,162.419,0],"t":249,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,161.659,0],"t":250,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160.753,0],"t":251,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,160,0],"t":252,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,159.407,0],"t":253,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.947,0],"t":254,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.588,0],"t":255,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.309,0],"t":256,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,158.091,0],"t":257,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.921,0],"t":258,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.791,0],"t":259,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.69,0],"t":260,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252,157.562,0],"t":262,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":504,"h":315,"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,459,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[200,128],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":18,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843137255,0.301960784314,0.18431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321317559","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[503.5,314.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277.5,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"op","nm":"Stroke align: Outside","a":{"a":0,"k":7,"ix":1},"lj":1,"ml":{"a":0,"k":4,"ix":3},"ix":3,"mn":"ADBE Vector Filter - Offset","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":457,"st":0,"ct":1,"bm":0}]},{"id":"comp_2","nm":"QS_App1","fr":60,"pfr":1,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[339.937,151.75,0],"ix":2,"l":2},"a":{"a":0,"k":[339.937,151.75,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.021,-1.766],[0,0],[-2.043,0],[0,0],[1.022,1.767]],"o":[[-1.021,-1.766],[0,0],[-1.022,1.767],[0,0],[2.043,0],[0,0]],"v":[[2.297,-7.675],[-2.297,-7.675],[-9.64,5.025],[-7.343,9],[7.343,9],[9.64,5.025]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":0,"k":9,"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Triangle","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[481.874,21],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Triangle","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,18],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[457.874,21],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[292,25],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Text field","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[334,279],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Text field","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[109,28],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Sent","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[425.5,208.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Sent","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[160,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":14,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Sent","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[400,158.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Sent","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[126,40],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":14,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Received","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[251,78.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Received","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"roundedMatte 2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","tt":1,"tp":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[334,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[340,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Message","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[82,171.125,0],"ix":2,"l":2},"a":{"a":0,"k":[82,171.125,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[80,177.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 4","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[94,165.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 3","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Avatar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[34,171.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[82.5,140.5,0],"ix":2,"l":2},"a":{"a":0,"k":[82,140.938,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,22],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Search","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[82,31.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"header","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[80,257.375],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 6","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[94,245.375],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 5","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Avatar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[34,251.375],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 3","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[132,64],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Message","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[82,171],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"block","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[64,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[80,96.875],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 2","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[92,8],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[94,84.875],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Line 1","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":200,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Avatar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[34,90.875],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"roundedMatte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","tt":1,"tp":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"app only","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"ct":1,"bm":0}]},{"id":"comp_3","nm":"QS_App2","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28,75.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-7,-0.65],[-7,8.5],[-2,8.5],[-2,2.5],[2,2.5],[2,8.5],[7,8.5],[7,-0.65],[9.8,1.5],[11,-0.1],[7,-3.15],[7,-7.5],[4,-7.5],[4,-5.45],[0,-8.5],[-11,-0.1],[-9.8,1.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,-0.533],[0,0],[-0.4,0.333],[-0.533,0],[-0.4,-0.35]],"o":[[0,0],[0,-0.533],[0.4,-0.35],[0.533,0],[0.4,0.333]],"v":[[2,-1.475],[-2,-1.475],[-1.4,-2.775],[0,-3.3],[1.4,-2.775]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":5,"nm":"Merge Paths 2","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[60,76,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[1.425,6.6],[-4.175,1],[8,1],[8,-1],[-4.175,-1],[1.425,-6.6],[0,-8],[-8,0],[0,8]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[92,76,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8,1],[4.175,1],[-1.425,6.6],[0,8],[8,0],[0,-8],[-1.425,-6.6],[4.175,-1],[-8,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[124,76,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.55,-1.55],[-2.233,0],[-1.433,1.117],[-0.467,1.767],[0,0],[1.033,-0.733],[1.283,0],[1.167,1.167],[0,1.667],[-1.167,1.167],[-1.667,0],[-0.917,-0.533],[-0.533,-0.933],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[1.05,0.467],[1.15,0],[1.55,-1.55],[0,-2.233]],"o":[[1.55,1.55],[1.833,0],[1.433,-1.117],[0,0],[-0.417,1.2],[-1.033,0.733],[-1.667,0],[-1.167,-1.167],[0,-1.667],[1.167,-1.167],[1.083,0],[0.933,0.533],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.75,-0.883],[-1.05,-0.483],[-2.233,0],[-1.55,1.55],[0,2.233]],"v":[[-5.675,5.675],[0,8],[4.9,6.325],[7.75,2],[5.65,2],[3.475,4.9],[0,6],[-4.25,4.25],[-6,0],[-4.25,-4.25],[0,-6],[3,-5.2],[5.2,-3],[1,-3],[1,-1],[8,-1],[8,-8],[6,-8],[6,-5.25],[3.3,-7.275],[0,-8],[-5.675,-5.675],[-8,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[320,76,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[336,24],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":360,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".onTertiaryFixedVariant","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"onTertiaryFixedVariant"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"appView Matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","tt":1,"tp":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,179.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-4.418],[0,0],[0,0],[0,0],[4.418,0]],"o":[[-4.418,0],[0,0],[0,0],[0,0],[0,-4.418],[0,0]],"v":[[-244,-135.5],[-252,-127.5],[-252,135.5],[252,135.5],[252,-127.5],[244,-135.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".onTertiaryFixed","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"onTertiaryFixed"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[158,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-7,1],[-1,1],[-1,7],[1,7],[1,1],[7,1],[7,-1],[1,-1],[1,-7],[-1,-7],[-1,-1],[-7,-1]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[32,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[18,18],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":39.375,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[124,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-7,5.6],[-5.6,7],[0,1.4],[5.6,7],[7,5.6],[1.4,0],[7,-5.6],[5.6,-7],[0,-1.4],[-5.6,-7],[-7,-5.6],[-1.4,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".tertiaryFixedDim","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"tertiaryFixedDim"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[78.5,28,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-6.627],[0,0],[0,0],[0,0],[6.627,0]],"o":[[-6.627,0],[0,0],[0,0],[0,0],[0,-6.627],[0,0]],"v":[[-50.5,-16],[-62.5,-4],[-62.5,20],[62.5,20],[62.5,-4],[50.5,-16]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450980619,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".onTertiaryFixed","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"onTertiaryFixed"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"background Matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","tt":1,"tp":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[252,157.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".onTertiaryFixedVariant","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"onTertiaryFixedVariant"}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"TrackpadBack_Success_Checkmark","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,198.5,0],"ix":2,"l":2},"a":{"a":0,"k":[95,95,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":190,"h":190,"ip":34,"op":78,"st":34,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".onTertiaryFixed","cl":"onTertiaryFixed","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":29,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":35,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":417,"s":[100]},{"t":420,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Global Position","np":4,"mn":"Pseudo/88900","ix":1,"en":1,"ef":[{"ty":10,"nm":"Master Parent","mn":"Pseudo/88900-0001","ix":1,"v":{"a":0,"k":2,"ix":1}},{"ty":3,"nm":"Global Position","mn":"Pseudo/88900-0002","ix":2,"v":{"k":[{"s":[277,197.5],"t":28,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[277,197.5],"t":77,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}]}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.039215687662,0.1254902035,0.027450982481,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":28,"op":78,"st":28,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".onTertiaryFixedVariant","cl":"onTertiaryFixedVariant","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,459,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[200,128],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":18,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.207843139768,0.301960796118,0.184313729405,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321317559","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":91,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":91,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Trackpad-Quickswitch_toRight","tt":1,"tp":4,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,282,0],"ix":2,"l":2},"a":{"a":0,"k":[277,282,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":554,"h":564,"ip":0,"op":36,"st":-247,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".tertiaryFixedDim","cl":"tertiaryFixedDim","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,197.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[504,315],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"op","nm":"Stroke align: Outside","a":{"a":0,"k":7,"ix":1},"lj":1,"ml":{"a":0,"k":4,"ix":3},"ix":3,"mn":"ADBE Vector Filter - Offset","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.811764717102,0.654901981354,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"frame","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":91,"st":0,"ct":1,"bm":0}],"markers":[{"tm":121,"cm":"gesture to R","dr":84},{"tm":371,"cm":"gesture to L","dr":84}],"props":{}}
\ No newline at end of file diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 752b71c2c4a0..c800b0374155 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -4000,13 +4000,13 @@ <!-- Touchpad switch apps gesture action name in tutorial [CHAR LIMIT=NONE] --> <string name="touchpad_switch_apps_gesture_action_title">Switch apps</string> <!-- Touchpad switch apps gesture guidance in gestures tutorial [CHAR LIMIT=NONE] --> - <string name="touchpad_switch_apps_gesture_guidance">Swipe left or right using four fingers on your touchpad</string> + <string name="touchpad_switch_apps_gesture_guidance">Swipe left using four fingers on your touchpad</string> <!-- Screen title after switch apps gesture was done successfully [CHAR LIMIT=NONE] --> <string name="touchpad_switch_apps_gesture_success_title">Great job!</string> <!-- Text shown to the user after they complete switch apps gesture tutorial [CHAR LIMIT=NONE] --> <string name="touchpad_switch_apps_gesture_success_body">You completed the switch apps gesture.</string> <!-- Text shown to the user after switch gesture was not done correctly [CHAR LIMIT=NONE] --> - <string name="touchpad_switch_gesture_error_body">Swipe left or right using four fingers on your touchpad to switch apps</string> + <string name="touchpad_switch_gesture_error_body">Swipe left using four fingers on your touchpad to switch apps</string> <!-- KEYBOARD TUTORIAL--> <!-- Action key tutorial title [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java index 81a520661cfe..643f3bb917d1 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -30,6 +30,7 @@ import android.os.Looper; import android.os.Parcelable; import android.os.Trace; import android.util.ArrayMap; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -52,6 +53,8 @@ import javax.inject.Provider; public class FragmentHostManager { + private static final String TAG = "FragmentHostManager"; + private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Context mContext; private final HashMap<String, ArrayList<FragmentListener>> mListeners = new HashMap<>(); @@ -84,7 +87,7 @@ public class FragmentHostManager { FragmentHostManager create(View rootView); } - private void createFragmentHost(Parcelable savedState) { + private void createFragmentHost(@Nullable Parcelable savedState) { mFragments = FragmentController.createController(new HostCallbacks()); mFragments.attachHost(null); mLifecycleCallbacks = new FragmentLifecycleCallbacks() { @@ -115,12 +118,21 @@ public class FragmentHostManager { mFragments.dispatchResume(); } + @Nullable private Parcelable destroyFragmentHost() { - mFragments.dispatchPause(); - Parcelable p = mFragments.saveAllState(); - mFragments.dispatchStop(); - mFragments.dispatchDestroy(); - mFragments.getFragmentManager().unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks); + Parcelable p = null; + try { + mFragments.dispatchPause(); + p = mFragments.saveAllState(); + mFragments.dispatchStop(); + mFragments.dispatchDestroy(); + mFragments + .getFragmentManager() + .unregisterFragmentLifecycleCallbacks(mLifecycleCallbacks); + } catch (IllegalStateException e) { + Log.e(TAG, "Failed to destroy fragment host. This is expected to happen only in " + + "tests when displays are added and removed quickly"); + } return p; } diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt index 21afa40c441b..8cbcba2c3b1c 100644 --- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt @@ -43,7 +43,6 @@ import androidx.compose.runtime.saveable.mapSaver import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.stringResource @@ -136,7 +135,7 @@ fun ActionTutorialContent( val buttonAlpha by animateFloatAsState(if (actionState is Finished) 1f else 0f) DoneButton( onDoneButtonClicked = onDoneButtonClicked, - modifier = Modifier.graphicsLayer { alpha = buttonAlpha }, + modifier = Modifier.padding(horizontal = 60.dp).graphicsLayer { alpha = buttonAlpha }, enabled = actionState is Finished, ) } @@ -216,7 +215,7 @@ fun TutorialDescription( Text( text = stringResource(id = bodyTextId), style = MaterialTheme.typography.bodyLarge, - color = Color.White, + color = config.colors.bodyText, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt index 26259912741a..eda23a51a1ae 100644 --- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt @@ -16,9 +16,12 @@ package com.android.systemui.inputdevice.tutorial.ui.composable +import androidx.annotation.ColorInt import androidx.annotation.RawRes import androidx.annotation.StringRes import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.core.graphics.ColorUtils import com.airbnb.lottie.compose.LottieDynamicProperties data class TutorialScreenConfig( @@ -30,8 +33,23 @@ data class TutorialScreenConfig( data class Colors( val background: Color, val title: Color, + val bodyText: Color, val animationColors: LottieDynamicProperties, - ) + ) { + constructor( + background: Color, + title: Color, + animationColors: LottieDynamicProperties, + ) : this(background, title, textColorOnBackground(background.toArgb()), animationColors) + + companion object { + private fun textColorOnBackground(@ColorInt background: Int): Color { + val whiteContrast = ColorUtils.calculateContrast(Color.White.toArgb(), background) + val blackContrast = ColorUtils.calculateContrast(Color.Black.toArgb(), background) + return if (whiteContrast >= blackContrast) Color.White else Color.Black + } + } + } data class Strings( @StringRes val titleResId: Int, diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt index a16b4a6892b4..f1945e657d52 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyboard.shortcut.ui import android.app.Dialog +import android.content.res.Resources import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width @@ -26,6 +27,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo import com.android.systemui.keyboard.shortcut.ui.composable.ShortcutCustomizationDialog import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState @@ -34,6 +36,8 @@ import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiSt import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCustomizationUiState.ResetShortcutDialog import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutCustomizationViewModel import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.res.R +import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.SystemUIDialogFactory import com.android.systemui.statusbar.phone.create import dagger.assisted.AssistedFactory @@ -46,6 +50,7 @@ class ShortcutCustomizationDialogStarter constructor( viewModelFactory: ShortcutCustomizationViewModel.Factory, private val dialogFactory: SystemUIDialogFactory, + @Main private val resources: Resources, ) : ExclusiveActivatable() { private var dialog: Dialog? = null @@ -97,14 +102,28 @@ constructor( coroutineScope.launch { viewModel.resetAllCustomShortcuts() } }, ) - dialog.setOnDismissListener { viewModel.onDialogDismissed() } - - // By default, apps cannot intercept action key. The system always handles it. This - // flag is needed to enable customisation dialog window to intercept action key - dialog.window?.addPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) + setDialogProperties(dialog, uiState) } } + private fun setDialogProperties(dialog: SystemUIDialog, uiState: ShortcutCustomizationUiState) { + dialog.setOnDismissListener { viewModel.onDialogDismissed() } + dialog.setTitle( + resources.getString( + when (uiState) { + is AddShortcutDialog -> + R.string.shortcut_customize_mode_add_shortcut_description + is DeleteShortcutDialog -> + R.string.shortcut_customize_mode_remove_shortcut_description + else -> R.string.shortcut_customize_mode_reset_shortcut_description + } + ) + ) + // By default, apps cannot intercept action key. The system always handles it. This + // flag is needed to enable customisation dialog window to intercept action key + dialog.window?.addPrivateFlags(PRIVATE_FLAG_ALLOW_ACTION_KEY_EVENTS) + } + @AssistedFactory interface Factory { fun create(): ShortcutCustomizationDialogStarter diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt index b42da5265d86..717437923e57 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt @@ -36,6 +36,7 @@ import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce @SysUISingleton @@ -80,6 +81,7 @@ constructor( /** * Listen for the signal that we're waking up and figure what state we need to transition to. */ + @OptIn(FlowPreview::class) private fun listenForAodToAwake() { // Use PowerInteractor's wakefulness, which is the earliest wake signal available. We // have all of the information we need at this time to make a decision about where to diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index 021cce6d1e23..4291181d8336 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -41,6 +41,7 @@ import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce @SysUISingleton @@ -114,6 +115,7 @@ constructor( } } + @OptIn(FlowPreview::class) @SuppressLint("MissingPermission") private fun listenForDozingToAny() { if (KeyguardWmStateRefactor.isEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index a9992112f893..82b8ca2a890b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -125,6 +125,7 @@ constructor( * the power button is pressed quickly, we may need to go directly from DREAMING to * GLANCEABLE_HUB as the transition to DOZING has not occurred yet. */ + @OptIn(FlowPreview::class) @SuppressLint("MissingPermission") private fun listenForDreamingToGlanceableHubFromPowerButton() { if (!communalSettingsInteractor.isCommunalFlagEnabled()) return diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 8f7f2a0a8cbb..1f3c08ca9f7a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -56,6 +56,7 @@ import javax.inject.Inject import javax.inject.Provider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -203,6 +204,7 @@ constructor( * examining the value of this flow, to let other consumers have enough time to also see that * same new value. */ + @OptIn(FlowPreview::class) val isAbleToDream: Flow<Boolean> = dozeTransitionModel .flatMapLatest { dozeTransitionModel -> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt index cd62d5f3b6e1..3dc123a81bde 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt @@ -30,6 +30,7 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce private val TAG = KeyguardTransitionAuditLogger::class.simpleName!! @@ -52,6 +53,7 @@ constructor( private val deviceEntryInteractor: DeviceEntryInteractor, ) { + @OptIn(FlowPreview::class) fun start() { scope.launch { powerInteractor.detailedWakefulness.collect { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt index 70632b33f532..c748e28e60b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt @@ -188,7 +188,11 @@ constructor( finish.addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { - animationWindowView.removeView(currentAnimatedView!!.view) + if (!::animationWindowView.isInitialized) { + return + } + val animatedView = currentAnimatedView ?: return + animationWindowView.removeView(animatedView.view) } } ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/layout/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/layout/StatusBarContentInsetsProvider.kt index f7a9094e0337..7358c513eaff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/layout/StatusBarContentInsetsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/layout/StatusBarContentInsetsProvider.kt @@ -53,6 +53,7 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import java.io.PrintWriter import java.lang.Math.max +import java.util.concurrent.CopyOnWriteArraySet /** * Encapsulates logic that can solve for the left/right insets required for the status bar contents. @@ -163,7 +164,7 @@ constructor( // Limit cache size as potentially we may connect large number of displays // (e.g. network displays) private val insetsCache = LruCache<CacheKey, Rect>(MAX_CACHE_SIZE) - private val listeners = mutableSetOf<StatusBarContentInsetsChangedListener>() + private val listeners = CopyOnWriteArraySet<StatusBarContentInsetsChangedListener>() private val isPrivacyDotEnabled: Boolean by lazy(LazyThreadSafetyMode.PUBLICATION) { context.resources.getBoolean(R.bool.config_enablePrivacyDot) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt index 629cb831f17a..a0e44bfd7620 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt @@ -24,7 +24,7 @@ import com.android.systemui.flags.RefactorFlagUtils @Suppress("NOTHING_TO_INLINE") object StabilizeHeadsUpGroup { /** The aconfig flag name */ - const val FLAG_NAME: String = Flags.FLAG_STABILIZE_HEADS_UP_GROUP + const val FLAG_NAME: String = Flags.FLAG_STABILIZE_HEADS_UP_GROUP_V2 /** A token used for dependency declaration */ val token: FlagToken @@ -33,7 +33,7 @@ object StabilizeHeadsUpGroup { /** Is the refactor enabled */ @JvmStatic inline val isEnabled - get() = Flags.stabilizeHeadsUpGroup() + get() = Flags.stabilizeHeadsUpGroupV2() /** * Called to ensure code is only run when the flag is enabled. This protects users from the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt index 5fa15b831299..a28d14fd908d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt @@ -30,6 +30,7 @@ import com.android.settingslib.notification.modes.ZenIcon import com.android.settingslib.notification.modes.ZenIconLoader import com.android.settingslib.notification.modes.ZenMode import com.android.settingslib.volume.shared.model.AudioStream +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.modes.shared.ModesUi import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository @@ -57,6 +58,7 @@ import kotlinx.coroutines.flow.stateIn * An interactor that performs business logic related to the status and configuration of Zen Mode * (or Do Not Disturb/DND Mode). */ + @SysUISingleton class ZenModeInteractor @Inject constructor( diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/SwitchAppsGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/SwitchAppsGestureTutorialScreen.kt index 3bb0dd779613..e16007ea4384 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/SwitchAppsGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/SwitchAppsGestureTutorialScreen.kt @@ -46,8 +46,8 @@ fun SwitchAppsGestureTutorialScreen( titleErrorResId = R.string.gesture_error_title, bodyErrorResId = R.string.touchpad_switch_gesture_error_body, ), - // TODO: replace animation - animations = TutorialScreenConfig.Animations(educationResId = R.raw.trackpad_back_edu), + animations = + TutorialScreenConfig.Animations(educationResId = R.raw.trackpad_switch_apps_edu), ) GestureTutorialScreen( screenConfig = screenConfig, diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/SwitchAppsGestureRecognizer.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/SwitchAppsGestureRecognizer.kt index 470048bd3b20..cc382d0a6148 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/SwitchAppsGestureRecognizer.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/gesture/SwitchAppsGestureRecognizer.kt @@ -16,9 +16,14 @@ package com.android.systemui.touchpad.tutorial.ui.gesture +import android.util.MathUtils import android.view.MotionEvent +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureDirection.LEFT +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureDirection.RIGHT +import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress +import kotlin.math.abs -// TODO: javadoc +/** Recognizes Quickswitch gesture i.e. using four fingers on touchpad, swiping right. */ class SwitchAppsGestureRecognizer(private val gestureDistanceThresholdPx: Int) : GestureRecognizer { private val distanceTracker = DistanceTracker() @@ -32,8 +37,26 @@ class SwitchAppsGestureRecognizer(private val gestureDistanceThresholdPx: Int) : gestureStateChangedCallback = {} } - // TODO: recognizer logic override fun accept(event: MotionEvent) { if (!isMultifingerTouchpadSwipe(event)) return + if (!isFourFingerTouchpadSwipe(event)) { + if (event.actionMasked == MotionEvent.ACTION_UP) { + gestureStateChangedCallback(GestureState.Error) + } + return + } + val gestureState = distanceTracker.processEvent(event) + updateGestureState( + gestureStateChangedCallback, + gestureState, + isFinished = { it.deltaX >= gestureDistanceThresholdPx }, + progress = ::getProgress, + ) + } + + private fun getProgress(it: Moving): InProgress { + val direction = if (it.deltaX > 0) RIGHT else LEFT + val value = MathUtils.saturate(abs(it.deltaX / gestureDistanceThresholdPx)) + return InProgress(value, direction) } } diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt index 0a139125afa2..93aed891478c 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt @@ -166,7 +166,7 @@ fun TouchpadTutorialScreen( SwitchAppsGestureTutorialScreen( switchAppsGestureScreenViewModel, easterEggGestureViewModel, - onDoneButtonClicked = { vm.goTo(SWITCH_APPS_GESTURE) }, + onDoneButtonClicked = { vm.goTo(TUTORIAL_SELECTION) }, onBack = { vm.goTo(TUTORIAL_SELECTION) }, ) } diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureScreenViewModel.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureScreenViewModel.kt index 6593db49745d..e53ddd206da3 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureScreenViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/viewmodel/SwitchAppsGestureScreenViewModel.kt @@ -26,15 +26,14 @@ import kotlinx.coroutines.flow.map class SwitchAppsGestureScreenViewModel(private val gestureRecognizer: GestureRecognizerAdapter) : TouchpadTutorialScreenViewModel { - // TODO: replace with correct markers and resource override val tutorialState: Flow<TutorialActionState> = gestureRecognizer.gestureState .map { it to TutorialAnimationProperties( - progressStartMarker = "drag with gesture", - progressEndMarker = "onPause", - successAnimation = R.raw.trackpad_recent_apps_success, + progressStartMarker = "gesture to R", + progressEndMarker = "end of gesture", + successAnimation = R.raw.trackpad_switch_apps_success, ) } .mapToTutorialState() diff --git a/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt index 2850ab7b1e41..f893aba240fc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/app/WallpaperManagerKosmos.kt @@ -19,9 +19,7 @@ import android.app.WallpaperManager import android.content.applicationContext import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.wallpaperManager: WallpaperManager by Fixture { WallpaperManager.getInstance(applicationContext) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt index c9458125e762..dfcda222e54f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt @@ -51,7 +51,6 @@ import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent @@ -148,7 +147,6 @@ interface SysUITestComponent<out T> { val underTest: T } -@OptIn(ExperimentalCoroutinesApi::class) fun <T : SysUITestComponent<*>> T.runTest(block: suspend T.() -> Unit): Unit = testScope.runTest { // Access underTest immediately to force Dagger to instantiate it prior to the test running @@ -157,7 +155,6 @@ fun <T : SysUITestComponent<*>> T.runTest(block: suspend T.() -> Unit): Unit = block() } -@OptIn(ExperimentalCoroutinesApi::class) fun SysUITestComponent<*>.runCurrent() = testScope.runCurrent() fun <T> SysUITestComponent<*>.collectLastValue( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt index a7917a0866bb..3c264b9d6a81 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/data/repository/FakeAuthenticationRepository.kt @@ -28,7 +28,6 @@ import com.android.systemui.dagger.SysUISingleton import dagger.Binds import dagger.Module import dagger.Provides -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -260,7 +259,6 @@ class FakeAuthenticationRepository(private val currentTime: () -> Long) : Authen } } -@OptIn(ExperimentalCoroutinesApi::class) @Module(includes = [FakeAuthenticationRepositoryModule.Bindings::class]) object FakeAuthenticationRepositoryModule { @Provides diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt index 79d58a1d4e40..e3bd6fa27d4c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.keyguard.ui.viewmodel.sideFpsProgressBarViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sideFpsOverlayViewBinder by Fixture { SideFpsOverlayViewBinder( applicationScope = applicationCoroutineScope, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt index e2386a6a42b4..220bb90303b8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/DeviceEntryUdfpsTouchOverlayViewModelKosmos.kt @@ -23,9 +23,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.phone.systemUIDialogManager import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryUdfpsTouchOverlayViewModel by Fixture { DeviceEntryUdfpsTouchOverlayViewModel( deviceEntryIconViewModel = deviceEntryIconViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt index de038559fc38..e79c089361af 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelKosmos.kt @@ -22,9 +22,7 @@ import com.android.systemui.biometrics.domain.interactor.sideFpsSensorInteractor import com.android.systemui.keyguard.domain.interactor.deviceEntrySideFpsOverlayInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sideFpsOverlayViewModel by Fixture { SideFpsOverlayViewModel( applicationContext = applicationContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt index 5c5969d359c3..7de71ff44bb1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerMessageViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.bouncer.ui.viewmodel import android.content.applicationContext @@ -30,7 +28,6 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.user.ui.viewmodel.userSwitcherViewModel import com.android.systemui.util.time.systemClock -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.bouncerMessageViewModel by Fixture { BouncerMessageViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt index 72541540226c..3bfd95816cf0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.bouncer.ui.viewmodel import android.app.admin.devicePolicyManager @@ -34,7 +32,6 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.user.domain.interactor.selectedUserInteractor import com.android.systemui.user.ui.viewmodel.userSwitcherViewModel -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.StateFlow val Kosmos.bouncerUserActionsViewModel by Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt index 82454817ecbb..b3c1411243c1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt @@ -5,7 +5,6 @@ import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey import com.android.systemui.communal.shared.model.CommunalScenes import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -16,7 +15,6 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch /** Fake implementation of [CommunalSceneRepository]. */ -@OptIn(ExperimentalCoroutinesApi::class) class FakeCommunalSceneRepository( private val applicationScope: CoroutineScope, override val currentScene: MutableStateFlow<SceneKey> = diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt index 1ae8449d8b4d..7b0c09cd80a6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelKosmos.kt @@ -26,9 +26,7 @@ import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTrans import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.communalTransitionViewModel by Kosmos.Fixture { CommunalTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/TestCoroutineSchedulerUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/TestCoroutineSchedulerUtils.kt index 84e2a5c7d4c2..2fb73264b3d4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/TestCoroutineSchedulerUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/TestCoroutineSchedulerUtils.kt @@ -13,12 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.coroutines import kotlin.time.Duration -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineScheduler /** diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt index cdeade1876a7..2a46437ed33e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/data/ui/viewmodel/UdfpsAccessibilityOverlayViewModelKosmos.kt @@ -22,9 +22,7 @@ import com.android.systemui.deviceentry.ui.viewmodel.DeviceEntryUdfpsAccessibili import com.android.systemui.keyguard.ui.viewmodel.deviceEntryForegroundIconViewModel import com.android.systemui.keyguard.ui.viewmodel.deviceEntryIconViewModel import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryUdfpsAccessibilityOverlayViewModel by Kosmos.Fixture { DeviceEntryUdfpsAccessibilityOverlayViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt index 3070cf4c06ad..015d4ddcd54e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/AuthRippleInteractorKosmos.kt @@ -17,9 +17,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.authRippleInteractor by Kosmos.Fixture { AuthRippleInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt index 77d39f066e08..6b6488122b68 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/BiometricMessageInteractorKosmos.kt @@ -20,9 +20,7 @@ import android.content.res.mainResources import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor import com.android.systemui.keyguard.domain.interactor.devicePostureInteractor import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.biometricMessageInteractor by Kosmos.Fixture { BiometricMessageInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractorKosmos.kt index 1bd105620813..281782ad726a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricAuthInteractorKosmos.kt @@ -14,13 +14,10 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryBiometricAuthInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricSettingsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricSettingsInteractorKosmos.kt index 4fcf43a2a055..44755897f88e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricSettingsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricSettingsInteractorKosmos.kt @@ -18,9 +18,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryBiometricSettingsInteractor by Kosmos.Fixture { DeviceEntryBiometricSettingsInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt index 4357289b227e..3c08e5c55349 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryBiometricsAllowedInteractorKosmos.kt @@ -14,13 +14,10 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.data.repository.facePropertyRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryBiometricsAllowedInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt index 3dfe0eea500f..33f8f40677af 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import android.content.applicationContext @@ -36,7 +34,6 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.user.data.repository.userRepository import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.faceAuthLogger by Kosmos.Fixture { mock<FaceAuthenticationLogger>() } val Kosmos.deviceEntryFaceAuthInteractor by diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorKosmos.kt index 66d3709d14dc..4a489ab2773c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthStatusInteractorKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import android.content.res.mainResources import com.android.systemui.keyguard.data.repository.deviceEntryFaceAuthRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryFaceAuthStatusInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorKosmos.kt index ebed922c423e..4d767e57e631 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFingerprintAuthInteractorKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryFingerprintAuthInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt index 490b89bf6b13..6f570a86b19e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryHapticsInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.keyguard.logging.biometricUnlockLogger @@ -27,9 +25,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardBypassInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.util.time.systemClock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.deviceEntryHapticsInteractor by Kosmos.Fixture { DeviceEntryHapticsInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt index 096022ce1507..1d3fd300da06 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryInteractorKosmos.kt @@ -24,9 +24,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.scene.domain.interactor.sceneBackInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryInteractor by Kosmos.Fixture { DeviceEntryInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt index f91a044ad802..845d481cbbb7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntrySourceInteractorKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.statusbar.phone.dozeScrimController -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntrySourceInteractor by Kosmos.Fixture { DeviceEntrySourceInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt index 81123d09b43a..44d3c33c95fb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryUdfpsInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor @@ -23,7 +21,6 @@ import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryUdfpsInteractor by Fixture { DeviceEntryUdfpsInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/FaceHelpMessageDeferralInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/FaceHelpMessageDeferralInteractorKosmos.kt index 724e943c9f55..79a9c57169a3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/FaceHelpMessageDeferralInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/FaceHelpMessageDeferralInteractorKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.deviceentry.domain.interactor import com.android.systemui.biometrics.domain.faceHelpMessageDeferralFactory import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.faceHelpMessageDeferralInteractor by Kosmos.Fixture { FaceHelpMessageDeferralInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorKosmos.kt index 3680e651246b..3d5c99cf180a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/domain/interactor/OccludingAppDeviceEntryInteractorKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.plugins.activityStarter import com.android.systemui.power.domain.interactor.powerInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.occludingAppDeviceEntryInteractor by Kosmos.Fixture { OccludingAppDeviceEntryInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt index 2fead91b430a..199a4a4d932c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/deviceentry/ui/binder/LiftToRunFaceAuthBinderKosmos.kt @@ -26,9 +26,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.util.sensors.asyncSensorManager -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.liftToRunFaceAuthBinder by Kosmos.Fixture { LiftToRunFaceAuthBinder( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt index 3df3ee983ecf..60a6f3d904d4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt @@ -211,6 +211,7 @@ val Kosmos.shortcutCustomizationDialogStarterFactory by return ShortcutCustomizationDialogStarter( shortcutCustomizationViewModelFactory, systemUIDialogFactory, + mainResources, ) } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt index 40131c772de7..26ebe2e41a17 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/BurnInInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.domain.interactor import android.content.applicationContext @@ -24,7 +22,6 @@ import com.android.systemui.doze.util.burnInHelperWrapper import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.burnInInteractor by Fixture { BurnInInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt index 75eb3c9ad7ad..b920dbf88e77 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/DevicePostureInteractorKosmos.kt @@ -18,9 +18,7 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.keyguard.data.repository.devicePostureRepository import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.devicePostureInteractor by Kosmos.Fixture { DevicePostureInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt index ce317d43e988..7b0d208298d0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractorKosmos.kt @@ -24,9 +24,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.fromAlternateBouncerTransitionInteractor by Kosmos.Fixture { FromAlternateBouncerTransitionInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt index e6c98cd83b5e..d995b868a162 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractorKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) var Kosmos.fromDreamingTransitionInteractor by Kosmos.Fixture { FromDreamingTransitionInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt index 09f5fd79eeca..1d7671170d5b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissActionInteractorKosmos.kt @@ -25,9 +25,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.keyguardDismissActionInteractor by Kosmos.Fixture { KeyguardDismissActionInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt index 339210c07437..277c2ffa6e9a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt @@ -26,9 +26,7 @@ import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.user.domain.interactor.selectedUserInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.keyguardDismissInteractor by Kosmos.Fixture { KeyguardDismissInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractorKosmos.kt index b5d5d641b0fe..87109b17ef0e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardSmartspaceInteractorKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.domain.interactor import com.android.systemui.keyguard.data.repository.keyguardSmartspaceRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.keyguardSmartspaceInteractor by Fixture { KeyguardSmartspaceInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt index 1a05d21cc30a..31fb36eb26db 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui import com.android.keyguard.logging.keyguardTransitionAnimationLogger import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.keyguardTransitionAnimationFlow by Fixture { KeyguardTransitionAnimationFlow( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt index 740d8919cbc0..697e7b9476ca 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt @@ -38,9 +38,7 @@ import com.android.systemui.log.logcatLogBuffer import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.gesture.TapGestureDetector import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.alternateBouncerViewBinder by Kosmos.Fixture { AlternateBouncerViewBinder( @@ -52,7 +50,6 @@ val Kosmos.alternateBouncerViewBinder by ) } -@ExperimentalCoroutinesApi private val Kosmos.alternateBouncerDependencies by Kosmos.Fixture { AlternateBouncerDependencies( @@ -69,7 +66,6 @@ private val Kosmos.alternateBouncerDependencies by ) } -@ExperimentalCoroutinesApi private val Kosmos.alternateBouncerUdfpsIconViewModel by Kosmos.Fixture { AlternateBouncerUdfpsIconViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt index b7d9676040d0..938556e71cbb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerMessageAreaViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor import com.android.systemui.deviceentry.domain.interactor.biometricMessageInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.util.time.systemClock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.alternateBouncerMessageAreaViewModel by Kosmos.Fixture { AlternateBouncerMessageAreaViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt index 3ed9392bab2a..7d729e38fdca 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToAodTransitionViewModel by Fixture { AlternateBouncerToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt index c6f07068aad4..71cfb40c11d6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsIntera import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.alternateBouncerToDozingTransitionViewModel by Fixture { AlternateBouncerToDozingTransitionViewModel( deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt index b943298f6b53..3ec0ee040269 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToGoneTransitionViewModel by Fixture { AlternateBouncerToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToLockscreenTransitionViewModelKosmos.kt index 6c644eee24ff..346580a91f9b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToLockscreenTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToLockscreenTransitionViewModel by Fixture { AlternateBouncerToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToOccludedTransitionViewModelKosmos.kt index 71ad3c6689f7..87367b24fc7d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToOccludedTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToOccludedTransitionViewModel by Fixture { AlternateBouncerToOccludedTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt index 79892442092c..7bf778deeab5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt @@ -14,17 +14,13 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.alternateBouncerToPrimaryBouncerTransitionViewModel by Fixture { AlternateBouncerToPrimaryBouncerTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt index f1d87fe3abb7..3da27cb3c11d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerViewModel by Fixture { AlternateBouncerViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelKosmos.kt index 92cfbef987f6..335ab84a0851 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerWindowViewModel by Fixture { AlternateBouncerWindowViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt index c3c2c8c95aad..1471ddbcea61 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.aodBurnInViewModel by Fixture { AodBurnInViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt index b6f278c1b466..6aad53a5d067 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToGoneTransitionViewModel by Fixture { AodToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt index b8fcec648393..25a8d5d201be 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.shade.domain.interactor.shadeInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToLockscreenTransitionViewModel by Fixture { AodToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt index 8d066fc05996..3b33ee47bc41 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToOccludedTransitionViewModel by Fixture { AodToOccludedTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerViewModelKosmos.kt index faa290be6129..ae411367fcfc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToPrimaryBouncerViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.aodToPrimaryBouncerTransitionViewModel by Fixture { AodToPrimaryBouncerTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt index 9774e4aa51a5..0b364eafb418 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor @@ -25,7 +23,6 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.bouncerToGoneFlows by Fixture { BouncerToGoneFlows( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt index fc4f3a553d51..bd0045501ec8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt @@ -21,9 +21,7 @@ import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryBackgroundViewModel by Fixture { DeviceEntryBackgroundViewModel( context = applicationContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt index 4f638d0e4a38..1a4bd338ade7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt @@ -23,9 +23,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsIntera import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.deviceEntryForegroundIconViewModel by Fixture { DeviceEntryForegroundViewModel( context = applicationContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt index 67fa857a1ecd..f8393d537f82 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelKosmos.kt @@ -29,7 +29,6 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testScope import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.fakeDeviceEntryIconViewModelTransition by Fixture { FakeDeviceEntryIconTransition() } @@ -37,7 +36,6 @@ val Kosmos.deviceEntryIconViewModelTransitionsMock by Fixture { setOf<DeviceEntryIconTransition>(fakeDeviceEntryIconViewModelTransition) } -@ExperimentalCoroutinesApi val Kosmos.deviceEntryIconViewModel by Fixture { DeviceEntryIconViewModel( transitions = deviceEntryIconViewModelTransitionsMock, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt index ef10459b45cb..87c3dbf9487e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGlanceableHubTransitionViewModelKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToGlanceableHubTransitionViewModel by Fixture { DozingToGlanceableHubTransitionViewModel(animationFlow = keyguardTransitionAnimationFlow) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt index 36ddc29b8914..7c066036b131 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToGoneTransitionViewModel by Fixture { DozingToGoneTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt index de52d848e94b..46f9f8dcd962 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToLockscreenTransitionViewModel by Fixture { DozingToLockscreenTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToOccludedTransitionViewModelKosmos.kt index 8162520e5d88..25865ae8700f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToOccludedTransitionViewModelKosmos.kt @@ -18,9 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToOccludedTransitionViewModel by Kosmos.Fixture { DozingToOccludedTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt index d3ccb297fc9d..39f9530bcb17 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dozingToPrimaryBouncerTransitionViewModel by Fixture { DozingToPrimaryBouncerTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModelKosmos.kt index b5f0b897deba..ec1f906dc179 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToAodTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.dreamingToAodTransitionViewModel by Fixture { DreamingToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGoneTransitionViewModelKosmos.kt index f389142554b1..1e832bdf82dd 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGoneTransitionViewModelKosmos.kt @@ -18,9 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dreamingToGoneTransitionViewModel by Kosmos.Fixture { DreamingToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt index d06bab2f5345..1d0a210110ed 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt @@ -19,9 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.dreamingToLockscreenTransitionViewModel by Fixture { DreamingToLockscreenTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt index b1c21b8fa6cf..bb1098f14ea6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt @@ -14,17 +14,13 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.glanceableHubToLockscreenTransitionViewModel by Fixture { GlanceableHubToLockscreenTransitionViewModel( configurationInteractor = configurationInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt index 8549a30c346e..2d24ef2fcfee 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor @@ -23,7 +21,6 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.power.domain.interactor.powerInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.goneToAodTransitionViewModel by Fixture { GoneToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt index b19d4e87e68c..3f7348be8fe5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsIntera import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.goneToDozingTransitionViewModel by Fixture { GoneToDozingTransitionViewModel( deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt index b267a962a1ff..86ef95cbab4c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.goneToDreamingTransitionViewModel by Fixture { GoneToDreamingTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt index 1b6fa064854d..4322a887928a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.goneToLockscreenTransitionViewModel by Fixture { GoneToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index 1c0f97d294df..40b8e0e62b03 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.communal.domain.interactor.communalInteractor @@ -31,7 +29,6 @@ import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificatio import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.phone.screenOffAnimationController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.keyguardRootViewModel by Fixture { KeyguardRootViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt index f45e33bf6865..5234b5bd17e2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor @@ -23,7 +21,6 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.power.domain.interactor.powerInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.lockscreenToAodTransitionViewModel by Fixture { LockscreenToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt index aa8e9a8c9a8c..bf1af3c47674 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsIntera import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.lockscreenToDozingTransitionViewModel by Fixture { LockscreenToDozingTransitionViewModel( deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt index 56d5ff6e30eb..1246b9455b4b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToDreamingTransitionViewModel by Fixture { LockscreenToDreamingTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt index 471381f7a13f..0e961ccaf07b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt @@ -14,17 +14,13 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.lockscreenToGlanceableHubTransitionViewModel by Fixture { LockscreenToGlanceableHubTransitionViewModel( configurationInteractor = configurationInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt index 7a023ee29299..172b4f8db92b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt @@ -20,9 +20,7 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.lockscreenToGoneTransitionViewModel by Fixture { LockscreenToGoneTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt index 9953d39e9a49..abd29cadb8f7 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToOccludedTransitionViewModel by Fixture { LockscreenToOccludedTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt index 68280d7622fd..b5c67b66ae5f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToPrimaryBouncerTransitionViewModel by Fixture { LockscreenToPrimaryBouncerTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAlternateBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAlternateBouncerTransitionViewModelKosmos.kt index 2acd1b40af3e..39a545a8c451 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAlternateBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAlternateBouncerTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.occludedToAlternateBouncerTransitionViewModel by Fixture { OccludedToAlternateBouncerTransitionViewModel(animationFlow = keyguardTransitionAnimationFlow) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt index b7867b6cabde..dd6d9acaa33e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.occludedToAodTransitionViewModel by Fixture { OccludedToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt index 4196e54a085d..4e8896ab11c1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToDozingTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.occludedToDozingTransitionViewModel by Fixture { OccludedToDozingTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt index 3b96912b53c6..70e9af1b1058 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGoneTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.occludedToGoneTransitionViewModel by Fixture { OccludedToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt index f86e9b7216ce..5b1d8f126f84 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.occludedToLockscreenTransitionViewModel by Fixture { OccludedToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModelKosmos.kt index 5d62a0f4a0cf..579819f6d265 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModelKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.offToLockscreenTransitionViewModel by Fixture { OffToLockscreenTransitionViewModel(animationFlow = keyguardTransitionAnimationFlow) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt index 043a49f5f640..73ef4328657a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor @@ -23,7 +21,6 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToAodTransitionViewModel by Fixture { PrimaryBouncerToAodTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt index 59ea2c93089c..99297351bdaa 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt @@ -21,9 +21,7 @@ import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi -@ExperimentalCoroutinesApi val Kosmos.primaryBouncerToDozingTransitionViewModel by Fixture { PrimaryBouncerToDozingTransitionViewModel( deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt index b470ab12828b..acf0827b1614 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.mockPrimaryBouncerInteractor @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToGoneTransitionViewModel by Fixture { PrimaryBouncerToGoneTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt index c3447753a86d..bd5a21195795 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt @@ -14,15 +14,12 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.blurConfig import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToLockscreenTransitionViewModel by Fixture { PrimaryBouncerToLockscreenTransitionViewModel( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt index 8da16fc4e855..e38c419a97f2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import android.content.applicationContext @@ -29,7 +27,6 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.statusbar.phone.dozeServiceHost -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.sideFpsProgressBarViewModel by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt index 439df543b9fb..a4c2cc275e44 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/GeneralKosmos.kt @@ -9,7 +9,6 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.settings.brightness.ui.BrightnessWarningToast import com.android.systemui.util.mockito.mock import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -73,7 +72,6 @@ fun <T> Kosmos.collectValues(flow: Flow<T>): FlowValue<List<T>> = testScope.coll * If you want to assert on a [Flow] that is not a [StateFlow], please use * [TestScope.collectLastValue], to make sure that the desired value is captured when emitted. */ -@OptIn(ExperimentalCoroutinesApi::class) fun <T> TestScope.currentValue(stateFlow: StateFlow<T>): T { val values = mutableListOf<T>() val job = backgroundScope.launch { stateFlow.collect(values::add) } @@ -90,7 +88,6 @@ fun <T> Kosmos.currentValue(fn: () -> T) = testScope.currentValue(fn) * Retrieve the result of [fn] after running all pending tasks. Do not use to retrieve the value of * a flow directly; for that, use either `currentValue(StateFlow)` or [collectLastValue] */ -@OptIn(ExperimentalCoroutinesApi::class) fun <T> TestScope.currentValue(fn: () -> T): T { runCurrent() return fn() @@ -102,7 +99,6 @@ fun <T> Kosmos.currentValue(stateFlow: StateFlow<T>): T { } /** Safely verify that a mock has been called after the test scope has caught up */ -@OptIn(ExperimentalCoroutinesApi::class) fun <T> TestScope.verifyCurrent(mock: T): T { runCurrent() return verify(mock) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index 39f1ad42797b..35e90f06ddde 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.kosmos import android.content.applicationContext @@ -92,7 +90,6 @@ import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisionin import com.android.systemui.statusbar.ui.viewmodel.keyguardStatusBarViewModel import com.android.systemui.util.time.systemClock import com.android.systemui.volume.domain.interactor.volumeDialogInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi /** * Helper for using [Kosmos] from Java. diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt index 5acadd7f192a..2ef3f4a70998 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediaprojection/taskswitcher/TaskSwitcherKosmos.kt @@ -23,7 +23,6 @@ import com.android.systemui.mediaprojection.data.repository.realMediaProjectionR import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.UnconfinedTestDispatcher val Kosmos.fakeActivityTaskManager by Kosmos.Fixture { FakeActivityTaskManager() } @@ -47,5 +46,4 @@ val Kosmos.taskSwitcherInteractor by val Kosmos.taskSwitcherViewModel by Kosmos.Fixture { TaskSwitcherNotificationViewModel(taskSwitcherInteractor, testDispatcher) } -@OptIn(ExperimentalCoroutinesApi::class) fun taskSwitcherKosmos() = Kosmos().apply { testDispatcher = UnconfinedTestDispatcher() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt index 49957f0b43cc..65e580cafcb5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt @@ -39,9 +39,7 @@ import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.shade.transition.largeScreenShadeInterpolator import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor import com.android.systemui.statusbar.sysuiStatusBarStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.qsFragmentComposeViewModelFactory by Kosmos.Fixture { object : QSFragmentComposeViewModel.Factory { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt index a4a63ec6ca21..9d18fbfccb36 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.scene.domain.resolver import com.android.compose.animation.scene.SceneKey @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.scene.shared.model.SceneFamilies -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.sceneFamilyResolvers: Map<SceneKey, SceneResolver> get() = mapOf(SceneFamilies.Home to homeSceneFamilyResolver) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/ScrimStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/ScrimStartableKosmos.kt index b64c84075936..12b46536b2a2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/ScrimStartableKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/ScrimStartableKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.scene.domain.startable import com.android.systemui.bouncer.domain.interactor.alternateBouncerInteractor @@ -31,7 +29,6 @@ import com.android.systemui.settings.brightness.domain.interactor.brightnessMirr import com.android.systemui.statusbar.phone.dozeServiceHost import com.android.systemui.statusbar.phone.scrimController import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.scrimStartable by Fixture { ScrimStartable( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt index ee69c30fe6b9..881d110dff25 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/startable/StatusBarStartableKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.scene.domain.startable import android.content.applicationContext @@ -33,7 +31,6 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.user.domain.interactor.selectedUserInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.statusBarStartable by Fixture { StatusBarStartable( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt index b9f0c9a70d3d..e2b2026550f1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.shade import com.android.systemui.assist.AssistManager @@ -39,7 +37,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.policy.deviceProvisionedController import com.android.systemui.statusbar.window.StatusBarWindowControllerStore import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.shadeControllerSceneImpl by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt index b3d89dbb834d..e143324baeae 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeTestUtil.kt @@ -25,7 +25,6 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.shade.data.repository.ShadeRepository -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope @@ -193,7 +192,6 @@ class ShadeTestUtilLegacyImpl( } /** Sets up shade state for tests when the scene container flag is enabled. */ -@OptIn(ExperimentalCoroutinesApi::class) class ShadeTestUtilSceneImpl( val testScope: TestScope, val sceneInteractor: SceneInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt index 88bf9a5f2d5b..6593547f393d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt @@ -27,9 +27,7 @@ import com.android.systemui.statusbar.notificationLockscreenUserManager import com.android.systemui.statusbar.policy.keyguardStateController import com.android.systemui.statusbar.policy.sensitiveNotificationProtectionController import com.android.systemui.user.domain.interactor.selectedUserInteractor -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) var Kosmos.sensitiveContentCoordinator: SensitiveContentCoordinator by Kosmos.Fixture { SensitiveContentCoordinatorImpl( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt index 774782cc019c..dc7595f7f2e4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.statusbar.notification.icon.domain.interactor import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor @@ -27,7 +25,6 @@ import com.android.systemui.statusbar.notification.data.repository.notifications import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.headsUpNotificationIconInteractor import com.android.wm.shell.bubbles.bubblesOptional -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alwaysOnDisplayNotificationIconsInteractor by Fixture { AlwaysOnDisplayNotificationIconsInteractor( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt index 65f4ec1c437c..d65a4a0532e3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/AmbientStateKosmos.kt @@ -23,9 +23,7 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.shade.transition.largeScreenShadeInterpolator import com.android.systemui.statusbar.notification.headsup.mockAvalancheController import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.ambientState by Fixture { AmbientState( /*context=*/ applicationContext, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt index b1e9d89dfd42..e250575ad3fc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.statusbar.notification.stack.domain.interactor import android.content.applicationContext @@ -25,7 +23,6 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.statusbar.policy.splitShadeStateController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.sharedNotificationContainerInteractor by Kosmos.Fixture { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt index 8461da77796d..45c56ae0ab7a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt @@ -60,9 +60,7 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.notif import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor import com.android.systemui.unfold.domain.interactor.unfoldTransitionInteractor import com.android.systemui.window.ui.viewmodel.fakeBouncerTransitions -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.sharedNotificationContainerViewModel by Fixture { SharedNotificationContainerViewModel( interactor = sharedNotificationContainerInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/BiometricUnlockController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/BiometricUnlockController.kt index f377e28bb51a..c87a20e660a1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/BiometricUnlockController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/BiometricUnlockController.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.statusbar.phone import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.biometricUnlockController: BiometricUnlockController by Fixture { mock<BiometricUnlockController>() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt index d0bf584d9a62..78140416cb40 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/DozeServiceHostKosmos.kt @@ -31,9 +31,7 @@ import com.android.systemui.statusbar.notificationShadeWindowController import com.android.systemui.statusbar.policy.batteryController import com.android.systemui.statusbar.policy.deviceProvisionedController import com.android.systemui.statusbar.pulseExpansionHandler -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.dozeServiceHost: DozeServiceHost by Kosmos.Fixture { DozeServiceHost( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ManagedProfileControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ManagedProfileControllerKosmos.kt index ef04b9d907f1..7c8ad12ccf0d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ManagedProfileControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ManagedProfileControllerKosmos.kt @@ -14,14 +14,11 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.statusbar.phone import android.testing.LeakCheck import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.utils.leaks.FakeManagedProfileController -import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.fakeManagedProfileController by Fixture { FakeManagedProfileController(LeakCheck()) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt index ddce4c896c14..4e15ea2d9377 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerKosmos.kt @@ -18,7 +18,5 @@ package com.android.systemui.statusbar.phone import com.android.systemui.kosmos.Kosmos import com.android.systemui.util.mockito.mock -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) var Kosmos.statusBarKeyguardViewManager by Kosmos.Fixture { mock<StatusBarKeyguardViewManager>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt index 7743a1c7e0cd..0d6ac4481742 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt @@ -47,9 +47,7 @@ import com.android.systemui.statusbar.notificationShadeWindowController import com.android.systemui.statusbar.policy.keyguardStateController import com.android.systemui.wmshell.bubblesManager import java.util.Optional -import kotlinx.coroutines.ExperimentalCoroutinesApi -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.statusBarNotificationActivityStarter by Kosmos.Fixture { StatusBarNotificationActivityStarter( diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt index 577620347991..a0d9227cc048 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/coroutines/MainDispatcherRule.kt @@ -17,7 +17,6 @@ package com.android.systemui.util.coroutines import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.setMain @@ -28,7 +27,6 @@ import org.junit.runner.Description * Overrides main dispatcher to passed testDispatcher. You probably want to use it when using * viewModelScope which has hardcoded main dispatcher. */ -@OptIn(ExperimentalCoroutinesApi::class) class MainDispatcherRule(val testDispatcher: TestDispatcher) : TestWatcher() { override fun starting(description: Description) { Dispatchers.setMain(testDispatcher) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt index f3a8b14abab8..703d6ad83eac 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt @@ -20,10 +20,8 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.currentTime -@OptIn(ExperimentalCoroutinesApi::class) val Kosmos.systemClock by Kosmos.Fixture<SystemClock> { mock { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 70c4c1311fc9..75c629b77700 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -21,8 +21,6 @@ import static android.view.MotionEvent.ACTION_SCROLL; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; -import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures; - import android.accessibilityservice.AccessibilityTrace; import android.annotation.MainThread; import android.annotation.NonNull; @@ -758,7 +756,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo addFirstEventHandler(Display.DEFAULT_DISPLAY, mMouseKeysInterceptor); } - if (enableTalkbackAndMagnifierKeyGestures() && isAnyMagnificationEnabled()) { + if (Flags.enableMagnificationKeyboardControl() && isAnyMagnificationEnabled()) { mMagnificationKeyHandler = new MagnificationKeyHandler( mAms.getMagnificationController()); addFirstEventHandler(Display.DEFAULT_DISPLAY, mMagnificationKeyHandler); diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationKeyHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationKeyHandler.java index a65580c82124..f20755328479 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationKeyHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationKeyHandler.java @@ -20,6 +20,7 @@ import android.view.Display; import android.view.KeyEvent; import com.android.server.accessibility.BaseEventStreamTransformation; +import com.android.server.accessibility.Flags; /* * A class that listens to key presses used to control magnification. @@ -79,7 +80,7 @@ public class MagnificationKeyHandler extends BaseEventStreamTransformation { @Override public void onKeyEvent(KeyEvent event, int policyFlags) { - if (!com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures()) { + if (!Flags.enableMagnificationKeyboardControl()) { // Send to the rest of the handlers. super.onKeyEvent(event, policyFlags); return; diff --git a/services/core/Android.bp b/services/core/Android.bp index bb493370f9fc..420dcfe9cea6 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -143,6 +143,7 @@ java_library_static { ":platform-compat-overrides", ":display-device-config", ":display-layout-config", + ":display-topology", ":device-state-config", "java/com/android/server/EventLogTags.logtags", "java/com/android/server/am/EventLogTags.logtags", diff --git a/services/core/java/com/android/server/display/DisplayTopologyStore.java b/services/core/java/com/android/server/display/DisplayTopologyStore.java new file mode 100644 index 000000000000..2256c11feee8 --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayTopologyStore.java @@ -0,0 +1,33 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import android.annotation.Nullable; +import android.hardware.display.DisplayTopology; + +/** + * Allows to save and restore {@link DisplayTopology}. + * See implementation: {@link DisplayTopologyXmlStore} + */ +interface DisplayTopologyStore { + boolean saveTopology(DisplayTopology topology); + + @Nullable + DisplayTopology restoreTopology(DisplayTopology topology); + + void reloadTopologies(int userId); +} diff --git a/services/core/java/com/android/server/display/DisplayTopologyXmlStore.java b/services/core/java/com/android/server/display/DisplayTopologyXmlStore.java new file mode 100644 index 000000000000..b7f31b75f6dc --- /dev/null +++ b/services/core/java/com/android/server/display/DisplayTopologyXmlStore.java @@ -0,0 +1,582 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.INVALID_DISPLAY; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Comparator.comparingInt; + +import android.annotation.Nullable; +import android.hardware.display.DisplayTopology; +import android.os.Environment; +import android.util.AtomicFile; +import android.util.AtomicFilePrintWriter; +import android.util.Slog; +import android.util.SparseArray; + +// automatically generated classes from display-topology.xsd +import com.android.server.display.topology.Children; +import com.android.server.display.topology.Display; +import com.android.server.display.topology.DisplayTopologyState; +import com.android.server.display.topology.Position; +import com.android.server.display.topology.Topology; +import com.android.server.display.topology.XmlParser; +import com.android.server.display.topology.XmlWriter; +import com.android.server.display.utils.DebugUtils; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.datatype.DatatypeConfigurationException; + +/** + * Saves and restores {@link DisplayTopology} to/from xml files with topologies for each + * {@link DisplayTopologyXmlStore#mUserId} user. + */ +class DisplayTopologyXmlStore implements DisplayTopologyStore { + private static final String TAG = "DisplayManager.DisplayTopologyXmlStore"; + private static final String ETC_DIR = "etc"; + private static final String DISPLAY_CONFIG_DIR = "displayconfig"; + + // To enable these logs, run: + // adb shell setprop persist.log.tag.DisplayManager.DisplayTopologyXmlStore DEBUG + // adb reboot + private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); + + private static final int PERSISTENT_TOPOLOGY_VERSION = 1; + /** + * {@link #restoreTopology} needs to reorder topologies to keep the most recently used + * topologies order close to 0. In case current topology displays change often, the persistence + * of the reordered topologies can become a performance issue. To avoid persistence for small + * changes in the order values lets use this constant, serving as the threshold when + * to trigger persistence during {@link #restoreTopology}. + */ + private static final int MIN_REORDER_WHICH_TRIGGERS_PERSISTENCE = 10; + private static final int MAX_NUMBER_OF_TOPOLOGIES = 100; + + static File getUserTopologyFile(int userId) { + return new File(Environment.getDataSystemCeDirectory(userId), "display_topology.xml"); + } + + private static File getVendorTopologyFile() { + return Environment.buildPath(Environment.getVendorDirectory(), + ETC_DIR, DISPLAY_CONFIG_DIR, "display_topology.xml"); + } + + private static File getProductTopologyFile() { + return Environment.buildPath(Environment.getProductDirectory(), + ETC_DIR, DISPLAY_CONFIG_DIR, "display_topology.xml"); + } + + private static List<Topology> readTopologiesFromInputStream( + @Nullable InputStream iStream) + throws DatatypeConfigurationException, XmlPullParserException, IOException { + if (null == iStream) { + if (DEBUG) { + Slog.d(TAG, "iStream is null"); + } + return List.of(); + } + // use parser automatically generated from display-topology.xsd + var topologyState = XmlParser.read(iStream); + if (topologyState.getVersion() > PERSISTENT_TOPOLOGY_VERSION) { + Slog.e(TAG, "Topology version=" + topologyState.getVersion() + + " is not supported by DisplayTopologyXmlStore version=" + + PERSISTENT_TOPOLOGY_VERSION); + return List.of(); + } + if (DEBUG) { + Slog.d(TAG, "readTopologiesFromInputStream: done"); + } + + var topologyList = topologyState.getTopology(); + topologyList.sort(comparingInt(Topology::getOrder)); + return topologyList; + } + + private static int getOrderOrDefault(@Nullable Topology topology, int defaultOrder) { + return null != topology ? topology.getOrder() : defaultOrder; + } + + private final Injector mInjector; + private int mUserId = -1; + private final List<Topology> mImmutableTopologies = new ArrayList<>(); + private final Map<String, Topology> mTopologies = new HashMap<>(); + + DisplayTopologyXmlStore(Injector injector) { + mInjector = injector; + reloadImmutableTopologies(); + } + + /** + * Persists the topology into XML + * @param topology the topology to persist + * @return true if persisted successfully, false otherwise + */ + @Override + public boolean saveTopology(DisplayTopology topology) { + String topologyId = getTopologyId(topology); + if (DEBUG) { + Slog.d(TAG, "saveTopology userId=" + mUserId + ", topologyId=" + topologyId); + } + if (null == topologyId) { + Slog.w(TAG, "saveTopology cancelled: topology id is null for " + topology); + return false; + } + + Topology topologyToPersist = convertTopologyForPersistence(topology, topologyId); + if (null == topologyToPersist) { + Slog.w(TAG, "saveTopology cancelled: can't convert topology " + topology); + return false; + } + + if (!prependTopology(topologyToPersist)) { + Slog.w(TAG, "saveTopology cancelled: can't prependTopology"); + return false; + } + saveTopologiesToFile(); + return true; + } + + /** + * Searches for the topology's id in the store. If topology is found in the store, + * then uses the passed topology display width and height, and the persisted topology + * structure, position and offset. + * @param topology original topology which we would like to restore to a state which was + * previously persisted, keeping the current width and height. + * @return null if topology is not found, or the new restored topology otherwise. + */ + @Nullable + @Override + public DisplayTopology restoreTopology(DisplayTopology topology) { + String topologyId = getTopologyId(topology); + if (DEBUG) { + Slog.d(TAG, "restoreTopology userId=" + mUserId + ", topologyId=" + topologyId); + } + if (null == topologyId) { + Slog.w(TAG, "restoreTopology cancelled: topology id is null for " + topology); + return null; + } + + Topology restoredTopology = mTopologies.get(topologyId); + if (null == restoredTopology) { + // Topology is not found in persistent storage. + if (DEBUG) { + Slog.d(TAG, "restoreTopology userId=" + mUserId + ", topologyId=" + topologyId + + " is not found"); + } + return null; + } + + // Reorder and save to file for significant changes in topologies order. + if (restoredTopology.getOrder() >= MIN_REORDER_WHICH_TRIGGERS_PERSISTENCE) { + moveTopologyToHead(restoredTopology); + saveTopologiesToFile(); + } + return convertPersistentTopologyToDisplayTopology(topology, restoredTopology.getDisplay(), + mInjector.getUniqueIdToDisplayIdMapping()); + } + + @Override + public void reloadTopologies(int userId) { + if (DEBUG) { + Slog.d(TAG, "reloadTopologies mUserId=" + mUserId + "->userId=" + userId); + } + if (mUserId != userId) { + mUserId = userId; + resetTopologies(); + } + reloadTopologies(); + } + + private void resetTopologies() { + mTopologies.clear(); + appendTopologies(mImmutableTopologies); + } + + /** + * Increases all orders by 1 for those topologies currently below the order of the + * passed topology. Sets the order of the passed topology to 0. + */ + private void moveTopologyToHead(Topology topology) { + if (topology.getOrder() == 0) { + return; + } + for (var t : mTopologies.values()) { + if (t.getOrder() < topology.getOrder()) { + t.setOrder(t.getOrder() + 1); + } + } + topology.setOrder(0); + } + + private void reloadImmutableTopologies() { + mImmutableTopologies.clear(); + try (InputStream iStream = mInjector.readProductTopologies()) { + mImmutableTopologies.addAll(readTopologiesFromInputStream(iStream)); + } catch (IOException | XmlPullParserException | DatatypeConfigurationException e) { + Slog.e(TAG, "reloadImmutableTopologies for product topologies failed", e); + } + try (InputStream iStream = mInjector.readVendorTopologies()) { + mImmutableTopologies.addAll(readTopologiesFromInputStream(iStream)); + } catch (IOException | XmlPullParserException | DatatypeConfigurationException e) { + Slog.e(TAG, "reloadImmutableTopologies for vendor topologies failed", e); + } + for (var topology : mImmutableTopologies) { + topology.setImmutable(true); + } + } + + private void reloadTopologies() { + if (mUserId < 0) { + Slog.e(TAG, "Can't reload topologies for userId=" + mUserId); + return; + } + try (InputStream iStream = mInjector.readUserTopologies(mUserId)) { + appendTopologies(readTopologiesFromInputStream(iStream)); + } catch (IOException | XmlPullParserException | DatatypeConfigurationException e) { + Slog.e(TAG, "reloadTopologies failed", e); + } + } + + private void appendTopologies(List<Topology> topologyList) { + for (var topology : topologyList) { + appendTopology(topology); + } + } + + private void appendTopology(Topology topology) { + Topology restoredTopology = mTopologies.get(topology.getId()); + if (null != restoredTopology && restoredTopology.getImmutable()) { + Slog.w(TAG, "addTopology: can't override immutable topology " + + topology.getId()); + return; + } + + // If topology is not found, and we exceed the limit of topologies + // (so we can't add more topologies), then skip this topology + if (null == restoredTopology && mTopologies.size() >= MAX_NUMBER_OF_TOPOLOGIES) { + if (DEBUG) { + Slog.d(TAG, "appendTopology: MAX_NUMBER_OF_TOPOLOGIES is reached," + + " can't append topology" + topology.getId()); + } + return; + } + topology.setOrder(getOrderOrDefault(restoredTopology, mTopologies.size())); + mTopologies.put(topology.getId(), topology); + } + + private boolean prependTopology(Topology topology) { + Topology restoredTopology = mTopologies.get(topology.getId()); + if (null != restoredTopology && restoredTopology.getImmutable()) { + Slog.w(TAG, "prependTopology: can't override immutable topology " + + topology.getId()); + return false; + } + + // If topology is not found, and we exceed the limit of topologies + // remove the max order mutable topology. + if (null == restoredTopology && mTopologies.size() >= MAX_NUMBER_OF_TOPOLOGIES) { + Topology topologyToRemove = findMaxOrderMutableTopology(); + if (topologyToRemove == null) { + Slog.w(TAG, "prependTopology: can't find a topology to remove to free up space"); + return false; + } + mTopologies.remove(topologyToRemove.getId()); + if (DEBUG) { + Slog.d(TAG, "prependTopology: remove topology " + topologyToRemove.getId()); + } + } + + topology.setOrder(Integer.MAX_VALUE); + moveTopologyToHead(topology); + mTopologies.put(topology.getId(), topology); + return true; + } + + /** + * Higher order of the topology means lower priority. + */ + @Nullable + private Topology findMaxOrderMutableTopology() { + Topology res = null; + for (var topology : mTopologies.values()) { + if (topology.getImmutable()) { + continue; + } + if (res == null || res.getOrder() < topology.getOrder()) { + res = topology; + } + } + return res; + } + + private void saveTopologiesToFile() { + if (mUserId < 0) { + Slog.e(TAG, "Can't save topologies for userId=" + mUserId); + return; + } + if (mTopologies.isEmpty()) { + if (DEBUG) { + Slog.d(TAG, "No topologies to save for userId=" + mUserId); + } + return; + } + var topologyState = new DisplayTopologyState(); + topologyState.setVersion(PERSISTENT_TOPOLOGY_VERSION); + for (var topology : mTopologies.values()) { + if (!topology.getImmutable()) { + topologyState.getTopology().add(topology); + } + } + + try (var pw = mInjector.getTopologyFilePrintWriter(mUserId)) { + // use writer automatically generated from display-topology.xsd + XmlWriter.write(new XmlWriter(pw), topologyState); + pw.markSuccess(); + if (DEBUG) Slog.d(TAG, "saveTopologiesToFile " + pw); + } catch (IOException e) { + Slog.e(TAG, "saveTopologiesToFile failed", e); + } + } + + private DisplayTopology convertPersistentTopologyToDisplayTopology( + DisplayTopology currentDisplayTopology, + Display persistentDisplayTopology, + Map<String, Integer> uniqueIdToDisplayIdMapping) { + var rootNode = convertPersistentDisplayToTreeNode(persistentDisplayTopology, + currentDisplayTopology, uniqueIdToDisplayIdMapping); + int primaryDisplayId = findPrimaryDisplayId(persistentDisplayTopology, + uniqueIdToDisplayIdMapping); + if (primaryDisplayId == INVALID_DISPLAY) { + Slog.e(TAG, "Primary display id is not found in persistent topology"); + primaryDisplayId = DEFAULT_DISPLAY; + } + return new DisplayTopology(rootNode, primaryDisplayId); + } + + private DisplayTopology.TreeNode convertPersistentDisplayToTreeNode( + Display persistentDisplay, + DisplayTopology currentDisplayTopology, + Map<String, Integer> uniqueIdToDisplayIdMapping + ) { + Integer displayId = uniqueIdToDisplayIdMapping.get(persistentDisplay.getId()); + if (null == displayId) { + throw new IllegalStateException("Can't map uniqueId=" + + persistentDisplay.getId() + " to displayId"); + } + + var displayNode = DisplayTopology.findDisplay(displayId, + currentDisplayTopology.getRoot()); + if (null == displayNode) { + throw new IllegalStateException("Can't find displayId=" + + displayId + " in current topology"); + } + + List<DisplayTopology.TreeNode> children = new ArrayList<>(); + for (var child : persistentDisplay.getChildren().getDisplay()) { + children.add(convertPersistentDisplayToTreeNode(child, currentDisplayTopology, + uniqueIdToDisplayIdMapping)); + } + + return new DisplayTopology.TreeNode( + displayId, displayNode.getWidth(), displayNode.getHeight(), + toDisplayTopologyPosition(persistentDisplay.getPosition()), + persistentDisplay.getOffset(), children); + } + + private int findPrimaryDisplayId(Display persistentDisplay, + Map<String, Integer> uniqueIdToDisplayIdMapping) { + if (persistentDisplay.getPrimary()) { + var displayId = uniqueIdToDisplayIdMapping.get(persistentDisplay.getId()); + if (null == displayId) { + throw new IllegalStateException("Can't map uniqueId=" + + persistentDisplay.getId() + " to displayId"); + } + return displayId; + } + for (var child : persistentDisplay.getChildren().getDisplay()) { + var displayId = findPrimaryDisplayId(child, uniqueIdToDisplayIdMapping); + if (displayId != INVALID_DISPLAY) { + return displayId; + } + } + return INVALID_DISPLAY; + } + + @Nullable + private Topology convertTopologyForPersistence(DisplayTopology topology, String topologyId) { + var rootNode = convertTreeNodeForPersistence(topology.getRoot(), + topology.getPrimaryDisplayId(), mInjector.getDisplayIdToUniqueIdMapping()); + if (null == rootNode) { + return null; + } + + Topology persistentTopology = new Topology(); + persistentTopology.setDisplay(rootNode); + persistentTopology.setId(topologyId); + return persistentTopology; + } + + @Nullable + private Display convertTreeNodeForPersistence( + @Nullable DisplayTopology.TreeNode node, + int primaryDisplayId, + SparseArray<String> idsToUniqueIds) { + if (null == node) { + Slog.e(TAG, "Can't convertTreeNodeForPersistence, node == null"); + return null; + } + var uniqueId = idsToUniqueIds.get(node.getDisplayId()); + if (null == uniqueId) { + Slog.e(TAG, "Can't convertTreeNodeForPersistence," + + " uniqueId is not found for " + node.getDisplayId()); + return null; + } + Children children = new Children(); + for (var child : node.getChildren()) { + var display = convertTreeNodeForPersistence(child, primaryDisplayId, idsToUniqueIds); + if (null == display) { + return null; + } + children.getDisplay().add(display); + } + var root = new Display(); + root.setPosition(toPersistentPosition(node.getPosition())); + root.setId(uniqueId); + root.setOffset(node.getOffset()); + root.setPrimary(node.getDisplayId() == primaryDisplayId); + root.setChildren(children); + return root; + } + + private Position toPersistentPosition(@DisplayTopology.TreeNode.Position int pos) { + return switch (pos) { + case DisplayTopology.TreeNode.POSITION_LEFT -> Position.left; + case DisplayTopology.TreeNode.POSITION_TOP -> Position.top; + case DisplayTopology.TreeNode.POSITION_RIGHT -> Position.right; + case DisplayTopology.TreeNode.POSITION_BOTTOM -> Position.bottom; + default -> throw new IllegalArgumentException("Unknown position=" + pos); + }; + } + + @DisplayTopology.TreeNode.Position + private int toDisplayTopologyPosition(Position pos) { + return switch (pos) { + case left -> DisplayTopology.TreeNode.POSITION_LEFT; + case top -> DisplayTopology.TreeNode.POSITION_TOP; + case right -> DisplayTopology.TreeNode.POSITION_RIGHT; + case bottom -> DisplayTopology.TreeNode.POSITION_BOTTOM; + }; + } + + private List<String> getUniqueIds(@Nullable DisplayTopology.TreeNode node, + SparseArray<String> mapping, List<String> uniqueIds) { + if (null == node) { + return uniqueIds; + } + uniqueIds.add(mapping.get(node.getDisplayId())); + for (var child : node.getChildren()) { + getUniqueIds(child, mapping, uniqueIds); + } + return uniqueIds; + } + + @Nullable + private String getTopologyId(DisplayTopology topology) { + SparseArray<String> mapping = mInjector.getDisplayIdToUniqueIdMapping(); + return getTopologyId(getUniqueIds(topology.getRoot(), mapping, new ArrayList<>())); + } + + @Nullable + private String getTopologyId(List<String> uniqueIds) { + if (uniqueIds.isEmpty() || uniqueIds.contains(null)) { + return null; + } + Collections.sort(uniqueIds); + return String.join("|", uniqueIds); + } + + abstract static class Injector { + /** + * Necessary mapping for conversion of {@link DisplayTopology} which uses + * {@link android.view.DisplayInfo#displayId} to {@link DisplayTopologyState} + * which uses {@link android.view.DisplayInfo#uniqueId} + * + * @return mapping from {@link android.view.DisplayInfo#displayId} + * to {@link android.view.DisplayInfo#uniqueId} + */ + public abstract SparseArray<String> getDisplayIdToUniqueIdMapping(); + + /** + * Necessary mapping for conversion opposite to {@link #getDisplayIdToUniqueIdMapping()} + * + * @return mapping from {@link android.view.DisplayInfo#uniqueId} + * to {@link android.view.DisplayInfo#displayId} + */ + public abstract Map<String, Integer> getUniqueIdToDisplayIdMapping(); + + /** + * Reads vendor topologies, if configured. + * @return input stream with vendor-defined topologies, or null if not configured. + */ + @Nullable + public InputStream readVendorTopologies() throws FileNotFoundException { + return getFileInputStream(getVendorTopologyFile()); + } + + /** + * Reads product topologies, if configured. + * @return input stream with product-defined topologies, or null if not configured. + */ + @Nullable + public InputStream readProductTopologies() throws FileNotFoundException { + return getFileInputStream(getProductTopologyFile()); + } + + @Nullable + InputStream readUserTopologies(int userId) throws FileNotFoundException { + return getFileInputStream(getUserTopologyFile(userId)); + } + + AtomicFilePrintWriter getTopologyFilePrintWriter(int userId) throws IOException { + var atomicFile = new AtomicFile(getUserTopologyFile(userId), + /*commitTag=*/ "topology-state"); + return new AtomicFilePrintWriter(atomicFile, UTF_8); + } + + @Nullable + private FileInputStream getFileInputStream(File file) throws FileNotFoundException { + if (DEBUG) { + Slog.d(TAG, "File: " + file + " exists=" + file.exists()); + } + return !file.exists() ? null : new FileInputStream(file); + } + } +} diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java index 5e1d7928e96d..eafc8be7bf77 100644 --- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java +++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java @@ -319,7 +319,13 @@ class SnapshotPersistQueue { @Override void onQueuedLocked() { // Remove duplicate request. - mStoreQueueItems.remove(this); + mStoreQueueItems.removeIf(item -> { + if (item.equals(this) && item.mSnapshot != mSnapshot) { + item.mSnapshot.removeReference(TaskSnapshot.REFERENCE_PERSIST); + return true; + } + return false; + }); mStoreQueueItems.offer(this); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8410f9f313be..5de0e9b6ed93 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4309,7 +4309,8 @@ public class WindowManagerService extends IWindowManager.Stub } } - boolean getIgnoreOrientationRequest(int displayId) { + @Override + public boolean getIgnoreOrientationRequest(int displayId) { synchronized (mGlobalLock) { final DisplayContent display = mRoot.getDisplayContent(displayId); if (display == null) { diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp index 0ecc0a8a9524..abd4cd25cf68 100644 --- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp +++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp @@ -435,8 +435,8 @@ static jlong vibratorPerformPwleV2Effect(JNIEnv* env, jclass /* clazz */, jlong auto composePwleV2Fn = [&composite, &callback](vibrator::HalWrapper* hal) { return hal->composePwleV2(composite, callback); }; - auto result = wrapper->halCall<void>(composePwleV2Fn, "composePwleV2"); - return result.isOk(); + auto result = wrapper->halCall<std::chrono::milliseconds>(composePwleV2Fn, "composePwleV2"); + return result.isOk() ? result.value().count() : (result.isUnsupported() ? 0 : -1); } static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id, diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp index 6a50d3834355..8b7bdf5cece2 100644 --- a/services/core/xsd/Android.bp +++ b/services/core/xsd/Android.bp @@ -30,6 +30,14 @@ xsd_config { } xsd_config { + name: "display-topology", + srcs: ["display-topology/display-topology.xsd"], + api_dir: "display-topology/schema", + package_name: "com.android.server.display.topology", + gen_writer: true, +} + +xsd_config { name: "display-device-config", srcs: ["display-device-config/display-device-config.xsd"], api_dir: "display-device-config/schema", diff --git a/services/core/xsd/display-topology/OWNERS b/services/core/xsd/display-topology/OWNERS new file mode 100644 index 000000000000..6ce1ee4d3de2 --- /dev/null +++ b/services/core/xsd/display-topology/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/display/OWNERS diff --git a/services/core/xsd/display-topology/display-topology.xsd b/services/core/xsd/display-topology/display-topology.xsd new file mode 100644 index 000000000000..00f766fe018c --- /dev/null +++ b/services/core/xsd/display-topology/display-topology.xsd @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2024 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- + This defines the format of the XML file used to define how displays are arranged + in topologies. + It is parsed in com/android/server/display/PersistentTopologyStore.java + More information on display topology can be found in DisplayTopology.java +--> +<xs:schema version="2.0" + elementFormDefault="qualified" + xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:simpleType name="position"> + <xs:restriction base="xs:string"> + <xs:enumeration value="left"/> + <xs:enumeration value="top"/> + <xs:enumeration value="right"/> + <xs:enumeration value="bottom"/> + </xs:restriction> + </xs:simpleType> + <xs:complexType name="children"> + <xs:sequence> + <xs:element type="display" name="display" maxOccurs="unbounded" minOccurs="0"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="display"> + <xs:sequence> + <xs:element type="position" name="position" /> + <xs:element type="xs:float" name="offset"/> + <xs:element type="children" name="children" /> + </xs:sequence> + <xs:attribute type="xs:string" name="id" use="required"/> + <xs:attribute type="xs:boolean" name="primary"/> + </xs:complexType> + <xs:complexType name="topology"> + <xs:sequence> + <xs:element type="display" name="display"/> + </xs:sequence> + <xs:attribute type="xs:string" name="id" use="required"/> + <xs:attribute type="xs:int" name="order" use="required"/> + <xs:attribute type="xs:boolean" name="immutable"/> + </xs:complexType> + <xs:element name="displayTopologyState"> + <xs:complexType> + <xs:sequence> + <xs:element type="topology" name="topology" maxOccurs="1000" minOccurs="0"/> + </xs:sequence> + <xs:attribute type="xs:int" name="version" use="required"/> + </xs:complexType> + </xs:element> +</xs:schema> diff --git a/services/core/xsd/display-topology/schema/current.txt b/services/core/xsd/display-topology/schema/current.txt new file mode 100644 index 000000000000..eb59e9ec5f7b --- /dev/null +++ b/services/core/xsd/display-topology/schema/current.txt @@ -0,0 +1,64 @@ +// Signature format: 2.0 +package com.android.server.display.topology { + + public class Children { + ctor public Children(); + method public java.util.List<com.android.server.display.topology.Display> getDisplay(); + } + + public class Display { + ctor public Display(); + method public com.android.server.display.topology.Children getChildren(); + method public String getId(); + method public float getOffset(); + method public com.android.server.display.topology.Position getPosition(); + method public boolean getPrimary(); + method public void setChildren(com.android.server.display.topology.Children); + method public void setId(String); + method public void setOffset(float); + method public void setPosition(com.android.server.display.topology.Position); + method public void setPrimary(boolean); + } + + public class DisplayTopologyState { + ctor public DisplayTopologyState(); + method public java.util.List<com.android.server.display.topology.Topology> getTopology(); + method public int getVersion(); + method public void setVersion(int); + } + + public enum Position { + method public String getRawName(); + enum_constant public static final com.android.server.display.topology.Position bottom; + enum_constant public static final com.android.server.display.topology.Position left; + enum_constant public static final com.android.server.display.topology.Position right; + enum_constant public static final com.android.server.display.topology.Position top; + } + + public class Topology { + ctor public Topology(); + method public com.android.server.display.topology.Display getDisplay(); + method public String getId(); + method public boolean getImmutable(); + method public int getOrder(); + method public void setDisplay(com.android.server.display.topology.Display); + method public void setId(String); + method public void setImmutable(boolean); + method public void setOrder(int); + } + + public class XmlParser { + ctor public XmlParser(); + method public static com.android.server.display.topology.DisplayTopologyState read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + + public class XmlWriter implements java.io.Closeable { + ctor public XmlWriter(java.io.PrintWriter); + method public void close(); + method public static void write(com.android.server.display.topology.XmlWriter, com.android.server.display.topology.DisplayTopologyState) throws java.io.IOException; + } + +} + diff --git a/services/core/xsd/display-topology/schema/last_current.txt b/services/core/xsd/display-topology/schema/last_current.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/services/core/xsd/display-topology/schema/last_current.txt diff --git a/services/core/xsd/display-topology/schema/last_removed.txt b/services/core/xsd/display-topology/schema/last_removed.txt new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/services/core/xsd/display-topology/schema/last_removed.txt diff --git a/services/core/xsd/display-topology/schema/removed.txt b/services/core/xsd/display-topology/schema/removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/services/core/xsd/display-topology/schema/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyXmlStoreTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyXmlStoreTest.java new file mode 100644 index 000000000000..48822821ba01 --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyXmlStoreTest.java @@ -0,0 +1,388 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.graphics.PointF; +import android.hardware.display.DisplayTopology; +import android.util.AtomicFilePrintWriter; +import android.util.SparseArray; + +import androidx.test.filters.SmallTest; + +import com.google.common.io.CharSource; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +/** + * Tests for {@link DisplayTopologyXmlStore} + * Run: atest PersistentTopologyStoreTest + */ +@SmallTest +@RunWith(TestParameterInjector.class) +public class DisplayTopologyXmlStoreTest { + private static final String NO_TOPOLOGIES = """ + <?xml version="1.0" encoding="utf-8"?> + <displayTopologyState version="1"/> + """; + + private static final String SIMPLE_TOPOLOGY = """ + <?xml version="1.0" encoding="utf-8"?> + <displayTopologyState version="1"> + <topology id="uniqueid0|uniqueid1" order="0"> + <display id="uniqueid0" primary="true"> + <position>left</position> + <offset>0.0</offset> + <children> + <display id="uniqueid1" primary="false"> + <position>top</position> + <offset>-560.0</offset> + <children> + </children> + </display> + </children> + </display> + </topology> + </displayTopologyState> + """; + + private static final String IMMUTABLE_TOPOLOGY = """ + <?xml version="1.0" encoding="utf-8"?> + <displayTopologyState version="1"> + <topology id="uniqueid10|uniqueid11" order="0" immutable="true"> + <display id="uniqueid10" primary="true"> + <position>left</position> + <offset>0.0</offset> + <children> + <display id="uniqueid11" primary="false"> + <position>top</position> + <offset>-560.0</offset> + <children> + </children> + </display> + </children> + </display> + </topology> + </displayTopologyState> + """; + + private static final String MULTIPLE_TOPOLOGIES = """ + <?xml version="1.0" encoding="utf-8"?> + <displayTopologyState version="1"> + <topology id="uniqueid0|uniqueid1" order="0"> + <display id="uniqueid0" primary="true"> + <position>left</position> + <offset>0.0</offset> + <children> + <display id="uniqueid1" primary="false"> + <position>top</position> + <offset>-560.0</offset> + <children> + </children> + </display> + </children> + </display> + </topology> + <topology id="uniqueid0|uniqueid1|uniqueid2|uniqueid3" order="0"> + <display id="uniqueid1" primary="false"> + <position>left</position> + <offset>0.0</offset> + <children> + <display id="uniqueid0" primary="false"> + <position>top</position> + <offset>-50</offset> + <children> + </children> + </display> + <display id="uniqueid2" primary="true"> + <position>right</position> + <offset>-100</offset> + <children> + <display id="uniqueid3" primary="false"> + <position>bottom</position> + <offset>-300</offset> + <children> + </children> + </display> + </children> + </display> + </children> + </display> + </topology> + </displayTopologyState> + """; + + private static InputStream asInputStream(String value) throws IOException { + return CharSource.wrap(value).asByteSource(UTF_8).openStream(); + } + + private static SparseArray<String> generateIdToUniqueId() { + var res = new SparseArray<String>(); + for (int i = 0; i < 200; i++) { + res.put(i, "uniqueid" + i); + } + return res; + } + + private static Map<String, Integer> generateUniqueIdToId() { + var res = new HashMap<String, Integer>(); + for (int i = 0; i < 200; i++) { + res.put("uniqueid" + i, i); + } + return res; + } + + private static DisplayTopology generateTopology(int displayId1, int displayId2) { + var topology = new DisplayTopology(); + topology.addDisplay(displayId1, 800f, 600f); + topology.addDisplay(displayId2, 1920f, 1080f); + return topology; + } + + @Mock + private DisplayTopologyXmlStore.Injector mInjector; + @Mock + private AtomicFilePrintWriter mPrintWriter0; + @Mock + private AtomicFilePrintWriter mPrintWriter1; + + private DisplayTopology mTopology; + + /** Setup tests. */ + @Before + public void setup() throws IOException { + MockitoAnnotations.initMocks(this); + configureTopologyFile(/*userId=*/ 0, NO_TOPOLOGIES, mPrintWriter0); + configureTopologyFile(/*userId=*/ 1, SIMPLE_TOPOLOGY, mPrintWriter1); + configureTopologyFile(/*userId=*/ 2, MULTIPLE_TOPOLOGIES, mPrintWriter1); + + when(mInjector.getDisplayIdToUniqueIdMapping()).thenReturn(generateIdToUniqueId()); + when(mInjector.getUniqueIdToDisplayIdMapping()).thenReturn(generateUniqueIdToId()); + + mTopology = generateTopology(0, 1); + } + + @Test + public void testSaveAndRestoreTopologyWithoutFileStreams() throws IOException { + final float initialOffset = -560f; + final float newOffset = -300f; + + var store = new DisplayTopologyXmlStore(mInjector); + assertThat(store.saveTopology(mTopology)).isTrue(); + assertThat(mTopology.getRoot().getChildren().getFirst().getOffset()) + .isEqualTo(initialOffset); + assertThat(mTopology.getRoot().getWidth()).isEqualTo(800f); + assertThat(mTopology.getRoot().getHeight()).isEqualTo(600f); + + // Change display size + assertThat(mTopology.updateDisplay(0, 640f, 480f)).isTrue(); + assertThat(mTopology.getRoot().getWidth()).isEqualTo(640f); + assertThat(mTopology.getRoot().getHeight()).isEqualTo(480f); + + // Move display#1. + mTopology.rearrange(Map.of(0, new PointF(0, 0), + 1, new PointF(newOffset, -1080f))); + assertThat(mTopology.getRoot().getChildren().getFirst().getOffset()).isEqualTo(newOffset); + + // Restore the topology, should apply saved offset, while keeping the current display sizes + mTopology = store.restoreTopology(mTopology); + + // Offset is taken from the persisted topology. + assertThat(mTopology.getRoot().getChildren().getFirst().getOffset()) + .isEqualTo(initialOffset); + + // Size is taken from the current topology + assertThat(mTopology.getRoot().getWidth()).isEqualTo(640f); + assertThat(mTopology.getRoot().getHeight()).isEqualTo(480f); + + // reloadTopologies was never called so, no file operations should have been performed. + verify(mInjector, never()).readUserTopologies(anyInt()); + verify(mInjector, never()).getTopologyFilePrintWriter(anyInt()); + } + + @Test + public void testSaveTopologyInPrintWriter() throws IOException { + var store = new DisplayTopologyXmlStore(mInjector); + store.reloadTopologies(/*userId=*/ 0); + assertThat(store.saveTopology(mTopology)).isTrue(); + verify(mPrintWriter0).print(eq(SIMPLE_TOPOLOGY)); + verify(mPrintWriter0).markSuccess(); + verify(mPrintWriter0).close(); + } + + @Test + public void testRestoreTopology() { + var store = new DisplayTopologyXmlStore(mInjector); + store.reloadTopologies(/*userId=*/ 0); + var restoredTopology = store.restoreTopology(mTopology); + + // Should return null because there was nothing persisted before. + assertThat(restoredTopology).isNull(); + + // Persist topology + assertThat(store.saveTopology(mTopology)).isTrue(); + + // Should return new instance (restored), but equal. + var restoredTopologyAfterSave = store.restoreTopology(mTopology); + assertThat(restoredTopologyAfterSave).isNotSameInstanceAs(mTopology); + assertThat(restoredTopologyAfterSave).isEqualTo(mTopology); + } + + @Test + public void testChangeUser() { + var store = new DisplayTopologyXmlStore(mInjector); + // Move display#1. + mTopology.rearrange(Map.of(0, new PointF(0, 0), + 1, new PointF(-10f, -1080f))); + assertThat(mTopology.getRoot().getChildren().getFirst().getOffset()).isEqualTo(-10f); + + store.reloadTopologies(/*userId=*/ 1); + // Should return new instance (restored), with new offset. + var restoredTopology = store.restoreTopology(mTopology); + assertThat(restoredTopology).isNotSameInstanceAs(mTopology); + assertThat(restoredTopology.getRoot().getChildren().getFirst().getOffset()) + .isEqualTo(-560f); + + // Change user. + store.reloadTopologies(/*userId=*/ 0); + // Should return null because the topology is not found for user 0. + assertThat(store.restoreTopology(mTopology)).isNull(); + } + + @Test + public void testMultipleUserTopologies() { + var store = new DisplayTopologyXmlStore(mInjector); + store.reloadTopologies(/*userId=*/ 2); + + var topology4Displays = new DisplayTopology(); + topology4Displays.addDisplay(0, 800f, 600f); + topology4Displays.addDisplay(1, 1920f, 1080f); + topology4Displays.addDisplay(2, 480f, 640f); + topology4Displays.addDisplay(3, 768f, 1024f); + + var restored = store.restoreTopology(topology4Displays); + assertThat(restored).isNotNull(); + assertThat(restored.getPrimaryDisplayId()).isEqualTo(2); + assertThat(restored.getRoot()).isNotNull(); + assertThat(restored.getRoot().getDisplayId()).isEqualTo(1); + assertThat(restored.getRoot().getWidth()).isEqualTo(1920f); + assertThat(restored.getRoot().getHeight()).isEqualTo(1080f); + assertThat(restored.getRoot().getOffset()).isEqualTo(0); + assertThat(restored.getRoot().getChildren().size()).isEqualTo(2); + assertThat(restored.getRoot().getChildren().getFirst().getDisplayId()).isEqualTo(0); + assertThat(restored.getRoot().getChildren().getFirst().getWidth()).isEqualTo(800f); + assertThat(restored.getRoot().getChildren().getFirst().getHeight()).isEqualTo(600f); + assertThat(restored.getRoot().getChildren().getFirst().getOffset()).isEqualTo(-50); + assertThat(restored.getRoot().getChildren().getFirst().getChildren().size()) + .isEqualTo(0); + assertThat(restored.getRoot().getChildren().getLast().getDisplayId()).isEqualTo(2); + assertThat(restored.getRoot().getChildren().getLast().getWidth()).isEqualTo(480f); + assertThat(restored.getRoot().getChildren().getLast().getHeight()).isEqualTo(640f); + assertThat(restored.getRoot().getChildren().getLast().getOffset()).isEqualTo(-100); + assertThat(restored.getRoot().getChildren().getLast().getChildren().size()) + .isEqualTo(1); + + assertThat(restored.getRoot().getChildren().getLast().getChildren().getFirst() + .getDisplayId()).isEqualTo(3); + assertThat(restored.getRoot().getChildren().getLast().getChildren().getFirst() + .getWidth()).isEqualTo(768f); + assertThat(restored.getRoot().getChildren().getLast().getChildren().getFirst() + .getHeight()).isEqualTo(1024f); + assertThat(restored.getRoot().getChildren().getLast().getChildren().getFirst() + .getOffset()).isEqualTo(-300); + } + + @Test + public void testLimitNumberOfTopologies() { + var store = new DisplayTopologyXmlStore(mInjector); + store.reloadTopologies(/*userId=*/ 0); + for (int i = 0; i < 110; i++) { + assertThat(store.saveTopology(generateTopology(i, i + 1))).isTrue(); + } + + assertThat(store.restoreTopology(generateTopology(110, 111))).isNull(); + assertThat(store.restoreTopology(generateTopology(109, 110))).isNotNull(); + assertThat(store.restoreTopology(generateTopology(10, 11))).isNotNull(); + assertThat(store.restoreTopology(generateTopology(9, 10))).isNull(); + for (int i = 0; i < 100; i++) { + assertThat(store.restoreTopology(generateTopology(i + 10, i + 11))).isNotNull(); + } + } + + @Test + public void testVendorTopology() throws IOException { + configureVendorTopologyFile(IMMUTABLE_TOPOLOGY); + var store = new DisplayTopologyXmlStore(mInjector); + store.reloadTopologies(/*userId=*/ 0); + var restored = store.restoreTopology(generateTopology(10, 11)); + assertThat(restored).isNotNull(); + assertThat(store.saveTopology(restored)).isFalse(); + + var userTopology = generateTopology(0, 1); + assertThat(store.restoreTopology(userTopology)).isNull(); + assertThat(store.saveTopology(userTopology)).isTrue(); + } + + @Test + public void testProductTopology() throws IOException { + configureProductTopologyFile(IMMUTABLE_TOPOLOGY); + var store = new DisplayTopologyXmlStore(mInjector); + store.reloadTopologies(/*userId=*/ 0); + var restored = store.restoreTopology(generateTopology(10, 11)); + assertThat(restored).isNotNull(); + assertThat(store.saveTopology(restored)).isFalse(); + + var userTopology = generateTopology(0, 1); + assertThat(store.restoreTopology(userTopology)).isNull(); + assertThat(store.saveTopology(userTopology)).isTrue(); + } + + private void configureTopologyFile(int userId, String initialFileContent, + AtomicFilePrintWriter printWriter) throws IOException { + doReturn(asInputStream(initialFileContent)).when(mInjector).readUserTopologies(eq(userId)); + doReturn(printWriter).when(mInjector).getTopologyFilePrintWriter(eq(userId)); + } + + private void configureVendorTopologyFile(String initialFileContent) throws IOException { + doReturn(asInputStream(initialFileContent)).when(mInjector).readVendorTopologies(); + } + + private void configureProductTopologyFile(String initialFileContent) throws IOException { + doReturn(asInputStream(initialFileContent)).when(mInjector).readProductTopologies(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java index fb31cfe762f2..ecc48bfc40e4 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java @@ -20,13 +20,13 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER; -import static com.android.hardware.input.Flags.FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES; import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK; import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER; import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS; import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS; import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION; import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER; +import static com.android.server.accessibility.Flags.FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -191,7 +191,7 @@ public class AccessibilityInputFilterTest { } @Test - @RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES) + @RequiresFlagsEnabled(FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL) public void testEventHandler_shouldIncreaseAndHaveCorrectOrderAfterOnDisplayAdded() { prepareLooper(); @@ -248,7 +248,7 @@ public class AccessibilityInputFilterTest { } @Test - @RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES) + @RequiresFlagsEnabled(FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL) public void testEventHandler_shouldHaveCorrectOrderForEventStreamTransformation() { prepareLooper(); @@ -274,7 +274,7 @@ public class AccessibilityInputFilterTest { } @Test - @RequiresFlagsDisabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES) + @RequiresFlagsDisabled(FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL) public void testEventHandler_shouldHaveCorrectOrderForEventStreamTransformation_noMagKeys() { prepareLooper(); @@ -455,7 +455,7 @@ public class AccessibilityInputFilterTest { } @Test - @RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES) + @RequiresFlagsEnabled(FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL) public void testEnabledFeatures_windowMagnificationMode_expectedMagnificationKeyHandler() { prepareLooper(); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW).when( @@ -468,7 +468,7 @@ public class AccessibilityInputFilterTest { } @Test - @RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES) + @RequiresFlagsEnabled(FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL) public void testEnabledFeatures_fullscreenMagnificationMode_expectedMagnificationKeyHandler() { prepareLooper(); doReturn(Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN).when( diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationKeyHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationKeyHandlerTest.java index d1ef33d8fb70..1c85086e2f42 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationKeyHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationKeyHandlerTest.java @@ -16,7 +16,7 @@ package com.android.server.accessibility.magnification; -import static com.android.hardware.input.Flags.FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES; +import static com.android.server.accessibility.Flags.FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL; import static com.android.server.accessibility.magnification.MagnificationController.PAN_DIRECTION_DOWN; import static com.android.server.accessibility.magnification.MagnificationController.PAN_DIRECTION_LEFT; import static com.android.server.accessibility.magnification.MagnificationController.PAN_DIRECTION_RIGHT; @@ -50,7 +50,7 @@ import org.mockito.MockitoAnnotations; * Tests for {@link MagnificationKeyHandler}. */ @RunWith(AndroidJUnit4.class) -@RequiresFlagsEnabled(FLAG_ENABLE_TALKBACK_AND_MAGNIFIER_KEY_GESTURES) +@RequiresFlagsEnabled(FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL) public class MagnificationKeyHandlerTest { @Rule diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 3b32701b5169..39206dcf21ef 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -1612,7 +1612,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { ); } - public void disabled_testThrottling() { + public void testThrottling() { final ShortcutInfo si1 = makeShortcut("shortcut1"); assertTrue(mManager.setDynamicShortcuts(list(si1))); @@ -1685,7 +1685,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime()); } - public void disabled_testThrottling_rewind() { + public void testThrottling_rewind() { final ShortcutInfo si1 = makeShortcut("shortcut1"); assertTrue(mManager.setDynamicShortcuts(list(si1))); @@ -1715,7 +1715,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(3, mManager.getRemainingCallCount()); } - public void disabled_testThrottling_perPackage() { + public void testThrottling_perPackage() { final ShortcutInfo si1 = makeShortcut("shortcut1"); assertTrue(mManager.setDynamicShortcuts(list(si1))); @@ -1847,7 +1847,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { }); } - public void disabled_testThrottling_foreground() throws Exception { + public void testThrottling_foreground() throws Exception { prepareCrossProfileDataSet(); dumpsysOnLogcat("Before save & load"); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java index 81ebf867fe2d..aad06c6d6c0e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest3.java @@ -171,12 +171,11 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { .haveRanksInOrder("ms1"); } - public void disabled_testSetDynamicShortcuts_withManifestShortcuts() { - runTestWithManifestShortcuts(() -> - disabled_testAddDynamicShortcuts_noManifestShortcuts()); + public void testSetDynamicShortcuts_withManifestShortcuts() { + runTestWithManifestShortcuts(() -> testSetDynamicShortcuts_noManifestShortcuts()); } - public void disabled_testAddDynamicShortcuts_noManifestShortcuts() { + public void testAddDynamicShortcuts_noManifestShortcuts() { mManager.addDynamicShortcuts(list( shortcut("s1", A1) )); @@ -265,8 +264,8 @@ public class ShortcutManagerTest3 extends BaseShortcutManagerTest { .haveIds("s1", "s2", "s4", "s5", "s10"); } - public void disabled_testAddDynamicShortcuts_withManifestShortcuts() { - runTestWithManifestShortcuts(() -> disabled_testAddDynamicShortcuts_noManifestShortcuts()); + public void testAddDynamicShortcuts_withManifestShortcuts() { + runTestWithManifestShortcuts(() -> testAddDynamicShortcuts_noManifestShortcuts()); } public void testUpdateShortcuts_noManifestShortcuts() { diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/BottomHalfPipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/BottomHalfPipAppHelper.kt index fe344c9b79f2..7b8b43af18da 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/BottomHalfPipAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/BottomHalfPipAppHelper.kt @@ -25,7 +25,7 @@ import com.android.server.wm.flicker.testapp.ActivityOptions.BottomHalfPip class BottomHalfPipAppHelper( instrumentation: Instrumentation, private val useLaunchingActivity: Boolean = false, - private val fillTaskOnCreate: Boolean = true, + private val fillTaskOnCreate: Boolean = false, ) : PipAppHelper( instrumentation, appName = BottomHalfPip.LABEL, diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BottomHalfPipActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BottomHalfPipActivity.java index 3bbb94515f69..1f82d674cfa7 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BottomHalfPipActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BottomHalfPipActivity.java @@ -31,7 +31,7 @@ import androidx.annotation.NonNull; public class BottomHalfPipActivity extends PipActivity { - private boolean mUseBottomHalfLayout; + private boolean mUseBottomHalfLayout = true; @Override public void onCreate(Bundle savedInstanceState) { diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h index ebb82ce1e2b7..af6063c37820 100644 --- a/tools/aapt/SdkConstants.h +++ b/tools/aapt/SdkConstants.h @@ -51,6 +51,7 @@ enum { SDK_TIRAMISU = 33, SDK_UPSIDE_DOWN_CAKE = 34, SDK_VANILLA_ICE_CREAM = 35, + SDK_BAKLAVA = 36, SDK_CUR_DEVELOPMENT = 10000, }; diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h index f131cc6d7553..2a93c177e2ce 100644 --- a/tools/aapt2/SdkConstants.h +++ b/tools/aapt2/SdkConstants.h @@ -61,6 +61,7 @@ enum : ApiVersion { SDK_TIRAMISU = 33, SDK_UPSIDE_DOWN_CAKE = 34, SDK_VANILLA_ICE_CREAM = 35, + SDK_BAKLAVA = 36, SDK_CUR_DEVELOPMENT = 10000, }; diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt index af753e5963a3..b62843ca3ff4 100644 --- a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt +++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt @@ -19,6 +19,7 @@ package com.google.android.lint import com.android.tools.lint.client.api.IssueRegistry import com.android.tools.lint.client.api.Vendor import com.android.tools.lint.detector.api.CURRENT_API +import com.google.android.lint.multiuser.PendingIntentGetActivityDetector import com.google.android.lint.parcel.SaferParcelChecker import com.google.auto.service.AutoService @@ -40,6 +41,7 @@ class AndroidFrameworkIssueRegistry : IssueRegistry() { PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE, PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD, FeatureAutomotiveDetector.ISSUE, + PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY, ) override val api: Int diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt new file mode 100644 index 000000000000..b9f22ebfa8ec --- /dev/null +++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetector.kt @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.lint.multiuser + +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import com.intellij.psi.PsiMethod +import java.util.EnumSet +import org.jetbrains.uast.UCallExpression + +/** + * Detector for flagging potential multiuser issues in `PendingIntent.getActivity()` calls. + * + * This detector checks for calls to `PendingIntent#getActivity()` and + * reports a warning if such a call is found, suggesting that the + * default user 0 context might not be the right one. + */ +class PendingIntentGetActivityDetector : Detector(), SourceCodeScanner { + + companion object { + + val description = """Flags potential multiuser issue in PendingIntent.getActivity() calls.""" + + val EXPLANATION = + """ + **Problem:** + + Calling `PendingIntent.getActivity()` in the `system_server` often accidentally uses the user 0 context. Moreover, since there's no explicit user parameter in the `getActivity` method, it can be hard to tell which user the `PendingIntent` activity is associated with, making the code error-prone and less readable. + + **Solution:** + + Always use the user aware methods to refer the correct user context. You can achieve this by: + + * **Using `PendingIntent.getActivityAsUser(...)`:** This API allows you to explicitly specify the user for the activity. + + ```java + PendingIntent.getActivityAsUser( + mContext, /*requestCode=*/0, intent, + PendingIntent.FLAG_IMMUTABLE, /*options=*/null, + UserHandle.of(mUserId)); + ``` + + **When to Ignore this Warning:** + + You can safely ignore this warning if you are certain that: + + * You've confirmed that the `PendingIntent` activity you're targeting is the correct one and is **rightly** associated with the context parameter passed into the `PendingIntent.getActivity` method. + + **Note:** If you are unsure about the user context, it's best to err on the side of caution and explicitly specify the user using the method specified above. + + **For any further questions, please reach out to go/multiuser-help.** + """.trimIndent() + + val ISSUE_PENDING_INTENT_GET_ACTIVITY: Issue = + Issue.create( + id = "PendingIntent#getActivity", + briefDescription = description, + explanation = EXPLANATION, + category = Category.SECURITY, + priority = 8, + severity = Severity.WARNING, + implementation = + Implementation( + PendingIntentGetActivityDetector::class.java, + EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES), + ), + ) + } + + override fun getApplicableMethodNames() = listOf("getActivity") + + override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { + // Check if the method call is PendingIntent.getActivity + if ( + context.evaluator.isMemberInClass(method, "android.app.PendingIntent") && + method.name == "getActivity" + ) { + context.report( + ISSUE_PENDING_INTENT_GET_ACTIVITY, + node, + context.getLocation(node), + "Using `PendingIntent.getActivity(...)` might not be multiuser-aware. " + + "Consider using the user aware method `PendingIntent.getActivityAsUser(...)`.", + ) + } + } +} diff --git a/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt new file mode 100644 index 000000000000..401055055232 --- /dev/null +++ b/tools/lint/framework/checks/src/test/java/com/google/android/lint/multiuser/PendingIntentGetActivityDetectorTest.kt @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.lint.multiuser + +import com.android.tools.lint.checks.infrastructure.LintDetectorTest +import com.android.tools.lint.checks.infrastructure.TestFile +import com.android.tools.lint.checks.infrastructure.TestLintTask +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue + +@Suppress("UnstableApiUsage") +class PendingIntentGetActivityDetectorTest : LintDetectorTest() { + + override fun getDetector(): Detector = PendingIntentGetActivityDetector() + + override fun getIssues(): List<Issue> = + listOf(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY) + + override fun lint(): TestLintTask = super.lint().allowMissingSdk(true) + + fun testPendingIntentGetActivity() { + lint() + .files( + java( + """ + package test.pkg; + + import android.app.PendingIntent; + import android.content.Context; + import android.content.Intent; + + public class TestClass { + private Context mContext; + + public void testMethod(Intent intent) { + PendingIntent.getActivity( + mContext, /*requestCode=*/0, intent, + PendingIntent.FLAG_IMMUTABLE, /*options=*/null + ); + } + } + """ + ) + .indented(), + *stubs, + ) + .issues(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY) + .run() + .expect( + """ + src/test/pkg/TestClass.java:11: Warning: Using PendingIntent.getActivity(...) might not be multiuser-aware. Consider using the user aware method PendingIntent.getActivityAsUser(...). [PendingIntent#getActivity] + PendingIntent.getActivity( + ^ + 0 errors, 1 warnings + """ + ) + } + + fun testPendingIntentGetActivityAsUser() { + lint() + .files( + java( + """ + package test.pkg; + + import android.app.PendingIntent; + import android.content.Context; + import android.content.Intent; + import android.os.UserHandle; + + public class TestClass { + private Context mContext; + + public void testMethod(Intent intent) { + PendingIntent.getActivityAsUser( + mContext, /*requestCode=*/0, intent, + 0, /*options=*/null, + UserHandle.CURRENT + ); + } + } + """ + ) + .indented(), + *stubs, + ) + .issues(PendingIntentGetActivityDetector.ISSUE_PENDING_INTENT_GET_ACTIVITY) + .run() + .expectClean() + } + + private val pendingIntentStub: TestFile = + java( + """ + package android.app; + + import android.content.Context; + import android.content.Intent; + import android.os.UserHandle; + + public class PendingIntent { + public static boolean getActivity(Context context, int requestCode, Intent intent, int flags) { + return true; + } + + public static boolean getActivityAsUser( + Context context, + int requestCode, + Intent intent, + int flags, + UserHandle userHandle + ) { + return true; + } + } + """ + ) + + private val contxtStub: TestFile = + java( + """ + package android.content; + + import android.os.UserHandle; + + public class Context { + + public Context createContextAsUser(UserHandle userHandle, int flags) { + return this; + } + } + + """ + ) + + private val userHandleStub: TestFile = + java( + """ + package android.os; + + public class UserHandle { + + } + + """ + ) + + private val intentStub: TestFile = + java( + """ + package android.content; + + public class Intent { + + } + """ + ) + + private val stubs = arrayOf(pendingIntentStub, contxtStub, userHandleStub, intentStub) +} |