diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-02-22 18:39:11 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-02-22 18:39:11 +0000 |
commit | abaab863d97b6cb24d98b03294d1bb2e6fc8ad2f (patch) | |
tree | b9afd83b25c973dcd492b874adb9248ff7ea0316 | |
parent | bd2f22cdca5c0c27b50d60b974e72df2f6267b2e (diff) | |
parent | 869863bb7845196390b0f96fdc8ea3ba02668b1d (diff) |
Snap for 9635940 from 869863bb7845196390b0f96fdc8ea3ba02668b1d to tm-platform-release
Change-Id: Ied175bec3a42276070525b316a1bdb010c20baf8
558 files changed, 18306 insertions, 10319 deletions
diff --git a/Android.bp b/Android.bp index 330c32ec89..0bbb3d2c1e 100644 --- a/Android.bp +++ b/Android.bp @@ -19,6 +19,54 @@ package { min_launcher3_sdk_version = "26" +// Common source files used to build launcher (java and kotlin) +// All sources are split so they can be reused in many other libraries/apps in other folders +filegroup { + name: "launcher-src", + srcs: [ "src/**/*.java", "src/**/*.kt" ], +} + +filegroup { + name: "launcher-quickstep-src", + srcs: [ "quickstep/src/**/*.java", "quickstep/src/**/*.kt" ], +} + +filegroup { + name: "launcher-go-src", + srcs: [ "go/src/**/*.java", "go/src/**/*.kt" ], +} + +filegroup { + name: "launcher-go-quickstep-src", + srcs: [ "go/quickstep/src/**/*.java", "go/quickstep/src/**/*.kt" ], +} + +filegroup { + name: "launcher-src_shortcuts_overrides", + srcs: [ "src_shortcuts_overrides/**/*.java", "src_shortcuts_overrides/**/*.kt" ], +} + +filegroup { + name: "launcher-src_ui_overrides", + srcs: [ "src_ui_overrides/**/*.java", "src_ui_overrides/**/*.kt" ], +} + +filegroup { + name: "launcher-ext_tests", + srcs: [ "ext_tests/**/*.java", "ext_tests/**/*.kt" ], +} + +filegroup { + name: "launcher-quickstep-ext_tests", + srcs: [ "quickstep/ext_tests/**/*.java", "quickstep/ext_tests/**/*.kt" ], +} + +// Proguard files for Launcher3 +filegroup { + name: "launcher-proguard-rules", + srcs: ["proguard.flags"], +} + android_library { name: "launcher-aosp-tapl", libs: [ @@ -105,6 +153,7 @@ android_library { "androidx.cardview_cardview", "com.google.android.material_material", "iconloader_base", + "view_capture" ], manifest: "AndroidManifest-common.xml", sdk_version: "current", @@ -139,14 +188,10 @@ android_app { "Launcher3CommonDepsLib", ], srcs: [ - "src/**/*.java", - "src/**/*.kt", - "src_shortcuts_overrides/**/*.java", - "src_shortcuts_overrides/**/*.kt", - "src_ui_overrides/**/*.java", - "src_ui_overrides/**/*.kt", - "ext_tests/src/**/*.java", - "ext_tests/src/**/*.kt", + ":launcher-src", + ":launcher-src_shortcuts_overrides", + ":launcher-src_ui_overrides", + ":launcher-ext_tests", ], resource_dirs: [ "ext_tests/res", @@ -202,61 +247,14 @@ android_library { } -// Source code used for test helpers -filegroup { - name: "launcher-src-ext-tests", - srcs: [ - "ext_tests/src/**/*.java", - "ext_tests/src/**/*.kt", - "quickstep/ext_tests/src/**/*.java", - "quickstep/ext_tests/src/**/*.kt", - ], -} - -// Common source files used to build launcher -filegroup { - name: "launcher-src-no-build-config", - srcs: [ - "src/**/*.java", - "src/**/*.kt", - "src_shortcuts_overrides/**/*.java", - "src_shortcuts_overrides/**/*.kt", - "quickstep/src/**/*.java", - "quickstep/src/**/*.kt", - ], -} - -// Common source files used to build go launcher except go/src files -filegroup { - name: "launcher-go-src-no-build-config", - srcs: [ - "src/**/*.java", - "src/**/*.kt", - "quickstep/src/**/*.java", - "quickstep/src/**/*.kt", - "go/quickstep/src/**/*.java", - "go/quickstep/src/**/*.kt", - ], -} - -// Proguard files for Launcher3 -filegroup { - name: "launcher-proguard-rules", - srcs: ["proguard.flags"], -} - // Library with all the dependencies for building Launcher Go android_library { name: "LauncherGoResLib", srcs: [ - "src/**/*.java", - "src/**/*.kt", - "quickstep/src/**/*.java", - "quickstep/src/**/*.kt", - "go/src/**/*.java", - "go/src/**/*.kt", - "go/quickstep/src/**/*.java", - "go/quickstep/src/**/*.kt", + ":launcher-src", + ":launcher-quickstep-src", + ":launcher-go-src", + ":launcher-go-quickstep-src", ], resource_dirs: [ "go/res", @@ -287,7 +285,9 @@ android_library { android_library { name: "Launcher3QuickStepLib", srcs: [ - ":launcher-src-no-build-config", + ":launcher-src", + ":launcher-quickstep-src", + ":launcher-src_shortcuts_overrides", ], resource_dirs: [], libs: [ @@ -319,9 +319,9 @@ android_app { static_libs: ["Launcher3CommonDepsLib"], srcs: [ - "src/**/*.java", - "src_ui_overrides/**/*.java", - "go/src/**/*.java", + ":launcher-src", + ":launcher-go-src", + ":launcher-src_ui_overrides", ], resource_dirs: ["go/res"], @@ -405,12 +405,7 @@ android_app { min_sdk_version: "current", target_sdk_version: "current", - srcs: [ - "src/**/*.java", - "quickstep/src/**/*.java", - "go/src/**/*.java", - "go/quickstep/src/**/*.java", - ], + srcs: [ ], resource_dirs: [ "go/quickstep/res", diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index 02b83fe889..951be4e54e 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -43,7 +43,8 @@ <!-- for rotating surface by arbitrary degree --> <uses-permission android:name="android.permission.ROTATE_SURFACE_FLINGER" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> - + <uses-permission android:name="android.permission.READ_HOME_APP_SEARCH_DATA" /> + <!-- Permissions required for read/write access to the workspace data. These permission name should not conflict with that defined in other apps, as such an app should embed its package diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java index a91ff44c8a..a645e58ecc 100644 --- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java +++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java @@ -17,6 +17,7 @@ package com.android.launcher3.testing; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.app.Activity; import android.app.Application; @@ -209,12 +210,19 @@ public class DebugTestInformationHandler extends TestInformationHandler { } case TestProtocol.REQUEST_USE_TEST_WORKSPACE_LAYOUT: { - useTestWorkspaceLayout(true); + useTestWorkspaceLayout( + LauncherSettings.Settings.ARG_DEFAULT_WORKSPACE_LAYOUT_TEST); + return response; + } + + case TestProtocol.REQUEST_USE_TEST2_WORKSPACE_LAYOUT: { + useTestWorkspaceLayout( + LauncherSettings.Settings.ARG_DEFAULT_WORKSPACE_LAYOUT_TEST2); return response; } case TestProtocol.REQUEST_USE_DEFAULT_WORKSPACE_LAYOUT: { - useTestWorkspaceLayout(false); + useTestWorkspaceLayout(null); return response; } @@ -248,17 +256,25 @@ public class DebugTestInformationHandler extends TestInformationHandler { return response; } + case TestProtocol.REQUEST_MODEL_QUEUE_CLEARED: + return getFromExecutorSync(MODEL_EXECUTOR, Bundle::new); + default: return super.call(method, arg, extras); } } - private void useTestWorkspaceLayout(boolean useTestWorkspaceLayout) { + private void useTestWorkspaceLayout(String layout) { final long identity = Binder.clearCallingIdentity(); try { - LauncherSettings.Settings.call(mContext.getContentResolver(), useTestWorkspaceLayout - ? LauncherSettings.Settings.METHOD_SET_USE_TEST_WORKSPACE_LAYOUT_FLAG - : LauncherSettings.Settings.METHOD_CLEAR_USE_TEST_WORKSPACE_LAYOUT_FLAG); + if (layout != null) { + LauncherSettings.Settings.call(mContext.getContentResolver(), + LauncherSettings.Settings.METHOD_SET_USE_TEST_WORKSPACE_LAYOUT_FLAG, + layout); + } else { + LauncherSettings.Settings.call(mContext.getContentResolver(), + LauncherSettings.Settings.METHOD_CLEAR_USE_TEST_WORKSPACE_LAYOUT_FLAG); + } } finally { Binder.restoreCallingIdentity(identity); } diff --git a/go/quickstep/res/values-en-rCA/strings.xml b/go/quickstep/res/values-en-rCA/strings.xml index 676ac43284..664bd94219 100644 --- a/go/quickstep/res/values-en-rCA/strings.xml +++ b/go/quickstep/res/values-en-rCA/strings.xml @@ -1,19 +1,19 @@ <?xml version="1.0" encoding="UTF-8"?> <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_share_drop_target_label" msgid="5804774105974539508">"Share app"</string> + <string name="app_share_drop_target_label" msgid="5804774105974539508">"Share App"</string> <string name="action_listen" msgid="2370304050784689486">"Listen"</string> <string name="action_translate" msgid="8028378961867277746">"Translate"</string> <string name="action_search" msgid="6269564710943755464">"Lens"</string> - <string name="dialog_acknowledge" msgid="2804025517675853172">"OK"</string> + <string name="dialog_acknowledge" msgid="2804025517675853172">"GOT IT"</string> <string name="dialog_cancel" msgid="6464336969134856366">"CANCEL"</string> <string name="dialog_settings" msgid="6564397136021186148">"SETTINGS"</string> <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"Translate or listen to text on screen"</string> - <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Information such as text on your screen, web addresses and screenshots may be shared with Google.\n\nTo change what information you share, go to "<b>"Settings > Apps > Default apps > Digital assistant app"</b>"."</string> + <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Information such as text on your screen, web addresses, and screenshots may be shared with Google.\n\nTo change what information you share, go to "<b>"Settings > Apps > Default apps > Digital assistant app"</b>"."</string> <string name="assistant_not_selected_title" msgid="5017072974603345228">"Choose an assistant to use this feature"</string> - <string name="assistant_not_selected_text" msgid="3244613673884359276">"To listen to or translate text on your screen, choose a digital assistant app in settings"</string> + <string name="assistant_not_selected_text" msgid="3244613673884359276">"To listen to or translate text on your screen, choose a digital assistant app in Settings"</string> <string name="assistant_not_supported_title" msgid="1675788067597484142">"Change your assistant to use this feature"</string> - <string name="assistant_not_supported_text" msgid="1708031078549268884">"To listen to or translate text on your screen, change your digital assistant app in settings"</string> + <string name="assistant_not_supported_text" msgid="1708031078549268884">"To listen to or translate text on your screen, change your digital assistant app in Settings"</string> <string name="tooltip_listen" msgid="7634466447860989102">"Tap here to listen to text on this screen"</string> <string name="tooltip_translate" msgid="4184845868901542567">"Tap here to translate text on this screen"</string> <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"This app can’t be shared"</string> diff --git a/go/quickstep/res/values-my/strings.xml b/go/quickstep/res/values-my/strings.xml index 0ca0e9c0bf..cbb485a6d2 100644 --- a/go/quickstep/res/values-my/strings.xml +++ b/go/quickstep/res/values-my/strings.xml @@ -5,7 +5,7 @@ <string name="action_listen" msgid="2370304050784689486">"နားထောင်ရန်"</string> <string name="action_translate" msgid="8028378961867277746">"ဘာသာပြန်ရန်"</string> <string name="action_search" msgid="6269564710943755464">"Lens"</string> - <string name="dialog_acknowledge" msgid="2804025517675853172">"ရပြီ"</string> + <string name="dialog_acknowledge" msgid="2804025517675853172">"နားလည်ပြီ"</string> <string name="dialog_cancel" msgid="6464336969134856366">"မလုပ်တော့"</string> <string name="dialog_settings" msgid="6564397136021186148">"ဆက်တင်များ"</string> <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"ဖန်သားပြင်ပေါ်ရှိ စာသားကို ဘာသာပြန်ပါ (သို့) နားထောင်ပါ"</string> diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java index c997e52dbd..253147d96b 100644 --- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java +++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java @@ -50,8 +50,8 @@ import androidx.annotation.IntDef; import androidx.annotation.VisibleForTesting; import com.android.launcher3.BaseActivity; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.views.ArrowTipView; import com.android.quickstep.util.AssistContentRequester; import com.android.quickstep.util.RecentsOrientedState; @@ -124,7 +124,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { AssistContentRequester assistContentRequester) { super(taskThumbnailView); mFactoryContentRequester = assistContentRequester; - mSharedPreferences = Utilities.getPrefs(mApplicationContext); + mSharedPreferences = LauncherPrefs.getPrefs(mApplicationContext); } /** @@ -151,7 +151,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot() && !isManagedProfileTask; getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task)); mTaskPackageName = task.key.getPackageName(); - mSharedPreferences = Utilities.getPrefs(mApplicationContext); + mSharedPreferences = LauncherPrefs.getPrefs(mApplicationContext); checkSettings(); if (!mAssistStructurePermitted || !mAssistScreenshotPermitted diff --git a/go/src/com/android/launcher3/model/WidgetsModel.java b/go/src/com/android/launcher3/model/WidgetsModel.java index 9a000d6b52..1aa5d03f6d 100644 --- a/go/src/com/android/launcher3/model/WidgetsModel.java +++ b/go/src/com/android/launcher3/model/WidgetsModel.java @@ -41,10 +41,8 @@ import java.util.Set; */ public class WidgetsModel { - // True if the widget support is disabled. + // True is the widget support is disabled. public static final boolean GO_DISABLE_WIDGETS = true; - // True if the shortcut support is disabled. - public static final boolean GO_DISABLE_SHORTCUTS = true; public static final boolean GO_DISABLE_NOTIFICATION_DOTS = true; private static final ArrayList<WidgetsListBaseEntry> EMPTY_WIDGET_LIST = new ArrayList<>(); diff --git a/lint-baseline-launcher3.xml b/lint-baseline-launcher3.xml index 107a34694b..a9dc0c604e 100644 --- a/lint-baseline-launcher3.xml +++ b/lint-baseline-launcher3.xml @@ -606,4 +606,20 @@ column="61"/> </issue> + <issue + id="NewApi" + message="Call requires API level 33 (current min is 26): `android.app.Activity#getOnBackInvokedDispatcher`"> + <location + file="packages/apps/Launcher3/src/com/android/launcher3/BaseActivity.java" + line="182"/> + </issue> + + <issue + id="NewApi" + message="Call requires API level 33 (current min is 26): `android.window.OnBackInvokedDispatcher#registerOnBackInvokedCallback`"> + <location + file="packages/apps/Launcher3/src/com/android/launcher3/BaseActivity.java" + line="182"/> + </issue> + </issues> diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto index 10eedc8578..677c9921a0 100644 --- a/protos/launcher_atom.proto +++ b/protos/launcher_atom.proto @@ -45,6 +45,9 @@ message ItemInfo { // Stores the origin of the Item repeated Attribute item_attributes = 12; + + // Stores whether the navigation bar is in kids mode. + optional bool is_kids_mode = 13; } message LauncherAttributes{ @@ -127,7 +130,7 @@ message TaskBarContainer { optional int32 cardinality = 2; } -// Next value 40 +// Next value 41 enum Attribute { UNKNOWN = 0; DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat @@ -183,6 +186,7 @@ enum Attribute { WEB_SEARCH_RESULT_PERSONAL = 36; WEB_SEARCH_RESULT_CALCULATOR = 37; WEB_SEARCH_RESULT_URL = 38; + WEB_SEARCH_RESULT_RICH_ANSWER = 40; WIDGETS_BOTTOM_TRAY = 28; WIDGETS_TRAY_PREDICTION = 29; diff --git a/protos/view_capture.proto b/protos/view_capture.proto deleted file mode 100644 index f363f36820..0000000000 --- a/protos/view_capture.proto +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -syntax = "proto2"; - -package com.android.launcher3.view; - -option java_outer_classname = "ViewCaptureData"; - -message ExportedData { - - repeated FrameData frameData = 1; - repeated string classname = 2; -} - -message FrameData { - optional int64 timestamp = 1; - optional ViewNode node = 2; -} - -message ViewNode { - optional int32 classname_index = 1; - optional int32 hashcode = 2; - - repeated ViewNode children = 3; - - optional string id = 4; - optional int32 left = 5; - optional int32 top = 6; - optional int32 width = 7; - optional int32 height = 8; - optional int32 scrollX = 9; - optional int32 scrollY = 10; - - optional float translationX = 11; - optional float translationY = 12; - optional float scaleX = 13 [default = 1]; - optional float scaleY = 14 [default = 1]; - optional float alpha = 15 [default = 1]; - - optional bool willNotDraw = 16; - optional bool clipChildren = 17; - optional int32 visibility = 18; - - optional float elevation = 19; -} diff --git a/quickstep/Android.bp b/quickstep/Android.bp index f739f8140c..f5a8253563 100644 --- a/quickstep/Android.bp +++ b/quickstep/Android.bp @@ -18,6 +18,11 @@ package { } filegroup { + name: "launcher3-quickstep-manifest", + srcs: ["AndroidManifest.xml"], +} + +filegroup { name: "launcher3-quickstep-robolectric-src", path: "robolectric_tests", srcs: ["robolectric_tests/src/**/*.java"], @@ -33,6 +38,7 @@ filegroup { name: "launcher3-quickstep-oop-tests-src", path: "tests", srcs: [ + "tests/src/com/android/quickstep/TaskbarModeSwitchRule.java", "tests/src/com/android/quickstep/NavigationModeSwitchRule.java", "tests/src/com/android/quickstep/AbstractQuickStepTest.java", "tests/src/com/android/quickstep/TaplTestsQuickstep.java", diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index 352cd3e7b6..3647e05f0a 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -37,6 +37,7 @@ <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY"/> <uses-permission android:name="android.permission.MONITOR_INPUT"/> <uses-permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"/> + <uses-permission android:name="android.permission.ACCESS_SHORTCUTS"/> <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" /> diff --git a/quickstep/res/drawable/ic_floating_task_button.xml b/quickstep/res/drawable/ic_floating_task_button.xml deleted file mode 100644 index e50f65cee7..0000000000 --- a/quickstep/res/drawable/ic_floating_task_button.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2022 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. - --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:pathData="M17.6258,4.96L19.0358,6.37L7.4058,18.01L5.9958,16.6L17.6258,4.96ZM16.1358,3.62L4.1258,15.63L3.0158,19.83C2.9058,20.45 3.3858,21 3.9958,21C4.0558,21 4.1058,21 4.1658,20.99L8.3658,19.88L20.3758,7.86C20.7758,7.46 20.9958,6.93 20.9958,6.37C20.9958,5.81 20.7758,5.28 20.3758,4.88L19.1058,3.61C18.7158,3.22 18.1858,3 17.6258,3C17.0658,3 16.5358,3.22 16.1358,3.62Z" - android:fillColor="#636C6F"/> - <path - android:pathData="M20.1936,15.3369C20.3748,16.3837 19.9151,17.5414 18.8846,18.7597C19.1546,18.872 19.4576,18.9452 19.7724,18.9867C20.0839,19.0278 20.3683,19.0325 20.5749,19.0266C20.6772,19.0236 20.7578,19.0181 20.8101,19.0138C20.8362,19.0116 20.855,19.0097 20.8657,19.0085L20.8754,19.0074L20.875,19.0075C21.4217,18.9385 21.9214,19.325 21.9918,19.8718C22.0624,20.4195 21.6756,20.9208 21.1279,20.9914L21,19.9996C21.1279,20.9914 21.1265,20.9916 21.1265,20.9916L21.1249,20.9918L21.1211,20.9923L21.1107,20.9935L21.0795,20.997C21.0542,20.9998 21.0199,21.0032 20.9775,21.0067C20.8929,21.0138 20.7753,21.0216 20.6323,21.0257C20.3481,21.0339 19.9533,21.0279 19.5109,20.9695C18.873,20.8854 18.0393,20.6793 17.3106,20.1662C16.9605,20.3559 16.5876,20.4952 16.2299,20.6003C15.5742,20.7927 14.8754,20.8968 14.2534,20.9534C13.6801,21.0055 13.4553,21.0037 13.1015,21.0008C13.0689,21.0005 13.0352,21.0002 13,21H12.8594C12.8214,21.0002 12.785,21.0006 12.7504,21.0009C12.6524,21.0019 12.5683,21.0027 12.5,21H12.0562C12.0277,21.0003 12.0054,21.0006 11.9926,21.001L11.9751,21H9L11,19H11.9795C11.9929,18.9997 12.0064,18.9997 12.0199,19H12.4117C12.4534,18.9996 12.4864,18.9995 12.5,19H12.9675C12.977,18.9999 12.9878,18.9999 13,19C13.0446,19.0003 13.0859,19.0007 13.1249,19.0011C13.4259,19.0038 13.591,19.0054 14.0723,18.9616C14.6201,18.9118 15.1795,18.8242 15.6665,18.6813C15.753,18.6559 15.8346,18.6295 15.9114,18.6022C15.0315,17.2981 14.7125,16.1044 15.015,15.0829C15.4095,13.7511 16.6784,13.2418 17.7026,13.2864C18.7262,13.3309 19.954,13.9529 20.1936,15.3369ZM16.9327,15.6508C16.873,15.8523 16.8651,16.3878 17.4697,17.334C18.2007,16.4284 18.2585,15.8839 18.2229,15.6781C18.1939,15.5108 18.0297,15.3025 17.6157,15.2845C17.2025,15.2665 16.9885,15.4626 16.9327,15.6508Z" - android:fillColor="#636C6F" - android:fillType="evenOdd"/> -</vector> diff --git a/quickstep/res/drawable/taskbar_edu_splitscreen.png b/quickstep/res/drawable/taskbar_edu_splitscreen.png Binary files differdeleted file mode 100644 index f9d2a63a0e..0000000000 --- a/quickstep/res/drawable/taskbar_edu_splitscreen.png +++ /dev/null diff --git a/quickstep/res/drawable/taskbar_edu_stashing.png b/quickstep/res/drawable/taskbar_edu_stashing.png Binary files differdeleted file mode 100644 index f9d2a63a0e..0000000000 --- a/quickstep/res/drawable/taskbar_edu_stashing.png +++ /dev/null diff --git a/quickstep/res/drawable/taskbar_edu_switch_apps.png b/quickstep/res/drawable/taskbar_edu_switch_apps.png Binary files differdeleted file mode 100644 index f9d2a63a0e..0000000000 --- a/quickstep/res/drawable/taskbar_edu_switch_apps.png +++ /dev/null diff --git a/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml b/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml new file mode 100644 index 0000000000..44b3ecbd97 --- /dev/null +++ b/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <TextView + android:id="@+id/navigation_settings" + style="@style/TextAppearance.GestureTutorial.LinkText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="24dp" + android:background="?android:attr/selectableItemBackground" + android:minHeight="48dp" + android:text="@string/allset_navigation_settings" + app:layout_constraintTop_toBottomOf="@id/subtitle" + app:layout_constraintStart_toStartOf="parent" /> + + <TextView + android:id="@+id/hint" + style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="24dp" + android:text="@string/allset_hint" + android:textSize="@dimen/allset_page_swipe_up_text_size" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + +</merge>
\ No newline at end of file diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml index 56e1d16281..f08cabe13e 100644 --- a/quickstep/res/layout/activity_allset.xml +++ b/quickstep/res/layout/activity_allset.xml @@ -34,8 +34,6 @@ android:layout_height="match_parent" android:gravity="center" android:scaleType="centerCrop" - - app:lottie_rawRes="@raw/all_set_page_bg" app:lottie_autoPlay="true" app:lottie_loop="true" /> @@ -79,42 +77,8 @@ app:layout_constraintStart_toStartOf="parent" android:gravity="start"/> - <androidx.constraintlayout.widget.Guideline - android:id="@+id/navigation_settings_guideline_bottom" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_percent="0.83" /> - - <TextView - android:id="@+id/navigation_settings" - style="@style/TextAppearance.GestureTutorial.LinkText" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toBottomOf="@id/navigation_settings_guideline_bottom" - android:minHeight="48dp" - android:background="?android:attr/selectableItemBackground" - android:text="@string/allset_navigation_settings" /> + <include layout="@layout/allset_navigation_and_hint"/> - <androidx.constraintlayout.widget.Guideline - android:id="@+id/hint_guideline_bottom" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:orientation="horizontal" - app:layout_constraintGuide_percent="0.94" /> - - <TextView - android:id="@+id/hint" - style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle" - android:textSize="14sp" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintBottom_toBottomOf="@id/hint_guideline_bottom" - android:text="@string/allset_hint"/> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/quickstep/res/layout/all_apps_edu_view.xml b/quickstep/res/layout/all_apps_edu_view.xml index e7ef6e699a..0dd4df14e0 100644 --- a/quickstep/res/layout/all_apps_edu_view.xml +++ b/quickstep/res/layout/all_apps_edu_view.xml @@ -3,4 +3,5 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="@dimen/swipe_edu_width" - android:layout_height="@dimen/swipe_edu_max_height"/> + android:layout_height="@dimen/swipe_edu_max_height" + android:accessibilityPaneTitle="@string/taskbar_edu_a11y_title"/> diff --git a/quickstep/res/layout/allset_navigation_and_hint.xml b/quickstep/res/layout/allset_navigation_and_hint.xml new file mode 100644 index 0000000000..4d5cf01eaa --- /dev/null +++ b/quickstep/res/layout/allset_navigation_and_hint.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/navigation_settings_guideline_bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.83" /> + + <TextView + android:id="@+id/navigation_settings" + style="@style/TextAppearance.GestureTutorial.LinkText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="?android:attr/selectableItemBackground" + android:minHeight="48dp" + android:text="@string/allset_navigation_settings" + app:layout_constraintBottom_toBottomOf="@id/navigation_settings_guideline_bottom" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/hint_guideline_bottom" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.94" /> + + <TextView + android:id="@+id/hint" + style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/allset_hint" + android:textSize="@dimen/allset_page_swipe_up_text_size" + app:layout_constraintBottom_toBottomOf="@id/hint_guideline_bottom" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" /> + +</merge>
\ No newline at end of file diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml index c4642e443c..d5e367097a 100644 --- a/quickstep/res/layout/digital_wellbeing_toast.xml +++ b/quickstep/res/layout/digital_wellbeing_toast.xml @@ -25,4 +25,6 @@ android:gravity="center" android:importantForAccessibility="noHideDescendants" android:textColor="?priv-android:attr/textColorOnAccent" - android:textSize="14sp"/>
\ No newline at end of file + android:textSize="14sp" + android:autoSizeTextType="uniform" + android:autoSizeMaxTextSize="14sp"/>
\ No newline at end of file diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml index 7e5b85c41d..bd11c1ef05 100644 --- a/quickstep/res/layout/task.xml +++ b/quickstep/res/layout/task.xml @@ -28,6 +28,19 @@ android:layout_width="match_parent" android:layout_height="match_parent"/> + <!-- Filtering affects only alpha instead of the visibility since visibility can be altered + separately through RecentsView#resetFromSplitSelectionState() --> + <ImageView + android:id="@+id/show_windows" + android:layout_height="@dimen/recents_filter_icon_size" + android:layout_width="@dimen/recents_filter_icon_size" + android:layout_gravity="end" + android:alpha="0" + android:tint="@color/recents_filter_icon" + android:contentDescription="@string/recents_filter_icon_desc" + android:importantForAccessibility="no" + android:src="@drawable/ic_select_windows" /> + <com.android.quickstep.views.IconView android:id="@+id/icon" android:layout_width="@dimen/task_thumbnail_icon_size" diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml new file mode 100644 index 0000000000..0c8543f414 --- /dev/null +++ b/quickstep/res/layout/task_desktop.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 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. +--> + +<com.android.quickstep.views.DesktopTaskView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipChildren="true" + android:clipToOutline="true" + android:defaultFocusHighlightEnabled="false" + android:focusable="true"> + + <!-- + TODO(b249371338): DesktopTaskView extends from TaskView. TaskView expects TaskThumbnailView + and IconView with these ids to be present. Need to refactor RecentsView to accept child + views that do not inherint from TaskView only or create a generic TaskView that have + N number of tasks. + --> + <com.android.quickstep.views.TaskThumbnailView + android:id="@+id/snapshot" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <com.android.quickstep.views.IconView + android:id="@+id/icon" + android:layout_width="0dp" + android:layout_height="0dp" + android:focusable="false" + android:importantForAccessibility="no" + android:visibility="gone" /> + +</com.android.quickstep.views.DesktopTaskView> diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml index cd5bcbdddd..ec03c694b8 100644 --- a/quickstep/res/layout/task_grouped.xml +++ b/quickstep/res/layout/task_grouped.xml @@ -38,6 +38,32 @@ android:layout_width="match_parent" android:layout_height="match_parent"/> + <!-- Filtering affects only alpha instead of the visibility since visibility can be altered + separately through RecentsView#resetFromSplitSelectionState() --> + <ImageView + android:id="@+id/show_windows" + android:layout_height="@dimen/recents_filter_icon_size" + android:layout_width="@dimen/recents_filter_icon_size" + android:layout_gravity="start" + android:alpha="0" + android:tint="@color/recents_filter_icon" + android:contentDescription="@string/recents_filter_icon_desc" + android:importantForAccessibility="no" + android:src="@drawable/ic_select_windows" /> + + <!-- Filtering affects only alpha instead of the visibility since visibility can be altered + separately through RecentsView#resetFromSplitSelectionState() --> + <ImageView + android:id="@+id/show_windows_right" + android:layout_height="@dimen/recents_filter_icon_size" + android:layout_width="@dimen/recents_filter_icon_size" + android:layout_gravity="end" + android:alpha="0" + android:tint="@color/recents_filter_icon" + android:contentDescription="@string/recents_filter_icon_desc" + android:importantForAccessibility="no" + android:src="@drawable/ic_select_windows" /> + <com.android.quickstep.views.IconView android:id="@+id/icon" android:layout_width="@dimen/task_thumbnail_icon_size" diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml index 34d4b231b1..976cd9e2a7 100644 --- a/quickstep/res/layout/taskbar_all_apps.xml +++ b/quickstep/res/layout/taskbar_all_apps.xml @@ -17,7 +17,8 @@ <com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:accessibilityPaneTitle="@string/all_apps_label"> <com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView android:id="@+id/apps_view" @@ -26,41 +27,5 @@ android:clipChildren="true" android:clipToPadding="false" android:focusable="false" - android:saveEnabled="false" - android:theme="?attr/allAppsTheme"> - - <include - layout="@layout/all_apps_bottom_sheet_background" - android:visibility="gone" /> - - <include - layout="@layout/search_results_rv_layout" - android:visibility="gone" /> - - <include - layout="@layout/all_apps_rv_layout" - android:visibility="gone" /> - - <com.android.launcher3.allapps.FloatingHeaderView - android:id="@+id/all_apps_header" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_below="@id/search_container_all_apps" - android:clipToPadding="false" - android:paddingTop="@dimen/all_apps_header_top_padding" - android:orientation="vertical"> - - <include layout="@layout/floating_header_content" /> - - <include layout="@layout/all_apps_personal_work_tabs" /> - </com.android.launcher3.allapps.FloatingHeaderView> - - <com.android.launcher3.taskbar.allapps.TaskbarAllAppsFallbackSearchContainer - android:id="@+id/search_container_all_apps" - android:layout_width="0dp" - android:layout_height="0dp" - android:visibility="gone" /> - - <include layout="@layout/all_apps_fast_scroller" /> - </com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView> + android:saveEnabled="false" /> </com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView> diff --git a/quickstep/res/layout/taskbar_all_apps_button.xml b/quickstep/res/layout/taskbar_all_apps_button.xml new file mode 100644 index 0000000000..6b665e5623 --- /dev/null +++ b/quickstep/res/layout/taskbar_all_apps_button.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> + +<!-- Note: The actual size will match the taskbar icon sizes in TaskbarView#onLayout(). --> +<com.android.launcher3.views.IconButtonView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="@dimen/taskbar_icon_min_touch_size" + android:layout_height="@dimen/taskbar_icon_min_touch_size" + android:contentDescription="@string/all_apps_button_label" + android:backgroundTint="@android:color/transparent" + android:icon="@drawable/ic_all_apps_button" + /> diff --git a/quickstep/res/layout/taskbar_edu.xml b/quickstep/res/layout/taskbar_edu.xml index 3796ff930e..d7daea31cd 100644 --- a/quickstep/res/layout/taskbar_edu.xml +++ b/quickstep/res/layout/taskbar_edu.xml @@ -40,74 +40,13 @@ android:layout_width="match_parent" android:layout_height="378dp" app:layout_constraintTop_toTopOf="parent" - launcher:pageIndicator="@+id/content_page_indicator"> - - <LinearLayout - android:id="@+id/page_switch_apps" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:gravity="center_horizontal"> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.TaskbarEdu.Title" - android:text="@string/taskbar_edu_switch_apps"/> - - <ImageView - android:layout_width="322dp" - android:layout_height="282dp" - android:layout_marginTop="16dp" - android:src="@drawable/taskbar_edu_switch_apps"/> - </LinearLayout> - - <LinearLayout - android:id="@+id/page_splitscreen" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:gravity="center_horizontal"> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.TaskbarEdu.Title" - android:text="@string/taskbar_edu_splitscreen"/> - - <ImageView - android:layout_width="322dp" - android:layout_height="282dp" - android:layout_marginTop="16dp" - android:src="@drawable/taskbar_edu_splitscreen"/> - </LinearLayout> - - <LinearLayout - android:id="@+id/page_stashing" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:gravity="center_horizontal"> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.TaskbarEdu.Title" - android:text="@string/taskbar_edu_stashing"/> - - <ImageView - android:layout_width="322dp" - android:layout_height="282dp" - android:layout_marginTop="16dp" - android:src="@drawable/taskbar_edu_stashing"/> - </LinearLayout> - </com.android.launcher3.taskbar.TaskbarEduPagedView> + launcher:pageIndicator="@+id/content_page_indicator" /> <Button android:id="@+id/edu_start_button" android:layout_width="wrap_content" android:layout_height="36dp" - android:layout_marginBottom="92dp" + android:layout_marginBottom="18dp" android:layout_marginTop="32dp" app:layout_constraintTop_toBottomOf="@id/content" app:layout_constraintBottom_toBottomOf="parent" diff --git a/quickstep/res/layout/taskbar_edu_pages_persistent.xml b/quickstep/res/layout/taskbar_edu_pages_persistent.xml new file mode 100644 index 0000000000..77ce31af95 --- /dev/null +++ b/quickstep/res/layout/taskbar_edu_pages_persistent.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 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. +--> + +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical"> + + <TextView + style="@style/TextAppearance.TaskbarEdu.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/taskbar_edu_splitscreen" /> + + <com.airbnb.lottie.LottieAnimationView + android:id="@+id/animation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + app:lottie_rawRes="@raw/taskbar_edu_splitscreen_persistent" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical"> + + <TextView + style="@style/TextAppearance.TaskbarEdu.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/taskbar_edu_suggestions" /> + + <com.airbnb.lottie.LottieAnimationView + android:id="@id/animation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + app:lottie_rawRes="@raw/taskbar_edu_suggestions_persistent" /> + </LinearLayout> +</merge> diff --git a/quickstep/res/layout/taskbar_edu_pages_transient.xml b/quickstep/res/layout/taskbar_edu_pages_transient.xml new file mode 100644 index 0000000000..b68e723280 --- /dev/null +++ b/quickstep/res/layout/taskbar_edu_pages_transient.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 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. +--> + +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical"> + + <TextView + style="@style/TextAppearance.TaskbarEdu.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/taskbar_edu_stashing" /> + + <com.airbnb.lottie.LottieAnimationView + android:id="@+id/animation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + app:lottie_rawRes="@raw/taskbar_edu_stashing_transient" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical"> + + <TextView + style="@style/TextAppearance.TaskbarEdu.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/taskbar_edu_splitscreen" /> + + <com.airbnb.lottie.LottieAnimationView + android:id="@id/animation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + app:lottie_rawRes="@raw/taskbar_edu_splitscreen_transient" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="vertical"> + + <TextView + style="@style/TextAppearance.TaskbarEdu.Title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/taskbar_edu_suggestions" /> + + <com.airbnb.lottie.LottieAnimationView + android:id="@id/animation" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + app:lottie_rawRes="@raw/taskbar_edu_suggestions_transient" /> + </LinearLayout> +</merge>
\ No newline at end of file diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml new file mode 100644 index 0000000000..f9ece84a4d --- /dev/null +++ b/quickstep/res/layout/transient_taskbar.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> +<com.android.launcher3.taskbar.TaskbarDragLayer + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/taskbar_container" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clipChildren="false"> + + <com.android.launcher3.taskbar.TaskbarView + android:id="@+id/taskbar_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center" + android:forceHasOverlappingRendering="false" + android:layout_gravity="bottom" + android:layout_marginBottom="@dimen/transient_taskbar_margin" + android:clipChildren="false" /> + + <com.android.launcher3.taskbar.TaskbarScrimView + android:id="@+id/taskbar_scrim" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + + <FrameLayout + android:id="@+id/navbuttons_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" > + + <FrameLayout + android:id="@+id/start_contextual_buttons" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:paddingStart="@dimen/taskbar_contextual_button_padding" + android:paddingEnd="@dimen/taskbar_contextual_button_padding" + android:paddingTop="@dimen/taskbar_contextual_padding_top" + android:gravity="center_vertical" + android:layout_gravity="start"/> + + <LinearLayout + android:id="@+id/end_nav_buttons" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="horizontal" + android:gravity="center_vertical" + android:layout_gravity="end"/> + + <FrameLayout + android:id="@+id/end_contextual_buttons" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:paddingTop="@dimen/taskbar_contextual_padding_top" + android:gravity="center_vertical" + android:layout_gravity="end"/> + </FrameLayout> + + <com.android.launcher3.taskbar.StashedHandleView + android:id="@+id/stashed_handle" + tools:comment1="The actual size and shape will be set as a ViewOutlineProvider at runtime" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/taskbar_stashed_handle_dark_color" + android:clipToOutline="true" + android:layout_gravity="bottom"/> + +</com.android.launcher3.taskbar.TaskbarDragLayer>
\ No newline at end of file diff --git a/quickstep/res/raw-night/taskbar_edu_splitscreen_persistent.json b/quickstep/res/raw-night/taskbar_edu_splitscreen_persistent.json new file mode 100644 index 0000000000..20280831c9 --- /dev/null +++ b/quickstep/res/raw-night/taskbar_edu_splitscreen_persistent.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":154,"w":412,"h":300,"nm":"Taskbar_Persistent_DT_Step_1","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp_Taskbar_Persistent_Layers","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 2","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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,"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"screen_matte","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Pre-comp_TaskBar_Persistent","parent":1,"tt":1,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1.5,87.892,0],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"screen 3","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":175,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":155,"s":[0]},{"t":175,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0.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":[320,174.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,-15.25],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":175,"op":11541,"st":141,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,59.005],[0.125,72.005],[-147,72.005],[-160,59.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,62.689],[-13,75.689],[-147,75.689],[-160,62.689],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,62.689],[-13,75.689],[-147,75.689],[-160,62.689],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,59.005],[0.125,72.005],[-147,72.005],[-160,59.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":43,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":93,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":155,"s":[0]},{"t":175,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".yellow100","cl":"yellow100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431373,0.937254901961,0.764705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_TaskBar_Persistent","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":362,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":392,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":365,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":395,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":386,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":359,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":389,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yelllow400","cl":"yelllow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294118,0.788235294118,0.203921568627,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"screen","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp_Taskbar_Persistent_Layers","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":205,"s":[206,150,0],"to":[-41.417,-45.917,0],"ti":[41.417,45.917,0]},{"t":285,"s":[-42.5,-125.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":205,"s":[100,100,100]},{"t":285,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0}],"markers":[{"tm":154,"cm":"","dr":0},{"tm":360,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw-night/taskbar_edu_splitscreen_transient.json b/quickstep/res/raw-night/taskbar_edu_splitscreen_transient.json new file mode 100644 index 0000000000..0c0e45f132 --- /dev/null +++ b/quickstep/res/raw-night/taskbar_edu_splitscreen_transient.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":94,"op":249,"w":412,"h":300,"nm":"Taskbar_Transient_Step_2","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp_TaskBar_Transient","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":550,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":580,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":553,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":583,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":544,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":574,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":547,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":577,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_Toggle","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":336,"s":[-12.5,0,0],"to":[3.75,0,0],"ti":[-3.75,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":356,"s":[10,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":416,"s":[10,0,0],"to":[-3.75,0,0],"ti":[3.75,0,0]},{"t":436,"s":[-12.5,0,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":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":336,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":416,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"t":436,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.5,133.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.837,0],[0,0],[0,-8.837],[0,0],[8.837,0],[0,0],[0,8.837],[0,0]],"o":[[0,0],[8.837,0],[0,0],[0,8.837],[0,0],[-8.837,0],[0,0],[0,-8.837]],"v":[[-10,-16],[10,-16],[26,0],[26,0],[10,16],[-10,16],[-26,0],[-26,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682352941176,0.796078431373,0.980392156863,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.784,0],[0,1.783],[1.783,0],[0,-1.783]],"o":[[1.783,0],[0,-1.783],[-1.784,0],[0,1.783]],"v":[[-43.755,-12.577],[-40.526,-15.806],[-43.755,-19.035],[-46.984,-15.806]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0.053]],"o":[[0,0.053],[0,0]],"v":[[-44.937,-23.822],[-44.937,-23.822]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.054]],"o":[[0,0.054],[0,0]],"v":[[-49.458,-21.078],[-49.458,-21.078]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.431,0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.216],[-0.054,-0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,-0.162],[0,0]],"o":[[0,0],[0,0],[0,0],[0.431,-0.162],[0,0],[0,0],[0,0],[0,0],[0,0],[0.054,-0.215],[0,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.377,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.377,0.323],[0,0],[0,0]],"v":[[-45.045,-8.215],[-42.515,-8.215],[-42.138,-10.529],[-41.654,-10.744],[-40.416,-11.444],[-39.986,-11.767],[-37.779,-10.906],[-36.487,-13.112],[-38.371,-14.565],[-38.317,-15.104],[-38.263,-15.803],[-38.317,-16.503],[-38.371,-17.041],[-36.487,-18.494],[-37.779,-20.701],[-39.986,-19.84],[-40.416,-20.163],[-41.654,-20.862],[-42.138,-21.078],[-42.461,-23.392],[-44.991,-23.392],[-45.314,-21.078],[-45.798,-20.862],[-47.036,-20.163],[-47.467,-19.84],[-49.673,-20.701],[-50.965,-18.494],[-49.081,-17.041],[-49.135,-16.503],[-49.189,-15.803],[-49.135,-15.104],[-49.081,-14.565],[-50.965,-13.112],[-49.673,-10.906],[-47.467,-11.767],[-47.036,-11.444],[-45.798,-10.744],[-45.368,-10.529]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.054,0]],"o":[[0.054,0],[0,0]],"v":[[-44.991,-7.784],[-44.991,-7.784]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.7,0],[0,0],[0.108,0.7],[0,0],[0.215,0.162],[0,0],[0.323,0.592],[0,0],[-0.484,0.376],[0,0],[0,0.161],[0,0.162],[0,0],[-0.376,0.593],[0,0],[-0.592,-0.215],[0,0],[-0.215,0.162],[0,0],[-0.7,0],[0,0],[-0.107,-0.7],[0,0],[-0.269,-0.162],[0,0],[-0.323,-0.592],[0,0],[0.484,-0.377],[0,0],[0,-0.162],[0,-0.161],[0,0],[0.323,-0.592],[0,0],[0.646,0.215],[0,0],[0.216,-0.162],[0,0]],"o":[[0,0],[-0.7,0],[0,0],[-0.269,-0.108],[0,0],[-0.646,0.215],[0,0],[-0.323,-0.592],[0,0],[0,-0.161],[0,-0.162],[0,0],[-0.538,-0.431],[0,0],[0.323,-0.592],[0,0],[0.215,-0.162],[0,0],[0.053,-0.646],[0,0],[0.699,0],[0,0],[0.269,0.108],[0,0],[0.646,-0.215],[0,0],[0.323,0.592],[0,0],[0,0.161],[0,0.161],[0,0],[0.538,0.431],[0,0],[-0.323,0.592],[0,0],[-0.215,0.161],[0,0],[0,0.538]],"v":[[-42.085,-6.385],[-45.475,-6.385],[-46.821,-7.569],[-47.09,-9.291],[-47.789,-9.722],[-49.458,-9.076],[-51.126,-9.668],[-52.795,-12.574],[-52.472,-14.296],[-51.072,-15.373],[-51.072,-15.803],[-51.072,-16.234],[-52.472,-17.31],[-52.795,-19.033],[-51.126,-21.939],[-49.512,-22.531],[-47.843,-21.831],[-47.144,-22.262],[-46.874,-24.038],[-45.529,-25.168],[-42.138,-25.168],[-40.793,-23.984],[-40.524,-22.262],[-39.77,-21.831],[-38.102,-22.477],[-36.433,-21.885],[-34.765,-18.979],[-35.088,-17.256],[-36.487,-16.18],[-36.487,-15.749],[-36.487,-15.319],[-35.088,-14.243],[-34.765,-12.52],[-36.487,-9.56],[-38.156,-8.968],[-39.824,-9.614],[-40.524,-9.183],[-40.793,-7.407]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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 2","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-43.792,-15.776],"ix":2},"a":{"a":0,"k":[-43.792,-15.776],"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 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-54,-33],[60,-33],[75,-18],[75,-13],[60,2],[-54,2],[-69,-13],[-69,-18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"press 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":381,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":391,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":416,"s":[100]},{"t":426,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[259.25,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":406,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":416,"s":[40,40,100]},{"t":426,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":381,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":406,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":381,"op":437,"st":176,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"press","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":301,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":336,"s":[100]},{"t":346,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":326,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":336,"s":[40,40,100]},{"t":346,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":301,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":326,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":301,"op":357,"st":96,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,194,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":15,"op":73,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"swipe up","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":15,"s":[-48.3,37.417,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":40,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.45,"y":0},"t":50,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"t":70,"s":[-15.3,-62.583,0],"h":1}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[80,80,100]},{"t":70,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":52,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":62,"s":[56,98]},{"t":72,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":52,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":62,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":72,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":15,"op":73,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"screen_matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Pre-comp_TaskBar_Transient","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.7,"y":0},"t":50,"s":[204.5,244.501,0],"to":[0,-2.5,0],"ti":[0,2.5,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":94,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[204.5,229.501,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[204.5,237.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[204.5,237.501,0],"to":[0,-1.333,0],"ti":[0,1.333,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.3,"y":0.3},"t":466,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":474,"s":[204.5,229.501,0],"to":[-42.083,-12.917,0],"ti":[42.083,12.917,0]},{"t":554,"s":[-48,152.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":50,"s":[70,70,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":94,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":474,"s":[100,100,100]},{"t":554,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.9,"y":0},"t":46,"s":[205.5,241.5,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"t":76,"s":[205.5,231.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":[[-1.381,0],[0,0],[0,-1.381],[0,0],[1.381,0],[0,0],[0,1.381],[0,0]],"o":[[0,0],[1.381,0],[0,0],[0,1.381],[0,0],[-1.381,0],[0,0],[0,-1.381]],"v":[[-42,-2.5],[42,-2.5],[44.5,0],[44.5,0],[42,2.5],[-42,2.5],[-44.5,0],[-44.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":65,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Pre-comp_Toggle","refId":"comp_1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":256,"s":[0]},{"i":{"x":[0.316],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":286,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":474,"s":[100]},{"t":554,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":235,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":249,"s":[0]},{"t":269,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":356,"s":[320,204.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":386,"s":[320,173.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":436,"s":[320,173.01]},{"t":466,"s":[320,204.01]}],"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.823529411765,0.890196078431,0.988235294118,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.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[-81,0],"to":[0,-2.542],"ti":[0,2.542]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[-81,-15.25],"to":[0,0],"ti":[0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[-81,-15.25],"to":[0,2.542],"ti":[0,-2.542]},{"t":466,"s":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":286,"op":11635,"st":235,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[132.562,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":137,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":187,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":249,"s":[0]},{"t":259,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431373,0.937254901961,0.764705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":100,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}],"markers":[{"tm":94,"cm":"","dr":0},{"tm":249,"cm":"","dr":0},{"tm":474,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw-night/taskbar_edu_stashing_transient.json b/quickstep/res/raw-night/taskbar_edu_stashing_transient.json new file mode 100644 index 0000000000..7714b41a66 --- /dev/null +++ b/quickstep/res/raw-night/taskbar_edu_stashing_transient.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":94,"w":412,"h":300,"nm":"Taskbar_Transient_Step_1","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp_TaskBar_Transient","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":550,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":580,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":553,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":583,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":544,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":574,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":547,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":577,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_Toggle","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":336,"s":[-12.5,0,0],"to":[3.75,0,0],"ti":[-3.75,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":356,"s":[10,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":416,"s":[10,0,0],"to":[-3.75,0,0],"ti":[3.75,0,0]},{"t":436,"s":[-12.5,0,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":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":336,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":416,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"t":436,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.5,133.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.837,0],[0,0],[0,-8.837],[0,0],[8.837,0],[0,0],[0,8.837],[0,0]],"o":[[0,0],[8.837,0],[0,0],[0,8.837],[0,0],[-8.837,0],[0,0],[0,-8.837]],"v":[[-10,-16],[10,-16],[26,0],[26,0],[10,16],[-10,16],[-26,0],[-26,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682352941176,0.796078431373,0.980392156863,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.784,0],[0,1.783],[1.783,0],[0,-1.783]],"o":[[1.783,0],[0,-1.783],[-1.784,0],[0,1.783]],"v":[[-43.755,-12.577],[-40.526,-15.806],[-43.755,-19.035],[-46.984,-15.806]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0.053]],"o":[[0,0.053],[0,0]],"v":[[-44.937,-23.822],[-44.937,-23.822]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.054]],"o":[[0,0.054],[0,0]],"v":[[-49.458,-21.078],[-49.458,-21.078]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.431,0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.216],[-0.054,-0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,-0.162],[0,0]],"o":[[0,0],[0,0],[0,0],[0.431,-0.162],[0,0],[0,0],[0,0],[0,0],[0,0],[0.054,-0.215],[0,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.377,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.377,0.323],[0,0],[0,0]],"v":[[-45.045,-8.215],[-42.515,-8.215],[-42.138,-10.529],[-41.654,-10.744],[-40.416,-11.444],[-39.986,-11.767],[-37.779,-10.906],[-36.487,-13.112],[-38.371,-14.565],[-38.317,-15.104],[-38.263,-15.803],[-38.317,-16.503],[-38.371,-17.041],[-36.487,-18.494],[-37.779,-20.701],[-39.986,-19.84],[-40.416,-20.163],[-41.654,-20.862],[-42.138,-21.078],[-42.461,-23.392],[-44.991,-23.392],[-45.314,-21.078],[-45.798,-20.862],[-47.036,-20.163],[-47.467,-19.84],[-49.673,-20.701],[-50.965,-18.494],[-49.081,-17.041],[-49.135,-16.503],[-49.189,-15.803],[-49.135,-15.104],[-49.081,-14.565],[-50.965,-13.112],[-49.673,-10.906],[-47.467,-11.767],[-47.036,-11.444],[-45.798,-10.744],[-45.368,-10.529]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.054,0]],"o":[[0.054,0],[0,0]],"v":[[-44.991,-7.784],[-44.991,-7.784]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.7,0],[0,0],[0.108,0.7],[0,0],[0.215,0.162],[0,0],[0.323,0.592],[0,0],[-0.484,0.376],[0,0],[0,0.161],[0,0.162],[0,0],[-0.376,0.593],[0,0],[-0.592,-0.215],[0,0],[-0.215,0.162],[0,0],[-0.7,0],[0,0],[-0.107,-0.7],[0,0],[-0.269,-0.162],[0,0],[-0.323,-0.592],[0,0],[0.484,-0.377],[0,0],[0,-0.162],[0,-0.161],[0,0],[0.323,-0.592],[0,0],[0.646,0.215],[0,0],[0.216,-0.162],[0,0]],"o":[[0,0],[-0.7,0],[0,0],[-0.269,-0.108],[0,0],[-0.646,0.215],[0,0],[-0.323,-0.592],[0,0],[0,-0.161],[0,-0.162],[0,0],[-0.538,-0.431],[0,0],[0.323,-0.592],[0,0],[0.215,-0.162],[0,0],[0.053,-0.646],[0,0],[0.699,0],[0,0],[0.269,0.108],[0,0],[0.646,-0.215],[0,0],[0.323,0.592],[0,0],[0,0.161],[0,0.161],[0,0],[0.538,0.431],[0,0],[-0.323,0.592],[0,0],[-0.215,0.161],[0,0],[0,0.538]],"v":[[-42.085,-6.385],[-45.475,-6.385],[-46.821,-7.569],[-47.09,-9.291],[-47.789,-9.722],[-49.458,-9.076],[-51.126,-9.668],[-52.795,-12.574],[-52.472,-14.296],[-51.072,-15.373],[-51.072,-15.803],[-51.072,-16.234],[-52.472,-17.31],[-52.795,-19.033],[-51.126,-21.939],[-49.512,-22.531],[-47.843,-21.831],[-47.144,-22.262],[-46.874,-24.038],[-45.529,-25.168],[-42.138,-25.168],[-40.793,-23.984],[-40.524,-22.262],[-39.77,-21.831],[-38.102,-22.477],[-36.433,-21.885],[-34.765,-18.979],[-35.088,-17.256],[-36.487,-16.18],[-36.487,-15.749],[-36.487,-15.319],[-35.088,-14.243],[-34.765,-12.52],[-36.487,-9.56],[-38.156,-8.968],[-39.824,-9.614],[-40.524,-9.183],[-40.793,-7.407]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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 2","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-43.792,-15.776],"ix":2},"a":{"a":0,"k":[-43.792,-15.776],"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 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-54,-33],[60,-33],[75,-18],[75,-13],[60,2],[-54,2],[-69,-13],[-69,-18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"press 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":381,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":391,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":416,"s":[100]},{"t":426,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[259.25,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":406,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":416,"s":[40,40,100]},{"t":426,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":381,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":406,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":381,"op":437,"st":176,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"press","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":301,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":336,"s":[100]},{"t":346,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":326,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":336,"s":[40,40,100]},{"t":346,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":301,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":326,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":301,"op":357,"st":96,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,194,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":15,"op":73,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"swipe up","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":15,"s":[-48.3,37.417,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":40,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.45,"y":0},"t":50,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"t":70,"s":[-15.3,-62.583,0],"h":1}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[80,80,100]},{"t":70,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":52,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":62,"s":[56,98]},{"t":72,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":52,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":62,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":72,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":15,"op":73,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"screen_matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Pre-comp_TaskBar_Transient","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.7,"y":0},"t":50,"s":[204.5,244.501,0],"to":[0,-2.5,0],"ti":[0,2.5,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":94,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[204.5,229.501,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[204.5,237.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[204.5,237.501,0],"to":[0,-1.333,0],"ti":[0,1.333,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.3,"y":0.3},"t":466,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":474,"s":[204.5,229.501,0],"to":[-42.083,-12.917,0],"ti":[42.083,12.917,0]},{"t":554,"s":[-48,152.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":50,"s":[70,70,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":94,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":474,"s":[100,100,100]},{"t":554,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.9,"y":0},"t":46,"s":[205.5,241.5,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"t":76,"s":[205.5,231.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":[[-1.381,0],[0,0],[0,-1.381],[0,0],[1.381,0],[0,0],[0,1.381],[0,0]],"o":[[0,0],[1.381,0],[0,0],[0,1.381],[0,0],[-1.381,0],[0,0],[0,-1.381]],"v":[[-42,-2.5],[42,-2.5],[44.5,0],[44.5,0],[42,2.5],[-42,2.5],[-44.5,0],[-44.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":65,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Pre-comp_Toggle","refId":"comp_1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":256,"s":[0]},{"i":{"x":[0.316],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":286,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":474,"s":[100]},{"t":554,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":235,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":249,"s":[0]},{"t":269,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":356,"s":[320,204.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":386,"s":[320,173.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":436,"s":[320,173.01]},{"t":466,"s":[320,204.01]}],"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.823529411765,0.890196078431,0.988235294118,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.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[-81,0],"to":[0,-2.542],"ti":[0,2.542]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[-81,-15.25],"to":[0,0],"ti":[0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[-81,-15.25],"to":[0,2.542],"ti":[0,-2.542]},{"t":466,"s":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":286,"op":11635,"st":235,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[132.562,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":137,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":187,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":249,"s":[0]},{"t":259,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431373,0.937254901961,0.764705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":100,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}],"markers":[{"tm":94,"cm":"","dr":0},{"tm":249,"cm":"","dr":0},{"tm":474,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw-night/taskbar_edu_suggestions_persistent.json b/quickstep/res/raw-night/taskbar_edu_suggestions_persistent.json new file mode 100644 index 0000000000..eec2c243f3 --- /dev/null +++ b/quickstep/res/raw-night/taskbar_edu_suggestions_persistent.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":186,"op":360,"w":412,"h":300,"nm":"Taskbar_Persistent_DT_Step_2","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp_Taskbar_Persistent_Layers","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 2","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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,"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"screen_matte","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Pre-comp_TaskBar_Persistent","parent":1,"tt":1,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1.5,87.892,0],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"screen 3","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":175,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":155,"s":[0]},{"t":175,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0.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":[320,174.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,-15.25],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":175,"op":11541,"st":141,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,59.005],[0.125,72.005],[-147,72.005],[-160,59.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,62.689],[-13,75.689],[-147,75.689],[-160,62.689],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,62.689],[-13,75.689],[-147,75.689],[-160,62.689],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,59.005],[0.125,72.005],[-147,72.005],[-160,59.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":43,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":93,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":155,"s":[0]},{"t":175,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".yellow100","cl":"yellow100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431373,0.937254901961,0.764705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_TaskBar_Persistent","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":362,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":392,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":365,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":395,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":386,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":359,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":389,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yelllow400","cl":"yelllow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294118,0.788235294118,0.203921568627,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"screen","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp_Taskbar_Persistent_Layers","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":205,"s":[206,150,0],"to":[-41.417,-45.917,0],"ti":[41.417,45.917,0]},{"t":285,"s":[-42.5,-125.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":205,"s":[100,100,100]},{"t":285,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0}],"markers":[{"tm":154,"cm":"","dr":0},{"tm":360,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw-night/taskbar_edu_suggestions_transient.json b/quickstep/res/raw-night/taskbar_edu_suggestions_transient.json new file mode 100644 index 0000000000..e7a4cacf70 --- /dev/null +++ b/quickstep/res/raw-night/taskbar_edu_suggestions_transient.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":548,"op":628,"w":412,"h":300,"nm":"Taskbar_Transient_Step_4","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp_TaskBar_Transient","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":550,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":580,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":553,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":583,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":544,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":574,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":547,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":577,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_Toggle","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":336,"s":[-12.5,0,0],"to":[3.75,0,0],"ti":[-3.75,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":356,"s":[10,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":416,"s":[10,0,0],"to":[-3.75,0,0],"ti":[3.75,0,0]},{"t":436,"s":[-12.5,0,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":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":336,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":416,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"t":436,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.5,133.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.837,0],[0,0],[0,-8.837],[0,0],[8.837,0],[0,0],[0,8.837],[0,0]],"o":[[0,0],[8.837,0],[0,0],[0,8.837],[0,0],[-8.837,0],[0,0],[0,-8.837]],"v":[[-10,-16],[10,-16],[26,0],[26,0],[10,16],[-10,16],[-26,0],[-26,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682352941176,0.796078431373,0.980392156863,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.784,0],[0,1.783],[1.783,0],[0,-1.783]],"o":[[1.783,0],[0,-1.783],[-1.784,0],[0,1.783]],"v":[[-43.755,-12.577],[-40.526,-15.806],[-43.755,-19.035],[-46.984,-15.806]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0.053]],"o":[[0,0.053],[0,0]],"v":[[-44.937,-23.822],[-44.937,-23.822]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.054]],"o":[[0,0.054],[0,0]],"v":[[-49.458,-21.078],[-49.458,-21.078]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.431,0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.216],[-0.054,-0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,-0.162],[0,0]],"o":[[0,0],[0,0],[0,0],[0.431,-0.162],[0,0],[0,0],[0,0],[0,0],[0,0],[0.054,-0.215],[0,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.377,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.377,0.323],[0,0],[0,0]],"v":[[-45.045,-8.215],[-42.515,-8.215],[-42.138,-10.529],[-41.654,-10.744],[-40.416,-11.444],[-39.986,-11.767],[-37.779,-10.906],[-36.487,-13.112],[-38.371,-14.565],[-38.317,-15.104],[-38.263,-15.803],[-38.317,-16.503],[-38.371,-17.041],[-36.487,-18.494],[-37.779,-20.701],[-39.986,-19.84],[-40.416,-20.163],[-41.654,-20.862],[-42.138,-21.078],[-42.461,-23.392],[-44.991,-23.392],[-45.314,-21.078],[-45.798,-20.862],[-47.036,-20.163],[-47.467,-19.84],[-49.673,-20.701],[-50.965,-18.494],[-49.081,-17.041],[-49.135,-16.503],[-49.189,-15.803],[-49.135,-15.104],[-49.081,-14.565],[-50.965,-13.112],[-49.673,-10.906],[-47.467,-11.767],[-47.036,-11.444],[-45.798,-10.744],[-45.368,-10.529]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.054,0]],"o":[[0.054,0],[0,0]],"v":[[-44.991,-7.784],[-44.991,-7.784]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.7,0],[0,0],[0.108,0.7],[0,0],[0.215,0.162],[0,0],[0.323,0.592],[0,0],[-0.484,0.376],[0,0],[0,0.161],[0,0.162],[0,0],[-0.376,0.593],[0,0],[-0.592,-0.215],[0,0],[-0.215,0.162],[0,0],[-0.7,0],[0,0],[-0.107,-0.7],[0,0],[-0.269,-0.162],[0,0],[-0.323,-0.592],[0,0],[0.484,-0.377],[0,0],[0,-0.162],[0,-0.161],[0,0],[0.323,-0.592],[0,0],[0.646,0.215],[0,0],[0.216,-0.162],[0,0]],"o":[[0,0],[-0.7,0],[0,0],[-0.269,-0.108],[0,0],[-0.646,0.215],[0,0],[-0.323,-0.592],[0,0],[0,-0.161],[0,-0.162],[0,0],[-0.538,-0.431],[0,0],[0.323,-0.592],[0,0],[0.215,-0.162],[0,0],[0.053,-0.646],[0,0],[0.699,0],[0,0],[0.269,0.108],[0,0],[0.646,-0.215],[0,0],[0.323,0.592],[0,0],[0,0.161],[0,0.161],[0,0],[0.538,0.431],[0,0],[-0.323,0.592],[0,0],[-0.215,0.161],[0,0],[0,0.538]],"v":[[-42.085,-6.385],[-45.475,-6.385],[-46.821,-7.569],[-47.09,-9.291],[-47.789,-9.722],[-49.458,-9.076],[-51.126,-9.668],[-52.795,-12.574],[-52.472,-14.296],[-51.072,-15.373],[-51.072,-15.803],[-51.072,-16.234],[-52.472,-17.31],[-52.795,-19.033],[-51.126,-21.939],[-49.512,-22.531],[-47.843,-21.831],[-47.144,-22.262],[-46.874,-24.038],[-45.529,-25.168],[-42.138,-25.168],[-40.793,-23.984],[-40.524,-22.262],[-39.77,-21.831],[-38.102,-22.477],[-36.433,-21.885],[-34.765,-18.979],[-35.088,-17.256],[-36.487,-16.18],[-36.487,-15.749],[-36.487,-15.319],[-35.088,-14.243],[-34.765,-12.52],[-36.487,-9.56],[-38.156,-8.968],[-39.824,-9.614],[-40.524,-9.183],[-40.793,-7.407]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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 2","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-43.792,-15.776],"ix":2},"a":{"a":0,"k":[-43.792,-15.776],"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 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-54,-33],[60,-33],[75,-18],[75,-13],[60,2],[-54,2],[-69,-13],[-69,-18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"press 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":381,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":391,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":416,"s":[100]},{"t":426,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[259.25,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":406,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":416,"s":[40,40,100]},{"t":426,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":381,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":406,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":381,"op":437,"st":176,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"press","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":301,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":336,"s":[100]},{"t":346,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":326,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":336,"s":[40,40,100]},{"t":346,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":301,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":326,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":301,"op":357,"st":96,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,194,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":15,"op":73,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"swipe up","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":15,"s":[-48.3,37.417,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":40,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.45,"y":0},"t":50,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"t":70,"s":[-15.3,-62.583,0],"h":1}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[80,80,100]},{"t":70,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":52,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":62,"s":[56,98]},{"t":72,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":52,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":62,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":72,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":15,"op":73,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"screen_matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Pre-comp_TaskBar_Transient","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.7,"y":0},"t":50,"s":[204.5,244.501,0],"to":[0,-2.5,0],"ti":[0,2.5,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":94,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[204.5,229.501,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[204.5,237.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[204.5,237.501,0],"to":[0,-1.333,0],"ti":[0,1.333,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.3,"y":0.3},"t":466,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":474,"s":[204.5,229.501,0],"to":[-42.083,-12.917,0],"ti":[42.083,12.917,0]},{"t":554,"s":[-48,152.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":50,"s":[70,70,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":94,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":474,"s":[100,100,100]},{"t":554,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.9,"y":0},"t":46,"s":[205.5,241.5,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"t":76,"s":[205.5,231.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":[[-1.381,0],[0,0],[0,-1.381],[0,0],[1.381,0],[0,0],[0,1.381],[0,0]],"o":[[0,0],[1.381,0],[0,0],[0,1.381],[0,0],[-1.381,0],[0,0],[0,-1.381]],"v":[[-42,-2.5],[42,-2.5],[44.5,0],[44.5,0],[42,2.5],[-42,2.5],[-44.5,0],[-44.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":65,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Pre-comp_Toggle","refId":"comp_1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":256,"s":[0]},{"i":{"x":[0.316],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":286,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":474,"s":[100]},{"t":554,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":235,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":249,"s":[0]},{"t":269,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":356,"s":[320,204.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":386,"s":[320,173.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":436,"s":[320,173.01]},{"t":466,"s":[320,204.01]}],"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.823529411765,0.890196078431,0.988235294118,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.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[-81,0],"to":[0,-2.542],"ti":[0,2.542]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[-81,-15.25],"to":[0,0],"ti":[0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[-81,-15.25],"to":[0,2.542],"ti":[0,-2.542]},{"t":466,"s":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":286,"op":11635,"st":235,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[132.562,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":137,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":187,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":249,"s":[0]},{"t":259,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431373,0.937254901961,0.764705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":100,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}],"markers":[{"tm":94,"cm":"","dr":0},{"tm":249,"cm":"","dr":0},{"tm":474,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw-sw600dp-land/all_set_page_bg.json b/quickstep/res/raw-sw600dp-land/all_set_page_bg.json new file mode 100644 index 0000000000..0863c31f61 --- /dev/null +++ b/quickstep/res/raw-sw600dp-land/all_set_page_bg.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":180,"w":1280,"h":800,"nm":"3Second_MainWelcomeScreen_Tablet_Landscape_V02","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[288,540,0],"ix":2,"l":2},"a":{"a":0,"k":[50,50,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"colorAccentPrimaryVariant","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[231.832,-1174.545,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":95,"s":[231.832,-1979,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[231.832,-1174.545,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[110,110,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"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":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"colorAccentPrimary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":95,"s":[-38]},{"t":180,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[138]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":95,"s":[-38]},{"t":180,"s":[138]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1535]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":95,"s":[1338]},{"t":180,"s":[1535]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file diff --git a/quickstep/res/raw-sw600dp/all_set_page_bg.json b/quickstep/res/raw-sw600dp/all_set_page_bg.json new file mode 100644 index 0000000000..14e8933da8 --- /dev/null +++ b/quickstep/res/raw-sw600dp/all_set_page_bg.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":180,"w":800,"h":1280,"nm":"3Second_MainWelcomeScreen_Tablet_Portrait_V02","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":1,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[288,528,0],"ix":2,"l":2},"a":{"a":0,"k":[50,50,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"sw":100,"sh":100,"sc":"#ffffff","ip":600,"op":600,"st":0,"bm":0,"hidden":0},{"ddd":0,"ind":2,"ty":4,"nm":".colorAccentPrimaryVariant","cl":"colorAccentPrimaryVariant","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[375.832,-1366.545,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":95,"s":[375.832,-2171,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[375.832,-1366.545,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[135,135,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"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":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":95,"s":[-38]},{"t":180,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[138]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":95,"s":[-38]},{"t":180,"s":[138]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1535]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":95,"s":[1338]},{"t":180,"s":[1535]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file diff --git a/res/raw/all_set_page_bg.json b/quickstep/res/raw/all_set_page_bg.json index 9705837912..859d3567a2 100644 --- a/res/raw/all_set_page_bg.json +++ b/quickstep/res/raw/all_set_page_bg.json @@ -1 +1 @@ -{"v":"5.7.8","fr":24,"ip":0,"op":72,"w":2472,"h":5352,"nm":"3Second_MAIN_Welcome","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 60","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1508,1364,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,"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"PinkFlower","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":72,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[1505.832,1379.455,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":38,"s":[1505.832,575,0],"to":[0,0,0],"ti":[0,0,0]},{"t":72,"s":[1505.832,1379.455,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,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":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.839215746113,0.439215716194,0.388235324037,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"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":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":288,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Ellipse_Bottom","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":38,"s":[-38]},{"t":72,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1720]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":38,"s":[1544]},{"t":72,"s":[1720]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[4069]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":38,"s":[3872]},{"t":72,"s":[4069]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.882353001015,0.894118006089,0.886274988511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0}],"markers":[]} +{"v":"5.7.8","fr":24,"ip":0,"op":72,"w":2472,"h":5352,"nm":"3Second_MAIN_Welcome","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 60","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1508,1364,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,"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"PinkFlower","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":72,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[1505.832,1379.455,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":38,"s":[1505.832,575,0],"to":[0,0,0],"ti":[0,0,0]},{"t":72,"s":[1505.832,1379.455,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,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":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.839215746113,0.439215716194,0.388235324037,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"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":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":288,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Ellipse_Bottom","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":38,"s":[-38]},{"t":72,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1720]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":38,"s":[1544]},{"t":72,"s":[1720]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[4069]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":38,"s":[3872]},{"t":72,"s":[4069]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.882353001015,0.894118006089,0.886274988511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"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":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file diff --git a/quickstep/res/raw/taskbar_edu_splitscreen_persistent.json b/quickstep/res/raw/taskbar_edu_splitscreen_persistent.json new file mode 100644 index 0000000000..1399828446 --- /dev/null +++ b/quickstep/res/raw/taskbar_edu_splitscreen_persistent.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":154,"w":412,"h":300,"nm":"Taskbar_Persistent_LT_Step_1","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp_Taskbar_Persistent_Layers_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 2","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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,"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"screen_matte","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Pre-comp_TaskBar_Persistent_LT","parent":1,"tt":1,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1.5,87.892,0],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"screen 3","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":175,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":155,"s":[0]},{"t":175,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0.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":[320,174.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,-15.25],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":175,"op":11541,"st":141,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,59.005],[0.125,72.005],[-147,72.005],[-160,59.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,62.689],[-13,75.689],[-147,75.689],[-160,62.689],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,62.689],[-13,75.689],[-147,75.689],[-160,62.689],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,59.005],[0.125,72.005],[-147,72.005],[-160,59.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":43,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":93,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":155,"s":[0]},{"t":175,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".yellow100","cl":"yellow100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.98431372549,0.78431372549,0.274509803922,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_TaskBar_Persistent_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":362,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":392,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":365,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":395,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":386,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":359,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":389,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yelllow400","cl":"yelllow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"screen","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp_Taskbar_Persistent_Layers_LT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":205,"s":[206,150,0],"to":[-41.417,-45.917,0],"ti":[41.417,45.917,0]},{"t":285,"s":[-42.5,-125.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":205,"s":[100,100,100]},{"t":285,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".white","cl":"white","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0}],"markers":[{"tm":154,"cm":"","dr":0},{"tm":360,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw/taskbar_edu_splitscreen_transient.json b/quickstep/res/raw/taskbar_edu_splitscreen_transient.json new file mode 100644 index 0000000000..0c65a0633b --- /dev/null +++ b/quickstep/res/raw/taskbar_edu_splitscreen_transient.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":94,"op":249,"w":412,"h":300,"nm":"Taskbar_Transient_Step_2_LT","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_Transient_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"press 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":381,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":391,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":416,"s":[100]},{"t":426,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[259.25,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":406,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":416,"s":[40,40,100]},{"t":426,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":381,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":406,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":381,"op":437,"st":176,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"press","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":301,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":336,"s":[100]},{"t":346,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":326,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":336,"s":[40,40,100]},{"t":346,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":301,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":326,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":301,"op":357,"st":96,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,194,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":15,"op":73,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"swipe up","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":15,"s":[-48.3,37.417,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":40,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.45,"y":0},"t":50,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"t":70,"s":[-15.3,-62.583,0],"h":1}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[80,80,100]},{"t":70,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":52,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":62,"s":[56,98]},{"t":72,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":52,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":62,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":72,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":15,"op":73,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"screen_matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Pre-comp_TaskBar_Transient_LT","tt":1,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.7,"y":0},"t":50,"s":[204.5,244.501,0],"to":[0,-2.5,0],"ti":[0,2.5,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":94,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[204.5,229.501,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[204.5,237.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[204.5,237.501,0],"to":[0,-1.333,0],"ti":[0,1.333,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.3,"y":0.3},"t":466,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":474,"s":[204.5,229.501,0],"to":[-42.083,-12.917,0],"ti":[42.083,12.917,0]},{"t":554,"s":[-48,152.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":50,"s":[70,70,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":94,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":474,"s":[100,100,100]},{"t":554,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.9,"y":0},"t":46,"s":[205.5,241.5,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"t":76,"s":[205.5,231.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":[[-1.381,0],[0,0],[0,-1.381],[0,0],[1.381,0],[0,0],[0,1.381],[0,0]],"o":[[0,0],[1.381,0],[0,0],[0,1.381],[0,0],[-1.381,0],[0,0],[0,-1.381]],"v":[[-42,-2.5],[42,-2.5],[44.5,0],[44.5,0],[42,2.5],[-42,2.5],[-44.5,0],[-44.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":65,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Pre-comp_Toggle_LT","refId":"comp_2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":256,"s":[0]},{"i":{"x":[0.316],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":286,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":474,"s":[100]},{"t":554,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":235,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":249,"s":[0]},{"t":269,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":356,"s":[320,204.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":386,"s":[320,173.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":436,"s":[320,173.01]},{"t":466,"s":[320,204.01]}],"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.549019607843,0.713725490196,0.964705882353,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.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[-81,0],"to":[0,-2.542],"ti":[0,2.542]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[-81,-15.25],"to":[0,0],"ti":[0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[-81,-15.25],"to":[0,2.542],"ti":[0,-2.542]},{"t":466,"s":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":286,"op":11635,"st":235,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[132.562,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":137,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":187,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":249,"s":[0]},{"t":259,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.98431372549,0.78431372549,0.274509803922,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":100,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_TaskBar_Transient_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":550,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":580,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":553,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":583,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":544,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":574,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":547,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":577,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]},{"id":"comp_2","nm":"Pre-comp_Toggle_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":336,"s":[-12.5,0,0],"to":[3.75,0,0],"ti":[-3.75,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":356,"s":[10,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":416,"s":[10,0,0],"to":[-3.75,0,0],"ti":[3.75,0,0]},{"t":436,"s":[-12.5,0,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":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":336,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":416,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"t":436,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.5,133.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.837,0],[0,0],[0,-8.837],[0,0],[8.837,0],[0,0],[0,8.837],[0,0]],"o":[[0,0],[8.837,0],[0,0],[0,8.837],[0,0],[-8.837,0],[0,0],[0,-8.837]],"v":[[-10,-16],[10,-16],[26,0],[26,0],[10,16],[-10,16],[-26,0],[-26,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682352941176,0.796078431373,0.980392156863,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100_T","cl":"blue100_T","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.784,0],[0,1.783],[1.783,0],[0,-1.783]],"o":[[1.783,0],[0,-1.783],[-1.784,0],[0,1.783]],"v":[[-43.755,-12.577],[-40.526,-15.806],[-43.755,-19.035],[-46.984,-15.806]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0.053]],"o":[[0,0.053],[0,0]],"v":[[-44.937,-23.822],[-44.937,-23.822]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.054]],"o":[[0,0.054],[0,0]],"v":[[-49.458,-21.078],[-49.458,-21.078]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.431,0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.216],[-0.054,-0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,-0.162],[0,0]],"o":[[0,0],[0,0],[0,0],[0.431,-0.162],[0,0],[0,0],[0,0],[0,0],[0,0],[0.054,-0.215],[0,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.377,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.377,0.323],[0,0],[0,0]],"v":[[-45.045,-8.215],[-42.515,-8.215],[-42.138,-10.529],[-41.654,-10.744],[-40.416,-11.444],[-39.986,-11.767],[-37.779,-10.906],[-36.487,-13.112],[-38.371,-14.565],[-38.317,-15.104],[-38.263,-15.803],[-38.317,-16.503],[-38.371,-17.041],[-36.487,-18.494],[-37.779,-20.701],[-39.986,-19.84],[-40.416,-20.163],[-41.654,-20.862],[-42.138,-21.078],[-42.461,-23.392],[-44.991,-23.392],[-45.314,-21.078],[-45.798,-20.862],[-47.036,-20.163],[-47.467,-19.84],[-49.673,-20.701],[-50.965,-18.494],[-49.081,-17.041],[-49.135,-16.503],[-49.189,-15.803],[-49.135,-15.104],[-49.081,-14.565],[-50.965,-13.112],[-49.673,-10.906],[-47.467,-11.767],[-47.036,-11.444],[-45.798,-10.744],[-45.368,-10.529]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.054,0]],"o":[[0.054,0],[0,0]],"v":[[-44.991,-7.784],[-44.991,-7.784]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.7,0],[0,0],[0.108,0.7],[0,0],[0.215,0.162],[0,0],[0.323,0.592],[0,0],[-0.484,0.376],[0,0],[0,0.161],[0,0.162],[0,0],[-0.376,0.593],[0,0],[-0.592,-0.215],[0,0],[-0.215,0.162],[0,0],[-0.7,0],[0,0],[-0.107,-0.7],[0,0],[-0.269,-0.162],[0,0],[-0.323,-0.592],[0,0],[0.484,-0.377],[0,0],[0,-0.162],[0,-0.161],[0,0],[0.323,-0.592],[0,0],[0.646,0.215],[0,0],[0.216,-0.162],[0,0]],"o":[[0,0],[-0.7,0],[0,0],[-0.269,-0.108],[0,0],[-0.646,0.215],[0,0],[-0.323,-0.592],[0,0],[0,-0.161],[0,-0.162],[0,0],[-0.538,-0.431],[0,0],[0.323,-0.592],[0,0],[0.215,-0.162],[0,0],[0.053,-0.646],[0,0],[0.699,0],[0,0],[0.269,0.108],[0,0],[0.646,-0.215],[0,0],[0.323,0.592],[0,0],[0,0.161],[0,0.161],[0,0],[0.538,0.431],[0,0],[-0.323,0.592],[0,0],[-0.215,0.161],[0,0],[0,0.538]],"v":[[-42.085,-6.385],[-45.475,-6.385],[-46.821,-7.569],[-47.09,-9.291],[-47.789,-9.722],[-49.458,-9.076],[-51.126,-9.668],[-52.795,-12.574],[-52.472,-14.296],[-51.072,-15.373],[-51.072,-15.803],[-51.072,-16.234],[-52.472,-17.31],[-52.795,-19.033],[-51.126,-21.939],[-49.512,-22.531],[-47.843,-21.831],[-47.144,-22.262],[-46.874,-24.038],[-45.529,-25.168],[-42.138,-25.168],[-40.793,-23.984],[-40.524,-22.262],[-39.77,-21.831],[-38.102,-22.477],[-36.433,-21.885],[-34.765,-18.979],[-35.088,-17.256],[-36.487,-16.18],[-36.487,-15.749],[-36.487,-15.319],[-35.088,-14.243],[-34.765,-12.52],[-36.487,-9.56],[-38.156,-8.968],[-39.824,-9.614],[-40.524,-9.183],[-40.793,-7.407]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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 2","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-43.792,-15.776],"ix":2},"a":{"a":0,"k":[-43.792,-15.776],"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 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-54,-33],[60,-33],[75,-18],[75,-13],[60,2],[-54,2],[-69,-13],[-69,-18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254901961,0.462745098039,0.898039215686,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 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Taskbar_Transient_LT","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11400,"st":0,"bm":0}],"markers":[{"tm":94,"cm":"","dr":0},{"tm":249,"cm":"","dr":0},{"tm":474,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw/taskbar_edu_stashing_transient.json b/quickstep/res/raw/taskbar_edu_stashing_transient.json new file mode 100644 index 0000000000..847a607607 --- /dev/null +++ b/quickstep/res/raw/taskbar_edu_stashing_transient.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":0,"op":94,"w":412,"h":300,"nm":"Taskbar_Transient_Step_1_LT","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_Transient_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"press 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":381,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":391,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":416,"s":[100]},{"t":426,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[259.25,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":406,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":416,"s":[40,40,100]},{"t":426,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":381,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":406,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":381,"op":437,"st":176,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"press","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":301,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":336,"s":[100]},{"t":346,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":326,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":336,"s":[40,40,100]},{"t":346,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":301,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":326,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":301,"op":357,"st":96,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,194,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":15,"op":73,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"swipe up","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":15,"s":[-48.3,37.417,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":40,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.45,"y":0},"t":50,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"t":70,"s":[-15.3,-62.583,0],"h":1}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[80,80,100]},{"t":70,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":52,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":62,"s":[56,98]},{"t":72,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":52,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":62,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":72,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":15,"op":73,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"screen_matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Pre-comp_TaskBar_Transient_LT","tt":1,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.7,"y":0},"t":50,"s":[204.5,244.501,0],"to":[0,-2.5,0],"ti":[0,2.5,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":94,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[204.5,229.501,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[204.5,237.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[204.5,237.501,0],"to":[0,-1.333,0],"ti":[0,1.333,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.3,"y":0.3},"t":466,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":474,"s":[204.5,229.501,0],"to":[-42.083,-12.917,0],"ti":[42.083,12.917,0]},{"t":554,"s":[-48,152.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":50,"s":[70,70,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":94,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":474,"s":[100,100,100]},{"t":554,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.9,"y":0},"t":46,"s":[205.5,241.5,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"t":76,"s":[205.5,231.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":[[-1.381,0],[0,0],[0,-1.381],[0,0],[1.381,0],[0,0],[0,1.381],[0,0]],"o":[[0,0],[1.381,0],[0,0],[0,1.381],[0,0],[-1.381,0],[0,0],[0,-1.381]],"v":[[-42,-2.5],[42,-2.5],[44.5,0],[44.5,0],[42,2.5],[-42,2.5],[-44.5,0],[-44.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":65,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Pre-comp_Toggle_LT","refId":"comp_2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":256,"s":[0]},{"i":{"x":[0.316],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":286,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":474,"s":[100]},{"t":554,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":235,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":249,"s":[0]},{"t":269,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":356,"s":[320,204.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":386,"s":[320,173.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":436,"s":[320,173.01]},{"t":466,"s":[320,204.01]}],"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.549019607843,0.713725490196,0.964705882353,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.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[-81,0],"to":[0,-2.542],"ti":[0,2.542]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[-81,-15.25],"to":[0,0],"ti":[0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[-81,-15.25],"to":[0,2.542],"ti":[0,-2.542]},{"t":466,"s":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":286,"op":11635,"st":235,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[132.562,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":137,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":187,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":249,"s":[0]},{"t":259,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.98431372549,0.78431372549,0.274509803922,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":100,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_TaskBar_Transient_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":550,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":580,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":553,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":583,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":544,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":574,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":547,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":577,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]},{"id":"comp_2","nm":"Pre-comp_Toggle_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":336,"s":[-12.5,0,0],"to":[3.75,0,0],"ti":[-3.75,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":356,"s":[10,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":416,"s":[10,0,0],"to":[-3.75,0,0],"ti":[3.75,0,0]},{"t":436,"s":[-12.5,0,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":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":336,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":416,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"t":436,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.5,133.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.837,0],[0,0],[0,-8.837],[0,0],[8.837,0],[0,0],[0,8.837],[0,0]],"o":[[0,0],[8.837,0],[0,0],[0,8.837],[0,0],[-8.837,0],[0,0],[0,-8.837]],"v":[[-10,-16],[10,-16],[26,0],[26,0],[10,16],[-10,16],[-26,0],[-26,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682352941176,0.796078431373,0.980392156863,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100_T","cl":"blue100_T","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.784,0],[0,1.783],[1.783,0],[0,-1.783]],"o":[[1.783,0],[0,-1.783],[-1.784,0],[0,1.783]],"v":[[-43.755,-12.577],[-40.526,-15.806],[-43.755,-19.035],[-46.984,-15.806]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0.053]],"o":[[0,0.053],[0,0]],"v":[[-44.937,-23.822],[-44.937,-23.822]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.054]],"o":[[0,0.054],[0,0]],"v":[[-49.458,-21.078],[-49.458,-21.078]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.431,0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.216],[-0.054,-0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,-0.162],[0,0]],"o":[[0,0],[0,0],[0,0],[0.431,-0.162],[0,0],[0,0],[0,0],[0,0],[0,0],[0.054,-0.215],[0,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.377,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.377,0.323],[0,0],[0,0]],"v":[[-45.045,-8.215],[-42.515,-8.215],[-42.138,-10.529],[-41.654,-10.744],[-40.416,-11.444],[-39.986,-11.767],[-37.779,-10.906],[-36.487,-13.112],[-38.371,-14.565],[-38.317,-15.104],[-38.263,-15.803],[-38.317,-16.503],[-38.371,-17.041],[-36.487,-18.494],[-37.779,-20.701],[-39.986,-19.84],[-40.416,-20.163],[-41.654,-20.862],[-42.138,-21.078],[-42.461,-23.392],[-44.991,-23.392],[-45.314,-21.078],[-45.798,-20.862],[-47.036,-20.163],[-47.467,-19.84],[-49.673,-20.701],[-50.965,-18.494],[-49.081,-17.041],[-49.135,-16.503],[-49.189,-15.803],[-49.135,-15.104],[-49.081,-14.565],[-50.965,-13.112],[-49.673,-10.906],[-47.467,-11.767],[-47.036,-11.444],[-45.798,-10.744],[-45.368,-10.529]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.054,0]],"o":[[0.054,0],[0,0]],"v":[[-44.991,-7.784],[-44.991,-7.784]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.7,0],[0,0],[0.108,0.7],[0,0],[0.215,0.162],[0,0],[0.323,0.592],[0,0],[-0.484,0.376],[0,0],[0,0.161],[0,0.162],[0,0],[-0.376,0.593],[0,0],[-0.592,-0.215],[0,0],[-0.215,0.162],[0,0],[-0.7,0],[0,0],[-0.107,-0.7],[0,0],[-0.269,-0.162],[0,0],[-0.323,-0.592],[0,0],[0.484,-0.377],[0,0],[0,-0.162],[0,-0.161],[0,0],[0.323,-0.592],[0,0],[0.646,0.215],[0,0],[0.216,-0.162],[0,0]],"o":[[0,0],[-0.7,0],[0,0],[-0.269,-0.108],[0,0],[-0.646,0.215],[0,0],[-0.323,-0.592],[0,0],[0,-0.161],[0,-0.162],[0,0],[-0.538,-0.431],[0,0],[0.323,-0.592],[0,0],[0.215,-0.162],[0,0],[0.053,-0.646],[0,0],[0.699,0],[0,0],[0.269,0.108],[0,0],[0.646,-0.215],[0,0],[0.323,0.592],[0,0],[0,0.161],[0,0.161],[0,0],[0.538,0.431],[0,0],[-0.323,0.592],[0,0],[-0.215,0.161],[0,0],[0,0.538]],"v":[[-42.085,-6.385],[-45.475,-6.385],[-46.821,-7.569],[-47.09,-9.291],[-47.789,-9.722],[-49.458,-9.076],[-51.126,-9.668],[-52.795,-12.574],[-52.472,-14.296],[-51.072,-15.373],[-51.072,-15.803],[-51.072,-16.234],[-52.472,-17.31],[-52.795,-19.033],[-51.126,-21.939],[-49.512,-22.531],[-47.843,-21.831],[-47.144,-22.262],[-46.874,-24.038],[-45.529,-25.168],[-42.138,-25.168],[-40.793,-23.984],[-40.524,-22.262],[-39.77,-21.831],[-38.102,-22.477],[-36.433,-21.885],[-34.765,-18.979],[-35.088,-17.256],[-36.487,-16.18],[-36.487,-15.749],[-36.487,-15.319],[-35.088,-14.243],[-34.765,-12.52],[-36.487,-9.56],[-38.156,-8.968],[-39.824,-9.614],[-40.524,-9.183],[-40.793,-7.407]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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 2","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-43.792,-15.776],"ix":2},"a":{"a":0,"k":[-43.792,-15.776],"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 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-54,-33],[60,-33],[75,-18],[75,-13],[60,2],[-54,2],[-69,-13],[-69,-18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254901961,0.462745098039,0.898039215686,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 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Taskbar_Transient_LT","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11400,"st":0,"bm":0}],"markers":[{"tm":94,"cm":"","dr":0},{"tm":249,"cm":"","dr":0},{"tm":474,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw/taskbar_edu_suggestions_persistent.json b/quickstep/res/raw/taskbar_edu_suggestions_persistent.json new file mode 100644 index 0000000000..86ad8cfc1e --- /dev/null +++ b/quickstep/res/raw/taskbar_edu_suggestions_persistent.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":186,"op":360,"w":412,"h":300,"nm":"Taskbar_Persistent_LT_Step_2","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp_Taskbar_Persistent_Layers_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 2","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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,"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"screen_matte","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Pre-comp_TaskBar_Persistent_LT","parent":1,"tt":1,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-1.5,87.892,0],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"screen 3","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":175,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":155,"s":[0]},{"t":175,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0.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":[320,174.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,-15.25],"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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":175,"op":11541,"st":141,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,59.005],[0.125,72.005],[-147,72.005],[-160,59.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,62.689],[-13,75.689],[-147,75.689],[-160,62.689],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,62.689],[-13,75.689],[-147,75.689],[-160,62.689],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,59.005],[0.125,72.005],[-147,72.005],[-160,59.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue100","cl":"blue100","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":43,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":93,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":155,"s":[0]},{"t":175,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".yellow100","cl":"yellow100","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.438,0,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":43,"s":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":93,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":155,"s":[95,95,100]},{"t":175,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":43,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":93,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.167,"y":0},"t":155,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,62.689],[147,75.689],[13,75.689],[0,62.689],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":175,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,59.005],[147,72.005],[-0.125,72.005],[-13.125,59.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.98431372549,0.78431372549,0.274509803922,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":175,"st":-94,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[81,0,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_TaskBar_Persistent_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":362,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":392,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":365,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":395,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":386,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":359,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":389,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yelllow400","cl":"yelllow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"screen","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp_Taskbar_Persistent_Layers_LT","tt":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":205,"s":[206,150,0],"to":[-41.417,-45.917,0],"ti":[41.417,45.917,0]},{"t":285,"s":[-42.5,-125.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":205,"s":[100,100,100]},{"t":285,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".white","cl":"white","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11306,"st":-94,"bm":0}],"markers":[{"tm":154,"cm":"","dr":0},{"tm":360,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/raw/taskbar_edu_suggestions_transient.json b/quickstep/res/raw/taskbar_edu_suggestions_transient.json new file mode 100644 index 0000000000..b2624b0aba --- /dev/null +++ b/quickstep/res/raw/taskbar_edu_suggestions_transient.json @@ -0,0 +1 @@ +{"v":"5.9.0","fr":60,"ip":548,"op":628,"w":412,"h":300,"nm":"Taskbar_Transient_Step_4_LT","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_Transient_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"press 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":381,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":391,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":416,"s":[100]},{"t":426,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[259.25,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":406,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":416,"s":[40,40,100]},{"t":426,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":381,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":406,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":381,"op":437,"st":176,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"press","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":301,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":336,"s":[100]},{"t":346,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":326,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":336,"s":[40,40,100]},{"t":346,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,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":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":301,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":326,"s":[0,0],"h":1}],"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":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":301,"op":357,"st":96,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,194,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":15,"op":73,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"swipe up","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":15,"s":[-48.3,37.417,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":40,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.45,"y":0},"t":50,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"t":70,"s":[-15.3,-62.583,0],"h":1}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[80,80,100]},{"t":70,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":52,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":62,"s":[56,98]},{"t":72,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":52,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":62,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":72,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":15,"op":73,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"screen_matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Pre-comp_TaskBar_Transient_LT","tt":1,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.7,"y":0},"t":50,"s":[204.5,244.501,0],"to":[0,-2.5,0],"ti":[0,2.5,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":94,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[204.5,229.501,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[204.5,237.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[204.5,237.501,0],"to":[0,-1.333,0],"ti":[0,1.333,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.3,"y":0.3},"t":466,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":474,"s":[204.5,229.501,0],"to":[-42.083,-12.917,0],"ti":[42.083,12.917,0]},{"t":554,"s":[-48,152.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":50,"s":[70,70,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":94,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":474,"s":[100,100,100]},{"t":554,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.9,"y":0},"t":46,"s":[205.5,241.5,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"t":76,"s":[205.5,231.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":[[-1.381,0],[0,0],[0,-1.381],[0,0],[1.381,0],[0,0],[0,1.381],[0,0]],"o":[[0,0],[1.381,0],[0,0],[0,1.381],[0,0],[-1.381,0],[0,0],[0,-1.381]],"v":[[-42,-2.5],[42,-2.5],[44.5,0],[44.5,0],[42,2.5],[-42,2.5],[-44.5,0],[-44.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":65,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Pre-comp_Toggle_LT","refId":"comp_2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":256,"s":[0]},{"i":{"x":[0.316],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":286,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":474,"s":[100]},{"t":554,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":235,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":249,"s":[0]},{"t":269,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":356,"s":[320,204.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":386,"s":[320,173.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":436,"s":[320,173.01]},{"t":466,"s":[320,204.01]}],"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.549019607843,0.713725490196,0.964705882353,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.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[-81,0],"to":[0,-2.542],"ti":[0,2.542]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[-81,-15.25],"to":[0,0],"ti":[0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[-81,-15.25],"to":[0,2.542],"ti":[0,-2.542]},{"t":466,"s":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":286,"op":11635,"st":235,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[132.562,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":137,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":187,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":249,"s":[0]},{"t":259,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.98431372549,0.78431372549,0.274509803922,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,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":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":[-81,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 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":100,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_TaskBar_Transient_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,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.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"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":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"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":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"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":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"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":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"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":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"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":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"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":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"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":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"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":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":550,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":580,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":553,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":583,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":544,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":574,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":547,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":577,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,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":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,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":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]},{"id":"comp_2","nm":"Pre-comp_Toggle_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":336,"s":[-12.5,0,0],"to":[3.75,0,0],"ti":[-3.75,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":356,"s":[10,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":416,"s":[10,0,0],"to":[-3.75,0,0],"ti":[3.75,0,0]},{"t":436,"s":[-12.5,0,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":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":336,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":416,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"t":436,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.5,133.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.837,0],[0,0],[0,-8.837],[0,0],[8.837,0],[0,0],[0,8.837],[0,0]],"o":[[0,0],[8.837,0],[0,0],[0,8.837],[0,0],[-8.837,0],[0,0],[0,-8.837]],"v":[[-10,-16],[10,-16],[26,0],[26,0],[10,16],[-10,16],[-26,0],[-26,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682352941176,0.796078431373,0.980392156863,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100_T","cl":"blue100_T","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.784,0],[0,1.783],[1.783,0],[0,-1.783]],"o":[[1.783,0],[0,-1.783],[-1.784,0],[0,1.783]],"v":[[-43.755,-12.577],[-40.526,-15.806],[-43.755,-19.035],[-46.984,-15.806]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0.053]],"o":[[0,0.053],[0,0]],"v":[[-44.937,-23.822],[-44.937,-23.822]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.054]],"o":[[0,0.054],[0,0]],"v":[[-49.458,-21.078],[-49.458,-21.078]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.431,0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.216],[-0.054,-0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,-0.162],[0,0]],"o":[[0,0],[0,0],[0,0],[0.431,-0.162],[0,0],[0,0],[0,0],[0,0],[0,0],[0.054,-0.215],[0,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.377,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.377,0.323],[0,0],[0,0]],"v":[[-45.045,-8.215],[-42.515,-8.215],[-42.138,-10.529],[-41.654,-10.744],[-40.416,-11.444],[-39.986,-11.767],[-37.779,-10.906],[-36.487,-13.112],[-38.371,-14.565],[-38.317,-15.104],[-38.263,-15.803],[-38.317,-16.503],[-38.371,-17.041],[-36.487,-18.494],[-37.779,-20.701],[-39.986,-19.84],[-40.416,-20.163],[-41.654,-20.862],[-42.138,-21.078],[-42.461,-23.392],[-44.991,-23.392],[-45.314,-21.078],[-45.798,-20.862],[-47.036,-20.163],[-47.467,-19.84],[-49.673,-20.701],[-50.965,-18.494],[-49.081,-17.041],[-49.135,-16.503],[-49.189,-15.803],[-49.135,-15.104],[-49.081,-14.565],[-50.965,-13.112],[-49.673,-10.906],[-47.467,-11.767],[-47.036,-11.444],[-45.798,-10.744],[-45.368,-10.529]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.054,0]],"o":[[0.054,0],[0,0]],"v":[[-44.991,-7.784],[-44.991,-7.784]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.7,0],[0,0],[0.108,0.7],[0,0],[0.215,0.162],[0,0],[0.323,0.592],[0,0],[-0.484,0.376],[0,0],[0,0.161],[0,0.162],[0,0],[-0.376,0.593],[0,0],[-0.592,-0.215],[0,0],[-0.215,0.162],[0,0],[-0.7,0],[0,0],[-0.107,-0.7],[0,0],[-0.269,-0.162],[0,0],[-0.323,-0.592],[0,0],[0.484,-0.377],[0,0],[0,-0.162],[0,-0.161],[0,0],[0.323,-0.592],[0,0],[0.646,0.215],[0,0],[0.216,-0.162],[0,0]],"o":[[0,0],[-0.7,0],[0,0],[-0.269,-0.108],[0,0],[-0.646,0.215],[0,0],[-0.323,-0.592],[0,0],[0,-0.161],[0,-0.162],[0,0],[-0.538,-0.431],[0,0],[0.323,-0.592],[0,0],[0.215,-0.162],[0,0],[0.053,-0.646],[0,0],[0.699,0],[0,0],[0.269,0.108],[0,0],[0.646,-0.215],[0,0],[0.323,0.592],[0,0],[0,0.161],[0,0.161],[0,0],[0.538,0.431],[0,0],[-0.323,0.592],[0,0],[-0.215,0.161],[0,0],[0,0.538]],"v":[[-42.085,-6.385],[-45.475,-6.385],[-46.821,-7.569],[-47.09,-9.291],[-47.789,-9.722],[-49.458,-9.076],[-51.126,-9.668],[-52.795,-12.574],[-52.472,-14.296],[-51.072,-15.373],[-51.072,-15.803],[-51.072,-16.234],[-52.472,-17.31],[-52.795,-19.033],[-51.126,-21.939],[-49.512,-22.531],[-47.843,-21.831],[-47.144,-22.262],[-46.874,-24.038],[-45.529,-25.168],[-42.138,-25.168],[-40.793,-23.984],[-40.524,-22.262],[-39.77,-21.831],[-38.102,-22.477],[-36.433,-21.885],[-34.765,-18.979],[-35.088,-17.256],[-36.487,-16.18],[-36.487,-15.749],[-36.487,-15.319],[-35.088,-14.243],[-34.765,-12.52],[-36.487,-9.56],[-38.156,-8.968],[-39.824,-9.614],[-40.524,-9.183],[-40.793,-7.407]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,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 2","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-43.792,-15.776],"ix":2},"a":{"a":0,"k":[-43.792,-15.776],"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 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,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":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-54,-33],[60,-33],[75,-18],[75,-13],[60,2],[-54,2],[-69,-13],[-69,-18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254901961,0.462745098039,0.898039215686,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 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Taskbar_Transient_LT","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11400,"st":0,"bm":0}],"markers":[{"tm":94,"cm":"","dr":0},{"tm":249,"cm":"","dr":0},{"tm":474,"cm":"","dr":0}]}
\ No newline at end of file diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml index 34805eae3d..1605c241c0 100644 --- a/quickstep/res/values-af/strings.xml +++ b/quickstep/res/values-af/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriaal <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Gereed!"</string> <string name="allset_hint" msgid="2384632994739392447">"Swiep op om na die tuisskerm toe te gaan"</string> - <string name="allset_description" msgid="6350320429953234580">"Jy is gereed om jou foon te begin gebruik"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Jy is gereed om jou tablet te begin gebruik"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tik op die tuisknoppie om na jou tuisskerm toe te gaan"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Jy is gereed om jou <xliff:g id="DEVICE">%1$s</xliff:g> te begin gebruik"</string> + <string name="default_device_name" msgid="6660656727127422487">"toestel"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Stelselnavigasie-instellings"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Deel"</string> <string name="action_screenshot" msgid="8171125848358142917">"Skermkiekie"</string> <string name="action_split" msgid="2098009717623550676">"Verdeel"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Probeer ander program om verdeelde skerm te gebruik"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Program steun nie verdeelde skerm nie."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Kies nog ’n app as jy verdeelde skerm wil gebruik"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Jou organisasie laat nie hierdie program toe nie"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Slaan navigasietutoriaal oor?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Jy kan dit later in die <xliff:g id="NAME">%1$s</xliff:g>-program kry"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Kanselleer"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Slaan oor"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Draai skerm"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Taakbalkopvoeding"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Taakbalkopvoeding het verskyn"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Taakbalkopvoeding is toegemaak"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gebruik die taakbalk om tussen programme te wissel"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Sleep na die kant om twee programme gelyktydig te gebruik"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Raak en hou om die taakbalk te versteek"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Sleep na die kant om 2 apps tegelyk te gebruik"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Kortswiep op om die taakbalk te wys"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Die taakbalk stel apps op grond van jou roetine voor"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Volgende"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Terug"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Maak toe"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Onlangs"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Kennisgewings"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kitsinstellings"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taakbalk"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasiebalk"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Skuif na regs onder"</string> </resources> diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml index 6ea7d8af54..df9fe66ec0 100644 --- a/quickstep/res/values-am/strings.xml +++ b/quickstep/res/values-am/strings.xml @@ -20,7 +20,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string> - <string name="recent_task_option_freeform" msgid="48863056265284071">"ነጻ ቅጽ"</string> + <string name="recent_task_option_freeform" msgid="48863056265284071">"ነፃ ቅጽ"</string> <string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string> <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"የመተግበሪያ አጠቃቀም ቅንብሮች"</string> <string name="recents_clear_all" msgid="5328176793634888831">"ሁሉንም አጽዳ"</string> @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"አጋዥ ሥልጠና <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"ሁሉም ዝግጁ!"</string> <string name="allset_hint" msgid="2384632994739392447">"ወደ መነሻ ለመሄድ በጣት ወደ ላይ ማንሸራተት"</string> - <string name="allset_description" msgid="6350320429953234580">"ስልክዎን መጠቀም ለመጀመር ዝግጁ ነዎት"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"ጡባዊዎን መጠቀም ለመጀመር ዝግጁ ነዎት"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ወደ መነሻ ማያ ገጽዎ ለመሄድ የመነሻ አዝራሩን መታ ያድርጉ"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"የእርስዎን <xliff:g id="DEVICE">%1$s</xliff:g> መጠቀም ለመጀመር ዝግጁ ነዎት"</string> + <string name="default_device_name" msgid="6660656727127422487">"መሣሪያ"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"የስርዓት አሰሳ ቅንብሮች"</annotation></string> <string name="action_share" msgid="2648470652637092375">"አጋራ"</string> <string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገጽ እይታ"</string> <string name="action_split" msgid="2098009717623550676">"ክፈል"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"የተከፈለ ማያን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"የተከፈለ ማያ ገጽን ለመቀበል ሌላ መተግበሪያ ይምረጡ"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ይህ ድርጊት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"የአሰሳ አጋዥ ሥልጠናን ይዝለሉ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ይህን በኋላ በ<xliff:g id="NAME">%1$s</xliff:g> መተግበሪያው ውስጥ ማግኘት ይችላሉ"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ይቅር"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ዝለል"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"ማያ ገጹን አዙር"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"የተግባር አሞሌ ትምህርት"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"የተግባር አሞሌ ትምህርት ይታያል"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"የተግባር አሞሌ ትምህርት ተዘግቷል"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"መተግበሪያዎችን ለመቀየር የተግባር አሞሌውን ይጠቀሙ"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"በአንድ ጊዜ ሁለት መተግበሪያዎችን ለመጠቀም ወደ ጎን ይጎትቱ"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"የተግባር አሞሌውን ለመደበቅ ነክተው ይያዙት"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"በአንድ ጊዜ 2 መተግበሪያዎችን ለመጠቀም ወደ ጎን ይጎትቱ"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"የተግባር አሞሌውን ለማሳየት አጭር ወደ ላይ ያንሸራትቱ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"የተግባር አሞሌው የዕለት ተዕለት ተግባርዎ ላይ በመመስረት መተግበሪያዎችን ይጠቁማል"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"ቀጣይ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"ተመለስ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"ዝጋ"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"የቅርብ ጊዜዎቹ"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"ማሳወቂያዎች"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ፈጣን ቅንብሮች"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"የተግባር አሞሌ"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"የአሰሳ አሞሌ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ወደ ላይ/ግራ ይውሰዱ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ወደ ታች/ቀኝ ይውሰዱ"</string> </resources> diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml index f9755d2d37..a6781ef379 100644 --- a/quickstep/res/values-ar/strings.xml +++ b/quickstep/res/values-ar/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"الدليل التوجيهي <xliff:g id="CURRENT">%1$d</xliff:g> من إجمالي <xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"اكتملت عملية الإعداد"</string> <string name="allset_hint" msgid="2384632994739392447">"مرِّر سريعًا للأعلى للانتقال إلى الشاشة الرئيسية."</string> - <string name="allset_description" msgid="6350320429953234580">"يمكنك الآن بدء استخدام هاتفك."</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"يمكنك الآن بدء استخدام جهازك اللوحي."</string> + <string name="allset_button_hint" msgid="2395219947744706291">"انقر على زر الشاشة الرئيسية للانتقال إلى الشاشة الرئيسية."</string> + <string name="allset_description_generic" msgid="5385500062202019855">"يمكنك الآن بدء استخدام \"<xliff:g id="DEVICE">%1$s</xliff:g>\"."</string> + <string name="default_device_name" msgid="6660656727127422487">"الجهاز"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"إعدادات التنقّل داخل النظام"</annotation></string> <string name="action_share" msgid="2648470652637092375">"مشاركة"</string> <string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string> <string name="action_split" msgid="2098009717623550676">"تقسيم"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"التطبيق لا يتيح تقسيم الشاشة."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اختَر تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string> <string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"هل تريد تخطي الدليل التوجيهي؟"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"يمكنك العثور على هذا الدليل التوجيهي لاحقًا في التطبيق \"<xliff:g id="NAME">%1$s</xliff:g>\""</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"إلغاء"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"التخطي"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"تدوير الشاشة"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"التعريف بشريط التطبيقات"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ظهرت لوحة تعليم استخدام شريط المهام."</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"تم إغلاق لوحة تعليم استخدام شريط المهام."</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"يمكنك استخدام شريط المهام للتبديل بين التطبيقات."</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"اسحبه إلى جانب الشاشة لاستخدام تطبيقين في آنٍ واحد."</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"انقر مع الاستمرار لإخفاء شريط المهام."</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"اسحبه إلى جانب الشاشة لاستخدام تطبيقَين في آنٍ واحد."</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"مرِّر سريعًا للأعلى تمريرة قصيرة لإظهار شريط التطبيقات."</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"يقترح شريط المهام تطبيقات بناءً على روتينك."</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"الشاشة التالية"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"رجوع"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"إغلاق"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"الأحدث"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"الإشعارات"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"إعدادات سريعة"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"شريط التطبيقات"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"شريط التنقل"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"الانتقال إلى يمين الشاشة أو أعلاها"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"الانتقال إلى يسار الشاشة أو أسفلها"</string> </resources> diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml index ec47dd4570..6e43c19aaf 100644 --- a/quickstep/res/values-as/strings.xml +++ b/quickstep/res/values-as/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"টিউট’ৰিয়েল <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"সকলো সাজু!"</string> <string name="allset_hint" msgid="2384632994739392447">"গৃহ স্ক্ৰীনলৈ যাবলৈ ওপৰলৈ ছোৱাইপ কৰক"</string> - <string name="allset_description" msgid="6350320429953234580">"আপুনি আপোনাৰ ফ’নটো ব্যৱহাৰ কৰিবলৈ সাজু"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"আপুনি আপোনাৰ টেবলেটটো ব্যৱহাৰ কৰিবলৈ সাজু"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"আপোনাৰ গৃহ স্ক্ৰীনলৈ যাবলৈ গৃহপৃষ্ঠা বুটামটো টিপক"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"আপুনি আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>টো ব্যৱহাৰ কৰিবলৈ সাজু"</string> + <string name="default_device_name" msgid="6660656727127422487">"ডিভাইচ"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ছিষ্টেম নেভিগেশ্বনৰ ছেটিং"</annotation></string> <string name="action_share" msgid="2648470652637092375">"শ্বেয়াৰ কৰক"</string> <string name="action_screenshot" msgid="8171125848358142917">"স্ক্ৰীনশ্বট"</string> <string name="action_split" msgid="2098009717623550676">"বিভাজন কৰক"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপত টিপক"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"এপ্টোৱে বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে।"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ বাছক"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"এপ্টোৱে অথবা আপোনাৰ প্ৰতিষ্ঠানে এই কাৰ্যটোৰ অনুমতি নিদিয়ে"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"নেভিগেশ্বনৰ টিউট’ৰিয়েল এৰিব বিচাৰে নেকি?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"আপুনি এয়া পাছত <xliff:g id="NAME">%1$s</xliff:g> এপ্টোত বিচাৰিব পাৰিব"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"বাতিল কৰক"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"এৰি যাওক"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"স্ক্ৰীনখন ঘূৰাওক"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"টাস্কবাৰৰ শিক্ষা"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো প্ৰদর্শিত হৈছে"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো বন্ধ হৈছে"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"এপ্ সলনি কৰিবলৈ টাস্কবাৰডাল ব্যৱহাৰ কৰক"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"এবাৰতে দুটা এপ্ ব্যৱহাৰ কৰিবলৈ কাষলৈ টানি আনি এৰক"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"টাস্কবাৰডাল লুকুৱাবলৈ স্পৰ্শ কৰি ধৰি ৰাখক"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"এবাৰতে দুটা এপ্ ব্যৱহাৰ কৰিবলৈ কাষলৈ টানি আনি এৰক"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"টাস্কবাৰ দেখুৱাবলৈ সামান্য পৰিমাণে ওপৰলৈ ছোৱাইপ কৰক"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"টাস্কবাৰে আপোনাৰ ৰুটিনৰ ভিত্তিত এপৰ পৰামৰ্শ দিয়ে"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"পৰৱৰ্তী"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"উভতি যাওক"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ কৰক"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"শেহতীয়া"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"জাননী"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ক্ষিপ্ৰ ছেটিং"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"টাস্কবাৰ"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"নেভিগেশ্বনৰ দণ্ড"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ওপৰৰ বাঁওফাললৈ নিয়ক"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"তলৰ সোঁফাললৈ নিয়ক"</string> </resources> diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml index 7d15232fd6..e844ec1ef9 100644 --- a/quickstep/res/values-az/strings.xml +++ b/quickstep/res/values-az/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Dərslik <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Hər şey hazırdır!"</string> <string name="allset_hint" msgid="2384632994739392447">"Əsas səhifəyə keçmək üçün yuxarı çəkin"</string> - <string name="allset_description" msgid="6350320429953234580">"Telefondan istifadəyə başlamağa hazırsınız"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Planşetdən istifadəyə başlamağa hazırsınız"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Əsas ekranınıza keçmək üçün əsas düyməyə toxunun"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazından istifadəyə başlamağa hazırsınız"</string> + <string name="default_device_name" msgid="6660656727127422487">"cihaz"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Sistem naviqasiya ayarları"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Paylaşın"</string> <string name="action_screenshot" msgid="8171125848358142917">"Skrinşot"</string> <string name="action_split" msgid="2098009717623550676">"Ayırın"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Bölmə ekranını istifadə etmək üçün başqa tətbiqə toxunun"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Tətbiq ekran bölünməsini dəstəkləmir."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekrandan istifadə üçün başqa tətbiq seçin"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Bu əməliyyata tətbiq və ya təşkilatınız tərəfindən icazə verilmir"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Naviqasiya dərsliyi ötürülsün?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bunu sonra <xliff:g id="NAME">%1$s</xliff:g> tətbiqində tapa bilərsiniz"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ləğv edin"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ötürün"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranı fırladın"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Tapşırıq panelində təhsil"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Tapşırıq panelindəki təlim bölməsi görünür"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Tapşırıq panelindəki təlim bölməsi bağlanıb"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Tətbiqləri keçirmək üçün tapşırıq panelindən istifadə edin"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Eyni anda iki tətbiqi istifadə etmək üçün yan tərəfə çəkin"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tapşırıq panelini toxunub saxlamaqla gizlədin"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Eyni anda 2 tətbiqi istifadə etmək üçün yan tərəfə çəkin"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Tapşırıq panelini göstərmək üçün azca yuxarı sürüşdürün"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Tapşırıq paneli rejiminizə əsasən tətbiqlər təklif edir"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Sonra"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Geri"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Bağlayın"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Sonuncular"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Bildirişlər"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Sürətli Ayarlar"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Tapşırıq paneli"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Naviqasiya paneli"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string> </resources> diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml index 638795369c..2699c3e4d7 100644 --- a/quickstep/res/values-b+sr+Latn/strings.xml +++ b/quickstep/res/values-b+sr+Latn/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Gotovo!"</string> <string name="allset_hint" msgid="2384632994739392447">"Prevucite nagore da biste otvorili početni ekran"</string> - <string name="allset_description" msgid="6350320429953234580">"Spremni ste da počnete da koristite telefon"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Spremni ste da počnete da koristite tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da bisti išli na početni ekran"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete da koristite <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Podešavanja kretanja kroz sistem"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Deli"</string> <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string> <string name="action_split" msgid="2098009717623550676">"Podeli"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Dodirnite drugu aplikaciju za podeljeni ekran"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacija ne podržava podeljeni ekran."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za podeljeni ekran"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili organizacija ne dozvoljavaju ovu radnju"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite da preskočite vodič za kretanje?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Možete da pronađete ovo kasnije u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Otkaži"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotirajte ekran"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Uputstva na traci zadataka"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukativno okno iz trake zadataka se pojavilo"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Edukativno okno iz trake zadataka je zatvoreno"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Koristite traku zadataka da biste menjali aplikacije"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Prevucite na stranu da koristite dve aplikacije odjednom"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i zadržite za skrivanje trake zadataka"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Prevucite na stranu da biste koristili 2 aplikacije odjednom"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Nakratko prevucite nagore da biste prikazali traku zadataka"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Traka zadataka predlaže aplikacije na osnovu rutine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Dalje"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Nazad"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Nedavno"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Obaveštenja"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brza podešavanja"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka zadataka"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Traka za navigaciju"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string> </resources> diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml index 5e5f147b16..0f38c75f3e 100644 --- a/quickstep/res/values-be/strings.xml +++ b/quickstep/res/values-be/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Дапаможнік <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Гатова!"</string> <string name="allset_hint" msgid="2384632994739392447">"Каб перайсці на галоўны экран, правядзіце пальцам уверх"</string> - <string name="allset_description" msgid="6350320429953234580">"Вы можаце пачаць карыстанне тэлефонам"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Вы можаце пачаць карыстанне планшэтам"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Каб перайсці на галоўны экран, націсніце кнопку галоўнага экрана"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Вы можаце пачаць карыстанне прыладай \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string> + <string name="default_device_name" msgid="6660656727127422487">"прылада"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Налады навігацыі ў сістэме"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Абагуліць"</string> <string name="action_screenshot" msgid="8171125848358142917">"Здымак экрана"</string> <string name="action_split" msgid="2098009717623550676">"Падзелены экран"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Для падзеленага экрана націсніце на іншую праграму"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Праграма не падтрымлівае рэжым падзеленага экрана."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Каб падзяліць экран, выберыце іншую праграму"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Гэта дзеянне не дазволена праграмай ці вашай арганізацыяй"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Прапусціць дапаможнік па навігацыі?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Знайсці дапаможнік можна ў праграме \"<xliff:g id="NAME">%1$s</xliff:g>\""</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Скасаваць"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прапусціць"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Павярнуць экран"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Інфармацыя пра панэль задач"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"З\'явілася панэль навучання на панэлі задач"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Панэль навучання на панэлі задач закрыта"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Выкарыстоўвайце панэль задач для пераключэння праграм"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Перацягніце ўбок, каб адначасова скарыстаць дзве праграмы"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Націсніце і ўтрымлівайце, каб схаваць панэль задач"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Перацягніце ўбок, каб адначасова скарыстаць 2 праграмы"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Хутка правядзіце пальцам уверх, каб убачыць панэль задач"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"На панэлі задач праграмы паказваюцца з улікам вашых дзеянняў"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Далей"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыць"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Нядаўнія"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Апавяшчэнні"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Хуткія налады"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Панэль задач"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панэль навігацыі"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перамясціць уверх/улева"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перамясціць уніз/управа"</string> </resources> diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml index ca61151db2..a2843940ef 100644 --- a/quickstep/res/values-bg/strings.xml +++ b/quickstep/res/values-bg/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Урок <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Готово!"</string> <string name="allset_hint" msgid="2384632994739392447">"Прекарайте пръст нагоре, за да отворите началния екран"</string> - <string name="allset_description" msgid="6350320429953234580">"Можете да започнете да използвате телефона си"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Можете да започнете да използвате таблета си"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Докоснете бутона „Начало“, за да преминете към началния екран"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Можете да започнете да използвате <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"устройството"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Настройки за навигиране в системата"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Споделяне"</string> <string name="action_screenshot" msgid="8171125848358142917">"Екранна снимка"</string> <string name="action_split" msgid="2098009717623550676">"Разделяне на екрана"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Докоснете друго прил., за да ползвате разд. екран"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Приложението не поддържа разделен екран."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"За разделен екран изберете още едно приложение"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Това действие не е разрешено от приложението или организацията ви"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропускане на урока за навигиране?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Урокът е налице в приложението <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Отказ"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропускане"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Завъртане на екрана"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Урок за лентата на задачите"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Показва се урокът за лентата на задачите"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Урокът за лентата на задачите бе затворен"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Използвайте лентата на задачите за превключване между прил."</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Плъзнете встрани, за да използвате едновременно 2 приложения"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Докоснете и задръжте, за да скриете лентата на задачите"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Плъзнете встрани, за да използвате едновременно 2 приложения"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Прекарайте пръст нагоре, за да видите лентата на задачите"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Лентата на задачите предлага приложения според навиците ви"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Напред"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Затваряне"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Скорошни"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Известия"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Бързи настройки"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Лента на задачите"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Лента за навигация"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Преместване горе/вляво"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Преместване долу/вдясно"</string> </resources> diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml index 268e73667f..e7691311bc 100644 --- a/quickstep/res/values-bn/strings.xml +++ b/quickstep/res/values-bn/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"টিউটোরিয়াল <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"সব রেডি!"</string> <string name="allset_hint" msgid="2384632994739392447">"হোম স্ক্রিনে যেতে উপরের দিকে সোয়াইপ করুন"</string> - <string name="allset_description" msgid="6350320429953234580">"এবারে আপনি ফোন ব্যবহার করতে পারবেন"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"এবারে আপনি ট্যাবলেট ব্যবহার করতে পারবেন"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"আপনার হোম স্ক্রিনে যাওয়ার জন্য হোম বোতামে ট্যাপ করুন"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> ব্যবহার শুরু করার জন্য আপনি রেডি"</string> + <string name="default_device_name" msgid="6660656727127422487">"ডিভাইস"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"সিস্টেম নেভিগেশন সেটিংস"</annotation></string> <string name="action_share" msgid="2648470652637092375">"শেয়ার করুন"</string> <string name="action_screenshot" msgid="8171125848358142917">"স্ক্রিনশট নিন"</string> <string name="action_split" msgid="2098009717623550676">"স্প্লিট"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"স্প্লিটস্ক্রিন ব্যবহার করতে অন্য অ্যাপে ট্যাপ করুন"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"স্প্লিট-স্ক্রিনে এই অ্যাপ কাজ করে না।"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"নেভিগেশন টিউটোরিয়াল এড়িয়ে যেতে চান?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"আপনি <xliff:g id="NAME">%1$s</xliff:g> অ্যাপে পরে এটি খুঁজে পাবেন"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"বাতিল করুন"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"এড়িয়ে যান"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"স্ক্রিন ঘোরান"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"টাস্কবার এডুকেশন"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"টাস্কবার এডুকেশন দেখানো হয়েছে"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"টাস্কবার এডুকেশন বন্ধ করা আছে"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"অ্যাপ পাল্টানোর জন্য টাস্কবার ব্যবহার করুন"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"একসাথে দুটি অ্যাপ ব্যবহার করতে পাশে টেনে আনুন"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"টাস্কবার লুকানোর জন্য টাচ করে ধরে থাকুন"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"একসাথে ২টি অ্যাপ ব্যবহার করতে পাশে টেনে আনুন"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"টাস্কবার দেখানোর জন্য শর্ট সোয়াইপ করুন"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"আপনার রুটিনের উপর নির্ভর করে টাস্কবার অ্যাপ সাজেস্ট করে"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"পরবর্তী"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"ফিরুন"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ করুন"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"সম্প্রতি"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"বিজ্ঞপ্তি"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"দ্রুত সেটিংস"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"টাস্কবার"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"নেভিগেশন বার"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"উপরে/বাঁদিকে সরান"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"নিচে/ডানদিকে সরান"</string> </resources> diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml index 1ff0817246..f0118a72c1 100644 --- a/quickstep/res/values-bs/strings.xml +++ b/quickstep/res/values-bs/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string> <string name="allset_hint" msgid="2384632994739392447">"Prevucite prema gore da odete na početni ekran"</string> - <string name="allset_description" msgid="6350320429953234580">"Sve je spremno da počnete koristiti telefon"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Sve je spremno da počnete koristiti tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete napočetni ekran"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Sve je spremno da počnete koristiti uređaj <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigiranja sistemom"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Dijeli"</string> <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string> <string name="action_split" msgid="2098009717623550676">"Podijeli"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacija ne podržava podijeljeni ekran."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu apl. da koristite podijeljeni ekran"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Ovu radnju ne dozvoljava aplikacija ili vaša organizacija"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Preskočiti vodič za navigiranje?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Možete ga pronaći kasnije u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Otkaži"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotiranje ekrana"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Edukacija o traci zadataka"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukacija o programskoj traci je prikazana"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Edukacija o programskoj traci je zatvorena"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Koristite programsku traku da promijenite aplikacije"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Prevucite u stranu da istovremeno koristite dvije aplikacije"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i držite da sakrijete programsku traku"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Prevucite u stranu da istovremeno koristite 2 aplikacije"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Nakratko prevucite nagore da prikažete traku zadataka"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Traka zadataka predlaže aplikacije na osnovu vaše rutine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Naprijed"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Nazad"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Nedavno"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Obavještenja"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brze postavke"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka zadataka"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigaciona traka"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore lijevo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje desno"</string> </resources> diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml index 4957aee817..d1219ad26a 100644 --- a/quickstep/res/values-ca/strings.xml +++ b/quickstep/res/values-ca/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Tot a punt!"</string> <string name="allset_hint" msgid="2384632994739392447">"Llisca cap amunt per anar a la pàgina d\'inici"</string> - <string name="allset_description" msgid="6350320429953234580">"Ja pots començar a utilitzar el telèfon"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Ja pots començar a utilitzar la tauleta"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Toca el botó d\'inici per anar a la pantalla d\'inici"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Ja pots començar a utilitzar <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"dispositiu"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configuració de navegació del sistema"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Comparteix"</string> <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string> <string name="action_split" msgid="2098009717623550676">"Divideix"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Toca una altra aplicació per dividir la pantalla"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"L\'aplicació no admet la pantalla dividida."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Tria una altra app per utilitzar pantalla dividida"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"L\'aplicació o la teva organització no permeten aquesta acció"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vols ometre el tutorial de navegació?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Pots trobar-lo més tard a l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel·la"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omet"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Gira la pantalla"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informació sobre Barra de tasques"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Ha aparegut el tauler educatiu de la barra de tasques"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"S\'ha tancat el tauler educatiu de la barra de tasques"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Utilitza la barra de tasques per canviar d\'aplicació"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arrossega al costat per utilitzar dues aplicacions alhora"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén premut per amagar la barra de tasques"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Arrossega al costat per utilitzar 2 aplicacions alhora"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Llisca una mica cap amunt per mostrar la barra de tasques"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"La barra de tasques suggereix apps basades en la teva rutina"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Següent"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Enrere"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Tanca"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recents"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificacions"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. ràpida"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tasques"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegació"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string> </resources> diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml index fa707ac652..868393d343 100644 --- a/quickstep/res/values-cs/strings.xml +++ b/quickstep/res/values-cs/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Výukový program <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Hotovo!"</string> <string name="allset_hint" msgid="2384632994739392447">"Přejetím nahoru se vrátíte na plochu"</string> - <string name="allset_description" msgid="6350320429953234580">"Jste připraveni začít používat telefon"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Jste připraveni začít používat tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Klepnutím na tlačítko plochy se vrátíte na plochu"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Jste připraveni začít používat <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"zařízení"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavení navigace v systému"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Sdílet"</string> <string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string> <string name="action_split" msgid="2098009717623550676">"Rozdělit"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Klepnutím na jinou aplikaci rozdělíte obrazovku"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikace nepodporuje režim rozdělené obrazovky."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vyberte podporovanou aplikaci"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikace nebo organizace zakazuje tuto akci"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Přeskočit výukový program k navigaci?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Program později najdete v aplikaci <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Zrušit"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Přeskočit"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Otočit obrazovku"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informace o panelu aplikací"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila se výuka k hlavnímu panelu"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnímu panelu byla zavřena"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Aplikace lze přepínat pomocí hlavního panelu"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Po přetažení na stranu lze používat dvě aplikace současně"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Hlavní panel můžete skrýt podržením"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Po přetažení na stranu lze používat dvě aplikace současně"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Krátkým přejetím nahoru zobrazíte panel aplikací"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Panel aplikací navrhuje aplikace na základě vašeho používání"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Další"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Zpět"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Zavřít"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Poslední"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Oznámení"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Rychlé nastavení"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Panel aplikací"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigační panel"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string> </resources> diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml index d88061d399..ae2a00a9bc 100644 --- a/quickstep/res/values-da/strings.xml +++ b/quickstep/res/values-da/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Selvstudie <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Alt er parat!"</string> <string name="allset_hint" msgid="2384632994739392447">"Stryg opad for at gå til startsiden"</string> - <string name="allset_description" msgid="6350320429953234580">"Du er klar til at bruge din telefon"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Du er klar til at bruge din tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tryk på knappen Hjem for at gå til din startskærm"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Du er klar til at bruge din <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"enhed"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Indstillinger for systemnavigation"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Del"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Opdel"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Tryk på en anden app for at bruge opdelt skærm"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Appen understøtter ikke opdelt skærm."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vælg en anden app for at bruge opdelt skærm"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du springe selvstudiet for navigation over?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du kan finde dette senere i appen <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuller"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Spring over"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Roter skærm"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Oplysninger om proceslinjen"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Vejledningen om proceslinjen blev åbnet"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Vejledningen om proceslinjen blev lukket"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Skift mellem apps ved hjælp af proceslinjen"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Træk til siden for at bruge to apps samtidig"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Du kan skjule proceslinjen ved at holde fingeren nede"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Træk til siden for at bruge 2 apps samtidig"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Stryg hurtigt opad for at se proceslinjen"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Proceslinjen foreslår apps baseret på din rutine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Næste"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Tilbage"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Luk"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Seneste"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifikationer"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kvikmenu"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Proceslinje"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigationslinje"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string> </resources> diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml index 3728b35ee3..c7664be036 100644 --- a/quickstep/res/values-de/strings.xml +++ b/quickstep/res/values-de/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Anleitung <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Fertig!"</string> <string name="allset_hint" msgid="2384632994739392447">"Nach oben wischen, um den Startbildschirm aufzurufen"</string> - <string name="allset_description" msgid="6350320429953234580">"Du kannst dein Smartphone jetzt verwenden"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Du kannst dein Tablet jetzt verwenden"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Startbildschirmtaste drücken, um zum Startbildschirm zu gehen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Du kannst dein <xliff:g id="DEVICE">%1$s</xliff:g> jetzt verwenden"</string> + <string name="default_device_name" msgid="6660656727127422487">"Gerät"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Einstellungen der Systemsteuerung"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Teilen"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Teilen"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Für „Bildschirm teilen“ auf weitere App tippen"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"„Geteilter Bildschirm“ wird v. d. App nicht unterstützt."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Für geteilten Bildschirm andere App auswählen"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigationstutorial überspringen?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du findest es später auch in der <xliff:g id="NAME">%1$s</xliff:g> App"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Abbrechen"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Überspringen"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Bildschirm drehen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informationen zur Taskleiste"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Anleitung für Taskleiste eingeblendet"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Anleitung für Taskleiste geschlossen"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Über die Taskleiste zwischen Apps wechseln"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Zur Seite ziehen, um zwei Apps gleichzeitig zu verwenden"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Gedrückt halten, um die Taskleiste auszublenden"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Zur Seite ziehen, um zwei Apps gleichzeitig zu verwenden"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Kurz nach oben wischen, um die Taskleiste anzuzeigen"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Taskleiste empfiehlt Apps basierend auf deinen Gewohnheiten"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Weiter"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Zurück"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Schließen"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Letzte Apps"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Benachrichtigungen"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Schnelleinstellungen"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskleiste"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigationsleiste"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string> </resources> diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml index 5ff882e967..807ce43174 100644 --- a/quickstep/res/values-el/strings.xml +++ b/quickstep/res/values-el/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Οδηγός <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Όλα έτοιμα!"</string> <string name="allset_hint" msgid="2384632994739392447">"Σύρετε προς τα πάνω για μετάβαση στην αρχική οθόνη."</string> - <string name="allset_description" msgid="6350320429953234580">"Είστε έτοιμοι να ξεκινήσετε να χρησιμοποιείτε το τηλέφωνό σας"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Είστε έτοιμοι να ξεκινήσετε να χρησιμοποιείτε το tablet."</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Πατήστε το κουμπί αρχικής οθόνης για να μεταβείτε στην αρχική οθόνη"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Είστε έτοιμοι να ξεκινήσετε να χρησιμοποιείτε το/τη <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"συσκευή"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ρυθμίσεις πλοήγησης συστήματος"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Κοινοποίηση"</string> <string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string> <string name="action_split" msgid="2098009717623550676">"Διαχωρισμός"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Πατήστε άλλη εφαρμογή για χρήση διαχωρισμού οθόνης"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Αυτή η ενέργεια δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας."</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Παράβλεψη οδηγού πλοήγησης;"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Βρείτε τον αργότερα στην εφαρμογή <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ακύρωση"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Παράβλεψη"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Περιστροφή οθόνης"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Πληροφορίες χρήσης της Γραμμής εργαλείων"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Η εκπαίδευση για τη γραμμή εργασιών εμφανίστηκε"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Η εκπαίδευση για τη γραμμή εργασιών έκλεισε"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Χρήση της γραμμής εργασιών για εναλλαγή εφαρμογών"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Σύρετε στο πλάι για ταυτόχρονη χρήση δύο εφαρμογών"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Αγγίξτε παρατεταμένα για απόκρυψη της γραμμής εργασιών."</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Σύρετε στο πλάι για ταυτόχρονη χρήση δύο εφαρμογών"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Σύρετε σύντομα προς τα πάνω για εμφάνιση γραμμής εργαλείων"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Η γραμμή εργαλείων συνιστά εφαρμογές βάσει της ρουτίνας σας"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Επόμενο"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Πίσω"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Κλείσιμο"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Πρόσφατα"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Ειδοποιήσεις"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Γρήγορες ρυθμ."</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Γραμμή εργαλείων"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Γραμμή πλοήγησης"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Μετακίνηση επάνω/αριστερά"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Μετακίνηση κάτω/δεξιά"</string> </resources> diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml index 5b378b41ac..414593ab62 100644 --- a/quickstep/res/values-en-rAU/strings.xml +++ b/quickstep/res/values-en-rAU/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Ready!"</string> <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go home"</string> - <string name="allset_description" msgid="6350320429953234580">"You’re ready to start using your phone"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"You’re ready to start using your tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"device"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"System navigation settings"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Share"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Split"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Taskbar education"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Drag to the side to use two apps at once"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Short swipe up to show the taskbar"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"The taskbar suggests apps based on your routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recents"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string> </resources> diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml index ab0a8e9a4b..41fb803fc8 100644 --- a/quickstep/res/values-en-rCA/strings.xml +++ b/quickstep/res/values-en-rCA/strings.xml @@ -25,18 +25,18 @@ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string> <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string> <string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string> - <string name="task_view_closed" msgid="9170038230110856166">"Task closed"</string> + <string name="task_view_closed" msgid="9170038230110856166">"Task Closed"</string> <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string> <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 minute"</string> <string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> left today"</string> <string name="title_app_suggestions" msgid="4185902664111965088">"App suggestions"</string> <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Your predicted apps"</string> - <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Get app suggestions on the bottom row of your home screen"</string> - <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Get app suggestions on the favourites row of your home screen"</string> - <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your home screen."</string> - <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps in the favourites row will move to your home screen."</string> + <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Get app suggestions on the bottom row of your Home screen"</string> + <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Get app suggestions on favorites row of your Home screen"</string> + <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Easily access your most-used apps right on the Home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your Home screen."</string> + <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Easily access your most-used apps right on the Home screen. Suggestions will change based on your routines. Apps in favorites row will move to your Home screen."</string> <string name="hotseat_edu_accept" msgid="1611544083278999837">"Get app suggestions"</string> - <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"No, thanks"</string> + <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"No thanks"</string> <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Settings"</string> <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Most-used apps appear here, and change based on routines"</string> <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Drag apps off the bottom row to get app suggestions"</string> @@ -44,58 +44,60 @@ <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"App suggestions enabled"</string> <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"App suggestions are disabled"</string> <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicted app: <xliff:g id="TITLE">%1$s</xliff:g>"</string> - <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Make sure that you swipe from the far-right or far-left edge."</string> - <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Make sure that you swipe from the right or left edge to the middle of the screen and let go."</string> - <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You learned how to swipe from the right to go back. Next, learn how to switch apps."</string> + <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Make sure you swipe from the far-right or far-left edge."</string> + <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Make sure you swipe from the right or left edge to the middle of the screen and let go."</string> + <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You learned how to swipe from the right to go back. Next up, learn how to switch apps."</string> <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"You completed the go back gesture."</string> - <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Make sure that you don\'t swipe too close to the bottom of the screen."</string> - <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change sensitivity of the back gesture, go to Settings"</string> + <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Make sure you don\'t swipe too close to the bottom of the screen."</string> + <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change the sensitivity of the back gesture, go to Settings"</string> <string name="back_gesture_intro_title" msgid="19551256430224428">"Swipe to go back"</string> <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"To go back to the last screen, swipe from the left or right edge to the middle of the screen."</string> - <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"To go back to the last screen, swipe with two fingers from the left or right edge to the middle of the screen."</string> - <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Make sure that you swipe up from the bottom edge of the screen."</string> - <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Make sure that you don\'t pause before letting go."</string> - <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Make sure that you swipe straight up."</string> - <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"You completed the go home gesture. Next, learn how to go back."</string> - <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"You completed the go home gesture."</string> + <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"To go back to the last screen, swipe with 2 fingers from the left or right edge to the middle of the screen."</string> + <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Make sure you swipe up from the bottom edge of the screen."</string> + <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Make sure you don\'t pause before letting go."</string> + <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Make sure you swipe straight up."</string> + <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"You completed the go Home gesture. Next up, learn how to go back."</string> + <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"You completed the go Home gesture."</string> <string name="home_gesture_intro_title" msgid="836590312858441830">"Swipe to go home"</string> - <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swipe up from the bottom of your screen. This gesture always takes you to the home screen."</string> - <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Swipe up with two fingers from the bottom of the screen. This gesture always takes you to the home screen."</string> - <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure that you swipe up from the bottom edge of the screen."</string> + <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swipe up from the bottom of your screen. This gesture always takes you to the Home screen."</string> + <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Swipe up with 2 fingers from the bottom of the screen. This gesture always takes you to the Home screen."</string> + <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure you swipe up from the bottom edge of the screen."</string> <string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Try holding the window for longer before releasing."</string> - <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure that you swipe straight up, then pause."</string> + <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure you swipe straight up, then pause."</string> <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to Settings."</string> <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"You completed the switch apps gesture."</string> <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Swipe to switch apps"</string> <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"To switch between apps, swipe up from the bottom of your screen, hold, then release."</string> - <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"To switch between apps, swipe up with two fingers from the bottom of your screen, hold, then release."</string> + <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"To switch between apps, swipe up with 2 fingers from the bottom of your screen, hold, then release."</string> <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"All set"</string> <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Done"</string> <string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Settings"</string> <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Try again"</string> <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Nice!"</string> <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> - <string name="allset_title" msgid="5021126669778966707">"Ready!"</string> - <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go home"</string> - <string name="allset_description" msgid="6350320429953234580">"You’re ready to start using your phone"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"You’re ready to start using your tablet"</string> + <string name="allset_title" msgid="5021126669778966707">"All set!"</string> + <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go Home"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"device"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"System navigation settings"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Share"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Split"</string> - <string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string> + <string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use splitscreen"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organization"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Taskbar education"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Drag to the side to use 2 apps at once"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Short swipe up to show the taskbar"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"The taskbar suggests apps based on your routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recents"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string> </resources> diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml index 5b378b41ac..414593ab62 100644 --- a/quickstep/res/values-en-rGB/strings.xml +++ b/quickstep/res/values-en-rGB/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Ready!"</string> <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go home"</string> - <string name="allset_description" msgid="6350320429953234580">"You’re ready to start using your phone"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"You’re ready to start using your tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"device"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"System navigation settings"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Share"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Split"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Taskbar education"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Drag to the side to use two apps at once"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Short swipe up to show the taskbar"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"The taskbar suggests apps based on your routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recents"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string> </resources> diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml index 5b378b41ac..414593ab62 100644 --- a/quickstep/res/values-en-rIN/strings.xml +++ b/quickstep/res/values-en-rIN/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Ready!"</string> <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go home"</string> - <string name="allset_description" msgid="6350320429953234580">"You’re ready to start using your phone"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"You’re ready to start using your tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"device"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"System navigation settings"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Share"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Split"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Taskbar education"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Drag to the side to use two apps at once"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Short swipe up to show the taskbar"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"The taskbar suggests apps based on your routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recents"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string> </resources> diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml index f0b2066d3f..45ce0c1b67 100644 --- a/quickstep/res/values-en-rXC/strings.xml +++ b/quickstep/res/values-en-rXC/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"All set!"</string> <string name="allset_hint" msgid="2384632994739392447">"Swipe up to go Home"</string> - <string name="allset_description" msgid="6350320429953234580">"You’re ready to start using your phone"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"You’re ready to start using your tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tap the home button to go to your home screen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"You’re ready to start using your <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"device"</string> <string name="allset_navigation_settings" msgid="4713404605961476027">""<annotation id="link">"System navigation settings"</annotation>""</string> <string name="action_share" msgid="2648470652637092375">"Share"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Split"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use splitscreen"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organization"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Taskbar education"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Drag to the side to use 2 apps at once"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Short swipe up to show the taskbar"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"The taskbar suggests apps based on your routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recents"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string> </resources> diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml index b9bb70f36f..cb7f51919f 100644 --- a/quickstep/res/values-es-rUS/strings.xml +++ b/quickstep/res/values-es-rUS/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Instructivo <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Todo listo"</string> <string name="allset_hint" msgid="2384632994739392447">"Desliza el dedo hacia arriba para ir a la pantalla principal"</string> - <string name="allset_description" msgid="6350320429953234580">"Ya puedes empezar a usar tu teléfono"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Ya puedes empezar a usar tu tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Presiona el botón de inicio para ir a la pantalla principal"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Ya puedes comenzar a usar <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configuración de navegación del sistema"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Compartir"</string> <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string> <string name="action_split" msgid="2098009717623550676">"Pantalla dividida"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Presiona otra app para usar la pantalla dividida"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"La app no es compatible con la función de pantalla dividida."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Omitir el instructivo de navegación?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puedes encontrarlo en la app de <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omitir"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar pantalla"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Información sobre la barra de tareas"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Se abrió la barra de herramientas Educación"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Se cerró la barra de herramientas Educación"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Usa la barra de tareas para cambiar de app"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arrastra a un lado para usar dos apps a la vez"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén presionado para ocultar la barra de tareas"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Arrastra a un lado para usar 2 apps a la vez"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Desliza un poco hacia arriba para mostrar la barra de tareas"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"La barra de tareas sugiere apps según tu rutina"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Siguiente"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recientes"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificaciones"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. rápida"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tareas"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover a la parte superior o izquierda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover a la parte inferior o derecha"</string> </resources> diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml index f3d7a31623..09cd305eed 100644 --- a/quickstep/res/values-es/strings.xml +++ b/quickstep/res/values-es/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"¡Ya está!"</string> <string name="allset_hint" msgid="2384632994739392447">"Desliza el dedo hacia arriba para ir a la pantalla de inicio"</string> - <string name="allset_description" msgid="6350320429953234580">"Ya puedes empezar a usar tu teléfono"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Ya puedes empezar a usar tu tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Toca el botón de inicio para ir a la pantalla de inicio"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Ya puedes empezar a usar tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ajustes de navegación del sistema"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Compartir"</string> <string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string> <string name="action_split" msgid="2098009717623550676">"Dividir"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Toca otra aplicación para usar la pantalla dividida"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"La aplicación no admite la pantalla dividida."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Saltar tutorial de navegación?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puedes consultarlo en otro momento en la aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Saltar"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar la pantalla"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Información sobre la barra de tareas"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Ha aparecido una nota sobre la barra de tareas"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Nota sobre la barra de tareas cerrada"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Usa la barra de tareas para cambiar de aplicación"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arrastra hacia un lado para usar dos aplicaciones a la vez"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén pulsada la barra de tareas para ocultarla"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Arrastra hacia un lado para usar 2 aplicaciones a la vez"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Desliza un poco hacia arriba para ver la barra de tareas"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"La barra de tareas sugiere aplicaciones según tus hábitos"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Siguiente"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recientes"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificaciones"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ajustes rápidos"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tareas"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string> </resources> diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml index 73c1c1da38..416031600d 100644 --- a/quickstep/res/values-et/strings.xml +++ b/quickstep/res/values-et/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Õpetus <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Valmis!"</string> <string name="allset_hint" msgid="2384632994739392447">"Avakuvale liikumiseks pühkige üles"</string> - <string name="allset_description" msgid="6350320429953234580">"Olete valmis oma telefoni kasutama."</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Olete valmis oma tahvelarvutit kasutama"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Avakuvale liikumiseks puudutage avakuva nuppu"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Olete valmis oma seadet <xliff:g id="DEVICE">%1$s</xliff:g> kasutama"</string> + <string name="default_device_name" msgid="6660656727127422487">"seade"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Süsteemi navigeerimisseaded"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Jaga"</string> <string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string> <string name="action_split" msgid="2098009717623550676">"Eralda"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Jagatud kuva kasutamiseks puudutage muud rakendust"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Rakendus ei toeta jagatud ekraani."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kas jätta navigeerimise õpetused vahele?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Leiate selle hiljem rakendusest <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Tühista"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Jäta vahele"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Pöörake ekraani"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Tegumiriba tutvustus"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Tegumiriba juhised kuvati"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Tegumiriba juhised on suletud"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Kasutage rakenduste vahetamiseks tegumiriba"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Kahe rakenduse korraga kasutamiseks lohistage külje poole"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tegumiriba peitmiseks puudutage pikalt"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Kahe rakenduse korraga kasutamiseks lohistage külje poole"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Tegumiriba kuvamiseks pühkige korraks"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Tegumiribal soovitatakse rakendusi teie rutiinide põhjal"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Järgmine"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Tagasi"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Sule"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Hiljutised"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Märguanded"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kiirseaded"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Tegumiriba"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeerimisriba"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string> </resources> diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml index 5b83633565..b302888a32 100644 --- a/quickstep/res/values-eu/strings.xml +++ b/quickstep/res/values-eu/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriala: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Dena prest!"</string> <string name="allset_hint" msgid="2384632994739392447">"Pasatu hatza gora hasierako pantailara joateko"</string> - <string name="allset_description" msgid="6350320429953234580">"Prest zaude telefonoa erabiltzen hasteko"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Prest zaude tableta erabiltzen hasteko"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Hasierako pantailara joateko, sakatu Hasiera botoia"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Prest zaude <xliff:g id="DEVICE">%1$s</xliff:g> erabiltzen hasteko"</string> + <string name="default_device_name" msgid="6660656727127422487">"gailua"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Sisteman nabigatzeko ezarpenak"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Partekatu"</string> <string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string> <string name="action_split" msgid="2098009717623550676">"Zatitu"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Sakatu beste aplikazio bat pantaila zatitzeko"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikazioak ez du onartzen pantaila zatitua."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pantaila zatitua ikusteko, aukeratu beste aplikazio bat"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Nabigazio-tutoriala saltatu nahi duzu?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioan dago eskuragarri tutoriala"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Utzi"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Saltatu"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Biratu pantaila"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Zereginen barra erabiltzeko argibideak"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Agertu egin da zereginen barraren tutoriala"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Itxi egin da zereginen barraren tutoriala"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Erabili zereginen barra aplikazioz aldatzeko"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Bi aplikazio batera erabiltzeko, arrastatu hatza albo batera"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Zereginen barra ezkutatzeko, eduki ezazu sakatuta"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Bi aplikazio batera erabiltzeko, arrastatu hatza albo batera"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Ataza-barra ikusteko, pasatu hatza bizkor gora"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Ataza-barran erabileran oinarritutako aplikazioak iradokitzen dira"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Hurrengoa"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Atzera"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Itxi"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Azkenak"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Jakinarazpenak"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ezarpen bizkorrak"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Zereginen barra"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Nabigazio-barra"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Eraman gora, ezkerretara"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Eraman behera, eskuinetara"</string> </resources> diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml index a64a876980..c922f8063e 100644 --- a/quickstep/res/values-fa/strings.xml +++ b/quickstep/res/values-fa/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"آموزش گامبهگام <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"همه چیز آماده است!"</string> <string name="allset_hint" msgid="2384632994739392447">"برای رفتن به «صفحه اصلی»، تند بهبالا بکشید"</string> - <string name="allset_description" msgid="6350320429953234580">"آمادهاید از تلفنتان استفاده کنید"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"آمادهاید از رایانه لوحیتان استفاده کنید"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"برای رفتن به صفحه اصلی، روی دکمه صفحه اصلی ضربه بزنید"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"آمادهاید از <xliff:g id="DEVICE">%1$s</xliff:g> خود استفاده کنید"</string> + <string name="default_device_name" msgid="6660656727127422487">"دستگاه"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"تنظیمات پیمایش سیستم"</annotation></string> <string name="action_share" msgid="2648470652637092375">"همرسانی"</string> <string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string> <string name="action_split" msgid="2098009717623550676">"دونیمه"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"برای استفاده از صفحهٔ دونیمه، روی برنامه دیگری ضربه بزنید"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"برنامه از صفحهٔ دونیمه پشتیبانی نمیکند."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"انتخاب برنامهای دیگر برای استفاده از صفحه دونیمه"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمیدهد این کنش انجام شود."</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"آموزش گامبهگام پیمایش رد شود؟"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"میتوانید آن را بعداً در برنامه <xliff:g id="NAME">%1$s</xliff:g> پیدا کنید"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"لغو"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"رد شدن"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"چرخاندن صفحه"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"آموزش نوار وظیفه"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"پانل آموزشی نوار وظیفه نمایان شد"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"پانل آموزشی نوار وظیفه بسته شد"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"برای جابهجایی بین برنامهها، از نوار وظیفه استفاده کنید"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"برای استفاده همزمان از دو برنامه، آن را به کنار بکشید"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"برای پنهان کردن نوار وظیفه، لمس کنید و نگه دارید"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"برای استفاده همزمان از دو برنامه، آن را به کنار بکشید"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"برای نمایش نوار وظیفه، کمی به بالا بکشید"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"نوار وظیفه برنامهها را براساس روال شما پیشنهاد میدهد"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"بعدی"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"برگشت"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"بستن"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"موارد اخیر"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"اعلانها"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"تنظیمات فوری"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"نوار وظیفه"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"نوار پیمایش"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"انتقال به بالا/ چپ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"انتقال به پایین/ راست"</string> </resources> diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml index 08a9248692..a07fdea641 100644 --- a/quickstep/res/values-fi/strings.xml +++ b/quickstep/res/values-fi/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Ohje <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Valmis"</string> <string name="allset_hint" msgid="2384632994739392447">"Siirry aloitusnäytölle pyyhkäisemällä ylös"</string> - <string name="allset_description" msgid="6350320429953234580">"Olet valmis aloittamaan puhelimen käytön"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Olet valmis aloittamaan tabletin käytön"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Siirry aloitusnäytölle napauttamalla aloitusnäyttöpainiketta"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> on nyt valmis käytettäväksi"</string> + <string name="default_device_name" msgid="6660656727127422487">"Laite"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Järjestelmän navigointiasetukset"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Jaa"</string> <string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string> <string name="action_split" msgid="2098009717623550676">"Jaa"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Sovellus ei tue jaetun näytön tilaa."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Sovellus tai organisaatio ei salli tätä toimintoa"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ohitetaanko navigointiohje?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Löydät tämän myöhemmin sovelluksesta: <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Peru"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ohita"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Käännä näyttö"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Tehtäväpalkin ohje"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Tehtäväpalkin ohje näkyvissä"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Tehtäväpalkin ohje suljettu"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Vaihda sovellusta tehtäväpalkin kautta"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Vetämällä sivuun voit käyttää kahta sovellusta samaan aikaan"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Piilota tehtäväpalkki koskettamalla pitkään"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Vetämällä sivuun voit käyttää kahta sovellusta samaan aikaan"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Näytä tehtäväpalkki pyyhkäisemällä ylös lyhyesti"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Tehtäväpalkki ehdottaa sovelluksia ohjelmasi perusteella"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Seuraava"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Takaisin"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Sulje"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Viimeaikaiset"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Ilmoitukset"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Pika-asetukset"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Tehtäväpalkki"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigointipalkki"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string> </resources> diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml index 6199a1421a..cf0fef5f54 100644 --- a/quickstep/res/values-fr-rCA/strings.xml +++ b/quickstep/res/values-fr-rCA/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Étape <xliff:g id="CURRENT">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g> du tutoriel"</string> <string name="allset_title" msgid="5021126669778966707">"Tout est prêt!"</string> <string name="allset_hint" msgid="2384632994739392447">"Balayez l\'écran vers le haut pour accéder à l\'écran d\'accueil"</string> - <string name="allset_description" msgid="6350320429953234580">"Vous êtes maintenant prêt à utiliser votre téléphone"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Vous êtes maintenant prêt à utiliser votre tablette"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Toucher le bouton d\'accueil pour passer sur votre écran d\'accueil"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Vous êtes maintenant prêt à utiliser votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"appareil"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Paramètres de navigation du système"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Partager"</string> <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string> <string name="action_split" msgid="2098009717623550676">"Séparé"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Touchez une autre appli pour partager l\'écran"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"L\'appli n\'est pas compatible avec l\'écran partagé."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choisir une autre application pour utiliser l\'écran partagé"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"L\'application ou votre organisation n\'autorise pas cette action"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel sur la navigation?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Vous trouverez le tutoriel dans l\'application <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuler"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ignorer"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informations sur la barre des tâches"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"La barre des tâches éducatives s\'est affichée"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"La barre des tâches éducatives est fermée"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Utilisez la barre des tâches pour changer les applications"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Glissez sur le côté pour utiliser 2 applications à la fois"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Maintenez le doigt sur la barre des tâches pour la masquer"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Faites glisser vers le côté pour utiliser 2 applis à la fois"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Faites glisser vers le haut pour afficher la barre de tâches"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"La barre des tâches suggère des applis selon votre routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Suivant"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Retour"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Récents"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Paramètres rapides"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barre des tâches"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string> </resources> diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml index c66da27883..a20fbc4992 100644 --- a/quickstep/res/values-fr/strings.xml +++ b/quickstep/res/values-fr/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriel <xliff:g id="CURRENT">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Tout est prêt !"</string> <string name="allset_hint" msgid="2384632994739392447">"Balayez l\'écran vers le haut pour revenir à l\'accueil"</string> - <string name="allset_description" msgid="6350320429953234580">"Vous pouvez maintenant utiliser votre téléphone"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Vous pouvez maintenant utiliser votre tablette"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Appuyez sur le bouton d\'accueil pour accéder à votre écran d\'accueil"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Vous pouvez maintenant utiliser votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"appareil"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Paramètres de navigation système"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Partager"</string> <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string> <string name="action_split" msgid="2098009717623550676">"Partager"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Appuyez sur autre appli pour utiliser écran partagé"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Appli incompatible avec l\'écran partagé."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Sélect. autre appli pour utiliser l\'écran partagé"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Cette action n\'est pas autorisée par l\'application ou par votre organisation"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel de navigation ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Vous le retrouverez dans l\'appli <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuler"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Passer"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Fonctionnement de la barre des tâches"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Infos sur la barre des tâches affichées"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Infos sur la barre des tâches fermées"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Utilisez la barre des tâches pour changer d\'application"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Faites glisser sur côté pour utiliser deux applis à la fois"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Appuyez de manière prolongée pour masquer barre des tâches"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Faites glisser sur le côté pour utiliser 2 applis à la fois"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Balayez rapidement vers haut pour afficher barre des tâches"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"La barre des tâches suggère des applis selon vos habitudes"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Suivant"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Retour"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Récents"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Réglages rapides"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barre des tâches"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string> </resources> diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml index 9946f17b4b..528dd0ad42 100644 --- a/quickstep/res/values-gl/strings.xml +++ b/quickstep/res/values-gl/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Titorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Todo listo"</string> <string name="allset_hint" msgid="2384632994739392447">"Pasa o dedo cara arriba para ir á pantalla de inicio"</string> - <string name="allset_description" msgid="6350320429953234580">"Xa podes comezar a utilizar o teléfono"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Todo está listo para comezar a utilizar a tableta"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Toca o botón de inicio para ir á pantalla de inicio"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Xa podes comezar a utilizar o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string> + <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configuración da navegación do sistema"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Compartir"</string> <string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string> <string name="action_split" msgid="2098009717623550676">"Dividir"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Para usar a pantalla dividida, toca outra app"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"A app non admite a función de pantalla dividida."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolle outra app para usar a pantalla dividida"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"A aplicación ou a túa organización non permite realizar esta acción"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Queres omitir o titorial de navegación?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Podes atopalo máis tarde na aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omitir"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Xira a pantalla"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Información sobre a función Barra de tarefas"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Panel de información de barra de tarefas aberto"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Panel de información de barra de tarefas pechado"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Usa a barra de ferramentas para cambiar de aplicación"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Para usar dúas aplicacións á vez, arrastra cara ao lado"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén premida a barra de tarefas para ocultala"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Para usar 2 aplicacións á vez, arrastra cara ao lado"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Pasa o dedo un pouco cara arriba para ver a barra de tarefas"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Na barra de tarefas suxírense apps segundo a túa rutina"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Pechar"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recentes"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificacións"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Configuración rápida"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string> </resources> diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml index 3439410d37..0ae9b03972 100644 --- a/quickstep/res/values-gu/strings.xml +++ b/quickstep/res/values-gu/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ટ્યૂટૉરિઅલ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"બધું સેટ થઈ ગયું!"</string> <string name="allset_hint" msgid="2384632994739392447">"હોમપેજ પર જવા માટે ઉપરની તરફ સ્વાઇપ કરો"</string> - <string name="allset_description" msgid="6350320429953234580">"તમે તમારા ફોનનો ઉપયોગ કરવા માટે તૈયાર છો"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"તમે તમારા ટૅબ્લેટનો ઉપયોગ કરવા માટે તૈયાર છો"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"તમારી હોમ સ્ક્રીન પર જવા માટે હોમ બટન ટૅપ કરો"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"તમે તમારા <xliff:g id="DEVICE">%1$s</xliff:g>નો ઉપયોગ કરવાનું શરૂ કરવા માટે તૈયાર છો"</string> + <string name="default_device_name" msgid="6660656727127422487">"ડિવાઇસ"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"સિસ્ટમના નૅવિગેશન સેટિંગ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"શેર કરો"</string> <string name="action_screenshot" msgid="8171125848358142917">"સ્ક્રીનશૉટ"</string> <string name="action_split" msgid="2098009717623550676">"વિભાજિત કરો"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"સ્પલિટસ્ક્રીનના વપરાશ માટે, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ઍપ સ્ક્રીન-વિભાજનને સપોર્ટ કરતી નથી."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"સ્ક્રીન વિભાજનનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"નૅવિગેશન ટ્યૂટૉરિઅલ છોડી દઈએ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"તમે આને પછીથી <xliff:g id="NAME">%1$s</xliff:g> ઍપમાં જોઈ શકો છો"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"રદ કરો"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"છોડો"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"સ્ક્રીન ફેરવો"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ટાસ્કબાર વિશે શિક્ષણ"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ટાસ્કબારનું શિક્ષણ આપતી પૅનલ દેખાય છે"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ટાસ્કબારનું શિક્ષણ આપતી પૅનલ બંધ થઈ છે"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ઍપ સ્વિચ કરવા માટે, ટાસ્કબારનો ઉપયોગ કરો"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"એક જ સમયે બે ઍપનો ઉપયોગ કરવા માટે, ખેંચીને બાજુ પર લઈ જાઓ"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ટાસ્કબાર છુપાવવા, તેને ટચ કરીને થોડીવાર દબાવી રાખો"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"એક જ સમયે 2 ઍપનો ઉપયોગ કરવા માટે, ખેંચીને બાજુ પર લઈ જાઓ"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ટાસ્કબાર બતાવવા માટે ઉપર થોડું સ્વાઇપ કરો"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ટાસ્કબાર તમારા રૂટિનના આધારે ઍપ સૂચવે છે"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"આગળ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"પાછળ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"બંધ કરો"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"તાજેતરના"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"નોટિફિકેશન"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ઝડપી સેટિંગ"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"ટાસ્કબાર"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"નૅવિગેશન બાર"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"સૌથી ઉપર ડાબી બાજુએ ખસેડો"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"સૌથી નીચે જમણી બાજુએ ખસેડો"</string> </resources> diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml index be5a2776b4..c9f3930eff 100644 --- a/quickstep/res/values-hi/strings.xml +++ b/quickstep/res/values-hi/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ट्यूटोरियल <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"हो गया!"</string> <string name="allset_hint" msgid="2384632994739392447">"होम स्क्रीन पर जाने के लिए, ऊपर की ओर स्वाइप करें"</string> - <string name="allset_description" msgid="6350320429953234580">"अब आपका फ़ोन, इस्तेमाल के लिए तैयार है"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"आप टैबलेट को इस्तेमाल करने के लिए तैयार हैं"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"होम स्क्रीन पर जाने के लिए, होम बटन पर टैप करें"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"आप <xliff:g id="DEVICE">%1$s</xliff:g> को इस्तेमाल करने के लिए तैयार हैं"</string> + <string name="default_device_name" msgid="6660656727127422487">"डिवाइस"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"सिस्टम नेविगेशन सेटिंग"</annotation></string> <string name="action_share" msgid="2648470652637092375">"शेयर करें"</string> <string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string> <string name="action_split" msgid="2098009717623550676">"स्प्लिट स्क्रीन मोड"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"स्प्लिट स्क्रीन मोड के लिए, दूसरे ऐप पर टैप करें"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"यह ऐप्लिकेशन, स्प्लिट स्क्रीन पर काम नहीं करता है."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन के लिए, दूसरा ऐप्लिकेशन चुनें"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"क्या आपको नेविगेशन ट्यूटोरियल छोड़ना है?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"इसे बाद में <xliff:g id="NAME">%1$s</xliff:g> ऐप्लिकेशन पर देखा जा सकता है"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द करें"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"छोड़ें"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रीन घुमाएं"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"टास्कबार का ट्यूटोरियल"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार ट्यूटोरियल दिखाया गया"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबार ट्यूटोरियल बंद किया गया"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ऐप्लिकेशन स्विच करने के लिए, टास्कबार का इस्तेमाल करें"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"एक साथ दो ऐप्लिकेशन इस्तेमाल करने के लिए, उन्हें किनारे की ओर खींचें और छोड़ें"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार को छिपाने के लिए, उसे दबाकर रखें"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"एक साथ दो ऐप इस्तेमाल करने के लिए, उन्हें किनारे की ओर खींचें और छोड़ें"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"टास्कबार दिखाने के लिए, ऊपर की ओर थोड़ा स्वाइप करें"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"टास्कबार, डिवाइस के इस्तेमाल के आधार पर ऐप के सुझाव देता है"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"आगे बढ़ें"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"वापस जाएं"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करें"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"हाल ही के"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"सूचनाएं"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"फटाफट सेटिंग"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेविगेशन बार"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ऊपर/बाईं तरफ़ ले जाएं"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"नीचे/दाईं तरफ़ ले जाएं"</string> </resources> diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml index 620ba51788..dd7de8cbbc 100644 --- a/quickstep/res/values-hr/strings.xml +++ b/quickstep/res/values-hr/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string> <string name="allset_hint" msgid="2384632994739392447">"Prijeđite prstom prema gore da biste otvorili početni zaslon"</string> - <string name="allset_description" msgid="6350320429953234580">"Spremni ste za početak upotrebe telefona"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Spremni ste za početak upotrebe tableta"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite gumb početnog zaslona da biste prešli na početni zaslon"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste za početak upotrebe uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigacije sustavom"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Podijeli"</string> <string name="action_screenshot" msgid="8171125848358142917">"Snimka zaslona"</string> <string name="action_split" msgid="2098009717623550676">"Podijeli"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Dodirnite drugu aplikaciju za podijeljeni zaslon"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacija ne podržava podijeljeni zaslon."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za upotrebu podijeljenog zaslona"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili vaša organizacija ne dopuštaju ovu radnju"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite li preskočiti vodič za kretanje?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Kasnije ga možete pronaći u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Odustani"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Zakretanje zaslona"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Upute za traku sa zadacima"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Upute za programsku traku su se pojavile"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Upute za programsku traku su zatvorene"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Upotrijebite program. traku da biste promijenili aplikaciju"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Povucite u stranu da biste istovremeno koristili dvije aplikacije"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i zadržite da biste sakrili programsku traku"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Povucite u stranu za istovremeno korištenje 2 aplikacije"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Kratki pokret prema gore za prikaz trake sa zadacima"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Traka sa zadacima predlaže aplikacije na temelju vaše rutine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Dalje"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Natrag"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Najnovije"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Obavijesti"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brze postavke"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka sa zadacima"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigacijska traka"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string> </resources> diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml index 61f0a3b31a..4d01f69666 100644 --- a/quickstep/res/values-hu/strings.xml +++ b/quickstep/res/values-hu/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Útmutató (<xliff:g id="TOTAL">%2$d</xliff:g>/<xliff:g id="CURRENT">%1$d</xliff:g>.)"</string> <string name="allset_title" msgid="5021126669778966707">"Kész is!"</string> <string name="allset_hint" msgid="2384632994739392447">"Felfelé csúsztatva megjelenik a Kezdőképernyő"</string> - <string name="allset_description" msgid="6350320429953234580">"Készen áll a telefon használatára"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Készen áll a táblagép használatára"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"A kezdőképernyőre való lépéshez koppintson a kezdőképernyő gombra"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Készen áll a(z) <xliff:g id="DEVICE">%1$s</xliff:g> használatára"</string> + <string name="default_device_name" msgid="6660656727127422487">"eszköz"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Rendszer-navigációs beállítások"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Megosztás"</string> <string name="action_screenshot" msgid="8171125848358142917">"Képernyőkép"</string> <string name="action_split" msgid="2098009717623550676">"Felosztás"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Koppintson másik appra a képernyőmegosztáshoz"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Az alkalmazás nem támogatja az osztott képernyőt."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Válasszon másik appot a képernyő felosztásához"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Az alkalmazás vagy az Ön szervezete nem engedélyezi ezt a műveletet"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kihagyja a navigáció bemutatóját?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ezt később megtalálhatja a(z) <xliff:g id="NAME">%1$s</xliff:g> alkalmazásban"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Mégse"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Kihagyás"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Képernyő elforgatása"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Tálca használatának ismertetése"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Az eszköztár használatát ismertető panel megjelent"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Az eszköztár használatát ismertető panel bezárult"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Az eszköztárral válthat az alkalmazások között"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Húzza oldalra, ha egyszerre két appot szeretne használni"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Nyomva tartással elrejthető az eszköztár"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Húzza oldalra, ha egyszerre két appot szeretne használni"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Röviden csúsztasson fel a Feladatsáv megjelenítéséhez"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"A Feladatsávban a szokásai alapján javasolt appok láthatók"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Tovább"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Vissza"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Bezárás"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Legutóbbiak"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Értesítések"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Gyorsbeállítások"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Tálca"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigációs sáv"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string> </resources> diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml index 0f9356a42d..28f13a937d 100644 --- a/quickstep/res/values-hy/strings.xml +++ b/quickstep/res/values-hy/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Ուղեցույց <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Պատրաստ է"</string> <string name="allset_hint" msgid="2384632994739392447">"Մատը սահեցրեք վերև՝ հիմնական էկրան անցնելու համար"</string> - <string name="allset_description" msgid="6350320429953234580">"Դուք արդեն կարող եք օգտագործել ձեր հեռախոսը"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Դուք արդեն կարող եք օգտագործել ձեր պլանշետը"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Հիմնական էկրան վերադառնալու համար սեղմեք գլխավոր էկրանի կոճակը"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Դուք արդեն կարող եք օգտագործել ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքը"</string> + <string name="default_device_name" msgid="6660656727127422487">"սարք"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Նավիգացիայի համակարգային կարգավորումներ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Կիսվել"</string> <string name="action_screenshot" msgid="8171125848358142917">"Սքրինշոթ անել"</string> <string name="action_split" msgid="2098009717623550676">"Տրոհել"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Հպեք այլ հավելվածի՝ էկրանը տրոհելու համար"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Հավելվածը չի աջակցում էկրանի տրոհումը։"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ընտրեք այլ հավելված՝ կիսված էկրանից օգտվելու համար"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Այս գործողությունն արգելված է հավելվածի կամ ձեր կազմակերպության կողմից"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Բաց թողնե՞լ նավիգացիայի ուղեցույցը"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Հետագայում սա կարող եք գտնել «<xliff:g id="NAME">%1$s</xliff:g>» հավելվածում"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Չեղարկել"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Բաց թողնել"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Պտտել էկրանը"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Խնդրագոտու «Կրթություն» պատուհան"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Խնդրագոտու «Կրթություն» վահանակը բացվեց"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Խնդրագոտու «Կրթություն» վահանակը փակվեց"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Օգտագործեք խնդրագոտին՝ մի հավելվածից մյուսին անցնելու համար"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Քաշեք մի կողմ՝ միաժամանակ երկու հավելված օգտագործելու համար"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Հպեք և պահեք՝ խնդրագոտին թաքցնելու համար"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Քաշեք մի կողմ՝ միաժամանակ 2 հավելված օգտագործելու համար"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Հավելվածների վահանակը բացելու համար մատն արագ սահեցրեք վերև"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Վահանակն առաջարկում է հավելվածներ ձեր գործողությունների հիման վրա"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Առաջ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Հետ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Փակել"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Վերջինները"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Ծանուցումներ"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Արագ կարգավորումներ"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Խնդրագոտի"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Նավիգացիայի գոտի"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Տեղափոխել վերևի ձախ անկյուն"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Տեղափոխել ներքևի աջ անկյուն"</string> </resources> diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml index b95871f9f6..6d42c3d470 100644 --- a/quickstep/res/values-in/strings.xml +++ b/quickstep/res/values-in/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Semua siap."</string> <string name="allset_hint" msgid="2384632994739392447">"Geser ke atas untuk beralih ke Layar utama"</string> - <string name="allset_description" msgid="6350320429953234580">"Anda sudah siap untuk mulai menggunakan ponsel"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Anda sudah siap untuk mulai menggunakan tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Ketuk tombol layar utama untuk membuka layar utama"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Anda sudah siap untuk mulai menggunakan <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"perangkat"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Setelan navigasi sistem"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Bagikan"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Pisahkan"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Ketuk aplikasi lain untuk menggunakan layar terpisah"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikasi tidak mendukung layar terpisah."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih aplikasi lain untuk memakai layar terpisah"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Lewati tutorial gestur?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Anda dapat menemukan tutorial ini di lain waktu di aplikasi <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Batal"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Lewati"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Putar layar"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Pengantar Taskbar"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukasi taskbar ditampilkan"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Edukasi taskbar ditutup"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gunakan taskbar untuk beralih aplikasi"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Tarik ke samping untuk menggunakan dua aplikasi sekaligus"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Sentuh lama untuk menyembunyikan taskbar"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Tarik ke samping untuk menggunakan 2 aplikasi sekaligus"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Geser sedikit ke atas untuk menampilkan taskbar"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Taskbar menyarankan aplikasi berdasarkan rutinitas Anda"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Berikutnya"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Kembali"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Terbaru"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifikasi"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Setelan Cepat"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Menu navigasi"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string> </resources> diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml index 5730900804..1b4ea2bc63 100644 --- a/quickstep/res/values-is/strings.xml +++ b/quickstep/res/values-is/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Leiðsögn <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Allt tilbúið!"</string> <string name="allset_hint" msgid="2384632994739392447">"Strjúktu upp til að fara á heimaskjáinn"</string> - <string name="allset_description" msgid="6350320429953234580">"Þú getur byrjað að nota símann"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Þú getur byrjað að nota spjaldtölvuna"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Ýttu á heimahnappinn til að fara á heimaskjáinn"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Þú getur byrjað að nota <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"tækið"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Stillingar kerfisstjórnunar"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Deila"</string> <string name="action_screenshot" msgid="8171125848358142917">"Skjámynd"</string> <string name="action_split" msgid="2098009717623550676">"Skipta"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Ýttu á annað forrit til að nota skjáskiptingu"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Forritið styður ekki að skjánum sé skipt."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Veldu annað forrit til að nota skjáskiptingu"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Forritið eða fyrirtækið leyfir ekki þessa aðgerð"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Sleppa flettileiðsögn?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Þú getur fundið þetta síðar í forritinu <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Hætta við"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Sleppa"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Snúa skjánum"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Leiðsögn verkefnastiku"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Leiðsögn verkefnastiku sýnileg"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Leiðsögn verkefnastiku lokað"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Notaðu verkefnastikuna til að skipta á milli forrita"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Dragðu til hliðar til að nota tvö forrit í einu"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Haltu inni til að fela verkefnastikuna"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Dragðu til hliðar til að nota 2 forrit í einu"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Stutt stroka upp til að sýna forritastiku"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Forritastikan mælir með forritum byggt á rútínunni þinni"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Áfram"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Til baka"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Loka"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Nýlegt"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Tilkynningar"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Flýtistillingar"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Verkstika"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Yfirlitsstika"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string> </resources> diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml index 7e04cf66ab..9a5cc9845a 100644 --- a/quickstep/res/values-it/strings.xml +++ b/quickstep/res/values-it/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Finito."</string> <string name="allset_hint" msgid="2384632994739392447">"Scorri verso l\'alto per andare alla schermata Home"</string> - <string name="allset_description" msgid="6350320429953234580">"Puoi iniziare a usare il tuo telefono"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Puoi iniziare a usare il tuo tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tocca il pulsante Home per andare alla schermata Home"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Puoi iniziare a usare il tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Impostazioni Navigazione del sistema"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Condividi"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Dividi"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Tocca un\'altra app per usare lo schermo diviso"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"L\'app non supporta la modalità Schermo diviso."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Scegli un\'altra app per usare lo schermo diviso"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Questa azione non è consentita dall\'app o dall\'organizzazione"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Saltare il tutorial di navigazione?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puoi trovarlo in un secondo momento nell\'app <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annulla"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Salta"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ruota lo schermo"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informazioni sulla barra delle applicazioni"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Riquadro Formazione barra delle applicazioni visualizzato"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Riquadro Formazione barra delle applicazioni chiuso"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Usa la barra delle applicazioni per cambiare app"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Trascina di lato per usare due app contemporaneamente"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tocca e tieni premuto per nascondere barra applicazioni"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Trascina di lato per usare 2 app contemporaneamente"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Scorri verso l\'alto per mostrare la barra delle applicazioni"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Barra delle applicazioni suggerisce app in base alla routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Avanti"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Indietro"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Chiudi"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recenti"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifiche"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Impostazioni rapide"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra delle applicazioni"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra di navigazione"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string> </resources> diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml index 56148e79ff..8722476002 100644 --- a/quickstep/res/values-iw/strings.xml +++ b/quickstep/res/values-iw/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"מדריך <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"הכול מוכן!"</string> <string name="allset_hint" msgid="2384632994739392447">"כדי לעבור לדף הבית, מחליקים כלפי מעלה"</string> - <string name="allset_description" msgid="6350320429953234580">"הכול מוכן ואפשר להתחיל להשתמש בטלפון"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"הכול מוכן ואפשר להתחיל להשתמש בטאבלט"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"כדי לעבור אל מסך הבית יש להקיש על הלחצן הראשי"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"הכול מוכן ואפשר להתחיל להשתמש ב<xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"מכשיר"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"הגדרות הניווט של המערכת"</annotation></string> <string name="action_share" msgid="2648470652637092375">"שיתוף"</string> <string name="action_screenshot" msgid="8171125848358142917">"צילום מסך"</string> <string name="action_split" msgid="2098009717623550676">"פיצול"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"צריך להקיש על אפליקציה אחרת כדי להשתמש במסך מפוצל"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"האפליקציה אינה תומכת במסך מפוצל."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"כדי להשתמש במסך מפוצל צריך לבחור אפליקציה אחרת"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"האפליקציה או הארגון שלך אינם מתירים את הפעולה הזאת"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"לדלג על המדריך לניווט?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ניתן למצוא את המדריך מאוחר יותר באפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ביטול"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"דילוג"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"סיבוב המסך"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"הסבר על סרגל האפליקציות"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"חלונית ההסברים על שורת המשימות מופיעה"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"חלונית ההסברים על שורת המשימות נסגרה"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"כדי לעבור בין אפליקציות, משתמשים בשורת המשימות"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"כדי להשתמש בשתי אפליקציות בו-זמנית, צריך לגרור לצד"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"כדי להסתיר את שורת המשימות, לוחצים לחיצה ארוכה"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"כדי להשתמש בשתי אפליקציות בו-זמנית, צריך לגרור לצד"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"צריך להחליק מעט כדי להציג את סרגל האפליקציות"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"האפליקציות מוצעות בסרגל האפליקציות על סמך השימוש השגרתי שלך"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"הבא"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"חזרה"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"סגירה"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"לאחרונה"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"התראות"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"הגדרות מהירות"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"סרגל האפליקציות"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"סרגל הניווט"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"העברה לפינה השמאלית/העליונה"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"העברה לפינה הימנית/התחתונה"</string> </resources> diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml index 013939f900..7bdb5ecd0c 100644 --- a/quickstep/res/values-ja/strings.xml +++ b/quickstep/res/values-ja/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"チュートリアル <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"設定完了"</string> <string name="allset_hint" msgid="2384632994739392447">"ホームに移動するには上にスワイプします"</string> - <string name="allset_description" msgid="6350320429953234580">"スマートフォンを使用する準備ができました"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"これでタブレットが使えるようになりました"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ホームボタンをタップすると、ホーム画面に移動します"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> を使用する準備ができました"</string> + <string name="default_device_name" msgid="6660656727127422487">"デバイス"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"システム ナビゲーションの設定"</annotation></string> <string name="action_share" msgid="2648470652637092375">"共有"</string> <string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string> <string name="action_split" msgid="2098009717623550676">"分割"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"分割画面を使用するには、他のアプリをタップします"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"アプリで分割画面がサポートされていません。"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"分割画面にするには、別のアプリを選択してください"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"操作チュートリアルをスキップしますか?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"チュートリアルは後から <xliff:g id="NAME">%1$s</xliff:g> アプリで確認できます"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"キャンセル"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"スキップ"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"画面を回転"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"タスクバーの説明"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"タスクバーの説明を開きました"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"タスクバーの説明を閉じました"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"アプリを切り替えるには、タスクバーを使用します"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"2 個のアプリを同時に使用するには、横にドラッグします"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"タスクバーを長押しすると非表示になります"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"2 個のアプリを同時に使用するには、横にドラッグします"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"タスクバーを表示するには、上に短くスワイプします"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ルーティンに基づくおすすめのアプリがタスクバーに表示されます"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"次へ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"戻る"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"閉じる"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"最近"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"通知"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"クイック設定"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"タスクバー"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ナビゲーション バー"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"上 / 左に移動"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"下 / 右に移動"</string> </resources> diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml index d54ac881c3..7259f048f3 100644 --- a/quickstep/res/values-ka/strings.xml +++ b/quickstep/res/values-ka/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"სახელმძღვანელო <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"მზადაა!"</string> <string name="allset_hint" msgid="2384632994739392447">"მთავარ გვერდზე გადასასვლელად გადაფურცლეთ ზევით"</string> - <string name="allset_description" msgid="6350320429953234580">"მზად ხართ ტელეფონის გამოსაყენებლად"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"მზად ხართ ტაბლეტის გამოსაყენებლად"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"შეეხეთ მთავარი ეკრანის ღილაკს მთავარ ეკრანზე გადასასვლელად"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"მზად ხართ, გამოიყენოთ <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"მოწყობილობა"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"სისტემის ნავიგაციის პარამეტრები"</annotation></string> <string name="action_share" msgid="2648470652637092375">"გაზიარება"</string> <string name="action_screenshot" msgid="8171125848358142917">"ეკრანის ანაბეჭდი"</string> <string name="action_split" msgid="2098009717623550676">"გაყოფა"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"შეეხეთ სხვა აპს ეკრანის გასაყოფად"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"აირჩიეთ სხვა აპი ეკრანის გასაყოფად"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ეს მოქმედება არ არის დაშვებული აპის ან თქვენი ორგანიზაციის მიერ"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"გსურთ, გამოტოვოთ ნავიგაციის სახელმძღვანელო?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ამის მოგვიანებით პოვნა <xliff:g id="NAME">%1$s</xliff:g> აპში შეგიძლიათ"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"გაუქმება"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"გამოტოვება"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"ეკრანის შეტრიალება"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ამოცანათა ზოლი: განათლება"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ამოცანების ზოლის სასწავლო არე გამოჩნდა"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ამოცანების ზოლის სასწავლო არე დაიხურა"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"აპების გადასართავად გამოიყენეთ ამოცანათა ზოლი"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"გადაათრიეთ კიდეზე ორი აპის ერთდოულად გამოსაყენებლად"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ხანგრძლივად შეეხეთ ამოცანების ზოლის დასამალად"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"გადაათრიეთ კიდეზე 2 აპის ერთდროულად გამოსაყენებლად"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"მოკლედ გადაფურცლეთ ზემოთ, რომ ამოცანათა ზოლი გამოაჩინოთ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ამოცანათა ზოლი გთავაზობთ აპებს თქვენი რუტინის მიხედვით"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"შემდეგი"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"უკან"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"დახურვა"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"ბოლოდროინდელი"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"შეტყობინებები"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"სწრაფი პარამეტრები"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"ამოცანათა ზოლი"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ნავიგაციის ზოლი"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ზემოთ/მარცხნივ გადატანა"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ქვემოთ/მარჯვნივ გადატანა"</string> </resources> diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml index bfa2a5cf37..d0f6a9a9b0 100644 --- a/quickstep/res/values-kk/strings.xml +++ b/quickstep/res/values-kk/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Оқулық: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Бәрі дайын!"</string> <string name="allset_hint" msgid="2384632994739392447">"Негізгі экранға өту үшін жоғары қарай сырғытыңыз."</string> - <string name="allset_description" msgid="6350320429953234580">"Телефоныңыз пайдалануға дайын."</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Планшетіңіз пайдалануға дайын."</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Негізгі экранға өту үшін негізгі экран түймесін түртіңіз."</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> пайдалануға дайын."</string> + <string name="default_device_name" msgid="6660656727127422487">"құрылғы"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Навигацияның жүйелік параметрлері"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Бөлісу"</string> <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string> <string name="action_split" msgid="2098009717623550676">"Бөлу"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Қолданбада экранды бөлу мүмкін емес."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Бұл әрекетке қолданба не ұйым рұқсат етпейді."</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Қимылдар оқулығын өткізіп жіберу керек пе?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Мұны кейін <xliff:g id="NAME">%1$s</xliff:g> қолданбасынан таба аласыз."</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Бас тарту"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Өткізіп жіберу"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Экранды бұру"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Тапсырмалар жолағы: үйрену"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапсырмалар тақтасы бойынша нұсқаулық ашылды."</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Тапсырмалар тақтасы бойынша нұсқаулық жабылды."</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Қолданбаларды ауыстыру үшін тапсырма тақтасын пайдаланыңыз."</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Екі қолданбаны бір уақытта пайдалану үшін шетке сүйреңіз."</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Тапсырмалар тақтасын жасыру үшін басып тұрыңыз."</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Екі қолданбаны бір уақытта пайдалану үшін шетке сүйреңіз."</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Тапсырмалар жолағын көру үшін жоғары қарай тез сырғытыңыз."</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Тапсырмалар жолағындағы ұсыныстар әдеттеріңізге негізделеді."</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Келесі"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Артқа"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Соңғылары"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Хабарландырулар"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Жылдам параметрлер"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Тапсырмалар жолағы"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Навигация жолағы"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жоғары/солға жылжыту"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмен/оңға жылжыту"</string> </resources> diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml index 4a78d9d79a..f9a7209b8d 100644 --- a/quickstep/res/values-km/strings.xml +++ b/quickstep/res/values-km/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"មេរៀនទី <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"រួចហើយ!"</string> <string name="allset_hint" msgid="2384632994739392447">"អូសឡើងលើ ដើម្បីទៅកាន់អេក្រង់ដើម"</string> - <string name="allset_description" msgid="6350320429953234580">"អ្នកអាចចាប់ផ្ដើមប្រើទូរសព្ទរបស់អ្នកបានហើយ"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"អ្នកអាចចាប់ផ្ដើមប្រើថេប្លេតរបស់អ្នកបានហើយ"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ចុចប៊ូតុងដើម ដើម្បីចូលទៅកាន់អេក្រង់ដើមរបស់អ្នក"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"អ្នកអាចចាប់ផ្ដើមប្រើ <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នកបានហើយ"</string> + <string name="default_device_name" msgid="6660656727127422487">"ឧបករណ៍"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ការកំណត់ការរុករកប្រព័ន្ធ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"ចែករំលែក"</string> <string name="action_screenshot" msgid="8171125848358142917">"រូបថតអេក្រង់"</string> <string name="action_split" msgid="2098009717623550676">"បំបែក"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"ចុចកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"កម្មវិធីមិនអាចប្រើមុខងារបំបែកអេក្រង់បានទេ។"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"សកម្មភាពនេះមិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី ឬស្ថាប័នរបស់អ្នកទេ"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"រំលងមេរៀនអំពីការរុករកឬ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"អ្នកអាចស្វែងរកមេរៀននេះនៅពេលក្រោយក្នុងកម្មវិធី <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"បោះបង់"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"រំលង"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"បង្វិលអេក្រង់"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ការអប់រំលើរបារកិច្ចការ"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ការបង្រៀនអំពីរបារកិច្ចការបានបង្ហាញ"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ការបង្រៀនអំពីរបារកិច្ចការត្រូវបានបិទ"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ប្រើរបារកិច្ចការ ដើម្បីប្ដូរកម្មវិធី"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"អូសទៅចំហៀង ដើម្បីប្រើកម្មវិធីពីរក្នុងពេលតែមួយ"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ចុចឱ្យជាប់ ដើម្បីលាក់របារកិច្ចការ"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"អូសទៅចំហៀង ដើម្បីប្រើកម្មវិធី 2 ក្នុងពេលតែមួយ"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"អូសឡើងលើបន្តិច ដើម្បីបង្ហាញរបារកិច្ចការ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"របារកិច្ចការនេះណែនាំកម្មវិធីផ្អែកលើទម្លាប់របស់អ្នក"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"បន្ទាប់"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"ថយក្រោយ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"បិទ"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"ថ្មីៗ"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"ការជូនដំណឹង"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ការកំណត់រហ័ស"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"របារកិច្ចការ"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"របាររុករក"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ផ្លាស់ទីទៅខាងលើ/ឆ្វេង"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ផ្លាស់ទីទៅខាងក្រោម/ស្ដាំ"</string> </resources> diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml index 91a12f86b7..b7c774ae72 100644 --- a/quickstep/res/values-kn/strings.xml +++ b/quickstep/res/values-kn/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ಟ್ಯುಟೋರಿಯಲ್ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"ಎಲ್ಲವೂ ಸಿದ್ಧವಾಗಿದೆ!"</string> <string name="allset_hint" msgid="2384632994739392447">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string> - <string name="allset_description" msgid="6350320429953234580">"ನಿಮ್ಮ ಫೋನ್ ಬಳಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸಲು ನೀವು ಸಿದ್ದರಾಗಿರುವಿರಿ"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಬಳಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸಲು ನೀವು ಸಿದ್ದರಾಗಿರುವಿರಿ"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ನಿಮ್ಮ ಮುಖಪುಟದ ಪರದೆಗೆ ಹೋಗಲು ಮುಖಪುಟ ಬಟನ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಬಳಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸಲು ನೀವು ಸಿದ್ಧರಾಗಿರುವಿರಿ"</string> + <string name="default_device_name" msgid="6660656727127422487">"ಸಾಧನ"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಶನ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</annotation></string> <string name="action_share" msgid="2648470652637092375">"ಹಂಚಿಕೊಳ್ಳಿ"</string> <string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string> <string name="action_split" msgid="2098009717623550676">"ವಿಭಜಿಸಿ"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬಳಸಲು ಬೇರೊಂದು ಆ್ಯಪ್ ಮೇಲೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"\"ಪರದೆ ಬೇರ್ಪಡಿಸಿ\" ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ನ್ಯಾವಿಗೇಶನ್ ಟ್ಯುಟೋರಿಯಲ್ ಸ್ಕಿಪ್ ಮಾಡಬೇಕೇ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ಆ್ಯಪ್ನಲ್ಲಿ ಇದನ್ನು ನಂತರ ಕಾಣಬಹುದು"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ರದ್ದುಮಾಡಿ"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ಸ್ಕಿಪ್ ಮಾಡಿ"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"ಸ್ಕ್ರೀನ್ ತಿರುಗಿಸಿ"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ ಕಾಣಿಸಿಕೊಂಡಿದೆ"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ ಮುಚ್ಚಿದೆ"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟಾಸ್ಕ್ ಬಾರ್ ಬಳಸಿ"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ಏಕಕಾಲದಲ್ಲಿ ಎರಡು ಆ್ಯಪ್ಗಳನ್ನು ಬಳಸಲು, ಬದಿಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ಟಾಸ್ಕ್ಬಾರ್ ಅನ್ನು ಮರೆಮಾಡಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ಏಕಕಾಲದಲ್ಲಿ 2 ಆ್ಯಪ್ಗಳನ್ನು ಬಳಸಲು ಬದಿಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ಟಾಸ್ಕ್ಬಾರ್ ಅನ್ನು ತೋರಿಸಲು ಚಿಕ್ಕದಾಗಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ಟಾಸ್ಕ್ಬಾರ್ ನಿಮ್ಮ ದಿನಚರಿ ಆಧರಿಸಿ ಆ್ಯಪ್ಗಳನ್ನು ಸೂಚಿಸುತ್ತದೆ"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"ಮುಂದೆ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"ಹಿಂದೆ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"ಮುಚ್ಚಿರಿ"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"ಇತ್ತೀಚಿನವು"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"ಅಧಿಸೂಚನೆಗಳು"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"ಟಾಸ್ಕ್ಬಾರ್"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ನ್ಯಾವಿಗೇಷನ್ ಬಾರ್"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ಮೇಲಿನ/ಎಡಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ಕೆಳಗಿನ/ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string> </resources> diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml index bfe98f9780..99309d260c 100644 --- a/quickstep/res/values-ko/strings.xml +++ b/quickstep/res/values-ko/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"튜토리얼 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"설정 완료"</string> <string name="allset_hint" msgid="2384632994739392447">"위로 스와이프하여 홈으로 이동"</string> - <string name="allset_description" msgid="6350320429953234580">"휴대전화를 사용할 준비가 되었습니다."</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"태블릿을 사용할 준비가 되었습니다."</string> + <string name="allset_button_hint" msgid="2395219947744706291">"홈 화면으로 이동하려면 홈 버튼을 탭하세요."</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> 기기를 사용할 준비가 되었습니다."</string> + <string name="default_device_name" msgid="6660656727127422487">"기기"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"시스템 탐색 설정"</annotation></string> <string name="action_share" msgid="2648470652637092375">"공유"</string> <string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string> <string name="action_split" msgid="2098009717623550676">"분할"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"다른 앱을 탭하여 화면 분할 사용"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"앱이 화면 분할을 지원하지 않습니다."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string> <string name="blocked_by_policy" msgid="2071401072261365546">"이 작업은 앱 또는 조직에서 허용되지 않습니다."</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"이동 방법 튜토리얼을 건너뛰시겠습니까?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"이 튜토리얼은 <xliff:g id="NAME">%1$s</xliff:g> 앱에서 다시 볼 수 있습니다."</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"취소"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"건너뛰기"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"화면 회전"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"태스크 바 정보"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"작업 표시줄 튜토리얼 패널 표시됨"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"작업 표시줄 튜토리얼 패널 닫힘"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"작업 표시줄을 사용하여 앱 전환"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"옆으로 드래그하여 한 번에 앱 두 개 사용"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"작업 표시줄을 숨기려면 길게 터치하세요."</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"옆으로 드래그하여 2개의 앱을 동시에 사용합니다."</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"위로 짧게 스와이프하여 태스크 바를 표시합니다."</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"태스크 바에서 루틴에 따라 앱을 제안합니다."</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"다음"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"뒤로"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"닫기"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"최근 항목"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"알림"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"빠른 설정"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"태스크 바"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"탐색 메뉴"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"상단/왼쪽으로 이동"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"하단/오른쪽으로 이동"</string> </resources> diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml index 5472eadc8b..55e5a11872 100644 --- a/quickstep/res/values-ky/strings.xml +++ b/quickstep/res/values-ky/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Үйрөткүч: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Бүттү!"</string> <string name="allset_hint" msgid="2384632994739392447">"Башкы бетке өтүү үчүн экранды өйдө сүрүңүз"</string> - <string name="allset_description" msgid="6350320429953234580">"Телефонуңузду колдоно берсеңиз болот"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Планшетиңизди колдоно берсеңиз болот"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Башкы экранга өтүү үчүн башкы бет баскычын таптап коюңуз"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүн колдоно берсеңиз болот"</string> + <string name="default_device_name" msgid="6660656727127422487">"түзмөк"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Өтүү аракетинин системалык параметрлери"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string> <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string> <string name="action_split" msgid="2098009717623550676">"Бөлүү"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Колдонмодо экран бөлүнбөйт."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Жаңсоолор үйрөткүчүн өткөрүп жибересизби?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Аны кийин <xliff:g id="NAME">%1$s</xliff:g> колдонмосунан табасыз"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Жокко чыгаруу"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Өткрп жиберүү"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Экранды буруу"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Тапшырмалар панели жөнүндө маалымат"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапшырмалар тактасынын окутуу панели көрсөтүлдү"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Тапшырмалар тактасынын окутуу панели жабылды"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Тапшырмалар тактасы аркылуу башка колдонмого которула аласыз"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Эки колдонмону бир убакта пайдалануу үчүн капталга сүрүңүз"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Тапшырмалар тактасын жашыруу үчүн коё бербей басып туруңуз"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"2 колдонмону бир убакта пайдалануу үчүн капталга сүйрөңүз"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Тапшырмалар тактасын көрүү үчүн экранды өйдө серпиңиз"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Тапшырмалар тактасы колдонмолорду аракеттериңизге жараша сунуштайт"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Кийинки"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Артка"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Жабуу"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Акыркылар"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Билдирмелер"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ыкчам жөндөөлөр"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Тапшырмалар панели"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Чабыттоо тилкеси"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жогорку/сол бурчка жылдыруу"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмөнкү/оң бурчка жылдыруу"</string> </resources> diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml index 905fbda7a3..30983c4d5a 100644 --- a/quickstep/res/values-land/dimens.xml +++ b/quickstep/res/values-land/dimens.xml @@ -76,8 +76,10 @@ <dimen name="gesture_tutorial_taskbar_padding_start_end">218dp</dimen> <!-- Taskbar 3 button spacing --> - <dimen name="taskbar_button_margin_5_5">94.5dp</dimen> + <dimen name="taskbar_button_margin_split">88dp</dimen> <dimen name="taskbar_button_margin_6_5">219.6dp</dimen> - <dimen name="taskbar_button_margin_4_5">84dp</dimen> - <dimen name="taskbar_button_margin_4_4">79dp</dimen> + <dimen name="taskbar_contextual_button_margin">48dp</dimen> + <dimen name="taskbar_suw_frame">96dp</dimen> + <dimen name="taskbar_suw_insets">24dp</dimen> + </resources>
\ No newline at end of file diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml index 7d87ec483e..4be7c8cb37 100644 --- a/quickstep/res/values-lo/strings.xml +++ b/quickstep/res/values-lo/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ການສອນການນຳໃຊ້ທີ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"ຮຽບຮ້ອຍໝົດແລ້ວ!"</string> <string name="allset_hint" msgid="2384632994739392447">"ປັດຂຶ້ນເພື່ອໄປຫາໜ້າຫຼັກ"</string> - <string name="allset_description" msgid="6350320429953234580">"ທ່ານພ້ອມເລີ່ມຕົ້ນໃຊ້ໂທລະສັບຂອງທ່ານແລ້ວ"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"ທ່ານພ້ອມເລີ່ມຕົ້ນໃຊ້ແທັບເລັດຂອງທ່ານແລ້ວ"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ແຕະປຸ່ມໜ້າທຳອິດເພື່ອໄປຫາໂຮມສະກຣີນຂອງທ່ານ"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"ທ່ານເລີ່ມໃຊ້ແທັບເລັດ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້ແລ້ວ"</string> + <string name="default_device_name" msgid="6660656727127422487">"ອຸປະກອນ"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ການຕັ້ງຄ່າການນຳທາງລະບົບ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"ແບ່ງປັນ"</string> <string name="action_screenshot" msgid="8171125848358142917">"ຮູບໜ້າຈໍ"</string> <string name="action_split" msgid="2098009717623550676">"ແບ່ງ"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"ແຕະແອັບອື່ນເພື່ອໃຊ້ການແຍກໜ້າຈໍ"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ແອັບບໍ່ຮອງຮັບການແບ່ງໜ້າຈໍ."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ເລືອກແອັບອື່ນເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ແອັບ ຫຼື ອົງການຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຄຳສັ່ງນີ້"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ຂ້າມການສອນການນຳໃຊ້ການນຳທາງບໍ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ທ່ານສາມາດຊອກສ່ວນນີ້ພາຍຫຼັງໄດ້ໃນແອັບ <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ຍົກເລີກ"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ຂ້າມ"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"ໝຸນໜ້າຈໍ"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ແຖບໜ້າວຽກ Education"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ສະແດງການສຶກສາແຖບໜ້າວຽກແລ້ວ"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ປິດການສຶກສາແຖບໜ້າວຽກແລ້ວ"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ໃຊ້ແຖບໜ້າວຽກເພື່ອສະຫຼັບແອັບ"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ລາກໄປທາງຂ້າງເພື່ອໃຊ້ສອງແອັບພ້ອມກັນ"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ແຕະຄ້າງໄວ້ເພື່ອເຊື່ອງແຖບໜ້າວຽກ"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ລາກໄປທາງຂ້າງເພື່ອໃຊ້ 2 ແອັບພ້ອມກັນ"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ປັດຂຶ້ນສັ້ນໆເພື່ອສະແດງແຖບໜ້າວຽກ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ແຖບໜ້າວຽກຈະແນະນຳແອັບໂດຍອີງຕາມສິ່ງທີ່ເຮັດປະຈຳຂອງທ່ານ"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"ຕໍ່ໄປ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"ກັບຄືນ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"ປິດ"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"ຫຼ້າສຸດ"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"ການແຈ້ງເຕືອນ"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ການຕັ້ງຄ່າດ່ວນ"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"ແຖບໜ້າວຽກ"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ແຖບການນຳທາງ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ຍ້າຍໄປຊ້າຍ/ເທິງ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ຍ້າຍໄປຂວາ/ລຸ່ມ"</string> </resources> diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml index b60146f35d..56a5d08e3e 100644 --- a/quickstep/res/values-lt/strings.xml +++ b/quickstep/res/values-lt/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Mokymo programa: <xliff:g id="CURRENT">%1$d</xliff:g> iš <xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Paruošta!"</string> <string name="allset_hint" msgid="2384632994739392447">"Perbraukite aukštyn, kad grįžtumėte į pagrindinį ekraną"</string> - <string name="allset_description" msgid="6350320429953234580">"Esate pasiruošę pradėti naudoti telefoną"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Esate pasiruošę pradėti naudoti planšetinį kompiuterį"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Norėdami eiti į pagrindinį ekraną, palieskite pagrindinio ekrano mygtuką"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Esate pasirengę pradėti naudoti <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"įrenginys"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Sistemos naršymo nustatymai"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Bendrinti"</string> <string name="action_screenshot" msgid="8171125848358142917">"Ekrano kopija"</string> <string name="action_split" msgid="2098009717623550676">"Išskaidymo režimas"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Pal. kitą progr., kad gal. naud. išsk. ekr. rež."</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Programoje nepalaikomas išskaidyto ekrano režimas."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Išskaidyto ekrano režimą naudokite kita programa"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Jūsų organizacijoje arba naudojant šią programą neleidžiama atlikti šio veiksmo"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Praleisti naršymo mokymo programą?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Tai galėsite rasti vėliau programoje „<xliff:g id="NAME">%1$s</xliff:g>“"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Atšaukti"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Praleisti"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Pasukti ekraną"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Užduočių juostos mokomoji informacija"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Užduočių juostos patarimai rodomi"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Užduočių juostos patarimai uždaryti"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Naudokite užduočių juostą, kad gal. perjungti programas"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Nuvilkite į šoną, kad gal. vienu metu naudoti dvi programas"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Palieskite ir palaikykite, kad paslėptumėte užduočių juostą"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Nuvilkite į šoną, kad vienu metu naudotumėte dvi programas"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Trumpai perbraukite, kad būtų rodoma užduočių juosta"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Užduočių juostoje siūlomos programos pagal jūsų veiklą"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Kitas"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Atgal"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Uždaryti"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Naujausi"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Pranešimai"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Spartieji nustatymai"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Užduočių juosta"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Naršymo juosta"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Perkelti aukštyn, kairėn"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Perkelti žemyn, dešinėn"</string> </resources> diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml index d3c3b80cad..da911c1378 100644 --- a/quickstep/res/values-lv/strings.xml +++ b/quickstep/res/values-lv/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"<xliff:g id="CURRENT">%1$d</xliff:g>. mācību darbība no <xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Gatavs!"</string> <string name="allset_hint" msgid="2384632994739392447">"Velciet augšup, lai pārietu uz sākuma ekrānu."</string> - <string name="allset_description" msgid="6350320429953234580">"Varat sākt izmantot savu tālruni"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Varat sākt izmantot savu planšetdatoru"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Pieskarieties pogai Sākums, lai dotos uz sākuma ekrānu"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Varat sākt izmantot savu ierīci (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string> + <string name="default_device_name" msgid="6660656727127422487">"ierīce"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Sistēmas navigācijas iestatījumi"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Kopīgot"</string> <string name="action_screenshot" msgid="8171125848358142917">"Veikt ekrānuzņēmumu"</string> <string name="action_split" msgid="2098009717623550676">"Sadalīt"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Piesk. citai lietotnei, lai izm. ekrāna sadalīšanu"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Lietotne vai jūsu organizācija neatļauj veikt šo darbību."</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vai izlaist navigācijas mācības?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Varēsiet to vēlāk atrast lietotnē <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Atcelt"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Izlaist"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Pagriezt ekrānu"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informācija par uzdevumu joslu"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Tika atvērta uzdevumjoslas apmācība"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Tika aizvērta uzdevumjoslas apmācība"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Izmantojiet uzdevumjoslu, lai pārslēgtu lietotnes."</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Velciet uz malu, lai izmantotu divas lietotnes vienlaikus."</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pieskarieties un turiet, lai paslēptu uzdevumjoslu."</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Velciet uz malu, lai izmantotu divas lietotnes vienlaikus"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Īsi velciet augšup, lai skatītu uzdevumu joslu"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Uzdevumu joslā tiek rādītas lietotnes, ņemot vērā lietojumu"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Tālāk"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Atpakaļ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Aizvērt"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Nesenie"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Paziņojumi"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ātrie iestatīj."</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Uzdevumu josla"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigācijas josla"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string> </resources> diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml index 7ac9ad0f9e..9deb0dcde3 100644 --- a/quickstep/res/values-mk/strings.xml +++ b/quickstep/res/values-mk/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Упатство <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Готово!"</string> <string name="allset_hint" msgid="2384632994739392447">"Повлечете нагоре за да појдете на почетниот екран"</string> - <string name="allset_description" msgid="6350320429953234580">"Спремни сте да почнете да го користите телефонот"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Спремни сте да почнете да го користите таблетот"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Допрете го копчето за почетен екран за да одите на почетниот екран"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Подготвени сте да почнете да го користите вашиот <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"уред"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Поставки за системска навигација"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Сподели"</string> <string name="action_screenshot" msgid="8171125848358142917">"Слика од екранот"</string> <string name="action_split" msgid="2098009717623550676">"Раздели"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Допрете друга апликација за да користите поделен екран"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Апликацијата не поддржува поделен екран."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Изберете друга апликација за да користите поделен екран"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Апликацијата или вашата организација не го дозволува дејствово"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Да се прескокне упатството за навигација?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ова може да го најдете подоцна во апликацијата <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Откажи"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескокни"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте го екранот"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Обука за лентата со задачи"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Се појави лентата за задачи за образование"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Затворена е лентата за задачи за образование"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Префрлувајте се меѓу апликации преку лентата за задачи"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Повлечете кон страната за да користите две апликации одеднаш"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Допрете и задржете за да се сокрие лентата за задачи"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Повлечете кон страната за да користите две апликации одеднаш"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Кратко повлечете нагоре за да се прикаже лентата со задачи"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Лентата со задачи предложува апликации според вашата рутина"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Следно"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Неодамнешни"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Известувања"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Брзи поставки"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Лента со задачи"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Лента за навигација"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести долу десно"</string> </resources> diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml index 90fc5138b4..bca7e350de 100644 --- a/quickstep/res/values-ml/strings.xml +++ b/quickstep/res/values-ml/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ട്യൂട്ടോറിയൽ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"എല്ലാം സജ്ജീകരിച്ചു!"</string> <string name="allset_hint" msgid="2384632994739392447">"ഹോമിലേക്ക് പോകാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string> - <string name="allset_description" msgid="6350320429953234580">"ഫോൺ ഉപയോഗിച്ച് തുടങ്ങാൻ നിങ്ങൾ തയ്യാറാണ്"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"ടാബ്ലെറ്റ് ഉപയോഗിച്ച് തുടങ്ങാൻ നിങ്ങൾ തയ്യാറാണ്"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"നിങ്ങളുടെ ഹോം സ്ക്രീനിലേക്ക് പോകാൻ ഹോം ബട്ടൺ ടാപ്പ് ചെയ്യുക"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"നിങ്ങൾക്ക് <xliff:g id="DEVICE">%1$s</xliff:g> ഉപയോഗിച്ചു തുടങ്ങാം"</string> + <string name="default_device_name" msgid="6660656727127422487">"ഉപകരണം"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"സിസ്റ്റം നാവിഗേഷൻ ക്രമീകരണം"</annotation></string> <string name="action_share" msgid="2648470652637092375">"പങ്കിടുക"</string> <string name="action_screenshot" msgid="8171125848358142917">"സ്ക്രീൻഷോട്ട്"</string> <string name="action_split" msgid="2098009717623550676">"വിഭജിക്കുക"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"സ്പ്ലിറ്റ് സ്ക്രീനിനായി മറ്റൊരു ആപ്പ് ടാപ്പുചെയ്യൂ"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"സ്ക്രീൻ വിഭജന മോഡിന് മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"നാവിഗേഷൻ ട്യൂട്ടോറിയൽ ഒഴിവാക്കണോ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ആപ്പിൽ നിങ്ങൾക്ക് ഇത് പിന്നീട് കാണാനാകും"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"റദ്ദാക്കുക"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ഒഴിവാക്കുക"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"സ്ക്രീൻ റൊട്ടേറ്റ് ചെയ്യുക"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ടാസ്ക്ബാർ മാർഗ്ഗനിർദ്ദേശ വിൻഡോ"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ടാസ്ക്ക്ബാർ വിവര പാനൽ ദൃശ്യമായി"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ടാസ്ക്ക്ബാർ വിവര പാനൽ അടച്ചു"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ആപ്പുകൾ മാറാൻ ടാസ്ക്ക്ബാർ ഉപയോഗിക്കുക"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"രണ്ട് ആപ്പുകൾ ഒരുമിച്ച് ഉപയോഗിക്കാൻ അരികിലേക്ക് വലിച്ചിടുക"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ടാസ്ക്ക്ബാർ മറയ്ക്കാൻ സ്പർശിച്ച് പിടിക്കുക"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ഒരേ സമയം 2 ആപ്പുകൾ ഉപയോഗിക്കാൻ വശത്തേയ്ക്ക് വലിച്ചിടുക"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ടാസ്ക്ബാർ ദൃശ്യമാക്കാൻ മുകളിലേക്ക് ചെറുതായി സ്വൈപ്പ് ചെയ്യൂ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ടാസ്ക്ബാർ നിങ്ങളുടെ ദിനചര്യ അനുസരിച്ച് ആപ്പുകൾ നിർദ്ദേശിക്കുന്നു"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"അടുത്തത്"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"മടങ്ങുക"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"അടയ്ക്കുക"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"അടുത്തിടെയുള്ളവ"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"അറിയിപ്പുകൾ"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ദ്രുത ക്രമീകരണം"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"ടാസ്ക്ബാർ"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"നാവിഗേഷൻ ബാർ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"മുകളിലേക്കോ ഇടത്തേക്കോ നീക്കുക"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"താഴേക്കോ വലത്തേക്കോ നീക്കുക"</string> </resources> diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml index c435528b66..9ad53c2a68 100644 --- a/quickstep/res/values-mn/strings.xml +++ b/quickstep/res/values-mn/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"<xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g> практик хичээл"</string> <string name="allset_title" msgid="5021126669778966707">"Тохируулж дууслаа!"</string> <string name="allset_hint" msgid="2384632994739392447">"Нүүр хуудас руу очихын тулд дээш шударна уу"</string> - <string name="allset_description" msgid="6350320429953234580">"Та утсаа ашиглаж эхлэхэд бэлэн боллоо"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Та таблетаа ашиглаж эхлэхэд бэлэн боллоо"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Үндсэн нүүр лүүгээ очихын тулд нүүр хуудасны товчлуурыг товшино уу"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Та <xliff:g id="DEVICE">%1$s</xliff:g>-г ашиглаж эхлэхэд бэлэн боллоо"</string> + <string name="default_device_name" msgid="6660656727127422487">"төхөөрөмж"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Системийн навигацын тохиргоо"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Хуваалцах"</string> <string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string> <string name="action_split" msgid="2098009717623550676">"Хуваах"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Дэлгэц хуваахыг ашиглах бол өөр аппыг товшино уу"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Апп дэлгэцийг хуваах горимыг дэмждэггүй."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Дэлгэцийг хуваах горим ашиглах өөр апп сонгоно уу"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Энэ үйлдлийг апп эсвэл танай байгууллага зөвшөөрдөггүй"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Навигацын практик хичээлийг алгасах уу?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Та үүнийг дараа нь <xliff:g id="NAME">%1$s</xliff:g> аппаас олох боломжтой"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Цуцлах"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Алгасах"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Дэлгэцийг эргүүлэх"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Ажлын хэсгийн боловсрол"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Боловсролын ажлын талбар гарч ирсэн"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Боловсролын ажлын талбарыг хаасан"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Аппуудыг сэлгэхийн тулд талбарыг ашиглана уу"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Хоёр аппыг зэрэг ашиглахын тулд хажуу тал руу чирнэ үү"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Ажлын талбарыг нуухын тулд хүрээд удаан дарна уу"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"2 аппыг зэрэг ашиглахын тулд хажуу тийш чирнэ үү"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Ажлын хэсгийг харуулахын тулд бага зэрэг дээш шударна уу"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Ажлын хэсэг таны хэвшилд тулгуурлан аппууд санал болгодог"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Дараах"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Буцах"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Хаах"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Саяхны"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Мэдэгдэл"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Шуурхай тохиргоо"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Ажлын хэсэг"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Навигацын самбар"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Зүүн дээд хэсэг рүү зөөх"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Баруун доод хэсэг рүү зөөх"</string> </resources> diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml index fc9027133b..ab97cc9114 100644 --- a/quickstep/res/values-mr/strings.xml +++ b/quickstep/res/values-mr/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ट्यूटोरियल <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"सर्व तयार आहे!"</string> <string name="allset_hint" msgid="2384632994739392447">"होम वर जाण्यासाठी वरती स्वाइप करा"</string> - <string name="allset_description" msgid="6350320429953234580">"तुम्ही तुमचा फोन वापरण्यास सुरुवात करू शकता"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"तुम्ही तुमचा टॅबलेट वापरण्यास सुरुवात करू शकता"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"तुमच्या होम स्क्रीनवर जाण्यासाठी होम बटणावर टॅप करा"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"तुम्ही तुमचे <xliff:g id="DEVICE">%1$s</xliff:g> वापरण्यास सुरुवात करू शकता"</string> + <string name="default_device_name" msgid="6660656727127422487">"डिव्हाइस"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"सिस्टीम नेव्हिगेशन सेटिंग्ज"</annotation></string> <string name="action_share" msgid="2648470652637092375">"शेअर करा"</string> <string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string> <string name="action_split" msgid="2098009717623550676">"स्प्लिट"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"स्प्लिटस्क्रीन वापरण्यासाठी दुसऱ्या ॲपवर टॅप करा"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"अॅप हे स्प्लिट-स्क्रीनला सपोर्ट करत नाही."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप निवडा"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"अॅप किंवा तुमच्या संस्थेद्वारे ही क्रिया करण्याची अनुमती नाही"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेव्हिगेशन ट्यूटोरियल वगळायचे आहे का?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"तुम्हाला हे नंतर <xliff:g id="NAME">%1$s</xliff:g> ॲपमध्ये मिळेल"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द करा"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"वगळा"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रीन फिरवा"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"टास्कबारशी संबंधित माहिती"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबारशी संबंधित माहिती देणारे पॅनल उघडले आहे"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबारशी संबंधित माहिती देणारे पॅनल बंद केले आहे"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ॲप्स स्विच करण्यासाठी टास्कबार वापरा"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"दोन ॲप्स एकत्र वापरण्यासाठी, त्यांना बाजूला नेऊन ड्रॅग करा"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार लपवण्यासाठी स्पर्श करा आणि धरून ठेवा"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"दोन ॲप्स एकत्र वापरण्यासाठी, ती बाजूला ड्रॅग करा"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"टास्कबार दाखवण्यासाठी थोडे वरती स्वाइप करा"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"टास्कबार हे तुमच्या दिनक्रमानुसार अॅप्स सुचवते"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"पुढे"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"मागे जा"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करा"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"अलीकडील"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"सूचना"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"क्विक सेटिंग्ज"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेव्हिगेशन बार"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सर्वात वरती/डावीकडे हलवा"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"तळाशी/उजवीकडे हलवा"</string> </resources> diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml index 5d3f4a8896..b7e82d0009 100644 --- a/quickstep/res/values-ms/strings.xml +++ b/quickstep/res/values-ms/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Siap!"</string> <string name="allset_hint" msgid="2384632994739392447">"Leret ke atas untuk kembali ke Laman Utama"</string> - <string name="allset_description" msgid="6350320429953234580">"Anda sudah sedia untuk mula menggunakan telefon anda"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Anda bersedia untuk mula menggunakan tablet anda"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Ketik butang skrin utama untuk pergi ke skrin utama anda"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Anda sudah sedia untuk mula menggunakan <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string> + <string name="default_device_name" msgid="6660656727127422487">"peranti"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Tetapan navigasi sistem"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Kongsi"</string> <string name="action_screenshot" msgid="8171125848358142917">"Tangkapan skrin"</string> <string name="action_split" msgid="2098009717623550676">"Pisah"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Ketik apl lain untuk menggunakan skrin pisah"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Apl tidak menyokong skrin pisah."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih apl lain untuk menggunakan skrin pisah"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak dibenarkan oleh apl atau organisasi anda"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Langkau tutorial navigasi?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Anda boleh mendapatkan tutorial ini kemudian dalam apl <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Batal"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Langkau"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Putar skrin"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Pendidikan bar tugas"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Pendidikan bar tugas muncul"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Pendidikan bar tugas ditutup"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gunakan bar tugas untuk menukar apl"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Seret ke tepi untuk menggunakan dua apl serentak"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Sentuh & tahan untuk menyembunyikan bar tugas"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Seret ke tepi untuk menggunakan 2 apl serentak"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Leret pendek ke atas untuk menunjukkan bar tugas"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Bar tugas mencadangkan apl berdasarkan rutin anda"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Seterusnya"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Kembali"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Terbaharu"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Pemberitahuan"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Tetapan Pantas"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Bar Tugas"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Bar navigasi"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Alihkan ke bawah/kanan"</string> </resources> diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml index 8f6af710ee..a5100f1d60 100644 --- a/quickstep/res/values-my/strings.xml +++ b/quickstep/res/values-my/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ရှင်းလင်းပို့ချချက် <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"အားလုံး အဆင်သင့်ပါ။"</string> <string name="allset_hint" msgid="2384632994739392447">"ပင်မစာမျက်နှာသို့သွားရန် အပေါ်သို့ ပွတ်ဆွဲပါ"</string> - <string name="allset_description" msgid="6350320429953234580">"သင့်ဖုန်း စသုံးရန် အသင့်ဖြစ်ပါပြီ"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"သင့်တက်ဘလက်ကို စသုံးရန် အသင့်ဖြစ်ပါပြီ"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ပင်မစာမျက်နှာသို့ သွားရန် ပင်မခလုတ်ကို တို့ပါ"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> ကို စသုံးရန် အသင့်ဖြစ်ပါပြီ"</string> + <string name="default_device_name" msgid="6660656727127422487">"စက်"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"စနစ် လမ်းညွှန် ဆက်တင်များ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"မျှဝေရန်"</string> <string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string> <string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"မျက်နှာပြင်ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"အက်ပ်တွင် မျက်နှာပြင် ခွဲ၍ပြသခြင်း သုံး၍မရပါ။"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"မျက်နှာပြင်ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ဤလုပ်ဆောင်ချက်ကို အက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"လမ်းညွှန်ခြင်း ရှင်းလင်းပို့ချချက်ကို ကျော်မလား။"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"၎င်းကို နောက်မှ <xliff:g id="NAME">%1$s</xliff:g> အက်ပ်တွင် ရှာနိုင်သည်"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"မလုပ်တော့"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ကျော်ရန်"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"ဖန်သားပြင်လှည့်ရန်"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"လုပ်ဆောင်စရာဘား ပညာပေး"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ပညာရေး လုပ်ဆောင်စရာဘား ပြထားသည်"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ပညာရေး လုပ်ဆောင်စရာဘား ပိတ်ထားသည်"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"အက်ပ်များပြောင်းရန် လုပ်ဆောင်စရာဘားကို သုံးပါ"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"အက်ပ်နှစ်ခု တစ်ပြိုင်တည်းသုံးရန် တစ်ဖက်သို့ ဖိဆွဲပါ"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"လုပ်ဆောင်စရာဘားကို ဖျောက်ရန် ထိပြီးဖိထားနိုင်သည်"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"အက်ပ် ၂ ခု တစ်ပြိုင်တည်းသုံးရန် ဘေးဖက်သို့ ဖိဆွဲပါ"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"လုပ်ဆောင်စရာဘားပြရန် အမြန် အပေါ်ပွတ်ဆွဲပါ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ပုံမှန်အစီအစဉ်ပေါ် အခြေခံ၍ လုပ်ဆောင်စရာဘားက အက်ပ်အကြံပြုသည်"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"ရှေ့သို့"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"နောက်သို့"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"ပိတ်ရန်"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"လတ်တလောများ"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"အကြောင်းကြားချက်"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"အမြန်ဆက်တင်များ"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"လုပ်ဆောင်စရာဘား"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"လမ်းညွှန်ဘား"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"အောက်ခြေ/ညာဘက်သို့ ရွှေ့ရန်"</string> </resources> diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml index eff2e3ca92..ce7634b632 100644 --- a/quickstep/res/values-nb/strings.xml +++ b/quickstep/res/values-nb/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Veiledning <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Alt er klart!"</string> <string name="allset_hint" msgid="2384632994739392447">"Sveip opp for å gå til startskjermen"</string> - <string name="allset_description" msgid="6350320429953234580">"Du er klar til å begynne å bruke telefonen"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Du er klar til å begynne å bruke nettbrettet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Trykk på hjemknappen for å gå til startskjermen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Nå kan du bruke <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"enheten"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Innstillinger for systemnavigasjon"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Del"</string> <string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string> <string name="action_split" msgid="2098009717623550676">"Del opp"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Trykk på en annen app for å bruke delt skjerm"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Appen støtter ikke delt skjerm."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Velg en annen app for å bruke delt skjerm"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisasjonen din tillater ikke denne handlingen"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du hoppe over navigeringsveiledningen?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du kan finne dette i <xliff:g id="NAME">%1$s</xliff:g>-appen senere"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Avbryt"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Hopp over"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotér skjermen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Veiledning for oppgavelinjen"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Opplæringen for oppgavelinjen vises"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Opplæringen for oppgavelinjen er lukket"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Bruk oppgavelinjen for å bytte app"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Dra til siden for å bruke to apper samtidig"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Trykk og hold for å skjule oppgavelinjen"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Dra til siden for å bruke to apper samtidig"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Kort sveip opp for å vise oppgavelinjen"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Oppgavelinjen foreslår apper basert på rutinene dine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Neste"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Tilbake"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Lukk"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Nylige"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Varsler"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hurtiginnst."</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Oppgavelinje"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasjonsrad"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string> </resources> diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml index 3a23567b74..b984de8102 100644 --- a/quickstep/res/values-ne/strings.xml +++ b/quickstep/res/values-ne/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ट्युटोरियल <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"सबै तयार भयो!"</string> <string name="allset_hint" msgid="2384632994739392447">"होममा जान माथितिर स्वाइप गर्नुहोस्"</string> - <string name="allset_description" msgid="6350320429953234580">"तपाईं आफ्नो फोन चलाउन थाल्न सक्नुहुन्छ"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"तपाईं अब आफ्नो ट्याब्लेट चलाउन थाल्न सक्नुहुन्छ"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"आफ्नो होम स्क्रिनमा जान होम बटनमा ट्याप गर्नुहोस्"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"तपाईं अब आफ्नो <xliff:g id="DEVICE">%1$s</xliff:g> चलाउन थाल्न सक्नुहुन्छ"</string> + <string name="default_device_name" msgid="6660656727127422487">"डिभाइस"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"सिस्टम नेभिगेसनसम्बन्धी सेटिङ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"सेयर गर्नुहोस्"</string> <string name="action_screenshot" msgid="8171125848358142917">"स्क्रिनसट"</string> <string name="action_split" msgid="2098009717623550676">"स्प्लिट गर्नुहोस्"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"स्प्लिटक्रिन प्रयोग गर्न अर्को एपमा ट्याप गर्नुहोस्"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"यो एपको स्क्रिन विभाजन गर्न मिल्दैन।"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेभिगेसन ट्युटोरियल स्किप गर्ने हो?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"तपाईं पछि <xliff:g id="NAME">%1$s</xliff:g> नामक एपमा गई यो ट्युटोरियल भेट्टाउन सक्नुहुन्छ"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द गर्नुहोस्"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"स्किप गर्नु…"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रिन घुमाउनुहोस्"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"टास्कबार एजुकेसन"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार एजुकेसन देखिएको छ"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबार एजुकेसन बन्द गरिएको छ"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"एउटा एपबाट अर्को एपमा जान टास्कबार प्रयोग गर्नुहोस्"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"टास्कबार छेउतिर ड्र्याग गरेर एकै पटक दुई वटा एप चलाउनुहोस्"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार लुकाउन टास्कबार थिचिराख्नुहोस्"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"टास्कबार छेउतिर ड्र्याग गरेर एकै पटक २ वटा एप चलाउनुहोस्"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"टास्कबार देखाउन माथितिर थोरै स्वाइप गर्नुहोस्"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"टास्कबारले तपाईंको रुटिनका आधारमा एपसम्बन्धी सुझाव देखाउँछ"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"अर्को"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"पछाडि"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"बन्द गर्नुहोस्"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"हालसालैका बटनहरू"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"सूचनाहरू"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"द्रुत सेटिङ"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"टास्कबार"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेभिगेसन बार"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string> </resources> diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml index 650e3403d0..ad207c0734 100644 --- a/quickstep/res/values-nl/strings.xml +++ b/quickstep/res/values-nl/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Klaar"</string> <string name="allset_hint" msgid="2384632994739392447">"Swipe omhoog om naar het startscherm te gaan"</string> - <string name="allset_description" msgid="6350320429953234580">"Je bent klaar om je telefoon te gebruiken"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Je bent klaar om je tablet te gebruiken"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tik op de startknop om naar je startscherm te gaan"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Je bent klaar om je <xliff:g id="DEVICE">%1$s</xliff:g> te gebruiken"</string> + <string name="default_device_name" msgid="6660656727127422487">"apparaat"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Navigatie-instellingen van systeem"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Delen"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Splitsen"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Tik op nog een app om je scherm te splitsen"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App ondersteunt geen gesplitst scherm."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Kies andere app om gesplitst scherm te gebruiken"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Deze actie wordt niet toegestaan door de app of je organisatie"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigatietutorial overslaan?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Je vindt dit later terug in de app <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuleren"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Overslaan"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Scherm draaien"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Taakbalk Onderwijs"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Uitleg van taakbalk geopend"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Uitleg van taakbalk gesloten"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gebruik de taakbalk om van app te wisselen"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Sleep naar de zijkant om 2 apps tegelijk te gebruiken"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tik en houd vast om de taakbalk te verbergen"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Sleep naar de zijkant om 2 apps tegelijk te gebruiken"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Swipe kort omhoog om de taakbalk te bekijken"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"De taakbalk stelt apps voor op basis van je routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Volgende"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Terug"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Sluiten"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recent"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Meldingen"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Snelle instellingen"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taakbalk"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatiebalk"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Naar boven/links verplaatsen"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Naar beneden/rechts verplaatsen"</string> </resources> diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml index 5016399d95..2f0614c002 100644 --- a/quickstep/res/values-or/strings.xml +++ b/quickstep/res/values-or/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ଟ୍ୟୁଟୋରିଆଲ୍ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"ସମ୍ପୂର୍ଣ୍ଣ ଭାବେ ପ୍ରସ୍ତୁତ!"</string> <string name="allset_hint" msgid="2384632994739392447">"ହୋମକୁ ଯିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string> - <string name="allset_description" msgid="6350320429953234580">"ଆପଣ ଆପଣଙ୍କ ଫୋନ୍ ବ୍ୟବହାର କରିବା ପାଇଁ ପ୍ରସ୍ତୁତ ଅଛନ୍ତି"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"ଆପଣ ଆପଣଙ୍କ ଟାବଲେଟ ବ୍ୟବହାର କରିବା ଆରମ୍ଭ କରିବାକୁ ପ୍ରସ୍ତୁତ ଅଛନ୍ତି"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନକୁ ଯିବା ପାଇଁ ହୋମ ବଟନରେ ଟାପ କରନ୍ତୁ"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"ଆପଣ ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g> ବ୍ୟବହାର କରିବା ଆରମ୍ଭ କରିବାକୁ ପ୍ରସ୍ତୁତ ଅଛନ୍ତି"</string> + <string name="default_device_name" msgid="6660656727127422487">"ଡିଭାଇସ"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ସିଷ୍ଟମ ନାଭିଗେସନ ସେଟିଂସ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"ସେୟାର୍ କରନ୍ତୁ"</string> <string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string> <string name="action_split" msgid="2098009717623550676">"ସ୍ପ୍ଲିଟ୍"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ସ୍ପ୍ଲିଟ-ସ୍କ୍ରିନକୁ ଆପ ସମର୍ଥନ କରେ ନାହିଁ।"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ନାଭିଗେସନ୍ ଟ୍ୟୁଟୋରିଆଲକୁ ବାଦ୍ ଦେବେ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ଆପଣ ପରେ ଏହାକୁ <xliff:g id="NAME">%1$s</xliff:g> ଆପରେ ପାଇପାରିବେ"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ବାତିଲ କରନ୍ତୁ"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ବାଦ୍ ଦିଅନ୍ତୁ"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"ସ୍କ୍ରିନ ଘୂରାନ୍ତୁ"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ଟାସ୍କବାର ଶିକ୍ଷା"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ଦେଖାଯାଇଛି"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ବନ୍ଦ ହୋଇଯାଇଛି"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ଆପଗୁଡ଼ିକୁ ସ୍ୱିଚ କରିବା ପାଇଁ ଟାସ୍କବାର ବ୍ୟବହାର କରନ୍ତୁ"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ଥରକେ ଦୁଇଟି ଆପ ବ୍ୟବହାର କରିବା ପାଇଁ ପାର୍ଶ୍ୱକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ଟାସ୍କବାରକୁ ଲୁଚାଇବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ଥରକେ 2ଟି ଆପ୍ସ ବ୍ୟବହାର କରିବା ପାଇଁ ପାର୍ଶ୍ୱକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ଟାସ୍କବାର ଦେଖାଇବା ପାଇଁ ଉପରକୁ ଅଳ୍ପ ସମୟ ସ୍ୱାଇପ କରନ୍ତୁ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ଟାସ୍କବାର ଆପଣଙ୍କ ରୁଟିନ ଆଧାରରେ ଆପ୍ସ ପରାମର୍ଶ ଦିଏ"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"ପରବର୍ତ୍ତୀ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"ପଛକୁ ଫେରନ୍ତୁ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"ବନ୍ଦ କରନ୍ତୁ"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"ବର୍ତ୍ତମାନର"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କ୍ୱିକ ସେଟିଂସ"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"ଟାସ୍କବାର"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ନାଭିଗେସନ ବାର"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ଶୀର୍ଷ/ବାମକୁ ମୁଭ କରନ୍ତୁ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ନିମ୍ନ/ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string> </resources> diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml index 7d1d2b5f66..dc9d78e571 100644 --- a/quickstep/res/values-pa/strings.xml +++ b/quickstep/res/values-pa/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ਟਿਊਟੋਰੀਅਲ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"ਪੂਰੀ ਤਰ੍ਹਾਂ ਤਿਆਰ!"</string> <string name="allset_hint" msgid="2384632994739392447">"ਹੋਮ \'ਤੇ ਜਾਣ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string> - <string name="allset_description" msgid="6350320429953234580">"ਤੁਸੀਂ ਆਪਣਾ ਫ਼ੋਨ ਵਰਤਣ ਲਈ ਤਿਆਰ ਹੋ"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"ਤੁਸੀਂ ਆਪਣਾ ਟੈਬਲੈੱਟ ਵਰਤਣ ਲਈ ਤਿਆਰ ਹੋ"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਜਾਣ ਲਈ ਹੋਮ ਬਟਨ \'ਤੇ ਟੈਪ ਕਰੋ"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"ਤੁਸੀਂ ਆਪਣਾ <xliff:g id="DEVICE">%1$s</xliff:g> ਵਰਤਣ ਲਈ ਤਿਆਰ ਹੋ"</string> + <string name="default_device_name" msgid="6660656727127422487">"ਡੀਵਾਈਸ"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਸੈਟਿੰਗਾਂ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"ਸਾਂਝਾ ਕਰੋ"</string> <string name="action_screenshot" msgid="8171125848358142917">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string> <string name="action_split" msgid="2098009717623550676">"ਸਪਲਿਟ"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ਕੀ ਨੈਵੀਗੇਸ਼ਨ ਟਿਊਟੋਰੀਅਲ ਨੂੰ ਛੱਡਣਾ ਹੈ?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ਤੁਸੀਂ ਇਸਨੂੰ ਬਾਅਦ ਵਿੱਚ <xliff:g id="NAME">%1$s</xliff:g> ਐਪ ਵਿੱਚ ਲੱਭ ਸਕਦੇ ਹੋ"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ਰੱਦ ਕਰੋ"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ਛੱਡੋ"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"ਸਕ੍ਰੀਨ ਘੁਮਾਓ"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ਟਾਸਕਬਾਰ ਸਿੱਖਿਆ"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਦਿਖਾਇਆ ਗਿਆ"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ਐਪਾਂ ਸਵਿੱਚ ਕਰਨ ਲਈ ਟਾਸਕਬਾਰ ਵਰਤੋ"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ਇੱਕ ਵਾਰ ਵਿੱਚ ਦੋ ਐਪਾਂ ਵਰਤਣ ਲਈ ਉਨ੍ਹਾਂ ਨੂੰ ਸਾਈਡ ਵੱਲ ਘਸੀਟੋ"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ਟਾਸਕਬਾਰ ਨੂੰ ਲੁਕਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ਇੱਕ ਵਾਰ ਵਿੱਚ 2 ਐਪਾਂ ਵਰਤਣ ਲਈ ਉਨ੍ਹਾਂ ਨੂੰ ਸਾਈਡ ਵੱਲ ਘਸੀਟੋ"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ ਥੋੜ੍ਹਾ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ਟਾਸਕਬਾਰ ਤੁਹਾਡੇ ਨਿਯਮਬੱਧ ਕੰਮ ਮੁਤਾਬਕ ਐਪਾਂ ਦਾ ਸੁਝਾਅ ਦਿੰਦਾ ਹੈ"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"ਅੱਗੇ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"ਪਿੱਛੇ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"ਬੰਦ ਕਰੋ"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"ਹਾਲੀਆ"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"ਸੂਚਨਾਵਾਂ"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"ਟਾਸਕਬਾਰ"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ਨੈਵੀਗੇਸ਼ਨ ਵਾਲੀ ਪੱਟੀ"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ਸਿਖਰਲੇ/ਖੱਬੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ਹੇਠਾਂ/ਸੱਜੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string> </resources> diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml index 3c73de487f..08fc4e2eac 100644 --- a/quickstep/res/values-pl/strings.xml +++ b/quickstep/res/values-pl/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Samouczek <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Wszystko gotowe"</string> <string name="allset_hint" msgid="2384632994739392447">"Aby przejść na ekran główny, przesuń palcem w górę"</string> - <string name="allset_description" msgid="6350320429953234580">"Teraz możesz zacząć używać telefonu"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Teraz możesz zacząć używać tabletu"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Kliknij przycisk ekranu głównego, aby otworzyć ekran główny"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Teraz możesz zacząć używać urządzenia <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"urządzenie"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ustawienia nawigacji w systemie"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Udostępnij"</string> <string name="action_screenshot" msgid="8171125848358142917">"Zrzut ekranu"</string> <string name="action_split" msgid="2098009717623550676">"Podziel"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Kliknij drugą aplikację, aby podzielić ekran"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacja nie obsługuje podzielonego ekranu."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Wybierz drugą aplikację, aby podzielić ekran"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Nie możesz wykonać tego działania, bo nie zezwala na to aplikacja lub Twoja organizacja"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Pominąć samouczek nawigacji?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Znajdziesz to później w aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anuluj"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Pomiń"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Obróć ekran"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informacje o pasku aplikacji"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Wskazówki na temat paska zadań zostały wyświetlone"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Wskazówki na temat paska zadań zostały zamknięte"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Używaj paska zadań, aby przełączać aplikacje"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Przeciągnij w bok, aby używać 2 aplikacji jednocześnie"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Naciśnij i przytrzymaj, aby ukryć pasek zadań"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Przeciągnij w bok, aby używać 2 aplikacji jednocześnie"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Przesuń palcem krótko w górę, aby wyświetlić pasek aplikacji"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Aplikacje na pasku są dobierane na podstawie Twojej rutyny"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Dalej"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Wstecz"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Zamknij"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Ostatnie"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Powiadomienia"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Szybkie ustawienia"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Pasek aplikacji"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Pasek nawigacyjny"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Przesuń w górny lewy róg"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Przesuń w dolny prawy róg"</string> </resources> diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml index 5e01dc187f..b663528b07 100644 --- a/quickstep/res/values-pt-rPT/strings.xml +++ b/quickstep/res/values-pt-rPT/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string> <string name="allset_hint" msgid="2384632994739392447">"Deslize rapidamente para cima para aceder ao ecrã principal"</string> - <string name="allset_description" msgid="6350320429953234580">"Já pode começar a utilizar o seu telemóvel"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Já pode começar a usar o seu tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão página inicial para aceder ao ecrã principal"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Já pode começar a usar o seu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Definições de navegação do sistema"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Partilhar"</string> <string name="action_screenshot" msgid="8171125848358142917">"Fazer captura de ecrã"</string> <string name="action_split" msgid="2098009717623550676">"Dividir"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Toque noutra app para utilizar o ecrã dividido"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"A app não é compatível com o ecrã dividido."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolher outra app para usar o ecrã dividido"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Esta ação não é permitida pela app ou a sua entidade."</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorar o tutorial de navegação?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Pode encontrar isto mais tarde na app <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ignorar"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rodar ecrã"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Educação da Barra de tarefas"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Informação da barra de tarefas apresentada"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Informação da barra de tarefas fechada"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Utilize a barra de ferramentas para alternar entre apps"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arraste para o lado para utilizar duas apps em simultâneo"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Toque sem soltar para ocultar a barra de tarefas"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Arraste para o lado para usar duas apps em simultâneo"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Deslize rápido curto para cima para ver a barra de tarefas"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"A barra de tarefas sugere apps baseadas na sua rotina"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Anterior"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recentes"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificações"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Definiç. rápidas"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para a parte superior esquerda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para a part superior direita"</string> </resources> diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml index fad2170e85..fbd5b782b8 100644 --- a/quickstep/res/values-pt/strings.xml +++ b/quickstep/res/values-pt/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string> <string name="allset_hint" msgid="2384632994739392447">"Deslize para cima para acessar a tela inicial"</string> - <string name="allset_description" msgid="6350320429953234580">"Você já pode começar a usar seu smartphone"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Você já pode começar a usar seu tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão home para ir para a tela inicial"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Você já pode começar a usar seu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configurações de navegação do sistema"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Compartilhar"</string> <string name="action_screenshot" msgid="8171125848358142917">"Capturar tela"</string> <string name="action_split" msgid="2098009717623550676">"Dividir"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Toque em outro app para dividir a tela"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"O app não tem suporte para a divisão de tela."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolha outro app para usar na tela dividida"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Essa ação não é permitida pelo app ou pela organização"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Pular o tutorial de navegação?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Veja o tutorial mais tarde no app <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Pular"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar a tela"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informações sobre a barra de tarefas"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"As dicas sobre a barra de tarefas foram abertas"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"As dicas sobre a barra de tarefas foram fechadas"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use a barra de tarefas para alternar entre apps"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arraste para o lado e use dois apps ao mesmo tempo"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantenha a barra de tarefas pressionada para ocultá-la"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Arraste para o lado para usar dois apps ao mesmo tempo"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Deslize para cima para mostrar a barra de tarefas"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"A barra de tarefas sugere apps com base na sua rotina"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Próxima"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Voltar"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recentes"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificações"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. rápidas"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Barra de tarefas"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para cima/para a esquerda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para baixo/para a direita"</string> </resources> diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml index 8b8c187033..a324d4a4d5 100644 --- a/quickstep/res/values-ro/strings.xml +++ b/quickstep/res/values-ro/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorialul <xliff:g id="CURRENT">%1$d</xliff:g> / <xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Gata!"</string> <string name="allset_hint" msgid="2384632994739392447">"Glisează în sus pentru a accesa ecranul de pornire"</string> - <string name="allset_description" msgid="6350320429953234580">"Ești gata să folosești telefonul"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Ești gata să folosești tableta"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Atinge butonul ecran de pornire ca să accesezi ecranul de pornire"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Ești gata să folosești <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"dispozitivul"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Setările de navigare ale sistemului"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Distribuie"</string> <string name="action_screenshot" msgid="8171125848358142917">"Captură de ecran"</string> <string name="action_split" msgid="2098009717623550676">"Împărțit"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Atinge altă aplicație pentru ecranul împărțit"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplicația nu acceptă ecranul împărțit."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Alege altă aplicație pentru ecranul împărțit"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Această acțiune nu este permisă de aplicație sau de organizația ta"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Omiți tutorialul de navigare?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Îl poți găsi mai târziu în aplicația <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anulează"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omite"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotește ecranul"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informații despre bara de activități"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Panoul cu informații despre bara de activități s-a afișat"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Panoul cu informații despre bara de activități s-a închis"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Folosește bara de activități ca să comuți între aplicații"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Trage în lateral ca să folosești două aplicații deodată"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Atinge lung oricând pentru a ascunde bara de activități"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Trage în lateral ca să folosești două aplicații deodată"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Glisează scurt în sus pentru a afișa bara de activități"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Bara de activități sugerează aplicații în funcție de rutina ta"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Înainte"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Înapoi"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Închide"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Recente"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificări"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Setări rapide"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Bară de activități"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Bară de navigare"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mută în dreapta jos"</string> </resources> diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml index e078ba0aad..d1c2e8d9dd 100644 --- a/quickstep/res/values-ru/strings.xml +++ b/quickstep/res/values-ru/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Руководство (шаг <xliff:g id="CURRENT">%1$d</xliff:g> из <xliff:g id="TOTAL">%2$d</xliff:g>)"</string> <string name="allset_title" msgid="5021126669778966707">"Готово!"</string> <string name="allset_hint" msgid="2384632994739392447">"Чтобы перейти на главный экран, проведите вверх."</string> - <string name="allset_description" msgid="6350320429953234580">"Теперь вы можете использовать телефон."</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Теперь вы можете использовать планшет."</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Нажмите кнопку главного экрана, чтобы открыть его."</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Теперь вы можете использовать <xliff:g id="DEVICE">%1$s</xliff:g>."</string> + <string name="default_device_name" msgid="6660656727127422487">"устройство"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Системные настройки навигации"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Поделиться"</string> <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string> <string name="action_split" msgid="2098009717623550676">"Разделить"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Для разделения экрана нажмите на другое приложение."</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Приложение не поддерживает разделение экрана."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Выберите другое приложение для разделения экрана."</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Это действие заблокировано приложением или организацией."</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустить руководство по жестам?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Его можно найти в приложении \"<xliff:g id="NAME">%1$s</xliff:g>\"."</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Отмена"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропустить"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Повернуть экран"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Обучение по работе с панелью задач"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Обучение по работе с панелью задач показано"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Обучение по работе с панелью задач скрыто"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Используйте панель задач, чтобы переключать приложения."</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Перетащите в сторону, чтобы использовать два приложения сразу."</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Чтобы скрыть панель задач, коснитесь ее и удерживайте."</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Перетащите в сторону, чтобы использовать 2 приложения сразу."</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Чтобы открыть панель задач, быстро проведите снизу вверх."</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Панель задач предлагает приложения, учитывая ваши действия."</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Далее"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыть"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Недавние"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Уведомления"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Быстрые настройки"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Панель задач"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панель навигации"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Переместить вверх или влево"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Переместить вниз или вправо"</string> </resources> diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml index f890548f58..e2f0944902 100644 --- a/quickstep/res/values-si/strings.xml +++ b/quickstep/res/values-si/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"නිබන්ධනය <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"සියල්ල සූදානම්!"</string> <string name="allset_hint" msgid="2384632994739392447">"මුල් පිටුවට යාමට ඉහළට ස්වයිප් කරන්න"</string> - <string name="allset_description" msgid="6350320429953234580">"ඔබ ඔබගේ දුරකථනය භාවිත කිරීම පටන් ගැනීමට සූදානම්"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"ඔබ ඔබගේ ටැබ්ලටය භාවිත කිරීම පටන් ගැනීමට සූදානම්"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"ඔබේ මුල් තිරය වෙත යාමට මුල් පිටුව බොත්තම තට්ටු කරන්න"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"ඔබ ඔබේ <xliff:g id="DEVICE">%1$s</xliff:g> භාවිත කිරීම පටන් ගැනීමට සූදානම්"</string> + <string name="default_device_name" msgid="6660656727127422487">"උපාංගය"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"පද්ධති සංචාලන සැකසීම්"</annotation></string> <string name="action_share" msgid="2648470652637092375">"බෙදා ගන්න"</string> <string name="action_screenshot" msgid="8171125848358142917">"තිර රුව"</string> <string name="action_split" msgid="2098009717623550676">"බෙදන්න"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"බෙදුම් තිරය භාවිත කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"යෙදුම බෙදුම් තිරය සඳහා සහාය නොදක්වයි."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"බෙදීම් තිරය භාවිතා කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"මෙම ක්රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"නිබන්ධනය සංචාලනය මඟ හරින්නද?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ඔබට මෙය පසුව <xliff:g id="NAME">%1$s</xliff:g> යෙදුම තුළ සොයා ගත හැකිය"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"අවලංගු කරන්න"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"මඟ හරින්න"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"තිරය කරකවන්න"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"කාර්ය තීරු අධ්යාපනය"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"කාර්ය තීරු අධ්යාපනය දිස් විය"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"කාර්ය තීරු අධ්යාපනය වසා ඇත"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"යෙදුම් මාරු කිරීමට කාර්ය තීරුව භාවිත කරන්න"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"එකවර යෙදුම් දෙකක් භාවිතා කිරීමට පැත්තට අදින්න"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"කාර්ය තීරුව සැඟවීමට ස්පර්ශ කර අල්ලා ගෙන සිටින්න"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"එකවර යෙදුම් 2 ක් භාවිත කිරීමට පැත්තට අදින්න"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"කාර්ය තීරුව පෙන්වීමට ඉහළට කෙටි ස්වයිප් කරන්න"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"කාර්ය තීරුව ඔබේ දිනචරියාව මත පදනම්ව යෙදුම් යෝජනා කරයි"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"ඊළඟ"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"ආපසු"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"වසන්න"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"මෑත"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"දැනුම්දීම්"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ඉක්මන් සැකසීම්"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"කාර්ය තීරුව"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"සංචලන තීරුව"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ඉහළ/වම වෙත ගෙන යන්න"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"පහළ/දකුණ වෙත ගෙන යන්න"</string> </resources> diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml index cdf33391ee..573c17b168 100644 --- a/quickstep/res/values-sk/strings.xml +++ b/quickstep/res/values-sk/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Návod <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Hotovo"</string> <string name="allset_hint" msgid="2384632994739392447">"Potiahnutím nahor prejdete na plochu"</string> - <string name="allset_description" msgid="6350320429953234580">"Telefón môžete začať používať"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Tablet môžete začať používať"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Na plochu prejdete klepnutím na tlačidlo plochy"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> môžete začať používať"</string> + <string name="default_device_name" msgid="6660656727127422487">"zariadenie"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavenia navigácie systémom"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Zdieľať"</string> <string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string> <string name="action_split" msgid="2098009717623550676">"Rozdeliť"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Rozdel. obrazovku spustíte klepnutím na inú aplik."</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikácia nepodporuje rozdelenú obrazovku."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Na použitie rozd. obrazovky vyberte inú aplikáciu"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikácia alebo vaša organizácia túto akciu nepovoľuje"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Chcete preskočiť návod na navigáciu?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Tento návod nájdete v aplikácii <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Zrušiť"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskočiť"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Otočiť obrazovku"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Panel vzdelávacích aplikácií"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila sa výuka k hlavnému panelu"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnému panelu bola zatvorená"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Aplikácie je možné prepínať pomocou panela úloh"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Po presunutí na stranu je možné používať dve aplikácie naraz"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Panel úloh skryjete pridržaním"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Po presunutí na stranu je možné používať dve aplikácie naraz"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Krátkym potiahnutím nahor zobrazíte panel aplikácií"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Panel aplikácií navrhuje aplikácie na základe vašich zvykov"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Ďalej"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Späť"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Zavrieť"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Nedávne"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Upozornenia"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Rýchle nastavenia"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Panel aplikácií"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigačný panel"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string> </resources> diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml index 3e7c5ce681..491b13de49 100644 --- a/quickstep/res/values-sl/strings.xml +++ b/quickstep/res/values-sl/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vadnica <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Končano"</string> <string name="allset_hint" msgid="2384632994739392447">"Povlecite navzgor za začetni zaslon"</string> - <string name="allset_description" msgid="6350320429953234580">"Pripravljeni ste, da začnete uporabljati telefon"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Pripravljeni ste, da začnete uporabljati tablični računalnik."</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Za pomik na začetni zaslon se dotaknite gumba za začetni zaslon."</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Pripravljeni ste, da začnete uporabljati <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"napravo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavitve krmarjenja po sistemu"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Deli"</string> <string name="action_screenshot" msgid="8171125848358142917">"Posnetek zaslona"</string> <string name="action_split" msgid="2098009717623550676">"Razdeli"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Za uporabo razdeljenega zaslona se dotaknite še ene aplikacije."</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacija ne podpira načina razdeljenega zaslona."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izberite drugo aplikacijo za uporabo razdeljenega zaslona."</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ali vaša organizacija ne dovoljuje tega dejanja"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite preskočiti vadnico za krmarjenje?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"To lahko pozneje najdete v aplikaciji <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Prekliči"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Sukanje zaslona"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Poučni nasveti o opravilni vrstici"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Poučni nasveti o opravilni vrstici so prikazani."</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Poučni nasveti o opravilni vrstici so zaprti."</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Za preklop aplikacij uporabite opravilno vrstico."</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Povlecite vstran za uporabo dveh aplikacij hkrati."</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pridržite, če želite opravilno vrstico skriti."</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Povlecite vstran za uporabo dveh aplikacij hkrati."</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Na kratko povlecite navzgor za prikaz opravilne vrstice."</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Opravilna vrstica predlaga aplikacije na podlagi vaših navad."</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Naprej"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Nazaj"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Zapri"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Nedavno"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Obvestila"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hitre nastavitve"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Opravilna vrstica"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Vrstica za krmarjenje"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premakni na vrh/levo"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premakni na dno/desno"</string> </resources> diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml index 04b7bc152f..d73aa4836d 100644 --- a/quickstep/res/values-sq/strings.xml +++ b/quickstep/res/values-sq/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Udhëzuesi <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Plotësisht gati!"</string> <string name="allset_hint" msgid="2384632994739392447">"Rrëshqit shpejt lart për të shkuar tek \"Ekrani bazë\""</string> - <string name="allset_description" msgid="6350320429953234580">"Je gati për të filluar përdorimin e telefonit tënd"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Je gati që të fillosh të përdorësh tabletin"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Trokit te butoni \"kreu\" për të shkuar tek ekrani bazë"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Je gati që të fillosh të përdorësh <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"pajisje"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Cilësimet e navigimit të sistemit"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Ndaj"</string> <string name="action_screenshot" msgid="8171125848358142917">"Pamja e ekranit"</string> <string name="action_split" msgid="2098009717623550676">"Ndaj"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Trokit aplikacion tjetër e përdor ekranin e ndarë"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacioni nuk mbështet ekranin e ndarë."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Zgjidh një aplikacion tjetër për të përdorur ekranin e ndarë"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Ky veprim nuk lejohet nga aplikacioni ose organizata jote"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Të kapërcehet udhëzuesi i navigimit?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Këtë mund ta gjesh më vonë tek aplikacioni \"<xliff:g id="NAME">%1$s</xliff:g>\""</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anulo"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Kapërce"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rrotullo ekranin"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Edukimi për shiritin e detyrave"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukimi i shiritit të detyrave u shfaq"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Edukimi nga shiriti i detyrave u mbyll"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Përdor shiritin e detyrave për të ndryshuar aplikacionet"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Zvarrit anash për të përdorur të dyja aplikacionet njëherësh"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Preke dhe mbaje prekur për ta fshehur shiritin e detyrave"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Zvarrit në anë për të përdorur 2 aplikacione njëherësh"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Kryej një rrëshqitje të shkurtër lart për të shfaqur shiritin e detyrave"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Shiriti i detyrave sugjeron aplikacione bazuar në rutinën tënde"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Para"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Pas"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Mbyll"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Të fundit"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Njoftimet"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Cilësimet shpejt"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Shiriti i detyrave"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Shiriti i navigimit"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string> </resources> diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml index 215fde9100..6e819abdf8 100644 --- a/quickstep/res/values-sr/strings.xml +++ b/quickstep/res/values-sr/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Водич <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Готово!"</string> <string name="allset_hint" msgid="2384632994739392447">"Превуците нагоре да бисте отворили почетни екран"</string> - <string name="allset_description" msgid="6350320429953234580">"Спремни сте да почнете да користите телефон"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Спремни сте да почнете да користите таблет"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисти ишли на почетни екран"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Спремни сте да почнете да користите <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"уређај"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Подешавања кретања кроз систем"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Дели"</string> <string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string> <string name="action_split" msgid="2098009717623550676">"Подели"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Додирните другу апликацију за подељени екран"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Апликација не подржава подељени екран."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Одаберите другу апликацију за подељени екран"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Желите да прескочите водич за кретање?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Можете да пронађете ово касније у апликацији <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Откажи"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескочи"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте екран"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Упутства на траци задатака"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Едукативно окно из траке задатака се појавило"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Едукативно окно из траке задатака је затворено"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Користите траку задатака да бисте мењали апликације"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Превуците на страну да користите две апликације одједном"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Додирните и задржите за скривање траке задатака"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Превуците на страну да бисте користили 2 апликације одједном"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Накратко превуците нагоре да бисте приказали траку задатака"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Трака задатака предлаже апликације на основу рутине"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Даље"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Недавно"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Обавештења"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Брза подешавања"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Трака задатака"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Трака за навигацију"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string> </resources> diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml index e7c0226337..bab195241c 100644 --- a/quickstep/res/values-sv/strings.xml +++ b/quickstep/res/values-sv/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Självstudie <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Klart!"</string> <string name="allset_hint" msgid="2384632994739392447">"Svep uppåt för att öppna startskärmen"</string> - <string name="allset_description" msgid="6350320429953234580">"Nu kan du börja använda telefonen"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Nu kan du börja använda surfplattan"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Tryck på hemknappen för att öppna startskärmen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Nu kan du börja använda din <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"enhet"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Systemnavigeringsinställningar"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Dela"</string> <string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string> <string name="action_split" msgid="2098009717623550676">"Delat"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Tryck på en annan app för att använda delad skärm"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Appen har inte stöd för delad skärm."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Välj en annan app för att använda delad skärm"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisationen tillåter inte den här åtgärden"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vill du hoppa över självstudierna?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du hittar det här igen i <xliff:g id="NAME">%1$s</xliff:g>-appen"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Avbryt"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Hoppa över"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotera skärmen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Aktivitetsfältsutbildning"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Information om aktivitetsfältet visades"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Information om aktivitetsfältet stängdes"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Använd aktivitetsfältet för att byta mellan appar"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Dra till sidan om du vill använda två appar samtidigt"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tryck länge för att dölja aktivitetsfältet"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Dra till sidan om du vill använda två appar samtidigt"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Svep en kort bit uppåt för att visa aktivitetsfältet"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"I aktivitetsfältet visas förslag på appar utifrån din rutin"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Nästa"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Tillbaka"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Stäng"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Senaste"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Aviseringar"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Snabbinställn."</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Aktivitetsfält"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeringsfält"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string> </resources> diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml index b1a178e9b3..f0990b3a27 100644 --- a/quickstep/res/values-sw/strings.xml +++ b/quickstep/res/values-sw/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Mafunzo ya <xliff:g id="CURRENT">%1$d</xliff:g> kati ya <xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Tayari!"</string> <string name="allset_hint" msgid="2384632994739392447">"Telezesha kidole juu ili uende kwenye skrini ya kwanza"</string> - <string name="allset_description" msgid="6350320429953234580">"Uko tayari kuanza kutumia simu yako"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Uko tayari kuanza kutumia kompyuta kibao yako"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Gusa kitufe cha ukurasa wa mwanzo ili uende kwenye skrini ya kwanza"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Uko tayari kuanza kutumia <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string> + <string name="default_device_name" msgid="6660656727127422487">"kifaa"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Mipangilio ya usogezaji kwenye mfumo"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Shiriki"</string> <string name="action_screenshot" msgid="8171125848358142917">"Picha ya skrini"</string> <string name="action_split" msgid="2098009717623550676">"Iliyogawanywa"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Gusa programu nyingine ili utumie skrini iliyogawanywa"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Programu haiwezi kutumia skrini iliyogawanywa."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chagua programu nyingine ili utumie hali ya kugawa skrini"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Kitendo hiki hakiruhusiwi na programu au shirika lako"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ungependa kuruka mafunzo ya usogezaji?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Utapata mafunzo haya baadaye katika programu ya <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ghairi"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ruka"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Zungusha skrini"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Elimu ya Upauzana"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Paneli ya elimu kwenye upau wa shughuli inaonyeshwa"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Paneli ya elimu kwenye upau wa shughuli imefungwa"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Tumia upau wa shughuli kubadilisha programu"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Buruta pembeni ili utumie programu mbili kwa wakati mmoja"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Gusa na ushikilie ili ufiche upau wa shughuli"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Buruta pembeni ili utumie programu 2 kwa wakati mmoja"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Telezesha kidole juu ili uonyeshe upauzana"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Upauzana hupendekeza programu kulingana na ratiba yako"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Endelea"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Nyuma"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Funga"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Vilivyotumika majuzi"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Arifa"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Mipangilio ya Haraka"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Upauzana"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Sehemu ya viungo muhimu"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sogeza chini/kulia"</string> </resources> diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml index 0cd9b2b700..dc10c24745 100644 --- a/quickstep/res/values-sw600dp-land/dimens.xml +++ b/quickstep/res/values-sw600dp-land/dimens.xml @@ -17,4 +17,8 @@ <resources> <!-- Overview actions --> <dimen name="overview_actions_top_margin">12dp</dimen> + + <!-- All Set page --> + <dimen name="allset_page_margin_horizontal">48dp</dimen> + </resources> diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml index cfbbf8dbf3..5899814600 100644 --- a/quickstep/res/values-sw600dp/dimens.xml +++ b/quickstep/res/values-sw600dp/dimens.xml @@ -33,4 +33,10 @@ <dimen name="overview_page_spacing">36dp</dimen> <!-- The space to the left and to the right of the "Clear all" button --> <dimen name="overview_grid_side_margin">64dp</dimen> + + <!-- All Set page --> + <dimen name="allset_page_margin_horizontal">120dp</dimen> + <dimen name="allset_page_allset_text_size">38sp</dimen> + <dimen name="allset_page_swipe_up_text_size">15sp</dimen> + </resources> diff --git a/quickstep/res/values-sw720dp/dimens.xml b/quickstep/res/values-sw720dp/dimens.xml index 284ce11582..d27561ab1d 100644 --- a/quickstep/res/values-sw720dp/dimens.xml +++ b/quickstep/res/values-sw720dp/dimens.xml @@ -33,4 +33,12 @@ <dimen name="overview_page_spacing">44dp</dimen> <!-- The space to the left and to the right of the "Clear all" button --> <dimen name="overview_grid_side_margin">64dp</dimen> + + <!-- All Set page--> + <dimen name="allset_page_allset_text_size">42sp</dimen> + <dimen name="allset_page_swipe_up_text_size">16sp</dimen> + + <!-- Transient taskbar --> + <dimen name="transient_taskbar_size">76dp</dimen> + <dimen name="transient_taskbar_icon_size">52dp</dimen> </resources> diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml index 431ae3cce5..1db0fab7d9 100644 --- a/quickstep/res/values-ta/strings.xml +++ b/quickstep/res/values-ta/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"பயிற்சி <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"அனைத்தையும் அமைத்துவிட்டீர்கள்!"</string> <string name="allset_hint" msgid="2384632994739392447">"முகப்புத் திரைக்குச் செல்ல மேல்நோக்கி ஸ்வைப் செய்யுங்கள்"</string> - <string name="allset_description" msgid="6350320429953234580">"மொபைலைப் பயன்படுத்தத் தயாராகிவிட்டீர்கள்"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"உங்கள் டேப்லெட்டைப் பயன்படுத்தத் தயாராகிவிட்டீர்கள்"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"முகப்புத் திரைக்குச் செல்வதற்கு முகப்பு பட்டனைத் தட்டவும்"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தைப் பயன்படுத்தத் தயாராகிவிட்டீர்கள்"</string> + <string name="default_device_name" msgid="6660656727127422487">"சாதனம்"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"சிஸ்டம் வழிசெலுத்தல் அமைப்புகள்"</annotation></string> <string name="action_share" msgid="2648470652637092375">"பகிர்"</string> <string name="action_screenshot" msgid="8171125848358142917">"ஸ்கிரீன்ஷாட்"</string> <string name="action_split" msgid="2098009717623550676">"பிரி"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"ஸ்பிளிட் ஸ்கிரீனுக்கு மற்றொரு ஆப்ஸைத் தட்டவும்"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"திரைப் பிரிப்பு அம்சத்தை ஆப்ஸ் ஆதரிக்கவில்லை."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"திரைப் பிரிப்பை பயன்படுத்த வேறு ஆப்ஸை தேர்வுசெய்க"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ஆப்ஸோ உங்கள் நிறுவனமோ இந்த செயலை அனுமதிப்பதில்லை"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"வழிகாட்டுதல் பயிற்சியைத் தவிர்க்கவா?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ஆப்ஸில் பிறகு இதைக் கண்டறியலாம்"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ரத்துசெய்"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"தவிர்"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"திரையைச் சுழற்றும்"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"செயல் பட்டியைப் பயன்படுத்தும் விதம்"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் காட்டப்படுகிறது"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் மூடப்பட்டது"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ஆப்ஸிற்கு இடையே மாற பணிப்பட்டியைப் பயன்படுத்தவும்"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ஒரே நேரத்தில் இரு ஆப்ஸை உபயோகிக்க பக்கவாட்டிற்கு இழுக்கவும்"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"பணிப்பட்டியை மறைக்கத் தொட்டுப் பிடிக்கவும்"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ஒரே நேரத்தில் 2 ஆப்ஸை உபயோகிக்க பக்கவாட்டிற்கு இழுக்கவும்"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"செயல் பட்டியைக் காட்டுவதற்கு மேலே சிறிது ஸ்வைப் செய்யவும்"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"உங்கள் வழக்கத்திற்கேற்ப ஆப்ஸை செயல் பட்டி பரிந்துரைக்கும்"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"அடுத்து"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"பின்செல்"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"மூடுக"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"சமீபத்தியவை"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"அறிவிப்புகள்"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"விரைவு அமைப்புகள்"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"செயல் பட்டி"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"வழிசெலுத்தல் பட்டி"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"மேலே/இடதுபுறம் நகர்த்தும்"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"கீழே/வலதுபுறம் நகர்த்தும்"</string> </resources> diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml index 7b6dedf757..c5564ddf43 100644 --- a/quickstep/res/values-te/strings.xml +++ b/quickstep/res/values-te/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ట్యుటోరియల్ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"అంతా సెట్ అయింది!"</string> <string name="allset_hint" msgid="2384632994739392447">"మొదటి స్క్రీన్కు వెళ్లడానికి పైకి స్వైప్ చేయండి"</string> - <string name="allset_description" msgid="6350320429953234580">"మీరు మీ ఫోన్ను ఉపయోగించడానికి సిద్ధంగా ఉన్నారు"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"మీరు మీ టాబ్లెట్ను ఉపయోగించడానికి సిద్ధంగా ఉన్నారు"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"మీ మొదటి స్క్రీన్కు వెళ్లడానికి హోమ్ బటన్ను ట్యాప్ చేయండి"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"మీరు ఇప్పుడు మీ <xliff:g id="DEVICE">%1$s</xliff:g>ను ఉపయోగించడం ప్రారంభించవచ్చు"</string> + <string name="default_device_name" msgid="6660656727127422487">"పరికరం"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"సిస్టమ్ నావిగేషన్ సెట్టింగ్లు"</annotation></string> <string name="action_share" msgid="2648470652637092375">"షేర్ చేయండి"</string> <string name="action_screenshot" msgid="8171125848358142917">"స్క్రీన్షాట్"</string> <string name="action_split" msgid="2098009717623550676">"స్ప్లిట్ చేయండి"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"స్క్రీన్ విభజనను ఉపయోగించడానికి మరొక యాప్ నొక్కండి"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"యాప్లో స్ప్లిట్-స్క్రీన్ పని చేయదు."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"స్ప్లిట్ స్క్రీన్ ఉపయోగానికి మరొక యాప్ ఎంచుకోండి"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ఈ చర్యను యాప్ గానీ, మీ సంస్థ గానీ అనుమతించవు"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"నావిగేషన్ ట్యుటోరియల్ను స్కిప్ చేయాలా?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> యాప్లో మీరు తర్వాత కనుగొనవచ్చు"</string> - <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"రద్దు చేయి"</string> + <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"రద్దు చేయండి"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"స్కిప్ చేయండి"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"స్క్రీన్ను తిప్పండి"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"టాస్క్బార్ ఎడ్యుకేషన్"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"టాస్క్బార్ శిక్షణకు సంబంధించిన ప్యానెల్ కనిపించింది"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"టాస్క్బార్ శిక్షణకు సంబంధించిన ప్యానెల్ మూసివేయబడింది"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"యాప్లను స్విచ్ చేయడానికి టాస్క్బార్ను ఉపయోగించండి"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ఒకేసారి రెండు యాప్లను ఉపయోగించడానికి పక్కకు లాగండి"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"టాస్క్బార్ను దాచడానికి తాకి, నొక్కి ఉంచండి"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ఒకేసారి 2 యాప్లను ఉపయోగించడానికి పక్కకు లాగండి"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"టాస్క్బార్ను చూపడానికి చిన్నగా పైకి స్వైప్ చేయండి"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"మీ రొటీన్ ఆధారంగా టాస్క్బార్ యాప్లను సూచిస్తుంది"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"తర్వాత"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"వెనుకకు"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"మూసివేయండి"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"ఇటీవలివి"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"నోటిఫికేషన్లు"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"క్విక్ సెట్టింగ్లు"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"టాస్క్బార్"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"నావిగేషన్ బార్"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ఎగువ/ఎడమ వైపునకు తరలించండి"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"దిగువ/కుడి వైపునకు తరలించండి"</string> </resources> diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml index 4d5794b8a7..7c7f44d4ee 100644 --- a/quickstep/res/values-th/strings.xml +++ b/quickstep/res/values-th/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"บทแนะนำ <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"เรียบร้อยแล้ว"</string> <string name="allset_hint" msgid="2384632994739392447">"ปัดขึ้นเพื่อไปที่หน้าแรก"</string> - <string name="allset_description" msgid="6350320429953234580">"คุณเริ่มใช้โทรศัพท์ได้แล้ว"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"คุณเริ่มใช้แท็บเล็ตได้แล้ว"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"แตะปุ่มหน้าแรกเพื่อไปที่หน้าจอหลัก"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"คุณเริ่มใช้<xliff:g id="DEVICE">%1$s</xliff:g>ได้แล้ว"</string> + <string name="default_device_name" msgid="6660656727127422487">"อุปกรณ์"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"การตั้งค่าการนำทางของระบบ"</annotation></string> <string name="action_share" msgid="2648470652637092375">"แชร์"</string> <string name="action_screenshot" msgid="8171125848358142917">"ภาพหน้าจอ"</string> <string name="action_split" msgid="2098009717623550676">"แยก"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"แตะที่แอปอื่นเพื่อใช้แบ่งหน้าจอ"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"แอปไม่รองรับการแบ่งหน้าจอ"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"เลือกแอปอื่นเพื่อใช้การแยกหน้าจอ"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ข้ามบทแนะนำการนำทางไหม"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"คุณดูบทแนะนำนี้ได้ภายหลังในแอป \"<xliff:g id="NAME">%1$s</xliff:g>\""</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ยกเลิก"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ข้าม"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"หมุนหน้าจอ"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"แถบงาน Education"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"แถบงาน Education ปรากฎขึ้น"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ปิดแถบงาน Education แล้ว"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ใช้แถบงานเพื่อเปลี่ยนแอป"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ลากไปด้านข้างเพื่อใช้ 2 แอปพร้อมกัน"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"แตะค้างไว้เพื่อซ่อนแถบงาน"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ลากไปด้านข้างเพื่อใช้ 2 แอปพร้อมกัน"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ปัดขึ้นสั้นๆ เพื่อแสดงแถบงาน"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"แถบงานจะแนะนำแอปโดยอิงตามกิจวัตรของคุณ"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"ถัดไป"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"กลับ"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"ปิด"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"ล่าสุด"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"การแจ้งเตือน"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"การตั้งค่าด่วน"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"แถบงาน"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"แถบนำทาง"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ย้ายไปที่ด้านบนหรือด้านซ้าย"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ย้ายไปที่ด้านล่างหรือด้านขวา"</string> </resources> diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml index 6699ed876d..7dcae6b8b6 100644 --- a/quickstep/res/values-tl/strings.xml +++ b/quickstep/res/values-tl/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Handa na ang lahat!"</string> <string name="allset_hint" msgid="2384632994739392447">"Mag-swipe pataas para pumunta sa Home"</string> - <string name="allset_description" msgid="6350320429953234580">"Handa mo nang simulan ang paggamit sa iyong telepono"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Handa mo nang simulan ang paggamit sa iyong tablet"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"I-tap ang button ng home para pumunta sa iyong home screen"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Handa mo nang simulan ang paggamit sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"device"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Mga setting ng navigation ng system"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Ibahagi"</string> <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string> <string name="action_split" msgid="2098009717623550676">"Split"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Mag-tap ng ibang app para gamitin ang splitscreen"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Hindi sinusuportahan ng app ang split-screen."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pumili ng ibang app para gamitin ang split screen"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Hindi pinapayagan ng app o ng iyong organisasyon ang pagkilos na ito"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Laktawan ang tutorial sa pag-navigate?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Makikita mo ito sa <xliff:g id="NAME">%1$s</xliff:g> app sa ibang pagkakataon"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Kanselahin"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Laktawan"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"I-rotate ang screen"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Impormasyon sa taskbar"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Lumabas ang edukasyon sa taskbar"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Sarado ang edukasyon sa taskbar"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gamitin ang taskbar para magpalipat-lipat sa mga app"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"I-drag sa gilid para makagamit ng dalawang app nang sabay"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pindutin nang matagal para itago ang taskbar"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"I-drag sa gilid para makagamit ng 2 app nang sabay"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Mag-swipe nang bahagya pataas para ipakita ang taskbar"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Nagmumungkahi ang taskbar ng mga app batay sa iyong routine"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Susunod"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Bumalik"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Isara"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Mga Kamakailan"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Mga Notification"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Taskbar"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Ilipat sa ibaba/kanan"</string> </resources> diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml index 24e25ff5bb..ea3fb5e14b 100644 --- a/quickstep/res/values-tr/strings.xml +++ b/quickstep/res/values-tr/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Eğitim <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"İşlem tamam!"</string> <string name="allset_hint" msgid="2384632994739392447">"Ana ekrana gitmek için yukarı kaydırın"</string> - <string name="allset_description" msgid="6350320429953234580">"Telefonunuzu kullanmaya hazırsınız"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Tabletinizi kullanmaya hazırsınız"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Ana ekranınıza gitmek için ana sayfa düğmesine dokunun"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızı kullanmaya hazırsınız"</string> + <string name="default_device_name" msgid="6660656727127422487">"cihaz"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Sistem gezinme ayarları"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Paylaş"</string> <string name="action_screenshot" msgid="8171125848358142917">"Ekran görüntüsü"</string> <string name="action_split" msgid="2098009717623550676">"Böl"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Bölünmüş ekran için başka bir uygulamaya dokunun"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Uygulama bölünmüş ekranı desteklemiyor."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekran kullanmak için başka bir uygulama seçin"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Uygulamanız veya kuruluşunuz bu işleme izin vermiyor"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Gezinme eğitimi atlansın mı?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bunu daha sonra <xliff:g id="NAME">%1$s</xliff:g> uygulamasında bulabilirsiniz"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"İptal"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Atla"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranı döndür"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Görev çubuğu eğitimi"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Görev çubuğu eğitimi görüntülendi"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Görev çubuğu eğitimi kapatıldı"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Görev çubuğundan uygulamalar arasında geçiş yapabilirsiniz"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Tek seferde iki uygulamayı kullanmak için yana sürükleyin"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Görev çubuğunu gizlemek için basılı tutun"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Tek seferde iki uygulamayı kullanmak için yana sürükleyin"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Görev çubuğunu göstermek için yukarı doğru kısa kaydırın"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Görev çubuğu, rutininize dayalı olarak uygulamalar önerir"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"İleri"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Geri"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Kapat"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Son Kullanılanlar"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Bildirimler"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hızlı Ayarlar"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Görev çubuğu."</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Gezinme çubuğu"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string> </resources> diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml index 8dd65e2cf0..b426c8baec 100644 --- a/quickstep/res/values-uk/strings.xml +++ b/quickstep/res/values-uk/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Навчальний посібник <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Готово."</string> <string name="allset_hint" msgid="2384632994739392447">"Щоб перейти на головний екран, проведіть пальцем угору"</string> - <string name="allset_description" msgid="6350320429953234580">"Тепер ви можете користуватися телефоном"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Тепер ви можете користуватися планшетом"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Натисніть кнопку головного екрана, щоб відкрити його"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Тепер ви можете користуватися цим пристроєм: <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"пристрій"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Системні налаштування навігації"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Поділитися"</string> <string name="action_screenshot" msgid="8171125848358142917">"Знімок екрана"</string> <string name="action_split" msgid="2098009717623550676">"Розділити"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Щоб розділити екран, виберіть ще один додаток"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Додаток не підтримує розділення екрана."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустити посібник із навігації?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ви знайдете його пізніше в додатку <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Скасувати"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропустити"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Обернути екран"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Панель завдань Education"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Панель завдань Education відкрито"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Панель завдань Education закрито"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Переходьте між додатками за допомогою панелі завдань"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Перетягніть убік, щоб використовувати два додатки одночасно"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Натисніть і втримуйте панель завдань, щоб сховати її"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Перетягніть убік, щоб використовувати 2 додатки одночасно"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Швидко проведіть пальцем угору, щоб відкрити панель завдань"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Панель завдань пропонує додатки на основі вашої програми"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Далі"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Закрити"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Нещодавні"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Сповіщення"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Швидкі налаштув."</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Панель завдань"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Панель навігації"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перемістити вгору або вліво"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перемістити вниз або вправо"</string> </resources> diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml index 2d9a1e30f2..576386a395 100644 --- a/quickstep/res/values-ur/strings.xml +++ b/quickstep/res/values-ur/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"ٹیوٹوریل <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"سب کچھ تیار ہے!"</string> <string name="allset_hint" msgid="2384632994739392447">"ہوم پر جانے کے لیے اوپر سوائپ کریں"</string> - <string name="allset_description" msgid="6350320429953234580">"آپ اپنا فون استعمال شروع کرنے کے لیے تیار ہیں"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"آپ اپنے ٹیبلیٹ کا استعمال شروع کرنے کے لیے تیار ہیں"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"اپنی ہوم اسکرین پر جانے کے لیے ہوم بٹن پر تھپتھپائیں"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"آپ اپنے <xliff:g id="DEVICE">%1$s</xliff:g> کا استعمال شروع کرنے کے لیے تیار ہیں"</string> + <string name="default_device_name" msgid="6660656727127422487">"آلہ"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"سسٹم نیویگیشن کی ترتیبات"</annotation></string> <string name="action_share" msgid="2648470652637092375">"اشتراک کریں"</string> <string name="action_screenshot" msgid="8171125848358142917">"اسکرین شاٹ"</string> <string name="action_split" msgid="2098009717623550676">"اسپلٹ"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"ایپ یا آپ کی تنظیم کی جانب سے اس کارروائی کی اجازت نہیں ہے"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"نیویگیشن کا ٹیوٹوریل نظر انداز کریں؟"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"آپ اسے بعد میں <xliff:g id="NAME">%1$s</xliff:g> ایپ میں تلاش کر سکتے ہیں"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"منسوخ کریں"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"نظر انداز کریں"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"اسکرین کو گھمائیں"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ٹاسک بار کی تعلیم"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"ٹاکس بار کا تعلیمی پینل ظاہر ہو گیا"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"ٹاسک بار کا تعلیمی پینل بند ہو گیا"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ایپس کو سوئچ کرنے کیلئے ٹاسک بار کا استعمال کریں"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ایک وقت میں دو ایپس استعمال کرنے کے لیے سائیڈ پر گھسیٹیں"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"ٹاسک بار کو کسی بھی وقت چھپانے کیلئے ٹچ کریں اور دبائے رکھیں"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ایک وقت میں 2 ایپس استعمال کرنے کے لیے سائیڈ پر گھسیٹیں"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ٹاسک بار دکھانے کے لیے تھوڑا اوپر سوائپ کریں"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ٹاسک بار آپ کی روٹین کی بنیاد پر ایپس تجویز کرتا ہے"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"آگے"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"پیچھے"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"بند کریں"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"حالیہ"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"اطلاعات"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"فوری ترتیبات"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"ٹاسک بار"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"نیویگیشن بار"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"اوپر/بائیں طرف منتقل کریں"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"نیچے/دائیں طرف منتقل کریں"</string> </resources> diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml index 9446325829..65197a4ae7 100644 --- a/quickstep/res/values-uz/strings.xml +++ b/quickstep/res/values-uz/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Darslik: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Hammasi tayyor!"</string> <string name="allset_hint" msgid="2384632994739392447">"Boshiga qaytish uchun tepaga suring"</string> - <string name="allset_description" msgid="6350320429953234580">"Telefoningiz xizmatga tayyor"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Planshetingiz xizmatga tayyor"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Bosh ekranga oʻtish uchun bosh ekran tugmasini bosing"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> xizmatga tayyor"</string> + <string name="default_device_name" msgid="6660656727127422487">"qurilma"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Tizim navigatsiya sozlamalari"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Ulashish"</string> <string name="action_screenshot" msgid="8171125848358142917">"Skrinshot"</string> <string name="action_split" msgid="2098009717623550676">"Ajratish"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Ekranni ikkiga ajratish uchun boshqa ilovani bosing"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Bu ilovada ekranni ikkiga ajratish ishlamaydi."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ekranni ikkiga ajratish uchun boshqa ilovani tanlang"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Bu amal ilova yoki tashkilotingiz tomonidan taqiqlangan"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigatsiya darsi yopilsinmi?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bu darslar <xliff:g id="NAME">%1$s</xliff:g> ilovasida chiqadi"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Bekor qilish"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Tashlab ketish"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranni burish"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Vazifalar paneli qoʻllanmasi"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Taʼlim vazifalar paneli chiqdi"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Taʼlim vazifalar paneli yopildi"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Ilovalarni vazifalar panelida almashtirish mumkin"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Bir vaqtda ikkita ilova ochish uchun birini yoniga torting"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Vazifalar panelini ustiga bosib turib yashirish mumkin"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Bir vaqtda 2 ta ilova ochish uchun birini yoniga torting"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Vazifalar panelini koʻrsatish uchun tepaga qisqa suring"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Vazifalar paneli harakatlaringiz asosida ilova taklif qiladi"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Keyingisi"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Orqaga"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Yopish"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Oxirgilar"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Bildirishnomalar"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Tezkor sozlamalar"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Vazifalar paneli"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatsiya paneli"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pastga yoki oʻngga oʻtkazish"</string> </resources> diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml index 55027aeda3..b0a6dab134 100644 --- a/quickstep/res/values-vi/strings.xml +++ b/quickstep/res/values-vi/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Hướng dẫn <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Đã hoàn tất!"</string> <string name="allset_hint" msgid="2384632994739392447">"Vuốt lên để chuyển đến Màn hình chính"</string> - <string name="allset_description" msgid="6350320429953234580">"Vậy là bạn đã sẵn sàng sử dụng điện thoại của mình"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Bạn đã sẵn sàng sử dụng máy tính bảng"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Nhấn vào nút màn hình chính để chuyển đến màn hình chính"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Bạn có thể bắt đầu sử dụng <xliff:g id="DEVICE">%1$s</xliff:g>"</string> + <string name="default_device_name" msgid="6660656727127422487">"thiết bị"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Chế độ cài đặt di chuyển trên hệ thống"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string> <string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string> <string name="action_split" msgid="2098009717623550676">"Chia đôi màn hình"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Nhấn vào một ứng dụng khác để dùng màn hình chia đôi"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Ứng dụng không hỗ trợ chia đôi màn hình."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Ứng dụng hoặc tổ chức của bạn không cho phép thực hiện hành động này"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Bỏ qua phần hướng dẫn thao tác?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bạn có thể tìm lại phần hướng dẫn này trong ứng dụng <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Hủy"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Bỏ qua"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Xoay màn hình"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Cách sử dụng thanh tác vụ"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Đã hiện bảng hướng dẫn trên thanh tác vụ"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Đã đóng bảng hướng dẫn trên thanh tác vụ"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Dùng thanh tác vụ để chuyển đổi ứng dụng"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Kéo sang bên để dùng hai ứng dụng cùng một lúc"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Chạm và giữ để ẩn thanh tác vụ"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Kéo sang bên để dùng 2 ứng dụng cùng một lúc"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Vuốt lên một chút để hiển thị thanh tác vụ"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Thanh tác vụ đề xuất các ứng dụng dựa trên thói quen của bạn"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Tiếp theo"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Quay lại"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Đóng"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Gần đây"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Thông báo"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Cài đặt nhanh"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"Thanh tác vụ"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Thanh điều hướng"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string> </resources> diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml index debf23a9cc..6b8f3e35b9 100644 --- a/quickstep/res/values-zh-rCN/strings.xml +++ b/quickstep/res/values-zh-rCN/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"教程 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"大功告成!"</string> <string name="allset_hint" msgid="2384632994739392447">"向上滑动即可转到主屏幕"</string> - <string name="allset_description" msgid="6350320429953234580">"您可以开始使用手机了"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"您可以开始使用平板电脑了"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"点按主屏幕按钮即可前往主屏幕"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"您可以开始使用<xliff:g id="DEVICE">%1$s</xliff:g>了"</string> + <string name="default_device_name" msgid="6660656727127422487">"设备"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"系统导航设置"</annotation></string> <string name="action_share" msgid="2648470652637092375">"分享"</string> <string name="action_screenshot" msgid="8171125848358142917">"屏幕截图"</string> <string name="action_split" msgid="2098009717623550676">"拆分"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"点按另一个应用即可使用分屏"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"应用不支持分屏。"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"另外选择一个应用才可使用分屏模式"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"该应用或您所在的单位不允许执行此操作"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要跳过导航教程吗?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"您之后可以在“<xliff:g id="NAME">%1$s</xliff:g>”应用中找到此教程"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"跳过"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋转屏幕"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"任务栏教程"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"任务栏教程已显示"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"任务栏教程已关闭"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"使用任务栏切换应用"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"拖动到一侧,以便一次使用两个应用"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"轻触并按住即可隐藏任务栏"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"拖动到一侧,即可一次使用两个应用"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"稍微向上滑动即可显示任务栏"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"任务栏会根据您的日常安排向您推荐应用"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"继续"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"关闭"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"最近用过"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"通知"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快捷设置"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"任务栏"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"导航栏"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string> </resources> diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml index c7a44e7d3f..5a9e0a1e01 100644 --- a/quickstep/res/values-zh-rHK/strings.xml +++ b/quickstep/res/values-zh-rHK/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"教學課程 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"設定完成!"</string> <string name="allset_hint" msgid="2384632994739392447">"向上滑動即可前往主畫面"</string> - <string name="allset_description" msgid="6350320429953234580">"您可以開始使用手機了"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"您可以開始使用平板電腦了"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"輕按主按鈕即可前往主畫面"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"您可以開始使用 <xliff:g id="DEVICE">%1$s</xliff:g> 了"</string> + <string name="default_device_name" msgid="6660656727127422487">"裝置"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"系統導覽設定"</annotation></string> <string name="action_share" msgid="2648470652637092375">"分享"</string> <string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string> <string name="action_split" msgid="2098009717623550676">"分割"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"輕按其他應用程式以使用分割螢幕"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"應用程式不支援分割螢幕。"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"選擇其他應用程式才能使用分割螢幕"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"應用程式或您的機構不允許此操作"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要略過手勢操作教學課程嗎?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"您之後可以在「<xliff:g id="NAME">%1$s</xliff:g>」應用程式找到這些說明"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"略過"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋轉螢幕"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"工作列教學"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"顯示咗工作列教學"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"閂咗工作列教學"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"使用工作列即可切換應用程式"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"拖曳至一側即可同時使用兩個應用程式"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"按住即可隱藏工作列"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"拖曳到一邊即可同時使用 2 個應用程式"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"輕輕向上滑動即可顯示工作列"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"工作列會根據您的日常安排提供應用程式建議"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"最近"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"通知"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快速設定"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"工作列"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"導覽列"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移至上方/左側"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移至底部/右側"</string> </resources> diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml index 15d5de5ecb..30ea100882 100644 --- a/quickstep/res/values-zh-rTW/strings.xml +++ b/quickstep/res/values-zh-rTW/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"教學課程 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"設定完成!"</string> <string name="allset_hint" msgid="2384632994739392447">"向上滑動即可前往主畫面"</string> - <string name="allset_description" msgid="6350320429953234580">"你可以開始使用手機了"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"你可以開始使用平板電腦了"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"輕觸主畫面按鈕即可前往主畫面"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"你可以開始使用「<xliff:g id="DEVICE">%1$s</xliff:g>」了"</string> + <string name="default_device_name" msgid="6660656727127422487">"裝置"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"系統操作機制設定"</annotation></string> <string name="action_share" msgid="2648470652637092375">"分享"</string> <string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string> <string name="action_split" msgid="2098009717623550676">"分割"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"輕觸另一個應用程式即可使用分割畫面"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"這個應用程式不支援分割畫面。"</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"必須選擇另一個應用程式才能使用分割畫面"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"這個應用程式或貴機構不允許執行這個動作"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要略過手勢操作教學課程嗎?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"你之後可以在「<xliff:g id="NAME">%1$s</xliff:g>」應用程式找到這些說明"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"略過"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋轉螢幕"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"工作列教學課程"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"工作列教學課程已顯示"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"工作列教學課程已關閉"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"使用工作列即可切換應用程式"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"拖曳到一邊即可同時使用兩個應用程式"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"按住即可隱藏工作列"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"拖曳到一邊即可同時使用 2 個應用程式"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"稍微向上滑動即可讓工作列顯示在畫面上"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"工作列會根據你的日常習慣提供應用程式建議"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"最近使用"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"通知"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快速設定"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"工作列"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"導覽列"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string> </resources> diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml index 3db58360db..0a7e418d81 100644 --- a/quickstep/res/values-zu/strings.xml +++ b/quickstep/res/values-zu/strings.xml @@ -77,25 +77,27 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Okokufundisa <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Konke kusethiwe!"</string> <string name="allset_hint" msgid="2384632994739392447">"Swayiphela phezulu ukuze uye Ekhaya"</string> - <string name="allset_description" msgid="6350320429953234580">"Usulungele ukuqala ukusebenzisa ifoni yakho"</string> - <string name="allset_description_tablet" msgid="7332070270570039247">"Usulungele ukuqala ukusebenzisa ithebulethi yakho"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Thepha inkinobho yasekhaya ukuze uye kusikrini sasekhaya"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"Usulungele ukuqala ukusebenzisa i-<xliff:g id="DEVICE">%1$s</xliff:g> yakho"</string> + <string name="default_device_name" msgid="6660656727127422487">"idivayisi"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Amasethingi wokuzulazula isistimu"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Yabelana"</string> <string name="action_screenshot" msgid="8171125848358142917">"Isithombe-skrini"</string> <string name="action_split" msgid="2098009717623550676">"Hlukanisa"</string> <string name="toast_split_select_app" msgid="5453865907322018352">"Thepha enye i-app ukuze usebenzise isikrini sokuhlukanisa"</string> - <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string> + <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Khetha enye i-app ukuze usebenzise ukuhlukanisa isikrini"</string> <string name="blocked_by_policy" msgid="2071401072261365546">"Lesi senzo asivunyelwanga uhlelo lokusebenza noma inhlangano yakho"</string> <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Yeqa isifundo sokuzulazula?"</string> <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Lokhu ungakuthola kamuva ku-app ye-<xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Khansela"</string> <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Yeqa"</string> <string name="accessibility_rotate_button" msgid="4771825231336502943">"Zungezisa isikrini"</string> + <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Imfundo ye-taskbar"</string> <string name="taskbar_edu_opened" msgid="3950252793551919129">"Imfuno yebha yomsebenzi ivelile"</string> <string name="taskbar_edu_closed" msgid="126643734478892862">"Imfundo yebha yomsebenzi ivaliwe"</string> - <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Sebenzisa ibha yomsebenzi ukushintsha ama-app"</string> - <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Hudula ngaseceleni ukuze usebenzise ama-app amabili ngesikhathi esisodwa"</string> - <string name="taskbar_edu_stashing" msgid="5212374387411764031">"Thinta futhi ubambe, bamba ukuze ufihle ibha yomsebenzi"</string> + <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Hudula ngaseceleni ukuze usebenzise ama-app angu-2 ngesikhathi esisodwa"</string> + <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Swayiphela phezulu okufushane ukuze ubonise i-taskbar"</string> + <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"I-taskbar iphakamisa ama-app ezisuselwe kumjikelezo wakho"</string> <string name="taskbar_edu_next" msgid="4007618274426775841">"Okulandelayo"</string> <string name="taskbar_edu_previous" msgid="459202320127201702">"Emuva"</string> <string name="taskbar_edu_close" msgid="887022990168191073">"Vala"</string> @@ -107,6 +109,8 @@ <string name="taskbar_button_recents" msgid="7273376136216613134">"Okwakamuva"</string> <string name="taskbar_button_notifications" msgid="7471740351507357318">"Izaziso"</string> <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Amasethingi Asheshayo"</string> + <string name="taskbar_a11y_title" msgid="6432169809852243110">"I-Taskbar"</string> + <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Ibha yokufuna"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Hamba phezulu/kwesokunxele"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Hamba phansi/kwesokudla"</string> </resources> diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml index 185c815ea1..f63997bdbb 100644 --- a/quickstep/res/values/colors.xml +++ b/quickstep/res/values/colors.xml @@ -76,4 +76,7 @@ <color name="all_set_page_background">#FFFFFFFF</color> + <!-- Recents overview --> + <color name="recents_filter_icon">#333333</color> + </resources>
\ No newline at end of file diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml index 198a6763ed..a91507ce92 100644 --- a/quickstep/res/values/config.xml +++ b/quickstep/res/values/config.xml @@ -25,6 +25,7 @@ <string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string> <string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string> <string name="window_manager_proxy_class" translatable="false">com.android.quickstep.util.SystemWindowManagerProxy</string> + <string name="widget_holder_factory_class" translatable="false">com.android.launcher3.uioverrides.QuickstepWidgetHolder$QuickstepHolderFactory</string> <!-- The number of thumbnails and icons to keep in the cache. The thumbnail cache size also determines how many thumbnails will be fetched in the background. --> diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index c85e71cebc..2eb4abc3fb 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -202,6 +202,9 @@ <!-- All Set page --> <dimen name="allset_page_margin_horizontal">40dp</dimen> + <dimen name="allset_page_allset_text_size">36sp</dimen> + <dimen name="allset_page_swipe_up_text_size">14sp</dimen> + <dimen name="allset_title_margin_top">24dp</dimen> <dimen name="allset_title_icon_margin_top">32dp</dimen> <dimen name="allset_subtitle_margin_top">24dp</dimen> @@ -252,13 +255,19 @@ <!-- Taskbar --> <dimen name="taskbar_size">@*android:dimen/taskbar_frame_height</dimen> <dimen name="taskbar_ime_size">48dp</dimen> - <dimen name="taskbar_icon_touch_size">48dp</dimen> + <dimen name="taskbar_icon_size">44dp</dimen> + <dimen name="taskbar_icon_min_touch_size">48dp</dimen> + <!-- Note that this applies to both sides of all icons, so visible space is double this. --> + <dimen name="taskbar_icon_spacing">12dp</dimen> <dimen name="taskbar_icon_drag_icon_size">54dp</dimen> <dimen name="taskbar_folder_margin">16dp</dimen> <dimen name="taskbar_contextual_button_padding">16dp</dimen> <dimen name="taskbar_contextual_padding_top">8dp</dimen> <dimen name="taskbar_nav_buttons_size">44dp</dimen> - <dimen name="taskbar_contextual_button_margin">47dp</dimen> + <dimen name="taskbar_split_instructions_margin">48dp</dimen> + <dimen name="taskbar_contextual_button_margin">120dp</dimen> + <dimen name="taskbar_suw_insets">48dp</dimen> + <dimen name="taskbar_suw_frame">48dp</dimen> <dimen name="taskbar_hotseat_nav_spacing">24dp</dimen> <dimen name="taskbar_contextual_buttons_size">35dp</dimen> <dimen name="taskbar_stashed_size">24dp</dimen> @@ -266,8 +275,7 @@ <dimen name="taskbar_stashed_small_screen">108dp</dimen> <dimen name="taskbar_unstash_input_area">316dp</dimen> <dimen name="taskbar_stashed_handle_height">4dp</dimen> - <dimen name="taskbar_edu_wave_anim_trans_y">25dp</dimen> - <dimen name="taskbar_edu_wave_anim_trans_y_return_overshoot">4dp</dimen> + <dimen name="taskbar_edu_horizontal_margin">112dp</dimen> <dimen name="taskbar_nav_buttons_width_kids">88dp</dimen> <dimen name="taskbar_nav_buttons_height_kids">40dp</dimen> <dimen name="taskbar_nav_buttons_corner_radius_kids">40dp</dimen> @@ -275,12 +283,37 @@ <dimen name="taskbar_home_button_left_margin_kids">48dp</dimen> <dimen name="taskbar_icon_size_kids">32dp</dimen> + <!-- Transient taskbar --> + <dimen name="transient_taskbar_size">72dp</dimen> + <dimen name="transient_taskbar_icon_size">48dp</dimen> + <dimen name="transient_taskbar_margin">24dp</dimen> + <dimen name="transient_taskbar_shadow_blur">40dp</dimen> + <dimen name="transient_taskbar_key_shadow_distance">10dp</dimen> + <dimen name="transient_taskbar_stashed_size">32dp</dimen> + <!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar --> + <dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen> + <!-- Taskbar swipe up thresholds --> + <dimen name="taskbar_nav_threshold">40dp</dimen> + <dimen name="taskbar_app_window_threshold">150dp</dimen> + <dimen name="taskbar_home_overview_threshold">225dp</dimen> + <dimen name="taskbar_catch_up_threshold">300dp</dimen> + + <dimen name="taskbar_nav_threshold_v2">30dp</dimen> + <dimen name="taskbar_app_window_threshold_v2">100dp</dimen> + <dimen name="taskbar_home_overview_threshold_v2">200dp</dimen> + <!-- Taskbar 3 button spacing --> <dimen name="taskbar_button_space_inbetween">24dp</dimen> <dimen name="taskbar_button_space_inbetween_phone">40dp</dimen> - <dimen name="taskbar_button_margin_5_5">26dp</dimen> + <dimen name="taskbar_button_margin_split">48dp</dimen> <dimen name="taskbar_button_margin_6_5">75dp</dimen> - <dimen name="taskbar_button_margin_4_5">47dp</dimen> - <dimen name="taskbar_button_margin_4_4">47dp</dimen> - <dimen name="taskbar_button_margin_default">47dp</dimen> + <dimen name="taskbar_button_margin_default">48dp</dimen> + + <!-- Recents overview --> + <dimen name="recents_filter_icon_size">30dp</dimen> + + <!-- Launcher splash screen --> + <!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml --> + <!-- starting_surface_exit_animation_window_shift_length --> + <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen> </resources> diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml index c0d52a42bd..e691522d5e 100644 --- a/quickstep/res/values/strings.xml +++ b/quickstep/res/values/strings.xml @@ -36,6 +36,13 @@ <!-- Recents: Title of a button that clears the task list, i.e. closes all tasks. [CHAR LIMIT=30] --> <string name="recents_clear_all">Clear all</string> + <!-- Recents: Title of a button that goes back from displaying tasks filtered by package name to displaying all tasks [CHAR LIMIT=30] --> + <string name="recents_back" translatable="false">Back</string> + + <!-- TODO: b/260610444. Content description of filtering icons needs to be updated --> + <!-- Recents: Content description for the icon on top of taskviews to initiate filtering --> + <string name="recents_filter_icon_desc" translatable="false">Click to show only this app\'s tasks</string> + <!-- Accessibility title for the list of recent apps [CHAR_LIMIT=none] --> <string name="accessibility_recent_apps">Recent apps</string> @@ -187,10 +194,12 @@ <string name="allset_title">All set!</string> <!-- Hint string at the bottom of "All Set" page [CHAR LIMIT=NONE] --> <string name="allset_hint">Swipe up to go Home</string> - <!-- Description of "All Set" page on phones [CHAR LIMIT=NONE] --> - <string name="allset_description">You\u2019re ready to start using your phone</string> - <!-- Description of "All Set" page on tablets [CHAR LIMIT=NONE] --> - <string name="allset_description_tablet">You\u2019re ready to start using your tablet</string> + <!-- Hint string at the bottom of "All Set" page for button navigation [CHAR LIMIT=NONE] --> + <string name="allset_button_hint">Tap the home button to go to your home screen</string> + <!-- Description of "All Set" page on the user's device [CHAR LIMIT=NONE] --> + <string name="allset_description_generic">You\u2019re ready to start using your <xliff:g id="device" example="Pixel 6">%1$s</xliff:g></string> + <!-- A default device name to use in the description of the "All Set" page [CHAR LIMIT=NONE] --> + <string name="default_device_name">device</string> <!-- String linking to navigation settings on "All Set" page [CHAR LIMIT=NONE] --> <string name="allset_navigation_settings"><annotation id="link">System navigation settings</annotation></string> @@ -204,7 +213,7 @@ <!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] --> <string name="toast_split_select_app">Tap another app to use splitscreen</string> <!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] --> - <string name="toast_split_app_unsupported">App does not support split-screen.</string> + <string name="toast_split_app_unsupported">Choose another app to use split screen</string> <!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] --> <string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string> @@ -222,19 +231,18 @@ <string name="accessibility_rotate_button">Rotate screen</string> <!-- ******* Taskbar Edu ******* --> + <!-- Accessibility title for the taskbar education window. [CHAR_LIMIT=NONE] --> + <string name="taskbar_edu_a11y_title">Taskbar education</string> <!-- Accessibility text spoken when the taskbar education panel appears [CHAR_LIMIT=NONE] --> <string name="taskbar_edu_opened">Taskbar education appeared</string> <!-- Accessibility text spoken when the taskbar education panel disappears [CHAR_LIMIT=NONE] --> <string name="taskbar_edu_closed">Taskbar education closed</string> - <!-- Text in dialog that lets a user know how they can use the taskbar to switch apps on their device. - [CHAR_LIMIT=60] --> - <string name="taskbar_edu_switch_apps">Use the taskbar to switch apps</string> - <!-- Text in dialog that lets a user know how they can use the taskbar to use multiple apps at once on their device. - [CHAR_LIMIT=60] --> - <string name="taskbar_edu_splitscreen">Drag to the side to use two apps at once</string> - <!-- Text in dialog that lets a user know how they can hide the taskbar on their device. - [CHAR_LIMIT=60] --> - <string name="taskbar_edu_stashing">Touch & hold to hide the taskbar</string> + <!-- Text in dialog that lets a user know how they can use the taskbar to use multiple apps at once on their device. [CHAR_LIMIT=60] --> + <string name="taskbar_edu_splitscreen">Drag to the side to use 2 apps at once</string> + <!-- Text in dialog that lets a user know how they can show the taskbar on their device. [CHAR_LIMIT=60] --> + <string name="taskbar_edu_stashing">Short swipe up to show the taskbar</string> + <!-- Text in dialog that lets a user know how the taskbar suggests apps based on their usage. [CHAR_LIMIT=60] --> + <string name="taskbar_edu_suggestions">The taskbar suggests apps based on your routine</string> <!-- Text on button to go to the next screen of a tutorial [CHAR_LIMIT=16] --> <string name="taskbar_edu_next">Next</string> <!-- Text on button to go to the previous screen of a tutorial [CHAR_LIMIT=16] --> @@ -257,6 +265,10 @@ <string name="taskbar_button_notifications">Notifications</string> <!-- Content description for quick settings button [CHAR_LIMIT=16] --> <string name="taskbar_button_quick_settings">Quick Settings</string> + <!-- Accessibility title for the taskbar window. [CHAR_LIMIT=NONE] --> + <string name="taskbar_a11y_title">Taskbar</string> + <!-- Accessibility title for the taskbar window on phones. [CHAR_LIMIT=NONE] --> + <string name="taskbar_phone_a11y_title">Navigation bar</string> <!-- Label for moving drop target to the top or left side of the screen, depending on orientation (from the taskbar only). --> <string name="move_drop_target_top_or_left">Move to top/left</string> diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml index 7225220876..eb75084697 100644 --- a/quickstep/res/values/styles.xml +++ b/quickstep/res/values/styles.xml @@ -41,7 +41,7 @@ parent="TextAppearance.GestureTutorial"> <item name="android:gravity">start</item> <item name="android:textColor">?android:attr/textColorPrimary</item> - <item name="android:fontFamily">google-sans-regular</item> + <item name="android:fontFamily">google-sans</item> <item name="android:letterSpacing">0.03</item> <item name="android:textSize">36sp</item> <item name="android:lineHeight">44sp</item> @@ -51,6 +51,7 @@ parent="TextAppearance.GestureTutorial.Feedback.Title"> <item name="android:letterSpacing">0.03</item> <item name="android:lineHeight">44sp</item> + <item name="android:textSize">@dimen/allset_page_allset_text_size</item> </style> <style name="TextAppearance.GestureTutorial.Dialog.Title" @@ -105,6 +106,7 @@ <item name="android:letterSpacing">0.02</item> <item name="android:textSize">16sp</item> <item name="android:textAllCaps">false</item> + <item name="android:fontFamily">google-sans-text-medium</item> </style> <style name="TextAppearance.GestureTutorial.CancelButtonLabel" @@ -151,6 +153,8 @@ <item name="android:background">@drawable/bg_overview_clear_all_button</item> <item name="android:minWidth">96dp</item> <item name="android:minHeight">48dp</item> + <item name="android:paddingStart">12dp</item> + <item name="android:paddingEnd">12dp</item> <item name="android:stateListAnimator">@null</item> </style> diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java index 62603e9d54..95a94ec149 100644 --- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java +++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java @@ -28,13 +28,13 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.os.Handler; +import android.view.RemoteAnimationTarget; import androidx.annotation.BinderThread; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.lang.ref.WeakReference; @@ -55,7 +55,7 @@ import java.lang.ref.WeakReference; * reference to the runner, leaving only the weak ref from the runner. */ @TargetApi(Build.VERSION_CODES.P) -public class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { +public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat { private static final RemoteAnimationFactory DEFAULT_FACTORY = (transit, appTargets, wallpaperTargets, nonAppTargets, result) -> @@ -82,9 +82,9 @@ public class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { @BinderThread public void onAnimationStart( int transit, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets, + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets, Runnable runnable) { Runnable r = () -> { finishExistingAnimation(); @@ -99,22 +99,6 @@ public class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { } } - // Called only in R platform - @BinderThread - public void onAnimationStart(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, Runnable runnable) { - onAnimationStart(0 /* transit */, appTargets, wallpaperTargets, - new RemoteAnimationTargetCompat[0], runnable); - } - - // Called only in Q platform - @BinderThread - @Deprecated - public void onAnimationStart(RemoteAnimationTargetCompat[] appTargets, Runnable runnable) { - onAnimationStart(appTargets, new RemoteAnimationTargetCompat[0], runnable); - } - - private RemoteAnimationFactory getFactory() { RemoteAnimationFactory factory = mFactory.get(); return factory != null ? factory : DEFAULT_FACTORY; @@ -133,7 +117,7 @@ public class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { */ @BinderThread @Override - public void onAnimationCancelled() { + public void onAnimationCancelled(boolean isKeyguardOccluded) { postAsyncCallback(mHandler, () -> { finishExistingAnimation(); getFactory().onAnimationCancelled(); @@ -229,9 +213,9 @@ public class LauncherAnimationRunner implements RemoteAnimationRunnerCompat { * call {@link AnimationResult#setAnimation} with the target animation to be run. */ void onCreateAnimation(int transit, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets, + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets, LauncherAnimationRunner.AnimationResult result); /** diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java index c4e85f6014..28bd701a48 100644 --- a/quickstep/src/com/android/launcher3/LauncherInitListener.java +++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java @@ -19,11 +19,11 @@ import android.animation.AnimatorSet; import android.annotation.TargetApi; import android.os.Build; import android.os.CancellationSignal; +import android.view.RemoteAnimationTarget; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.RemoteAnimationProvider; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.BiPredicate; @@ -52,8 +52,8 @@ public class LauncherInitListener extends ActivityInitListener<Launcher> { CancellationSignal cancellationSignal = new CancellationSignal(); appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() { @Override - public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { + public AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets) { // On the first call clear the reference. cancellationSignal.cancel(); diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 9a1ed4d56d..2aa0af4113 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -16,9 +16,19 @@ package com.android.launcher3; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.provider.Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING; +import static android.view.RemoteAnimationTarget.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_OPENING; +import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; +import static android.view.WindowManager.TRANSIT_OPEN; +import static android.view.WindowManager.TRANSIT_TO_BACK; +import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; +import static android.window.TransitionFilter.CONTAINER_ORDER_TOP; import static com.android.launcher3.BaseActivity.INVISIBLE_ALL; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS; @@ -42,15 +52,13 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAU import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION; import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY; import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; -import static com.android.launcher3.statehandlers.DepthController.STATE_DEPTH; +import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; import static com.android.launcher3.views.FloatingIconView.getFloatingIconView; import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch; import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius; import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -81,6 +89,9 @@ import android.provider.Settings; import android.util.Pair; import android.util.Size; import android.view.CrossWindowBlurListeners; +import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationDefinition; +import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; @@ -89,6 +100,8 @@ import android.view.WindowManager; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; +import android.window.RemoteTransition; +import android.window.TransitionFilter; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -98,6 +111,7 @@ import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorListeners; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.shortcuts.DeepShortcutView; @@ -107,6 +121,7 @@ import com.android.launcher3.testing.shared.ResourceUtils; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.ActivityOptionsWrapper; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DynamicResource; import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.util.RunnableList; @@ -122,6 +137,8 @@ import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.StaggeredWorkspaceAnim; +import com.android.quickstep.util.SurfaceTransaction; +import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.WorkspaceRevealAnim; import com.android.quickstep.views.FloatingWidgetView; @@ -129,12 +146,7 @@ import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.BlurUtils; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; -import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.RemoteTransitionCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.wm.shell.startingsurface.IStartingWindowListener; import java.util.ArrayList; @@ -182,6 +194,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener public static final int SPLIT_DIVIDER_ANIM_DURATION = 100; public static final int CONTENT_ALPHA_DURATION = 217; + public static final int TRANSIENT_TASKBAR_TRANSITION_DURATION = 417; public static final int TASKBAR_TO_APP_DURATION = 600; // TODO(b/236145847): Tune TASKBAR_TO_HOME_DURATION to 383 after conflict with unlock animation // is solved. @@ -213,7 +226,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener private RemoteAnimationFactory mKeyguardGoingAwayRunner; private RemoteAnimationFactory mWallpaperOpenTransitionRunner; - private RemoteTransitionCompat mLauncherOpenTransition; + private RemoteTransition mLauncherOpenTransition; private LauncherBackAnimationController mBackAnimationController; private final AnimatorListenerAdapter mForceInvisibleListener = new AnimatorListenerAdapter() { @@ -290,12 +303,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION - STATUS_BAR_TRANSITION_PRE_DELAY; - RemoteAnimationAdapterCompat adapterCompat = - new RemoteAnimationAdapterCompat(runner, duration, statusBarTransitionDelay, - mLauncher.getIApplicationThread()); ActivityOptions options = ActivityOptions.makeRemoteAnimation( - adapterCompat.getWrapped(), - adapterCompat.getRemoteTransition().getTransition()); + new RemoteAnimationAdapter(runner, duration, statusBarTransitionDelay), + new RemoteTransition(runner.toRemoteTransition(), + mLauncher.getIApplicationThread())); return new ActivityOptionsWrapper(options, onEndCallback); } @@ -310,7 +321,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * @return true if the app is launching from recents, false if it most likely is not */ protected boolean isLaunchingFromRecents(@NonNull View v, - @Nullable RemoteAnimationTargetCompat[] targets) { + @Nullable RemoteAnimationTarget[] targets) { return mLauncher.getStateManager().getState().overviewUi && findTaskViewToLaunch(mLauncher.getOverviewPanel(), v, targets) != null; } @@ -324,18 +335,18 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * @param launcherClosing true if the launcher app is closing */ protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, - @NonNull RemoteAnimationTargetCompat[] appTargets, - @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, - @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing) { + @NonNull RemoteAnimationTarget[] appTargets, + @NonNull RemoteAnimationTarget[] wallpaperTargets, + @NonNull RemoteAnimationTarget[] nonAppTargets, boolean launcherClosing) { TaskViewUtils.composeRecentsLaunchAnimator(anim, v, appTargets, wallpaperTargets, nonAppTargets, launcherClosing, mLauncher.getStateManager(), mLauncher.getOverviewPanel(), mLauncher.getDepthController()); } - private boolean areAllTargetsTranslucent(@NonNull RemoteAnimationTargetCompat[] targets) { + private boolean areAllTargetsTranslucent(@NonNull RemoteAnimationTarget[] targets) { boolean isAllOpeningTargetTrs = true; for (int i = 0; i < targets.length; i++) { - RemoteAnimationTargetCompat target = targets[i]; + RemoteAnimationTarget target = targets[i]; if (target.mode == MODE_OPENING) { isAllOpeningTargetTrs &= target.isTranslucent; } @@ -353,21 +364,18 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * @param launcherClosing true if launcher is closing */ private void composeIconLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, - @NonNull RemoteAnimationTargetCompat[] appTargets, - @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, - @NonNull RemoteAnimationTargetCompat[] nonAppTargets, + @NonNull RemoteAnimationTarget[] appTargets, + @NonNull RemoteAnimationTarget[] wallpaperTargets, + @NonNull RemoteAnimationTarget[] nonAppTargets, boolean launcherClosing) { // Set the state animation first so that any state listeners are called // before our internal listeners. mLauncher.getStateManager().setCurrentAnimation(anim); - final int rotationChange = getRotationChange(appTargets); // Note: the targetBounds are relative to the launcher int startDelay = getSingleFrameMs(mLauncher); - Rect windowTargetBounds = getWindowTargetBounds(appTargets, rotationChange); - Animator windowAnimator = getOpeningWindowAnimators(v, appTargets, wallpaperTargets, - nonAppTargets, windowTargetBounds, areAllTargetsTranslucent(appTargets), - rotationChange); + Animator windowAnimator = getOpeningWindowAnimators( + v, appTargets, wallpaperTargets, nonAppTargets, launcherClosing); windowAnimator.setStartDelay(startDelay); anim.play(windowAnimator); if (launcherClosing) { @@ -381,40 +389,19 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener launcherContentAnimator.second.run(); } }); - } else { - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mLauncher.addOnResumeCallback(() -> - ObjectAnimator.ofFloat(mLauncher.getDepthController(), STATE_DEPTH, - mLauncher.getStateManager().getState().getDepth( - mLauncher)).start()); - } - }); } } private void composeWidgetLaunchAnimator( @NonNull AnimatorSet anim, @NonNull LauncherAppWidgetHostView v, - @NonNull RemoteAnimationTargetCompat[] appTargets, - @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, - @NonNull RemoteAnimationTargetCompat[] nonAppTargets) { + @NonNull RemoteAnimationTarget[] appTargets, + @NonNull RemoteAnimationTarget[] wallpaperTargets, + @NonNull RemoteAnimationTarget[] nonAppTargets, + boolean launcherClosing) { mLauncher.getStateManager().setCurrentAnimation(anim); - - Rect windowTargetBounds = getWindowTargetBounds(appTargets, getRotationChange(appTargets)); - anim.play(getOpeningWindowAnimatorsForWidget(v, appTargets, wallpaperTargets, nonAppTargets, - windowTargetBounds, areAllTargetsTranslucent(appTargets))); - - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - mLauncher.addOnResumeCallback(() -> - ObjectAnimator.ofFloat(mLauncher.getDepthController(), STATE_DEPTH, - mLauncher.getStateManager().getState().getDepth( - mLauncher)).start()); - } - }); + anim.play(getOpeningWindowAnimatorsForWidget( + v, appTargets, wallpaperTargets, nonAppTargets, launcherClosing)); } /** @@ -422,10 +409,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * In multiwindow mode, we need to get the final size of the opening app window target to help * figure out where the floating view should animate to. */ - private Rect getWindowTargetBounds(@NonNull RemoteAnimationTargetCompat[] appTargets, + private Rect getWindowTargetBounds(@NonNull RemoteAnimationTarget[] appTargets, int rotationChange) { - RemoteAnimationTargetCompat target = null; - for (RemoteAnimationTargetCompat t : appTargets) { + RemoteAnimationTarget target = null; + for (RemoteAnimationTarget t : appTargets) { if (t.mode != MODE_OPENING) continue; target = t; break; @@ -447,7 +434,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener 4 - rotationChange); } } - if (mDeviceProfile.isTaskbarPresentInApps && !target.willShowImeOnTarget) { + if (mDeviceProfile.isTaskbarPresentInApps + && !target.willShowImeOnTarget + && !DisplayController.isTransientTaskbar(mLauncher)) { // Animate to above the taskbar. bounds.bottom -= target.contentInsets.bottom; } @@ -493,6 +482,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final View appsView = mLauncher.getAppsView(); final float startAlpha = appsView.getAlpha(); final float startScale = SCALE_PROPERTY.get(appsView); + if (mDeviceProfile.isTablet) { + // AllApps should not fade at all in tablets. + alphas = new float[]{1, 1}; + } appsView.setAlpha(alphas[0]); ObjectAnimator alpha = ObjectAnimator.ofFloat(appsView, View.ALPHA, alphas); @@ -551,7 +544,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final boolean scrimEnabled = ENABLE_SCRIM_FOR_APP_LAUNCH.get(); if (scrimEnabled) { - boolean useTaskbarColor = mDeviceProfile.isTaskbarPresentInApps; + boolean useTaskbarColor = mDeviceProfile.isTaskbarPresentInApps + && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get(); int scrimColor = useTaskbarColor ? mLauncher.getResources().getColor(R.color.taskbar_background) : Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor); @@ -646,10 +640,14 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * @return Animator that controls the window of the opening targets from app icons. */ private Animator getOpeningWindowAnimators(View v, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets, - Rect windowTargetBounds, boolean appTargetsAreTranslucent, int rotationChange) { + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets, + boolean launcherClosing) { + int rotationChange = getRotationChange(appTargets); + Rect windowTargetBounds = getWindowTargetBounds(appTargets, rotationChange); + boolean appTargetsAreTranslucent = areAllTargetsTranslucent(appTargets); + RectF launcherIconBounds = new RectF(); FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v, !appTargetsAreTranslucent, launcherIconBounds, true /* isOpening */); @@ -661,7 +659,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(floatingView); openingTargets.addReleaseCheck(surfaceApplier); - RemoteAnimationTargetCompat navBarTarget = openingTargets.getNavBarRemoteAnimationTarget(); + RemoteAnimationTarget navBarTarget = openingTargets.getNavBarRemoteAnimationTarget(); int[] dragLayerBounds = new int[2]; mDragLayer.getLocationOnScreen(dragLayerBounds); @@ -813,10 +811,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return; } - ArrayList<SurfaceParams> params = new ArrayList<>(); + SurfaceTransaction transaction = new SurfaceTransaction(); + for (int i = appTargets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = appTargets[i]; - SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash); + RemoteAnimationTarget target = appTargets[i]; + SurfaceProperties builder = transaction.forSurface(target.leash); if (target.mode == MODE_OPENING) { matrix.setScale(scale, scale); @@ -837,14 +836,13 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener floatingView.update(mIconAlpha.value, 255, floatingIconBounds, percent, 0f, mWindowRadius.value * scale, true /* isOpening */); - builder.withMatrix(matrix) - .withWindowCrop(crop) - .withAlpha(1f - mIconAlpha.value) - .withCornerRadius(mWindowRadius.value) - .withShadowRadius(mShadowRadius.value); + builder.setMatrix(matrix) + .setWindowCrop(crop) + .setAlpha(1f - mIconAlpha.value) + .setCornerRadius(mWindowRadius.value) + .setShadowRadius(mShadowRadius.value); } else if (target.mode == MODE_CLOSING) { if (target.localBounds != null) { - final Rect localBounds = target.localBounds; tmpPos.set(target.localBounds.left, target.localBounds.top); } else { tmpPos.set(target.position.x, target.position.y); @@ -861,29 +859,26 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener tmpPos.y = tmp; } matrix.setTranslate(tmpPos.x, tmpPos.y); - builder.withMatrix(matrix) - .withWindowCrop(crop) - .withAlpha(1f); + builder.setMatrix(matrix) + .setWindowCrop(crop) + .setAlpha(1f); } - params.add(builder.build()); } if (navBarTarget != null) { - final SurfaceParams.Builder navBuilder = - new SurfaceParams.Builder(navBarTarget.leash); + SurfaceProperties navBuilder = + transaction.forSurface(navBarTarget.leash); if (mNavFadeIn.value > mNavFadeIn.getStartValue()) { matrix.setScale(scale, scale); matrix.postTranslate(windowTransX0, windowTransY0); - navBuilder.withMatrix(matrix) - .withWindowCrop(crop) - .withAlpha(mNavFadeIn.value); + navBuilder.setMatrix(matrix) + .setWindowCrop(crop) + .setAlpha(mNavFadeIn.value); } else { - navBuilder.withAlpha(mNavFadeOut.value); + navBuilder.setAlpha(mNavFadeOut.value); } - params.add(navBuilder.build()); } - - surfaceApplier.scheduleApply(params.toArray(new SurfaceParams[params.size()])); + surfaceApplier.scheduleApply(transaction); } }; appAnimator.addUpdateListener(listener); @@ -892,7 +887,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener // If app targets are translucent, do not animate the background as it causes a visible // flicker when it resets itself at the end of its animation. - if (appTargetsAreTranslucent) { + if (appTargetsAreTranslucent || !launcherClosing) { animatorSet.play(appAnimator); } else { animatorSet.playTogether(appAnimator, getBackgroundAnimator()); @@ -901,17 +896,19 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } private Animator getOpeningWindowAnimatorsForWidget(LauncherAppWidgetHostView v, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets, Rect windowTargetBounds, - boolean appTargetsAreTranslucent) { + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets, boolean launcherClosing) { + Rect windowTargetBounds = getWindowTargetBounds(appTargets, getRotationChange(appTargets)); + boolean appTargetsAreTranslucent = areAllTargetsTranslucent(appTargets); + final RectF widgetBackgroundBounds = new RectF(); final Rect appWindowCrop = new Rect(); final Matrix matrix = new Matrix(); RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING); - RemoteAnimationTargetCompat openingTarget = openingTargets.getFirstAppTarget(); + RemoteAnimationTarget openingTarget = openingTargets.getFirstAppTarget(); int fallbackBackgroundColor = 0; if (openingTarget != null && supportsSSplashScreen()) { fallbackBackgroundColor = mTaskStartParams.containsKey(openingTarget.taskId) @@ -935,7 +932,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(floatingView); openingTargets.addReleaseCheck(surfaceApplier); - RemoteAnimationTargetCompat navBarTarget = openingTargets.getNavBarRemoteAnimationTarget(); + RemoteAnimationTarget navBarTarget = openingTargets.getNavBarRemoteAnimationTarget(); AnimatorSet animatorSet = new AnimatorSet(); ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1); @@ -999,43 +996,39 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener matrix.postScale(mAppWindowScale, mAppWindowScale, widgetBackgroundBounds.left, widgetBackgroundBounds.top); - ArrayList<SurfaceParams> params = new ArrayList<>(); + SurfaceTransaction transaction = new SurfaceTransaction(); float floatingViewAlpha = appTargetsAreTranslucent ? 1 - mPreviewAlpha.value : 1; for (int i = appTargets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = appTargets[i]; - SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash); + RemoteAnimationTarget target = appTargets[i]; + SurfaceProperties builder = transaction.forSurface(target.leash); if (target.mode == MODE_OPENING) { floatingView.update(widgetBackgroundBounds, floatingViewAlpha, mWidgetForegroundAlpha.value, mWidgetFallbackBackgroundAlpha.value, mCornerRadiusProgress.value); - builder.withMatrix(matrix) - .withWindowCrop(appWindowCrop) - .withAlpha(mPreviewAlpha.value) - .withCornerRadius(mWindowRadius.value / mAppWindowScale); + builder.setMatrix(matrix) + .setWindowCrop(appWindowCrop) + .setAlpha(mPreviewAlpha.value) + .setCornerRadius(mWindowRadius.value / mAppWindowScale); } - params.add(builder.build()); } if (navBarTarget != null) { - final SurfaceParams.Builder navBuilder = - new SurfaceParams.Builder(navBarTarget.leash); + SurfaceProperties navBuilder = transaction.forSurface(navBarTarget.leash); if (mNavFadeIn.value > mNavFadeIn.getStartValue()) { - navBuilder.withMatrix(matrix) - .withWindowCrop(appWindowCrop) - .withAlpha(mNavFadeIn.value); + navBuilder.setMatrix(matrix) + .setWindowCrop(appWindowCrop) + .setAlpha(mNavFadeIn.value); } else { - navBuilder.withAlpha(mNavFadeOut.value); + navBuilder.setAlpha(mNavFadeOut.value); } - params.add(navBuilder.build()); } - - surfaceApplier.scheduleApply(params.toArray(new SurfaceParams[params.size()])); + surfaceApplier.scheduleApply(transaction); } }); // If app targets are translucent, do not animate the background as it causes a visible // flicker when it resets itself at the end of its animation. - if (appTargetsAreTranslucent) { + if (appTargetsAreTranslucent || !launcherClosing) { animatorSet.play(appAnimator); } else { animatorSet.playTogether(appAnimator, getBackgroundAnimator()); @@ -1053,8 +1046,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener && BlurUtils.supportsBlursOnWindows(); MyDepthController depthController = new MyDepthController(mLauncher); - ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController, STATE_DEPTH, - BACKGROUND_APP.getDepth(mLauncher)) + ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController.stateDepth, + MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mLauncher)) .setDuration(APP_LAUNCH_DURATION); if (allowBlurringLauncher) { @@ -1093,28 +1086,26 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener if (hasControlRemoteAppTransitionPermission()) { mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */); - RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat(); + RemoteAnimationDefinition definition = new RemoteAnimationDefinition(); definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_WALLPAPER_OPEN, WindowConfiguration.ACTIVITY_TYPE_STANDARD, - new RemoteAnimationAdapterCompat( + new RemoteAnimationAdapter( new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner, false /* startAtFrontOfQueue */), - CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */, - mLauncher.getIApplicationThread())); + CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */)); if (KEYGUARD_ANIMATION.get()) { mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */); definition.addRemoteAnimation( WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER, - new RemoteAnimationAdapterCompat( + new RemoteAnimationAdapter( new LauncherAnimationRunner( mHandler, mKeyguardGoingAwayRunner, true /* startAtFrontOfQueue */), - CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */, - mLauncher.getIApplicationThread())); + CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */)); } - mLauncher.registerRemoteAnimations(definition.getWrapped()); + mLauncher.registerRemoteAnimations(definition); } } @@ -1127,11 +1118,25 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } if (hasControlRemoteAppTransitionPermission()) { mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */); - mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition( + mLauncherOpenTransition = new RemoteTransition( new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner, - false /* startAtFrontOfQueue */), mLauncher.getIApplicationThread()); - mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName()); - SystemUiProxy.INSTANCE.get(mLauncher).registerRemoteTransition(mLauncherOpenTransition); + false /* startAtFrontOfQueue */).toRemoteTransition(), + mLauncher.getIApplicationThread()); + + TransitionFilter homeCheck = new TransitionFilter(); + // No need to handle the transition that also dismisses keyguard. + homeCheck.mNotFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY; + homeCheck.mRequirements = + new TransitionFilter.Requirement[]{new TransitionFilter.Requirement(), + new TransitionFilter.Requirement()}; + homeCheck.mRequirements[0].mActivityType = ACTIVITY_TYPE_HOME; + homeCheck.mRequirements[0].mTopActivity = mLauncher.getComponentName(); + homeCheck.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; + homeCheck.mRequirements[0].mOrder = CONTAINER_ORDER_TOP; + homeCheck.mRequirements[1].mActivityType = ACTIVITY_TYPE_STANDARD; + homeCheck.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; + SystemUiProxy.INSTANCE.get(mLauncher) + .registerRemoteTransition(mLauncherOpenTransition, homeCheck); } if (mBackAnimationController != null) { mBackAnimationController.registerBackCallbacks(mHandler); @@ -1177,8 +1182,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } } - private boolean launcherIsATargetWithMode(RemoteAnimationTargetCompat[] targets, int mode) { - for (RemoteAnimationTargetCompat target : targets) { + private boolean launcherIsATargetWithMode(RemoteAnimationTarget[] targets, int mode) { + for (RemoteAnimationTarget target : targets) { if (target.mode == mode && target.taskInfo != null // Compare component name instead of task-id because transitions will promote // the target up to the root task while getTaskId returns the leaf. @@ -1190,9 +1195,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return false; } - private boolean hasMultipleTargetsWithMode(RemoteAnimationTargetCompat[] targets, int mode) { + private boolean hasMultipleTargetsWithMode(RemoteAnimationTarget[] targets, int mode) { int numTargets = 0; - for (RemoteAnimationTargetCompat target : targets) { + for (RemoteAnimationTarget target : targets) { if (target.mode == mode) { numTargets++; } @@ -1214,8 +1219,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener /** * Animator that controls the transformations of the windows when unlocking the device. */ - private Animator getUnlockWindowAnimator(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { + private Animator getUnlockWindowAnimator(RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets) { SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer); ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1); unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS); @@ -1224,24 +1229,23 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener unlockAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - SurfaceParams[] params = new SurfaceParams[appTargets.length]; + SurfaceTransaction transaction = new SurfaceTransaction(); for (int i = appTargets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = appTargets[i]; - params[i] = new SurfaceParams.Builder(target.leash) - .withAlpha(1f) - .withWindowCrop(target.screenSpaceBounds) - .withCornerRadius(cornerRadius) - .build(); + RemoteAnimationTarget target = appTargets[i]; + transaction.forSurface(target.leash) + .setAlpha(1f) + .setWindowCrop(target.screenSpaceBounds) + .setCornerRadius(cornerRadius); } - surfaceApplier.scheduleApply(params); + surfaceApplier.scheduleApply(transaction); } }); return unlockAnimator; } - private static int getRotationChange(RemoteAnimationTargetCompat[] appTargets) { + private static int getRotationChange(RemoteAnimationTarget[] appTargets) { int rotationChange = 0; - for (RemoteAnimationTargetCompat target : appTargets) { + for (RemoteAnimationTarget target : appTargets) { if (Math.abs(target.rotationChange) > Math.abs(rotationChange)) { rotationChange = target.rotationChange; } @@ -1252,8 +1256,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener /** * Returns view on launcher that corresponds to the closing app in the list of app targets */ - private @Nullable View findLauncherView(RemoteAnimationTargetCompat[] appTargets) { - for (RemoteAnimationTargetCompat appTarget : appTargets) { + private @Nullable View findLauncherView(RemoteAnimationTarget[] appTargets) { + for (RemoteAnimationTarget appTarget : appTargets) { if (appTarget.mode == MODE_CLOSING) { View launcherView = findLauncherView(appTarget); if (launcherView != null) { @@ -1267,7 +1271,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener /** * Returns view on launcher that corresponds to the {@param runningTaskTarget}. */ - private @Nullable View findLauncherView(RemoteAnimationTargetCompat runningTaskTarget) { + private @Nullable View findLauncherView(RemoteAnimationTarget runningTaskTarget) { if (runningTaskTarget == null || runningTaskTarget.taskInfo == null) { return null; } @@ -1328,15 +1332,15 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * Closing animator that animates the window into its final location on the workspace. */ private RectFSpringAnim getClosingWindowAnimators(AnimatorSet animation, - RemoteAnimationTargetCompat[] targets, View launcherView, PointF velocityPxPerS, + RemoteAnimationTarget[] targets, View launcherView, PointF velocityPxPerS, RectF closingWindowStartRect, float startWindowCornerRadius) { FloatingIconView floatingIconView = null; FloatingWidgetView floatingWidget = null; RectF targetRect = new RectF(); - RemoteAnimationTargetCompat runningTaskTarget = null; + RemoteAnimationTarget runningTaskTarget = null; boolean isTransluscent = false; - for (RemoteAnimationTargetCompat target : targets) { + for (RemoteAnimationTarget target : targets) { if (target.mode == MODE_CLOSING) { runningTaskTarget = target; isTransluscent = runningTaskTarget.isTranslucent; @@ -1430,7 +1434,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener /** * Closing window animator that moves the window down and offscreen. */ - private Animator getFallbackClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets) { + private Animator getFallbackClosingWindowAnimators(RemoteAnimationTarget[] appTargets) { final int rotationChange = getRotationChange(appTargets); SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer); Matrix matrix = new Matrix(); @@ -1451,10 +1455,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener @Override public void onUpdate(float percent, boolean initOnly) { - SurfaceParams[] params = new SurfaceParams[appTargets.length]; + SurfaceTransaction transaction = new SurfaceTransaction(); for (int i = appTargets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = appTargets[i]; - SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash); + RemoteAnimationTarget target = appTargets[i]; + SurfaceProperties builder = transaction.forSurface(target.leash); if (target.localBounds != null) { tmpPos.set(target.localBounds.left, target.localBounds.top); @@ -1476,20 +1480,19 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener tmpRect.centerY()); matrix.postTranslate(0, mDy.value); matrix.postTranslate(tmpPos.x, tmpPos.y); - builder.withMatrix(matrix) - .withWindowCrop(crop) - .withAlpha(mAlpha.value) - .withCornerRadius(windowCornerRadius) - .withShadowRadius(mShadowRadius.value); + builder.setMatrix(matrix) + .setWindowCrop(crop) + .setAlpha(mAlpha.value) + .setCornerRadius(windowCornerRadius) + .setShadowRadius(mShadowRadius.value); } else if (target.mode == MODE_OPENING) { matrix.setTranslate(tmpPos.x, tmpPos.y); - builder.withMatrix(matrix) - .withWindowCrop(crop) - .withAlpha(1f); + builder.setMatrix(matrix) + .setWindowCrop(crop) + .setAlpha(1f); } - params[i] = builder.build(); } - surfaceApplier.scheduleApply(params); + surfaceApplier.scheduleApply(transaction); } }); @@ -1553,8 +1556,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * the transition. */ public Pair<RectFSpringAnim, AnimatorSet> createWallpaperOpenAnimations( - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, boolean fromUnlock, RectF startRect, float startWindowCornerRadius) { @@ -1596,8 +1599,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener true /* animateOverviewScrim */, launcherView).getAnimators()); if (!areAllTargetsTranslucent(appTargets)) { - anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController(), - STATE_DEPTH, + anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth, + MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mLauncher), NORMAL.getDepth(mLauncher))); } @@ -1663,9 +1666,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener @Override public void onCreateAnimation(int transit, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets, + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets, LauncherAnimationRunner.AnimationResult result) { if (mLauncher.isDestroyed()) { AnimatorSet anim = new AnimatorSet(); @@ -1679,9 +1682,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener mLauncher.getStateManager().moveToRestState(); } + RectF windowTargetBounds = + new RectF(getWindowTargetBounds(appTargets, getRotationChange(appTargets))); Pair<RectFSpringAnim, AnimatorSet> pair = createWallpaperOpenAnimations( - appTargets, wallpaperTargets, mFromUnlock, - new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx), + appTargets, wallpaperTargets, mFromUnlock, windowTargetBounds, QuickStepContract.getWindowCornerRadius(mLauncher)); mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL); @@ -1704,9 +1708,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener @Override public void onCreateAnimation(int transit, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets, + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets, LauncherAnimationRunner.AnimationResult result) { AnimatorSet anim = new AnimatorSet(); boolean launcherClosing = @@ -1717,7 +1721,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final boolean skipFirstFrame; if (launchingFromWidget) { composeWidgetLaunchAnimator(anim, (LauncherAppWidgetHostView) mV, appTargets, - wallpaperTargets, nonAppTargets); + wallpaperTargets, nonAppTargets, launcherClosing); addCujInstrumentation( anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_WIDGET); skipFirstFrame = true; @@ -1833,7 +1837,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * RectFSpringAnim update listener to be used for app to home animation. */ private class SpringAnimRunner implements RectFSpringAnim.OnUpdateListener { - private final RemoteAnimationTargetCompat[] mAppTargets; + private final RemoteAnimationTarget[] mAppTargets; private final Matrix mMatrix = new Matrix(); private final Point mTmpPos = new Point(); private final Rect mCurrentRect = new Rect(); @@ -1844,7 +1848,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener private final Rect mTmpRect = new Rect(); - SpringAnimRunner(RemoteAnimationTargetCompat[] appTargets, RectF targetRect, + SpringAnimRunner(RemoteAnimationTarget[] appTargets, RectF targetRect, Rect windowTargetBounds, float startWindowCornerRadius) { mAppTargets = appTargets; mStartRadius = startWindowCornerRadius; @@ -1859,10 +1863,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener @Override public void onUpdate(RectF currentRectF, float progress) { - SurfaceParams[] params = new SurfaceParams[mAppTargets.length]; + SurfaceTransaction transaction = new SurfaceTransaction(); for (int i = mAppTargets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = mAppTargets[i]; - SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash); + RemoteAnimationTarget target = mAppTargets[i]; + SurfaceProperties builder = transaction.forSurface(target.leash); if (target.localBounds != null) { mTmpPos.set(target.localBounds.left, target.localBounds.top); @@ -1897,18 +1901,17 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener mMatrix.setScale(scale, scale); mMatrix.postTranslate(mCurrentRect.left, mCurrentRect.top); - builder.withMatrix(mMatrix) - .withWindowCrop(mTmpRect) - .withAlpha(getWindowAlpha(progress)) - .withCornerRadius(getCornerRadius(progress) / scale); + builder.setMatrix(mMatrix) + .setWindowCrop(mTmpRect) + .setAlpha(getWindowAlpha(progress)) + .setCornerRadius(getCornerRadius(progress) / scale); } else if (target.mode == MODE_OPENING) { mMatrix.setTranslate(mTmpPos.x, mTmpPos.y); - builder.withMatrix(mMatrix) - .withAlpha(1f); + builder.setMatrix(mMatrix) + .setAlpha(1f); } - params[i] = builder.build(); } - mSurfaceApplier.scheduleApply(params); + mSurfaceApplier.scheduleApply(transaction); } protected float getWindowAlpha(float progress) { diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java index c54d119904..4fbe8cfd26 100644 --- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -30,7 +30,6 @@ import androidx.annotation.Nullable; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -51,7 +50,7 @@ import java.util.List; import java.util.stream.Collectors; @TargetApi(Build.VERSION_CODES.P) -public class PredictionRowView<T extends Context & ActivityContext & DeviceProfileListenable> +public class PredictionRowView<T extends Context & ActivityContext> extends LinearLayout implements OnDeviceProfileChangeListener, FloatingHeaderRow { private final T mActivityContext; diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index 21008344f7..ba412c9909 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -38,6 +38,7 @@ import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.views.AbstractSlideInView; @@ -192,7 +193,7 @@ public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements I icon.setEnabled(false); icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); icon.verifyHighRes(); - CellLayout.LayoutParams lp = new CellLayout.LayoutParams(i, 0, 1, 1); + CellLayoutLayoutParams lp = new CellLayoutLayoutParams(i, 0, 1, 1, -1); mSampleHotseat.addViewToCellLayout(icon, i, info.getViewId(), lp, true); } } diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 05b81671c3..0a2a9b37ba 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -305,7 +305,7 @@ public class HotseatPredictionController implements DragController.DragListener, * Sets or updates the predicted items only once the hotseat becomes hidden to the user */ private void applyPredictedItems(FixedContainerItems items) { - mPredictedItems = items.items; + mPredictedItems = new ArrayList(items.items); if (mPredictedItems.isEmpty()) { HotseatRestoreHelper.restoreBackup(mLauncher); } diff --git a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java index bc3253fcfb..e504141024 100644 --- a/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java +++ b/quickstep/src/com/android/launcher3/model/PredictionUpdateTask.java @@ -30,12 +30,14 @@ import android.os.UserHandle; import androidx.annotation.NonNull; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.Utilities; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.QuickstepModelDelegate.PredictorState; import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -59,7 +61,7 @@ public class PredictionUpdateTask extends BaseModelUpdateTask { Context context = app.getContext(); // TODO: remove this - Utilities.getDevicePrefs(context).edit() + LauncherPrefs.getDevicePrefs(context).edit() .putBoolean(LAST_PREDICTION_ENABLED_STATE, !mTargets.isEmpty()).apply(); Set<UserHandle> usersForChangedShortcuts = @@ -68,7 +70,7 @@ public class PredictionUpdateTask extends BaseModelUpdateTask { .map(info -> info.user) .collect(Collectors.toSet()); - FixedContainerItems fci = new FixedContainerItems(mPredictorState.containerId); + List<ItemInfo> items = new ArrayList<>(mTargets.size()); for (AppTarget target : mTargets) { WorkspaceItemInfo itemInfo; ShortcutInfo si = target.getShortcutInfo(); @@ -107,10 +109,11 @@ public class PredictionUpdateTask extends BaseModelUpdateTask { } } - itemInfo.container = fci.containerId; - fci.items.add(itemInfo); + itemInfo.container = mPredictorState.containerId; + items.add(itemInfo); } + FixedContainerItems fci = new FixedContainerItems(mPredictorState.containerId, items); dataModel.extraItems.put(fci.containerId, fci); bindExtraContainerItems(fci); usersForChangedShortcuts.forEach( diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index de0b14d4fa..118cfc6620 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -18,12 +18,12 @@ package com.android.launcher3.model; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.formatElapsedTime; +import static com.android.launcher3.LauncherPrefs.getDevicePrefs; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; -import static com.android.launcher3.Utilities.getDevicePrefs; import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle; import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo; import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation; @@ -132,7 +132,8 @@ public class QuickstepModelDelegate extends ModelDelegate { // Widgets prediction isn't used frequently. And thus, it is not persisted on disk. mDataModel.extraItems.put(mWidgetsRecommendationState.containerId, - new FixedContainerItems(mWidgetsRecommendationState.containerId)); + new FixedContainerItems(mWidgetsRecommendationState.containerId, + new ArrayList<>())); mActive = true; } diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java index 68ed682792..fb2d0dcc3c 100644 --- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java +++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java @@ -18,8 +18,6 @@ package com.android.launcher3.model; import static android.content.ContentResolver.SCHEME_CONTENT; -import static com.android.launcher3.Utilities.newContentObserver; - import android.annotation.TargetApi; import android.app.RemoteAction; import android.content.ContentProviderClient; diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java index 7a483a808a..6160378767 100644 --- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java +++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java @@ -18,22 +18,23 @@ package com.android.launcher3.model; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION; import android.app.prediction.AppTarget; -import android.content.ComponentName; import android.text.TextUtils; import androidx.annotation.NonNull; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.BgDataModel.FixedContainerItems; import com.android.launcher3.model.QuickstepModelDelegate.PredictorState; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.widget.PendingAddWidgetInfo; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; /** Task to update model as a result of predicted widgets update */ @@ -59,50 +60,45 @@ public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask { Set<ComponentKey> widgetsInWorkspace = dataModel.appWidgets.stream().map( widget -> new ComponentKey(widget.providerName, widget.user)).collect( Collectors.toSet()); + Predicate<WidgetItem> notOnWorkspace = w -> !widgetsInWorkspace.contains(w); Map<PackageUserKey, List<WidgetItem>> allWidgets = dataModel.widgetsModel.getAllWidgetsWithoutShortcuts(); - FixedContainerItems fixedContainerItems = - new FixedContainerItems(mPredictorState.containerId); + List<WidgetItem> servicePredictedItems = new ArrayList<>(); + List<WidgetItem> localFilteredWidgets = new ArrayList<>(); - if (FeatureFlags.ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER.get()) { - for (AppTarget app : mTargets) { - PackageUserKey packageUserKey = new PackageUserKey(app.getPackageName(), - app.getUser()); - if (allWidgets.containsKey(packageUserKey)) { - List<WidgetItem> notAddedWidgets = allWidgets.get(packageUserKey).stream() - .filter(item -> - !widgetsInWorkspace.contains( - new ComponentKey(item.componentName, item.user))) - .collect(Collectors.toList()); - if (notAddedWidgets.size() > 0) { - // Even an apps have more than one widgets, we only include one widget. - fixedContainerItems.items.add( - new PendingAddWidgetInfo( - notAddedWidgets.get(0).widgetInfo, - CONTAINER_WIDGETS_PREDICTION)); - } - } + for (AppTarget app : mTargets) { + PackageUserKey packageUserKey = new PackageUserKey(app.getPackageName(), app.getUser()); + List<WidgetItem> widgets = allWidgets.get(packageUserKey); + if (widgets == null || widgets.isEmpty()) { + continue; } - } else { - Map<ComponentKey, WidgetItem> widgetItems = - allWidgets.values().stream().flatMap(List::stream).distinct() - .collect(Collectors.toMap(widget -> (ComponentKey) widget, - widget -> widget)); - for (AppTarget app : mTargets) { - if (TextUtils.isEmpty(app.getClassName())) { + String className = app.getClassName(); + if (!TextUtils.isEmpty(className)) { + WidgetItem item = widgets.stream() + .filter(w -> className.equals(w.componentName.getClassName())) + .filter(notOnWorkspace) + .findFirst() + .orElse(null); + if (item != null) { + servicePredictedItems.add(item); continue; } - ComponentKey targetWidget = new ComponentKey( - new ComponentName(app.getPackageName(), app.getClassName()), app.getUser()); - if (widgetItems.containsKey(targetWidget)) { - fixedContainerItems.items.add( - new PendingAddWidgetInfo(widgetItems.get( - targetWidget).widgetInfo, - CONTAINER_WIDGETS_PREDICTION)); - } } + // No widget was added by the service, try local filtering + widgets.stream().filter(notOnWorkspace).findFirst() + .ifPresent(localFilteredWidgets::add); + } + if (servicePredictedItems.isEmpty()) { + servicePredictedItems.addAll(localFilteredWidgets); } + + List<ItemInfo> items = servicePredictedItems.stream() + .map(it -> new PendingAddWidgetInfo(it.widgetInfo, CONTAINER_WIDGETS_PREDICTION)) + .collect(Collectors.toList()); + FixedContainerItems fixedContainerItems = + new FixedContainerItems(mPredictorState.containerId, items); + dataModel.extraItems.put(mPredictorState.containerId, fixedContainerItems); bindExtraContainerItems(fixedContainerItems); diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java index 7c3281a046..9554bd3d9c 100644 --- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java +++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java @@ -15,21 +15,37 @@ */ package com.android.launcher3.popup; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE; import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition; +import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.View; +import androidx.annotation.Nullable; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.R; +import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; +import com.android.quickstep.util.SplitSelectStateController; +import com.android.quickstep.views.FloatingTaskView; import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.recents.model.Task; + +import java.util.function.Consumer; public interface QuickstepSystemShortcut { @@ -44,6 +60,10 @@ public interface QuickstepSystemShortcut { class SplitSelectSystemShortcut extends SystemShortcut<QuickstepLauncher> { + private final int mSplitPlaceholderSize; + private final int mSplitPlaceholderInset; + + private final Rect mTempRect = new Rect(); private final SplitPositionOption mPosition; public SplitSelectSystemShortcut(QuickstepLauncher launcher, ItemInfo itemInfo, @@ -51,6 +71,11 @@ public interface QuickstepSystemShortcut { super(position.iconResId, position.textResId, launcher, itemInfo, originalView); mPosition = position; + + mSplitPlaceholderSize = launcher.getResources().getDimensionPixelSize( + R.dimen.split_placeholder_size); + mSplitPlaceholderInset = launcher.getResources().getDimensionPixelSize( + R.dimen.split_placeholder_inset); } @Override @@ -72,11 +97,53 @@ public interface QuickstepSystemShortcut { return; } - RecentsView recentsView = mTarget.getOverviewPanel(); StatsLogManager.EventEnum splitEvent = getLogEventForPosition(mPosition.stagePosition); - recentsView.initiateSplitSelect( - new SplitSelectSource(mOriginalView, new BitmapDrawable(bitmap), intent, - mPosition, mItemInfo, splitEvent)); + RecentsView recentsView = mTarget.getOverviewPanel(); + // Check if there is already an instance of this app running, if so, initiate the split + // using that. + recentsView.findLastActiveTaskAndDoSplitOperation( + intent.getComponent(), + (Consumer<Task>) foundTask -> { + SplitSelectSource source = new SplitSelectSource(mOriginalView, + new BitmapDrawable(bitmap), intent, mPosition, mItemInfo, + splitEvent, foundTask); + if (ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) { + startSplitToHome(source); + } else { + recentsView.initiateSplitSelect(source); + } + } + ); + } + + private void startSplitToHome(SplitSelectSource source) { + AbstractFloatingView.closeAllOpenViews(mTarget); + + SplitSelectStateController controller = mTarget.getSplitSelectStateController(); + controller.setInitialTaskSelect(source.intent, source.position.stagePosition, + source.itemInfo, source.splitEvent, source.alreadyRunningTask); + + RecentsView recentsView = mTarget.getOverviewPanel(); + recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds( + mSplitPlaceholderSize, mSplitPlaceholderInset, mTarget.getDeviceProfile(), + controller.getActiveSplitStagePosition(), mTempRect); + + PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration()); + RectF startingTaskRect = new RectF(); + final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(mTarget, + source.view, null /* thumbnail */, source.drawable, startingTaskRect); + floatingTaskView.setAlpha(1); + floatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect, + false /* fadeWithThumbnail */, true /* isStagedTask */); + controller.setFirstFloatingTaskView(floatingTaskView); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + mTarget.getDragLayer().removeView(floatingTaskView); + controller.resetState(); + } + }); + anim.buildAnim().start(); } } @@ -86,18 +153,21 @@ public interface QuickstepSystemShortcut { public final Drawable drawable; public final Intent intent; public final SplitPositionOption position; - public final ItemInfo mItemInfo; + public final ItemInfo itemInfo; public final StatsLogManager.EventEnum splitEvent; + @Nullable + public final Task alreadyRunningTask; public SplitSelectSource(View view, Drawable drawable, Intent intent, SplitPositionOption position, ItemInfo itemInfo, - StatsLogManager.EventEnum splitEvent) { + StatsLogManager.EventEnum splitEvent, @Nullable Task foundTask) { this.view = view; this.drawable = drawable; this.intent = intent; this.position = position; - this.mItemInfo = itemInfo; + this.itemInfo = itemInfo; this.splitEvent = splitEvent; + this.alreadyRunningTask = foundTask; } } } diff --git a/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java b/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java index 5bf727a60b..8720bd8f26 100644 --- a/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java +++ b/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java @@ -18,7 +18,9 @@ package com.android.launcher3.secondarydisplay; import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT; import android.content.Context; +import android.view.View; +import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.appprediction.AppsDividerView; import com.android.launcher3.appprediction.PredictionRowView; import com.android.launcher3.model.BgDataModel; @@ -39,10 +41,13 @@ public final class SecondaryDisplayPredictionsImpl extends SecondaryDisplayPredi @Override void updateAppDivider() { OnboardingPrefs<?> onboardingPrefs = mActivityContext.getOnboardingPrefs(); - mActivityContext.getAppsView().getFloatingHeaderView() - .findFixedRowByType(AppsDividerView.class) - .setShowAllAppsLabel(!onboardingPrefs.hasReachedMaxCount(ALL_APPS_VISITED_COUNT)); - onboardingPrefs.incrementEventCount(ALL_APPS_VISITED_COUNT); + if (onboardingPrefs != null) { + mActivityContext.getAppsView().getFloatingHeaderView() + .findFixedRowByType(AppsDividerView.class) + .setShowAllAppsLabel( + !onboardingPrefs.hasReachedMaxCount(ALL_APPS_VISITED_COUNT)); + onboardingPrefs.incrementEventCount(ALL_APPS_VISITED_COUNT); + } } @Override @@ -51,4 +56,12 @@ public final class SecondaryDisplayPredictionsImpl extends SecondaryDisplayPredi .findFixedRowByType(PredictionRowView.class) .setPredictedApps(item.items); } + + @Override + public void setLongClickListener(ActivityAllAppsContainerView<?> appsView, + View.OnLongClickListener onIconLongClickListener) { + appsView.getFloatingHeaderView() + .findFixedRowByType(PredictionRowView.class) + .setOnIconLongClickListener(onIconLongClickListener); + } } diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java index e3fd3f9a06..867e168dd2 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java @@ -19,11 +19,11 @@ package com.android.launcher3.statehandlers; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH; import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER; +import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.util.FloatProperty; import android.view.CrossWindowBlurListeners; import android.view.View; import android.view.ViewRootImpl; @@ -32,7 +32,6 @@ import android.view.ViewTreeObserver; import com.android.launcher3.BaseActivity; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; @@ -47,43 +46,12 @@ import java.util.function.Consumer; public class DepthController extends BaseDepthController implements StateHandler<LauncherState>, BaseActivity.MultiWindowModeChangedListener { - /** - * A property that updates the background blur within a given range of values (ie. even if the - * animator goes beyond 0..1, the interpolated value will still be bounded). - */ - public static class ClampedDepthProperty extends FloatProperty<DepthController> { - private final float mMinValue; - private final float mMaxValue; - - public ClampedDepthProperty(float minValue, float maxValue) { - super("depthClamped"); - mMinValue = minValue; - mMaxValue = maxValue; - } - - @Override - public void setValue(DepthController depthController, float depth) { - depthController.setDepth(Utilities.boundToRange(depth, mMinValue, mMaxValue)); - } - - @Override - public Float get(DepthController depthController) { - return depthController.mDepth; - } - } - private final ViewTreeObserver.OnDrawListener mOnDrawListener = this::onLauncherDraw; private final Consumer<Boolean> mCrossWindowBlurListener = this::setCrossWindowBlursEnabled; private final Runnable mOpaquenessListener = this::applyDepthAndBlur; - /** - * If we're launching and app and should not be blurring the screen for performance reasons. - */ - private boolean mBlurDisabledForAppLaunch; - - // Workaround for animating the depth when multiwindow mode changes. private boolean mIgnoreStateChangesDuringMultiWindowAnimation = false; @@ -145,12 +113,8 @@ public class DepthController extends BaseDepthController implements StateHandler return; } - float toDepth = toState.getDepth(mLauncher); - if (Float.compare(mDepth, toDepth) != 0) { - setDepth(toDepth); - } else if (toState == LauncherState.OVERVIEW) { - applyDepthAndBlur(); - } else if (toState == LauncherState.BACKGROUND_APP) { + stateDepth.setValue(toState.getDepth(mLauncher)); + if (toState == LauncherState.BACKGROUND_APP) { mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener); } } @@ -164,10 +128,8 @@ public class DepthController extends BaseDepthController implements StateHandler } float toDepth = toState.getDepth(mLauncher); - if (Float.compare(mDepth, toDepth) != 0) { - animation.setFloat(this, STATE_DEPTH, toDepth, - config.getInterpolator(ANIM_DEPTH, LINEAR)); - } + animation.setFloat(stateDepth, MULTI_PROPERTY_VALUE, toDepth, + config.getInterpolator(ANIM_DEPTH, LINEAR)); } @Override @@ -180,7 +142,7 @@ public class DepthController extends BaseDepthController implements StateHandler public void onMultiWindowModeChanged(boolean isInMultiWindowMode) { mIgnoreStateChangesDuringMultiWindowAnimation = true; - ObjectAnimator mwAnimation = ObjectAnimator.ofFloat(this, STATE_DEPTH, + ObjectAnimator mwAnimation = ObjectAnimator.ofFloat(stateDepth, MULTI_PROPERTY_VALUE, mLauncher.getStateManager().getState().getDepth(mLauncher, isInMultiWindowMode)) .setDuration(300); mwAnimation.addListener(new AnimatorListenerAdapter() { @@ -198,9 +160,9 @@ public class DepthController extends BaseDepthController implements StateHandler writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius); writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled); writer.println(prefix + "\tmSurface=" + mSurface); - writer.println(prefix + "\tmDepth=" + mDepth); + writer.println(prefix + "\tmStateDepth=" + stateDepth.getValue()); + writer.println(prefix + "\tmWidgetDepth=" + widgetDepth.getValue()); writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur); - writer.println(prefix + "\tmBlurDisabledForAppLaunch=" + mBlurDisabledForAppLaunch); writer.println(prefix + "\tmInEarlyWakeUp=" + mInEarlyWakeUp); writer.println(prefix + "\tmIgnoreStateChangesDuringMultiWindowAnimation=" + mIgnoreStateChangesDuringMultiWindowAnimation); diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java new file mode 100644 index 0000000000..bbc0627517 --- /dev/null +++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2022 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.launcher3.statehandlers; + +import android.os.SystemProperties; +import android.view.View; + +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; +import com.android.launcher3.statemanager.StatefulActivity; +import com.android.launcher3.uioverrides.QuickstepLauncher; + +/** + * Controls the visibility of the workspace and the resumed / paused state when desktop mode + * is enabled. + */ +public class DesktopVisibilityController { + + private final Launcher mLauncher; + + private boolean mFreeformTasksVisible; + private boolean mInOverviewState; + + public DesktopVisibilityController(Launcher launcher) { + mLauncher = launcher; + } + + /** + * Whether desktop mode is supported. + */ + private boolean isDesktopModeSupported() { + return SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false) + || SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false); + } + + /** + * Whether freeform windows are visible in desktop mode. + */ + public boolean areFreeformTasksVisible() { + return mFreeformTasksVisible; + } + + /** + * Sets whether freeform windows are visible and updates launcher visibility based on that. + */ + public void setFreeformTasksVisible(boolean freeformTasksVisible) { + if (freeformTasksVisible != mFreeformTasksVisible) { + mFreeformTasksVisible = freeformTasksVisible; + updateLauncherVisibility(); + } + } + + /** + * Sets whether the overview is visible and updates launcher visibility based on that. + */ + public void setOverviewStateEnabled(boolean overviewStateEnabled) { + if (overviewStateEnabled != mInOverviewState) { + mInOverviewState = overviewStateEnabled; + updateLauncherVisibility(); + } + } + + /** + * Updates launcher visibility and state to look like it is paused or resumed depending on + * whether freeform windows are showing in desktop mode. + */ + private void updateLauncherVisibility() { + StatefulActivity<LauncherState> activity = + QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity(); + View workspaceView = mLauncher.getWorkspace(); + if (activity == null || workspaceView == null || !isDesktopModeSupported()) { + return; + } + + if (mFreeformTasksVisible) { + workspaceView.setVisibility(View.INVISIBLE); + if (!mInOverviewState) { + // When freeform is visible & we're not in overview, we want launcher to appear + // paused, this ensures that taskbar displays. + activity.setPaused(); + } + } else { + workspaceView.setVisibility(View.VISIBLE); + // If freeform isn't visible ensure that launcher appears resumed to behave normally. + // Check activity state before calling setResumed(). Launcher may have been actually + // paused (eg fullscreen task moved to front). + // In this case we should not mark the activity as resumed. + if (activity.isResumed()) { + activity.setResumed(); + } + } + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java index b4052e3d71..82d18307ca 100644 --- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java @@ -19,18 +19,16 @@ import android.content.Context; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.util.Themes; -import com.android.launcher3.views.AppLauncher; +import com.android.launcher3.views.ActivityContext; import java.util.ArrayList; import java.util.List; // TODO(b/218912746): Share more behavior to avoid all apps context depending directly on taskbar. /** Base for common behavior between taskbar window contexts. */ -public abstract class BaseTaskbarContext extends ContextThemeWrapper implements AppLauncher, - DeviceProfileListenable { +public abstract class BaseTaskbarContext extends ContextThemeWrapper implements ActivityContext { protected final LayoutInflater mLayoutInflater; private final List<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>(); diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java index 0ab3cfd547..48481d88b9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java @@ -18,6 +18,8 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_NOTIFICATIONS; import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_QUICK_SETTINGS; +import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -31,6 +33,8 @@ public class DesktopNavbarButtonsViewController extends NavbarButtonsViewControl private final TaskbarActivityContext mContext; private final FrameLayout mNavButtonsView; private final ViewGroup mNavButtonContainer; + private final ViewGroup mStartContextualContainer; + private final View mAllAppsButton; private TaskbarControllers mControllers; @@ -40,6 +44,12 @@ public class DesktopNavbarButtonsViewController extends NavbarButtonsViewControl mContext = context; mNavButtonsView = navButtonsView; mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons); + mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons); + mAllAppsButton = LayoutInflater.from(context) + .inflate(R.layout.taskbar_all_apps_button, mStartContextualContainer, false); + mAllAppsButton.setOnClickListener((View v) -> { + mControllers.taskbarAllAppsController.show(); + }); } /** @@ -57,6 +67,8 @@ public class DesktopNavbarButtonsViewController extends NavbarButtonsViewControl addButton(R.drawable.ic_sysbar_notifications, BUTTON_NOTIFICATIONS, mNavButtonContainer, mControllers.navButtonController, R.id.notifications_button); + // All apps button + mStartContextualContainer.addView(mAllAppsButton); } /** Cleans up on destroy */ diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java index f1e67479f5..df867cb831 100644 --- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java @@ -21,6 +21,7 @@ import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH import android.animation.Animator; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StateManager; import com.android.quickstep.RecentsActivity; import com.android.quickstep.fallback.RecentsState; @@ -40,8 +41,7 @@ public class FallbackTaskbarUIController extends TaskbarUIController { animateToRecentsState(toState); // Handle tapping on live tile. - RecentsView recentsView = mRecentsActivity.getOverviewPanel(); - recentsView.setTaskLaunchListener(toState == RecentsState.DEFAULT + getRecentsView().setTaskLaunchListener(toState == RecentsState.DEFAULT ? (() -> animateToRecentsState(RecentsState.BACKGROUND_APP)) : null); } }; @@ -70,12 +70,14 @@ public class FallbackTaskbarUIController extends TaskbarUIController { * Currently this animation just force stashes the taskbar in Overview. */ public Animator createAnimToRecentsState(RecentsState toState, long duration) { - boolean forceStashed = toState.hasOverviewActions(); + boolean useStashedLauncherState = toState.hasOverviewActions(); + boolean stashedLauncherState = + useStashedLauncherState && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get(); TaskbarStashController controller = mControllers.taskbarStashController; // Set both FLAG_IN_STASHED_LAUNCHER_STATE and FLAG_IN_APP to ensure the state is respected. // For all other states, just use the current stashed-in-app setting (e.g. if long clicked). - controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, forceStashed); - controller.updateStateForFlag(FLAG_IN_APP, !forceStashed); + controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, stashedLauncherState); + controller.updateStateForFlag(FLAG_IN_APP, !useStashedLauncherState); return controller.applyStateWithoutStart(duration); } @@ -85,4 +87,9 @@ public class FallbackTaskbarUIController extends TaskbarUIController { anim.start(); } } + + @Override + public RecentsView getRecentsView() { + return mRecentsActivity.getOverviewPanel(); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/FloatingTaskIntentResolver.java b/quickstep/src/com/android/launcher3/taskbar/FloatingTaskIntentResolver.java deleted file mode 100644 index 5f4d239532..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/FloatingTaskIntentResolver.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2022 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.launcher3.taskbar; - -import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; - -import android.annotation.Nullable; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.text.TextUtils; -import android.util.Log; - -import com.android.launcher3.R; - -// TODO: This would be replaced by the thing that has the role and provides the intent. -/** - * Helper to determine what intent should be used to display in a floating window, if one - * exists. - */ -public class FloatingTaskIntentResolver { - private static final String TAG = FloatingTaskIntentResolver.class.getSimpleName(); - - @Nullable - /** Gets an intent for a floating task, if one exists. */ - public static Intent getIntent(Context context) { - PackageManager pm = context.getPackageManager(); - String pkg = context.getString(R.string.floating_task_package); - String action = context.getString(R.string.floating_task_action); - if (TextUtils.isEmpty(pkg) || TextUtils.isEmpty(action)) { - Log.d(TAG, "intent could not be found, pkg= " + pkg + " action= " + action); - return null; - } - Intent intent = createIntent(pm, null, pkg, action); - if (intent != null) { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - return intent; - } - Log.d(TAG, "No valid intent found!"); - return null; - } - - @Nullable - private static Intent createIntent(PackageManager pm, @Nullable String activityName, - String packageName, String action) { - if (TextUtils.isEmpty(activityName)) { - activityName = queryActivityForAction(pm, packageName, action); - } - if (TextUtils.isEmpty(activityName)) { - Log.d(TAG, "Activity name is empty even after action search: " + action); - return null; - } - ComponentName component = new ComponentName(packageName, activityName); - Intent intent = new Intent(action).setComponent(component).setPackage(packageName); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Log.d(TAG, "createIntent returning: " + intent); - return intent; - } - - @Nullable - private static String queryActivityForAction(PackageManager pm, String packageName, - String action) { - Intent intent = new Intent(action).setPackage(packageName); - ResolveInfo resolveInfo = pm.resolveActivity(intent, MATCH_DEFAULT_ONLY); - if (resolveInfo == null || resolveInfo.activityInfo == null) { - Log.d(TAG, "queryActivityForAction: + " + resolveInfo); - return null; - } - ActivityInfo info = resolveInfo.activityInfo; - if (!info.exported) { - Log.d(TAG, "queryActivityForAction: + " + info + " not exported"); - return null; - } - if (!info.enabled) { - Log.d(TAG, "queryActivityForAction: + " + info + " not enabled"); - return null; - } - return resolveInfo.activityInfo.name; - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/LaunchFloatingTaskButton.java b/quickstep/src/com/android/launcher3/taskbar/LaunchFloatingTaskButton.java deleted file mode 100644 index b15669b5ef..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/LaunchFloatingTaskButton.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2022 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.launcher3.taskbar; - -import android.content.Context; -import android.graphics.Bitmap; -import android.util.AttributeSet; -import android.view.ContextThemeWrapper; - -import com.android.launcher3.BubbleTextView; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.R; -import com.android.launcher3.icons.FastBitmapDrawable; - -/** - * Button in Taskbar that opens something in a floating task. - */ -public class LaunchFloatingTaskButton extends BubbleTextView { - - public LaunchFloatingTaskButton(Context context) { - this(context, null); - } - - public LaunchFloatingTaskButton(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public LaunchFloatingTaskButton(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - Context theme = new ContextThemeWrapper(context, R.style.AllAppsButtonTheme); - Bitmap bitmap = LauncherAppState.getInstance(context).getIconCache().getIconFactory() - .createScaledBitmapWithShadow( - theme.getDrawable(R.drawable.ic_floating_task_button)); - setIcon(new FastBitmapDrawable(bitmap)); - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index a219ac6324..a18aabebab 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -17,6 +17,7 @@ package com.android.launcher3.taskbar; import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; +import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION; import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_RESUMED; import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS; @@ -26,7 +27,6 @@ import android.annotation.ColorInt; import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; -import android.view.MotionEvent; import android.view.TaskTransitionSpec; import android.view.WindowManagerGlobal; @@ -38,17 +38,18 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.OnboardingPrefs; -import com.android.quickstep.AnimatedFloat; import com.android.quickstep.RecentsAnimationCallbacks; +import com.android.quickstep.views.RecentsView; import java.io.PrintWriter; -import java.util.Arrays; import java.util.Set; import java.util.stream.Stream; @@ -116,7 +117,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController { @Override protected boolean isTaskbarTouchable() { - return !mTaskbarLauncherStateController.isAnimatingToLauncher(); + return !(mTaskbarLauncherStateController.isAnimatingToLauncher() + && mTaskbarLauncherStateController.goingToAlignedLauncherState()); } public void setShouldDelayLauncherStateAnim(boolean shouldDelayLauncherStateAnim) { @@ -154,9 +156,11 @@ public class LauncherTaskbarUIController extends TaskbarUIController { isResumed, fromInit, /* startAnimation= */ true, - !isResumed - ? QuickstepTransitionManager.TASKBAR_TO_APP_DURATION - : QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION); + DisplayController.isTransientTaskbar(mLauncher) + ? TRANSIENT_TASKBAR_TRANSITION_DURATION + : (!isResumed + ? QuickstepTransitionManager.TASKBAR_TO_APP_DURATION + : QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION)); } @Nullable @@ -171,7 +175,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } } - if (ENABLE_SHELL_TRANSITIONS + if (ENABLE_SHELL_TRANSITIONS && isResumed && !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) { // Launcher is resumed, but in a state where taskbar is still independent, so // ignore the state change. @@ -190,16 +194,15 @@ public class LauncherTaskbarUIController extends TaskbarUIController { */ public Animator createAnimToLauncher(@NonNull LauncherState toState, @NonNull RecentsAnimationCallbacks callbacks, long duration) { - return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration); - } - - /** - * @param ev MotionEvent in screen coordinates. - * @return Whether any Taskbar item could handle the given MotionEvent if given the chance. - */ - public boolean isEventOverAnyTaskbarItem(MotionEvent ev) { - return mControllers.taskbarViewController.isEventOverAnyItem(ev) - || mControllers.navbarButtonsViewController.isEventOverAnyItem(ev); + AnimatorSet set = new AnimatorSet(); + Animator taskbarState = mTaskbarLauncherStateController + .createAnimToLauncher(toState, callbacks, duration); + long halfDuration = Math.round(duration * 0.5f); + Animator translation = + mControllers.taskbarTranslationController.createAnimToLauncher(halfDuration); + + set.playTogether(taskbarState, translation); + return set; } public boolean isDraggingItem() { @@ -225,7 +228,9 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } else { // Adjust task transition spec to account for taskbar being visible @ColorInt int taskAnimationBackgroundColor = - mLauncher.getColor(R.color.taskbar_background); + DisplayController.isTransientTaskbar(mLauncher) + ? mLauncher.getColor(R.color.transient_taskbar_background) + : mLauncher.getColor(R.color.taskbar_background); TaskTransitionSpec customTaskAnimationSpec = new TaskTransitionSpec( taskAnimationBackgroundColor, @@ -249,11 +254,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mTaskbarOverrideBackgroundAlpha.updateValue(forceHide ? 0 : 1); } - @Override - public Stream<ItemInfoWithIcon> getAppIconsForEdu() { - return Arrays.stream(mLauncher.getAppsView().getAppsStore().getApps()); - } - /** * Starts the taskbar education flow, if the user hasn't seen it yet. */ @@ -274,13 +274,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController { && !mLauncher.getOnboardingPrefs().getBoolean(OnboardingPrefs.TASKBAR_EDU_SEEN); } - /** - * Manually ends the taskbar education flow. - */ - public void hideEdu() { - mControllers.taskbarEduController.hideEdu(); - } - @Override public void onTaskbarIconLaunched(ItemInfo item) { InstanceId instanceId = new InstanceIdSequence().newInstanceId(); @@ -291,9 +284,16 @@ public class LauncherTaskbarUIController extends TaskbarUIController { @Override public void setSystemGestureInProgress(boolean inProgress) { super.setSystemGestureInProgress(inProgress); - // Launcher's ScrimView will draw the background throughout the gesture. But once the - // gesture ends, start drawing taskbar's background again since launcher might stop drawing. - forceHideBackground(inProgress); + if (DisplayController.isTransientTaskbar(mLauncher)) { + forceHideBackground(false); + return; + } + if (!FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) { + // Launcher's ScrimView will draw the background throughout the gesture. But once the + // gesture ends, start drawing taskbar's background again since launcher might stop + // drawing. + forceHideBackground(inProgress); + } } /** @@ -310,7 +310,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController { return; } mTaskbarInAppDisplayProgress.put(progressIndex, progress); - if (!mControllers.taskbarStashController.isInApp() + if (mControllers.uiController.isIconAlignedWithHotseat() && !mTaskbarLauncherStateController.isAnimatingToLauncher()) { // Only animate the nav buttons while home and not animating home, otherwise let // the TaskbarViewController handle it. @@ -351,6 +351,17 @@ public class LauncherTaskbarUIController extends TaskbarUIController { } @Override + public boolean isIconAlignedWithHotseat() { + return mTaskbarLauncherStateController.isIconAlignedWithHotseat(); + } + + @Override + public boolean isHotseatIconOnTopWhenAligned() { + return mTaskbarLauncherStateController.isInHotseatOnTopStates() + && getInAppDisplayProgress(MINUS_ONE_PAGE_PROGRESS_INDEX) == 0; + } + + @Override public void dumpLogs(String prefix, PrintWriter pw) { super.dumpLogs(prefix, pw); @@ -383,4 +394,9 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw); } + + @Override + public RecentsView getRecentsView() { + return mLauncher.getOverviewPanel(); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index 1c345a6aa4..cbee58bc2f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -23,7 +23,6 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor; import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX; import static com.android.launcher3.taskbar.TaskbarManager.isPhoneButtonNavMode; -import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode; import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y; import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK; import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME; @@ -32,6 +31,7 @@ import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RE import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_KEYGUARD; import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_SMALL_SCREEN; import static com.android.launcher3.taskbar.Utilities.appendFlag; +import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED; @@ -54,6 +54,7 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; import android.graphics.Region.Op; @@ -80,11 +81,15 @@ import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AlphaUpdateListener; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton; +import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory; +import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter; +import com.android.launcher3.util.DimensionUtils; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; -import com.android.quickstep.AnimatedFloat; import com.android.systemui.shared.rotation.FloatingRotationButton; import com.android.systemui.shared.rotation.RotationButton; import com.android.systemui.shared.rotation.RotationButtonController; @@ -126,7 +131,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT public static final int ALPHA_INDEX_IMMERSIVE_MODE = 0; public static final int ALPHA_INDEX_KEYGUARD_OR_DISABLE = 1; - private static final int NUM_ALPHA_CHANNELS = 2; + public static final int ALPHA_INDEX_SUW = 2; + private static final int NUM_ALPHA_CHANNELS = 3; private final ArrayList<StatePropertyHolder> mPropertyHolders = new ArrayList<>(); private final ArrayList<ImageView> mAllButtons = new ArrayList<>(); @@ -180,6 +186,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT private final ViewTreeObserver.OnComputeInternalInsetsListener mSeparateWindowInsetsComputer = this::onComputeInsetsForSeparateWindow; private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender(); + private View mRecentsButton; public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) { mContext = context; @@ -202,9 +209,11 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT boolean isThreeButtonNav = mContext.isThreeButtonNav(); DeviceProfile deviceProfile = mContext.getDeviceProfile(); Resources resources = mContext.getResources(); - mNavButtonsView.getLayoutParams().height = !isPhoneMode(deviceProfile) ? - deviceProfile.taskbarSize : - resources.getDimensionPixelSize(R.dimen.taskbar_size); + Point p = !mContext.isUserSetupComplete() + ? new Point(0, controllers.taskbarActivityContext.getSetupWindowHeight()) + : DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources, + TaskbarManager.isPhoneMode(deviceProfile)); + mNavButtonsView.getLayoutParams().height = p.y; mIsImeRenderingNavButtons = InputMethodService.canImeRenderGesturalNavButtons() && mContext.imeDrawsImeNavBar(); @@ -220,13 +229,13 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mPropertyHolders.add(new StatePropertyHolder( mControllers.taskbarViewController.getTaskbarIconAlpha() - .getProperty(ALPHA_INDEX_KEYGUARD), + .get(ALPHA_INDEX_KEYGUARD), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0)); mPropertyHolders.add(new StatePropertyHolder( mControllers.taskbarViewController.getTaskbarIconAlpha() - .getProperty(ALPHA_INDEX_SMALL_SCREEN), + .get(ALPHA_INDEX_SMALL_SCREEN), flags -> (flags & FLAG_SMALL_SCREEN) == 0)); mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController @@ -265,83 +274,6 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mControllers.navButtonController); updateButtonLayoutSpacing(); updateStateForFlag(FLAG_SMALL_SCREEN, isPhoneButtonNavMode(mContext)); - if (isInSetup) { - // Since setup wizard only has back button enabled, it looks strange to be - // end-aligned, so start-align instead. - FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams) - mNavButtonContainer.getLayoutParams(); - navButtonsLayoutParams.setMarginStart(navButtonsLayoutParams.getMarginEnd()); - navButtonsLayoutParams.setMarginEnd(0); - navButtonsLayoutParams.gravity = Gravity.START; - mNavButtonContainer.requestLayout(); - - // TODO(b/210906568) Dark intensity is currently not propagated during setup, so set - // it based on dark theme for now. - int mode = resources.getConfiguration().uiMode - & Configuration.UI_MODE_NIGHT_MASK; - boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES; - mTaskbarNavButtonDarkIntensity.updateValue(isDarkTheme ? 0 : 1); - } else if (isInKidsMode) { - int iconSize = resources.getDimensionPixelSize( - R.dimen.taskbar_icon_size_kids); - int buttonWidth = resources.getDimensionPixelSize( - R.dimen.taskbar_nav_buttons_width_kids); - int buttonHeight = resources.getDimensionPixelSize( - R.dimen.taskbar_nav_buttons_height_kids); - int buttonRadius = resources.getDimensionPixelSize( - R.dimen.taskbar_nav_buttons_corner_radius_kids); - int paddingleft = (buttonWidth - iconSize) / 2; - int paddingRight = paddingleft; - int paddingTop = (buttonHeight - iconSize) / 2; - int paddingBottom = paddingTop; - - // Update icons - ((ImageView) mBackButton).setImageDrawable( - mBackButton.getContext().getDrawable(R.drawable.ic_sysbar_back_kids)); - ((ImageView) mBackButton).setScaleType(ImageView.ScaleType.FIT_CENTER); - mBackButton.setPadding(paddingleft, paddingTop, paddingRight, paddingBottom); - ((ImageView) mHomeButton).setImageDrawable( - mHomeButton.getContext().getDrawable(R.drawable.ic_sysbar_home_kids)); - ((ImageView) mHomeButton).setScaleType(ImageView.ScaleType.FIT_CENTER); - mHomeButton.setPadding(paddingleft, paddingTop, paddingRight, paddingBottom); - - // Home button layout - LinearLayout.LayoutParams homeLayoutparams = new LinearLayout.LayoutParams( - buttonWidth, - buttonHeight - ); - int homeButtonLeftMargin = resources.getDimensionPixelSize( - R.dimen.taskbar_home_button_left_margin_kids); - homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0); - mHomeButton.setLayoutParams(homeLayoutparams); - - // Back button layout - LinearLayout.LayoutParams backLayoutParams = new LinearLayout.LayoutParams( - buttonWidth, - buttonHeight - ); - int backButtonLeftMargin = resources.getDimensionPixelSize( - R.dimen.taskbar_back_button_left_margin_kids); - backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0); - mBackButton.setLayoutParams(backLayoutParams); - - // Button backgrounds - int whiteWith10PctAlpha = Color.argb(0.1f, 1, 1, 1); - PaintDrawable buttonBackground = new PaintDrawable(whiteWith10PctAlpha); - buttonBackground.setCornerRadius(buttonRadius); - mHomeButton.setBackground(buttonBackground); - mBackButton.setBackground(buttonBackground); - - // Update alignment within taskbar - FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams) - mNavButtonContainer.getLayoutParams(); - navButtonsLayoutParams.setMarginStart(navButtonsLayoutParams.getMarginEnd() / 2); - navButtonsLayoutParams.setMarginEnd(navButtonsLayoutParams.getMarginStart()); - navButtonsLayoutParams.gravity = Gravity.CENTER; - mNavButtonContainer.requestLayout(); - - mHomeButton.setOnLongClickListener(null); - } // Animate taskbar background when either.. // notification shade expanded AND not on keyguard @@ -410,7 +342,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mBackButtonAlpha = new MultiValueAlpha(mBackButton, NUM_ALPHA_CHANNELS); mBackButtonAlpha.setUpdateVisibility(true); mPropertyHolders.add(new StatePropertyHolder( - mBackButtonAlpha.getProperty(ALPHA_INDEX_KEYGUARD_OR_DISABLE), + mBackButtonAlpha.get(ALPHA_INDEX_KEYGUARD_OR_DISABLE), flags -> { // Show only if not disabled, and if not on the keyguard or otherwise only when // the bouncer or a lockscreen app is showing above the keyguard @@ -438,26 +370,26 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mHomeButtonAlpha = new MultiValueAlpha(mHomeButton, NUM_ALPHA_CHANNELS); mHomeButtonAlpha.setUpdateVisibility(true); mPropertyHolders.add( - new StatePropertyHolder(mHomeButtonAlpha.getProperty( + new StatePropertyHolder(mHomeButtonAlpha.get( ALPHA_INDEX_KEYGUARD_OR_DISABLE), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_HOME) == 0)); // Recents button - View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS, + mRecentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS, navContainer, navButtonController, R.id.recent_apps); - mHitboxExtender.init(recentsButton, mNavButtonsView, mContext.getDeviceProfile(), + mHitboxExtender.init(mRecentsButton, mNavButtonsView, mContext.getDeviceProfile(), () -> { float[] recentsCoords = new float[2]; - getDescendantCoordRelativeToAncestor(recentsButton, mNavButtonsView, + getDescendantCoordRelativeToAncestor(mRecentsButton, mNavButtonsView, recentsCoords, false); return recentsCoords; }, new Handler()); - recentsButton.setOnClickListener(v -> { + mRecentsButton.setOnClickListener(v -> { navButtonController.onButtonClick(BUTTON_RECENTS, v); mHitboxExtender.onRecentsButtonClicked(); }); - mPropertyHolders.add(new StatePropertyHolder(recentsButton, + mPropertyHolders.add(new StatePropertyHolder(mRecentsButton, flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0 && !mContext.isNavBarKidsModeActive())); @@ -738,91 +670,167 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT if (mFloatingRotationButton != null) { mFloatingRotationButton.onConfigurationChanged(configChanges); } + if (!mContext.isUserSetupComplete()) { + handleSetupUi(); + } updateButtonLayoutSpacing(); } + private void handleSetupUi() { + // Since setup wizard only has back button enabled, it looks strange to be + // end-aligned, so start-align instead. + FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams) + mNavButtonContainer.getLayoutParams(); + Resources resources = mContext.getResources(); + DeviceProfile deviceProfile = mContext.getDeviceProfile(); + int setupMargin = resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_margin); + navButtonsLayoutParams.setMarginStart(setupMargin); + navButtonsLayoutParams.bottomMargin = !deviceProfile.isLandscape + ? 0 + : setupMargin - + (resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2); + navButtonsLayoutParams.setMarginEnd(0); + navButtonsLayoutParams.gravity = Gravity.START; + mNavButtonsView.getLayoutParams().height = + mControllers.taskbarActivityContext.getSetupWindowHeight(); + mNavButtonContainer.setLayoutParams(navButtonsLayoutParams); + } + /** - * Adds the correct spacing to 3 button nav container. No-op if using gesture nav or kids mode. + * Adds the correct spacing to 3 button nav container depending on if device is in kids mode, + * setup wizard, or normal 3 button nav. */ private void updateButtonLayoutSpacing() { - if (!mContext.isThreeButtonNav() || mContext.isNavBarKidsModeActive()) { - return; - } - - if (isPhoneButtonNavMode(mContext)) { - updatePhoneButtonSpacing(); - return; - } - DeviceProfile dp = mContext.getDeviceProfile(); Resources res = mContext.getResources(); + boolean isInSetup = !mContext.isUserSetupComplete(); + // TODO(b/244231596) we're getting the incorrect kidsMode value in small-screen + boolean isInKidsMode = mContext.isNavBarKidsModeActive(); - // Add spacing after the end of the last nav button - FrameLayout.LayoutParams navButtonParams = - (FrameLayout.LayoutParams) mNavButtonContainer.getLayoutParams(); - navButtonParams.gravity = Gravity.END; - navButtonParams.width = FrameLayout.LayoutParams.WRAP_CONTENT; - navButtonParams.height = MATCH_PARENT; - - int navMarginEnd = (int) res.getDimension(dp.inv.inlineNavButtonsEndSpacing); - int contextualWidth = mEndContextualContainer.getWidth(); - // If contextual buttons are showing, we check if the end margin is enough for the - // contextual button to be showing - if not, move the nav buttons over a smidge - if (isContextualButtonShowing() && navMarginEnd < contextualWidth) { - // Additional spacing, eat up half of space between last icon and nav button - navMarginEnd += res.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing) / 2; - } - navButtonParams.setMarginEnd(navMarginEnd); - mNavButtonContainer.setLayoutParams(navButtonParams); - - // Add the spaces in between the nav buttons - int spaceInBetween = res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween); - for (int i = 0; i < mNavButtonContainer.getChildCount(); i++) { - View navButton = mNavButtonContainer.getChildAt(i); - LinearLayout.LayoutParams buttonLayoutParams = - (LinearLayout.LayoutParams) navButton.getLayoutParams(); - buttonLayoutParams.weight = 0; - if (i == 0) { - buttonLayoutParams.setMarginEnd(spaceInBetween / 2); - } else if (i == mNavButtonContainer.getChildCount() - 1) { - buttonLayoutParams.setMarginStart(spaceInBetween / 2); - } else { - buttonLayoutParams.setMarginStart(spaceInBetween / 2); - buttonLayoutParams.setMarginEnd(spaceInBetween / 2); - } + if (TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) { + boolean isThreeButtonNav = mContext.isThreeButtonNav(); + + NavButtonLayoutter navButtonLayoutter = + NavButtonLayoutFactory.Companion.getUiLayoutter( + dp, mNavButtonsView, res, isInKidsMode, isInSetup, isThreeButtonNav, + TaskbarManager.isPhoneMode(dp)); + navButtonLayoutter.layoutButtons(dp, isContextualButtonShowing()); + return; } - } - /** Uniformly spaces out the 3 button nav for smaller phone screens */ - private void updatePhoneButtonSpacing() { - DeviceProfile dp = mContext.getDeviceProfile(); - Resources res = mContext.getResources(); + if (isInSetup) { + handleSetupUi(); - // TODO: Polish pending, this is just to make it usable - FrameLayout.LayoutParams navContainerParams = - (FrameLayout.LayoutParams) mNavButtonContainer.getLayoutParams(); - int endStartMargins = res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size); - navContainerParams.gravity = Gravity.CENTER; - navContainerParams.setMarginEnd(endStartMargins); - navContainerParams.setMarginStart(endStartMargins); - mNavButtonContainer.setLayoutParams(navContainerParams); - - // Add the spaces in between the nav buttons - int spaceInBetween = res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone); - for (int i = 0; i < mNavButtonContainer.getChildCount(); i++) { - View navButton = mNavButtonContainer.getChildAt(i); - LinearLayout.LayoutParams buttonLayoutParams = - (LinearLayout.LayoutParams) navButton.getLayoutParams(); - buttonLayoutParams.weight = 1; - if (i == 0) { - buttonLayoutParams.setMarginEnd(spaceInBetween / 2); - } else if (i == mNavButtonContainer.getChildCount() - 1) { - buttonLayoutParams.setMarginStart(spaceInBetween / 2); - } else { - buttonLayoutParams.setMarginStart(spaceInBetween / 2); - buttonLayoutParams.setMarginEnd(spaceInBetween / 2); + // Hide back button in SUW if keyboard is showing (IME draws its own back). + mPropertyHolders.add(new StatePropertyHolder( + mBackButtonAlpha.get(ALPHA_INDEX_SUW), + flags -> (flags & FLAG_IME_VISIBLE) == 0)); + + // TODO(b/210906568) Dark intensity is currently not propagated during setup, so set + // it based on dark theme for now. + int mode = res.getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_MASK; + boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES; + mTaskbarNavButtonDarkIntensity.updateValue(isDarkTheme ? 0 : 1); + } else if (isInKidsMode) { + int iconSize = res.getDimensionPixelSize( + R.dimen.taskbar_icon_size_kids); + int buttonWidth = res.getDimensionPixelSize( + R.dimen.taskbar_nav_buttons_width_kids); + int buttonHeight = res.getDimensionPixelSize( + R.dimen.taskbar_nav_buttons_height_kids); + int buttonRadius = res.getDimensionPixelSize( + R.dimen.taskbar_nav_buttons_corner_radius_kids); + int paddingleft = (buttonWidth - iconSize) / 2; + int paddingRight = paddingleft; + int paddingTop = (buttonHeight - iconSize) / 2; + int paddingBottom = paddingTop; + + // Update icons + ((ImageView) mBackButton).setImageDrawable( + mBackButton.getContext().getDrawable(R.drawable.ic_sysbar_back_kids)); + ((ImageView) mBackButton).setScaleType(ImageView.ScaleType.FIT_CENTER); + mBackButton.setPadding(paddingleft, paddingTop, paddingRight, paddingBottom); + ((ImageView) mHomeButton).setImageDrawable( + mHomeButton.getContext().getDrawable(R.drawable.ic_sysbar_home_kids)); + ((ImageView) mHomeButton).setScaleType(ImageView.ScaleType.FIT_CENTER); + mHomeButton.setPadding(paddingleft, paddingTop, paddingRight, paddingBottom); + + // Home button layout + LinearLayout.LayoutParams homeLayoutparams = new LinearLayout.LayoutParams( + buttonWidth, + buttonHeight + ); + int homeButtonLeftMargin = res.getDimensionPixelSize( + R.dimen.taskbar_home_button_left_margin_kids); + homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0); + mHomeButton.setLayoutParams(homeLayoutparams); + + // Back button layout + LinearLayout.LayoutParams backLayoutParams = new LinearLayout.LayoutParams( + buttonWidth, + buttonHeight + ); + int backButtonLeftMargin = res.getDimensionPixelSize( + R.dimen.taskbar_back_button_left_margin_kids); + backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0); + mBackButton.setLayoutParams(backLayoutParams); + + // Button backgrounds + int whiteWith10PctAlpha = Color.argb(0.1f, 1, 1, 1); + PaintDrawable buttonBackground = new PaintDrawable(whiteWith10PctAlpha); + buttonBackground.setCornerRadius(buttonRadius); + mHomeButton.setBackground(buttonBackground); + mBackButton.setBackground(buttonBackground); + + // Update alignment within taskbar + FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams) + mNavButtonContainer.getLayoutParams(); + navButtonsLayoutParams.setMarginStart( + navButtonsLayoutParams.getMarginEnd() / 2); + navButtonsLayoutParams.setMarginEnd(navButtonsLayoutParams.getMarginStart()); + navButtonsLayoutParams.gravity = Gravity.CENTER; + mNavButtonContainer.requestLayout(); + + mHomeButton.setOnLongClickListener(null); + } else if (mContext.isThreeButtonNav()) { + // Setup normal 3 button + // Add spacing after the end of the last nav button + FrameLayout.LayoutParams navButtonParams = + (FrameLayout.LayoutParams) mNavButtonContainer.getLayoutParams(); + navButtonParams.gravity = Gravity.END; + navButtonParams.width = FrameLayout.LayoutParams.WRAP_CONTENT; + navButtonParams.height = MATCH_PARENT; + + int navMarginEnd = (int) res.getDimension(dp.inv.inlineNavButtonsEndSpacing); + int contextualWidth = mEndContextualContainer.getWidth(); + // If contextual buttons are showing, we check if the end margin is enough for the + // contextual button to be showing - if not, move the nav buttons over a smidge + if (isContextualButtonShowing() && navMarginEnd < contextualWidth) { + // Additional spacing, eat up half of space between last icon and nav button + navMarginEnd += res.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing) / 2; + } + navButtonParams.setMarginEnd(navMarginEnd); + mNavButtonContainer.setLayoutParams(navButtonParams); + + // Add the spaces in between the nav buttons + int spaceInBetween = res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween); + for (int i = 0; i < mNavButtonContainer.getChildCount(); i++) { + View navButton = mNavButtonContainer.getChildAt(i); + LinearLayout.LayoutParams buttonLayoutParams = + (LinearLayout.LayoutParams) navButton.getLayoutParams(); + buttonLayoutParams.weight = 0; + if (i == 0) { + buttonLayoutParams.setMarginEnd(spaceInBetween / 2); + } else if (i == mNavButtonContainer.getChildCount() - 1) { + buttonLayoutParams.setMarginStart(spaceInBetween / 2); + } else { + buttonLayoutParams.setMarginStart(spaceInBetween / 2); + buttonLayoutParams.setMarginEnd(spaceInBetween / 2); + } } } + } public void onDestroy() { @@ -834,6 +842,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT moveNavButtonsBackToTaskbarWindow(); mNavButtonContainer.removeAllViews(); + mEndContextualContainer.removeAllViews(); + mStartContextualContainer.removeAllViews(); mAllButtons.clear(); } @@ -1039,9 +1049,9 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mAnimator.addListener(new AlphaUpdateListener(view)); } - StatePropertyHolder(MultiValueAlpha.AlphaProperty alphaProperty, + StatePropertyHolder(MultiProperty alphaProperty, IntPredicate enableCondition) { - this(alphaProperty, enableCondition, MultiValueAlpha.VALUE, 1, 0); + this(alphaProperty, enableCondition, MULTI_PROPERTY_VALUE, 1, 0); } StatePropertyHolder(AnimatedFloat animatedFloat, IntPredicate enableCondition) { diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index 6b67b50fd8..74e73754df 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -26,13 +26,15 @@ import android.view.View; import android.view.ViewOutlineProvider; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; -import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.RevealOutlineAnimation; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.Executors; +import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.MultiValueAlpha; -import com.android.quickstep.AnimatedFloat; import com.android.systemui.shared.navigationbar.RegionSamplingHelper; import java.io.PrintWriter; @@ -65,6 +67,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT // Initialized in init. private TaskbarControllers mControllers; + private int mTaskbarSize; // The bounds we want to clip to in the settled state when showing the stashed handle. private final Rect mStashedHandleBounds = new Rect(); @@ -78,7 +81,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT public StashedHandleViewController(TaskbarActivityContext activity, StashedHandleView stashedHandleView) { mActivity = activity; - mPrefs = Utilities.getPrefs(mActivity); + mPrefs = LauncherPrefs.getPrefs(mActivity); mStashedHandleView = stashedHandleView; mTaskbarStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, NUM_ALPHA_CHANNELS); mTaskbarStashedHandleAlpha.setUpdateVisibility(true); @@ -95,17 +98,20 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT DeviceProfile deviceProfile = mActivity.getDeviceProfile(); Resources resources = mActivity.getResources(); if (isPhoneGestureNavMode(mActivity.getDeviceProfile())) { - mStashedHandleView.getLayoutParams().height = - resources.getDimensionPixelSize(R.dimen.taskbar_size); + mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_size); mStashedHandleWidth = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen); } else { - mStashedHandleView.getLayoutParams().height = deviceProfile.taskbarSize; - mStashedHandleWidth = - resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width); + mTaskbarSize = deviceProfile.taskbarSize; + mStashedHandleWidth = resources + .getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width); } + int taskbarBottomMargin = DisplayController.isTransientTaskbar(mActivity) + ? resources.getDimensionPixelSize(R.dimen.transient_taskbar_margin) + : 0; + mStashedHandleView.getLayoutParams().height = mTaskbarSize + taskbarBottomMargin; - mTaskbarStashedHandleAlpha.getProperty(ALPHA_INDEX_STASHED).setValue( + mTaskbarStashedHandleAlpha.get(ALPHA_INDEX_STASHED).setValue( isPhoneGestureNavMode(deviceProfile) ? 1 : 0); mTaskbarStashedHandleHintScale.updateValue(1f); @@ -166,7 +172,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT return TaskbarManager.isPhoneMode(deviceProfile) && !mActivity.isThreeButtonNav(); } - public MultiValueAlpha getStashedHandleAlpha() { + public MultiPropertyFactory<View> getStashedHandleAlpha() { return mTaskbarStashedHandleAlpha; } @@ -180,9 +186,17 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT * morphs into the size of where the taskbar icons will be. */ public Animator createRevealAnimToIsStashed(boolean isStashed) { + Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds()); + + if (DisplayController.isTransientTaskbar(mActivity)) { + // Account for the full visual height of the transient taskbar. + int heightDiff = (mTaskbarSize - visualBounds.height()) / 2; + visualBounds.top -= heightDiff; + visualBounds.bottom += heightDiff; + } + final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider( - mStashedHandleRadius, mStashedHandleRadius, - mControllers.taskbarViewController.getIconLayoutBounds(), mStashedHandleBounds); + mStashedHandleRadius, mStashedHandleRadius, visualBounds, mStashedHandleBounds); boolean isReversed = !isStashed; boolean changingDirection = mWasLastRevealAnimReversed != isReversed; @@ -219,10 +233,17 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT } /** + * Sets the translation of the stashed handle during the swipe up gesture. + */ + protected void setTranslationYForSwipe(float transY) { + mStashedHandleView.setTranslationY(transY); + } + + /** * Should be called when the home button is disabled, so we can hide this handle as well. */ public void setIsHomeButtonDisabled(boolean homeDisabled) { - mTaskbarStashedHandleAlpha.getProperty(ALPHA_INDEX_HOME_DISABLED).setValue( + mTaskbarStashedHandleAlpha.get(ALPHA_INDEX_HOME_DISABLED).setValue( homeDisabled ? 0 : 1); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 9d15ea88c3..731eea78e9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -23,7 +23,10 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE; +import static com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN; +import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING; +import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN; import static com.android.launcher3.taskbar.TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW; import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; @@ -75,10 +78,14 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupDataProvider; +import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag; +import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback; import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.ItemClickHandler; +import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.NavigationMode; import com.android.launcher3.util.PackageManagerHelper; @@ -86,9 +93,11 @@ import com.android.launcher3.util.SettingsCache; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.ViewCache; import com.android.launcher3.views.ActivityContext; +import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.rotation.RotationButtonController; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.unfold.updates.RotationChangeProvider; import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider; import java.io.PrintWriter; @@ -127,36 +136,40 @@ public class TaskbarActivityContext extends BaseTaskbarContext { private final boolean mIsUserSetupComplete; private final boolean mIsNavBarForceVisible; private final boolean mIsNavBarKidsMode; + private boolean mIsDestroyed = false; // The flag to know if the window is excluded from magnification region computation. private boolean mIsExcludeFromMagnificationRegion = false; private boolean mBindingItems = false; private boolean mAddedWindow = false; + // The bounds of the taskbar items relative to TaskbarDragLayer + private final Rect mTransientTaskbarBounds = new Rect(); private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate; - public TaskbarActivityContext(Context windowContext, DeviceProfile dp, + public TaskbarActivityContext(Context windowContext, DeviceProfile launcherDp, TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider) { super(windowContext); - mDeviceProfile = dp.copy(this); - final Resources resources = getResources(); + matchDeviceProfile(launcherDp, getResources()); + mNavMode = DisplayController.getNavigationMode(windowContext); mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false); mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode", () -> getPackageManager().isSafeMode()); - mIsUserSetupComplete = SettingsCache.INSTANCE.get(this).getValue( + SettingsCache settingsCache = SettingsCache.INSTANCE.get(this); + mIsUserSetupComplete = settingsCache.getValue( Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0); - mIsNavBarForceVisible = SettingsCache.INSTANCE.get(this).getValue( + mIsNavBarForceVisible = settingsCache.getValue( Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0); - mIsNavBarKidsMode = SettingsCache.INSTANCE.get(this).getValue( + // TODO(b/244231596) For shared Taskbar window, update this value in init() instead so + // to get correct value when recreating the taskbar + mIsNavBarKidsMode = settingsCache.getValue( Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0); - updateIconSize(resources); - // Get display and corners first, as views might use them in constructor. Display display = windowContext.getDisplay(); Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY @@ -167,8 +180,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT); // Inflate views. - mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate( - R.layout.taskbar, null, false); + int taskbarLayout = DisplayController.isTransientTaskbar(this) + ? R.layout.transient_taskbar + : R.layout.taskbar; + mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false); TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view); TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim); FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view); @@ -197,7 +212,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new TaskbarViewController(this, taskbarView), new TaskbarScrimViewController(this, taskbarScrimView), new TaskbarUnfoldAnimationController(this, unfoldTransitionProgressProvider, - mWindowManager, WindowManagerGlobal.getWindowManagerService()), + mWindowManager, + new RotationChangeProvider(WindowManagerGlobal.getWindowManagerService(), this, + getMainExecutor())), new TaskbarKeyguardController(this), new StashedHandleViewController(this, stashedHandleView), new TaskbarStashController(this), @@ -205,9 +222,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new TaskbarAutohideSuspendController(this), new TaskbarPopupController(this), new TaskbarForceVisibleImmersiveController(this), - new TaskbarAllAppsController(this, dp), + new TaskbarOverlayController(this, launcherDp), + new TaskbarAllAppsController(), new TaskbarInsetsController(this), new VoiceInteractionWindowController(this), + new TaskbarTranslationController(this), isDesktopMode ? new DesktopTaskbarRecentAppsController(this) : TaskbarRecentAppsController.DEFAULT); @@ -235,11 +254,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } /** Updates {@link DeviceProfile} instances for any Taskbar windows. */ - public void updateDeviceProfile(DeviceProfile dp, NavigationMode navMode) { + public void updateDeviceProfile(DeviceProfile launcherDp, NavigationMode navMode) { mNavMode = navMode; - mControllers.taskbarAllAppsController.updateDeviceProfile(dp); - mDeviceProfile = dp.copy(this); - updateIconSize(getResources()); + mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp); + matchDeviceProfile(launcherDp, getResources()); AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE); // Reapply fullscreen to take potential new screen size into account. @@ -248,11 +266,34 @@ public class TaskbarActivityContext extends BaseTaskbarContext { dispatchDeviceProfileChanged(); } + /** + * Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update + * the icon size + */ + private void matchDeviceProfile(DeviceProfile originDeviceProfile, Resources resources) { + mDeviceProfile = originDeviceProfile.copy(this); + // Taskbar should match the number of icons of hotseat + mDeviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons; + // Same QSB width to have a smooth animation + mDeviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth; + // Update the size of the icons + updateIconSize(resources); + } + + private void updateIconSize(Resources resources) { - float taskbarIconSize = resources.getDimension(R.dimen.taskbar_icon_size); - mDeviceProfile.updateIconSize(1, resources); - float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx; - mDeviceProfile.updateIconSize(iconScale, resources); + mDeviceProfile.iconSizePx = resources.getDimensionPixelSize( + DisplayController.isTransientTaskbar(this) + ? R.dimen.transient_taskbar_icon_size + : R.dimen.taskbar_icon_size); + mDeviceProfile.updateIconSize(1f, resources); + } + + /** + * Returns the View bounds of transient taskbar. + */ + public Rect getTransientTaskbarBounds() { + return mTransientTaskbarBounds; } @VisibleForTesting @@ -272,28 +313,49 @@ public class TaskbarActivityContext extends BaseTaskbarContext { * @param type The window type to pass to the created WindowManager.LayoutParams. */ public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type) { + DeviceProfile deviceProfile = getDeviceProfile(); + // Taskbar is on the logical bottom of the screen + boolean isVerticalBarLayout = TaskbarManager.isPhoneMode(deviceProfile) && + deviceProfile.isLandscape; + + int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_SLIPPERY + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH; + if (DisplayController.isTransientTaskbar(this) + && !IS_RUNNING_IN_TEST_HARNESS) { + windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; + } WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams( - MATCH_PARENT, - mLastRequestedNonFullscreenHeight, + isVerticalBarLayout ? mLastRequestedNonFullscreenHeight : MATCH_PARENT, + isVerticalBarLayout ? MATCH_PARENT : mLastRequestedNonFullscreenHeight, type, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_SLIPPERY - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + windowFlags, PixelFormat.TRANSLUCENT); windowLayoutParams.setTitle(WINDOW_TITLE); windowLayoutParams.packageName = getPackageName(); - windowLayoutParams.gravity = Gravity.BOTTOM; + windowLayoutParams.gravity = !isVerticalBarLayout ? + Gravity.BOTTOM : + Gravity.END; // TODO(b/230394142): seascape + windowLayoutParams.setFitInsetsTypes(0); windowLayoutParams.receiveInsetsIgnoringZOrder = true; windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; windowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; windowLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; + windowLayoutParams.accessibilityTitle = getString( + TaskbarManager.isPhoneMode(mDeviceProfile) + ? R.string.taskbar_phone_a11y_title + : R.string.taskbar_a11y_title); return windowLayoutParams; } public void onConfigurationChanged(@Config int configChanges) { mControllers.onConfigurationChanged(configChanges); + if (!mIsUserSetupComplete) { + setTaskbarWindowHeight(getSetupWindowHeight()); + } } public boolean isThreeButtonNav() { @@ -439,7 +501,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { @Override public void onDragEnd() { - maybeSetTaskbarWindowNotFullscreen(); + onDragEndOrViewRemoved(); } @Override @@ -508,7 +570,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) { float alpha = isExpanded ? 0 : 1; AnimatorSet anim = new AnimatorSet(); - anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().getProperty( + anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().get( TaskbarViewController.ALPHA_INDEX_NOTIFICATION_EXPANDED).animateToValue(alpha)); if (!isThreeButtonNav()) { anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar() @@ -544,24 +606,33 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } /** + * Called to update a {@link AutohideSuspendFlag} with a new value. + */ + public void setAutohideSuspendFlag(@AutohideSuspendFlag int flag, boolean newValue) { + mControllers.taskbarAutohideSuspendController.updateFlag(flag, newValue); + } + + /** * Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size. */ public void setTaskbarWindowFullscreen(boolean fullscreen) { - mControllers.taskbarAutohideSuspendController.updateFlag( - TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen); + setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen); mIsFullscreen = fullscreen; setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight); } /** - * Reverts Taskbar window to its original size, if all floating views are closed and there is - * no system drag operation in progress. + * Called when drag ends or when a view is removed from the DragLayer. */ - void maybeSetTaskbarWindowNotFullscreen() { - if (AbstractFloatingView.getAnyView(this, TYPE_ALL) == null - && !mControllers.taskbarDragController.isSystemDragInProgress()) { + void onDragEndOrViewRemoved() { + boolean isDragInProgress = mControllers.taskbarDragController.isSystemDragInProgress(); + + if (!isDragInProgress && !AbstractFloatingView.hasOpenView(this, TYPE_ALL)) { + // Reverts Taskbar window to its original size setTaskbarWindowFullscreen(false); } + + setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, isDragInProgress); } public boolean isTaskbarWindowFullscreen() { @@ -608,15 +679,32 @@ public class TaskbarActivityContext extends BaseTaskbarContext { * Returns the default height of the window, including the static corner radii above taskbar. */ public int getDefaultTaskbarWindowHeight() { + Resources resources = getResources(); + if (FLAG_HIDE_NAVBAR_WINDOW && mDeviceProfile.isPhone) { - Resources resources = getResources(); return isThreeButtonNav() ? resources.getDimensionPixelSize(R.dimen.taskbar_size) : resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size); } + + if (!isUserSetupComplete()) { + return getSetupWindowHeight(); + } + + if (DisplayController.isTransientTaskbar(this)) { + int taskbarSize = resources.getDimensionPixelSize(R.dimen.transient_taskbar_size); + return taskbarSize + + (2 * resources.getDimensionPixelSize(R.dimen.transient_taskbar_margin)) + + resources.getDimensionPixelSize(R.dimen.transient_taskbar_shadow_blur); + } + return mDeviceProfile.taskbarSize + Math.max(getLeftCornerRadius(), getRightCornerRadius()); } + public int getSetupWindowHeight() { + return getResources().getDimensionPixelSize(R.dimen.taskbar_suw_frame); + } + /** * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar * window. @@ -663,6 +751,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { Task task = (Task) tag; ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, ActivityOptions.makeBasic()); + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true); } else if (tag instanceof FolderInfo) { FolderIcon folderIcon = (FolderIcon) view; Folder folder = folderIcon.getFolder(); @@ -693,44 +782,67 @@ public class TaskbarActivityContext extends BaseTaskbarContext { }); } else if (tag instanceof WorkspaceItemInfo) { WorkspaceItemInfo info = (WorkspaceItemInfo) tag; - if (info.isDisabled()) { - ItemClickHandler.handleDisabledItemClicked(info, this); - } else { - Intent intent = new Intent(info.getIntent()) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) { - Toast.makeText(this, R.string.safemode_shortcut_error, - Toast.LENGTH_SHORT).show(); - } else if (info.isPromise()) { - TestLogging.recordEvent( - TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon"); - intent = new PackageManagerHelper(this) - .getMarketIntent(info.getTargetPackage()) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - - } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - TestLogging.recordEvent( - TestProtocol.SEQUENCE_MAIN, "start: taskbarDeepShortcut"); - String id = info.getDeepShortcutId(); - String packageName = intent.getPackage(); - getSystemService(LauncherApps.class) - .startShortcut(packageName, id, null, null, info.user); - } else { - startItemInfoActivity(info); + if (!info.isDisabled() || !ItemClickHandler.handleDisabledItemClicked(info, this)) { + TaskbarUIController taskbarUIController = mControllers.uiController; + RecentsView recents = taskbarUIController.getRecentsView(); + if (recents != null + && taskbarUIController.getRecentsView().isSplitSelectionActive()) { + // If we are selecting a second app for split, launch the split tasks + taskbarUIController.triggerSecondAppForSplit(info, info.intent, view); + } else { + // Else launch the selected task + Intent intent = new Intent(info.getIntent()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) { + Toast.makeText(this, R.string.safemode_shortcut_error, + Toast.LENGTH_SHORT).show(); + } else if (info.isPromise()) { + TestLogging.recordEvent( + TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon"); + intent = new PackageManagerHelper(this) + .getMarketIntent(info.getTargetPackage()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + + } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) { + TestLogging.recordEvent( + TestProtocol.SEQUENCE_MAIN, "start: taskbarDeepShortcut"); + String id = info.getDeepShortcutId(); + String packageName = intent.getPackage(); + getSystemService(LauncherApps.class) + .startShortcut(packageName, id, null, null, info.user); + } else { + startItemInfoActivity(info); + } + + mControllers.uiController.onTaskbarIconLaunched(info); + } catch (NullPointerException + | ActivityNotFoundException + | SecurityException e) { + Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT) + .show(); + Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e); } - - mControllers.uiController.onTaskbarIconLaunched(info); - } catch (NullPointerException | ActivityNotFoundException | SecurityException e) { - Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT) - .show(); - Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e); } + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true); } } else if (tag instanceof AppInfo) { - startItemInfoActivity((AppInfo) tag); - mControllers.uiController.onTaskbarIconLaunched((AppInfo) tag); + AppInfo info = (AppInfo) tag; + TaskbarUIController taskbarUIController = mControllers.uiController; + RecentsView recents = taskbarUIController.getRecentsView(); + if (recents != null + && taskbarUIController.getRecentsView().isSplitSelectionActive()) { + // If we are selecting a second app for split, launch the split tasks + taskbarUIController.triggerSecondAppForSplit(info, info.intent, view); + } else { + // Else launch the selected task + startItemInfoActivity((AppInfo) tag); + mControllers.uiController.onTaskbarIconLaunched((AppInfo) tag); + } + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true); + } else if (tag instanceof ItemClickProxy) { + ((ItemClickProxy) tag).onItemClicked(view); } else { Log.e(TAG, "Unknown type clicked: " + tag); } @@ -766,6 +878,39 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } /** + * Called when we want to unstash taskbar when user performs swipes up gesture. + */ + public void onSwipeToUnstashTaskbar() { + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false); + } + + /** Returns {@code true} if taskbar All Apps is open. */ + public boolean isTaskbarAllAppsOpen() { + return mControllers.taskbarAllAppsController.isOpen(); + } + + /** + * Called to start the taskbar translation spring to its settled translation (0). + */ + public void startTranslationSpring() { + mControllers.taskbarTranslationController.startSpring(); + } + + /** + * Returns a callback to help monitor the swipe gesture. + */ + public TransitionCallback getTranslationCallbacks() { + return mControllers.taskbarTranslationController.getTransitionCallback(); + } + + /** + * Called when a transient Autohide flag suspend status changes. + */ + public void onTransientAutohideSuspendFlagChanged(boolean isSuspended) { + mControllers.taskbarStashController.updateTaskbarTimeout(isSuspended); + } + + /** * Called when we detect a motion down or up/cancel in the nav region while stashed. * @param animateForward Whether to animate towards the unstashed hint state or back to stashed. */ @@ -783,19 +928,32 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } /** + * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar + * testing. + */ + @VisibleForTesting + public void enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout) { + mControllers.taskbarStashController.enableBlockingTimeoutDuringTests(enableBlockingTimeout); + } + + /** * Unstashes the Taskbar if it is stashed. This method should only be used to unstash the * taskbar at the end of a test. */ @VisibleForTesting public void unstashTaskbarIfStashed() { - mControllers.taskbarStashController.onLongPressToUnstashTaskbar(); + if (DisplayController.isTransientTaskbar(this)) { + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false); + } else { + mControllers.taskbarStashController.onLongPressToUnstashTaskbar(); + } } protected boolean isUserSetupComplete() { return mIsUserSetupComplete; } - protected boolean isNavBarKidsModeActive() { + public boolean isNavBarKidsModeActive() { return mIsNavBarKidsMode && isThreeButtonNav(); } @@ -829,12 +987,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext { } mControllers.taskbarStashController.addUnstashToHotseatAnimation(fullAnimation, duration); - if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { + View allAppsButton = mControllers.taskbarViewController.getAllAppsButtonView(); + if (allAppsButton != null && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1); alphaOverride.setDuration(duration); alphaOverride.addUpdateListener(a -> { // Override the alpha updates in the icon alignment animation. - mControllers.taskbarViewController.getAllAppsButtonView().setAlpha(0); + allAppsButton.setAlpha(0); }); fullAnimation.play(alphaOverride); } @@ -888,4 +1047,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.dumpLogs(prefix + "\t", pw); mDeviceProfile.dump(this, prefix, pw); } + + @VisibleForTesting + public int getTaskbarAllAppsTopPadding() { + return mControllers.taskbarAllAppsController.getTaskbarAllAppsTopPadding(); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java index 3cf9c997c9..4350e9c280 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java @@ -33,21 +33,28 @@ import java.util.StringJoiner; public class TaskbarAutohideSuspendController implements TaskbarControllers.LoggableTaskbarController { + // Taskbar window is fullscreen. public static final int FLAG_AUTOHIDE_SUSPEND_FULLSCREEN = 1 << 0; + // User is dragging item. public static final int FLAG_AUTOHIDE_SUSPEND_DRAGGING = 1 << 1; + // User has touched down but has not lifted finger. + public static final int FLAG_AUTOHIDE_SUSPEND_TOUCHING = 1 << 2; @IntDef(flag = true, value = { FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, FLAG_AUTOHIDE_SUSPEND_DRAGGING, + FLAG_AUTOHIDE_SUSPEND_TOUCHING, }) @Retention(RetentionPolicy.SOURCE) public @interface AutohideSuspendFlag {} + private final TaskbarActivityContext mActivity; private final SystemUiProxy mSystemUiProxy; private @AutohideSuspendFlag int mAutohideSuspendFlags = 0; public TaskbarAutohideSuspendController(TaskbarActivityContext activity) { + mActivity = activity; mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity); } @@ -59,12 +66,27 @@ public class TaskbarAutohideSuspendController implements * Adds or removes the given flag, then notifies system UI proxy whether to suspend auto-hide. */ public void updateFlag(@AutohideSuspendFlag int flag, boolean enabled) { + int flagsBefore = mAutohideSuspendFlags; if (enabled) { mAutohideSuspendFlags |= flag; } else { mAutohideSuspendFlags &= ~flag; } - mSystemUiProxy.notifyTaskbarAutohideSuspend(mAutohideSuspendFlags != 0); + if (flagsBefore == mAutohideSuspendFlags) { + // Nothing has changed, no need to notify. + return; + } + + boolean isSuspended = isSuspended(); + mSystemUiProxy.notifyTaskbarAutohideSuspend(isSuspended); + mActivity.onTransientAutohideSuspendFlagChanged(isSuspended); + } + + /** + * Returns true iff taskbar autohide is currently suspended. + */ + public boolean isSuspended() { + return mAutohideSuspendFlags != 0; } @Override @@ -79,6 +101,7 @@ public class TaskbarAutohideSuspendController implements appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, "FLAG_AUTOHIDE_SUSPEND_FULLSCREEN"); appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_DRAGGING, "FLAG_AUTOHIDE_SUSPEND_DRAGGING"); + appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TOUCHING, "FLAG_AUTOHIDE_SUSPEND_TOUCHING"); return str.toString(); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt index 1177bdb484..ff7e8e9af2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt @@ -16,10 +16,16 @@ package com.android.launcher3.taskbar +import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound +import com.android.launcher3.Utilities.mapToRange + import android.graphics.Canvas +import android.graphics.Color import android.graphics.Paint import android.graphics.Path import com.android.launcher3.R +import com.android.launcher3.anim.Interpolators +import com.android.launcher3.util.DisplayController /** * Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. @@ -28,9 +34,23 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) { val paint: Paint = Paint() var backgroundHeight = context.deviceProfile.taskbarSize.toFloat() + var translationYForSwipe = 0f + + private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat() + private val transientBackgroundBounds = context.transientTaskbarBounds + + private val isTransientTaskbar = DisplayController.isTransientTaskbar(context); - private val leftCornerRadius = context.leftCornerRadius.toFloat() - private val rightCornerRadius = context.rightCornerRadius.toFloat() + private var shadowBlur = 0f + private var keyShadowDistance = 0f + private var bottomMargin = 0 + + private val fullLeftCornerRadius = context.leftCornerRadius.toFloat() + private val fullRightCornerRadius = context.rightCornerRadius.toFloat() + private var leftCornerRadius = fullLeftCornerRadius + private var rightCornerRadius = fullRightCornerRadius + private val square: Path = Path() + private val circle: Path = Path() private val invertedLeftCornerPath: Path = Path() private val invertedRightCornerPath: Path = Path() @@ -39,13 +59,38 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) { paint.flags = Paint.ANTI_ALIAS_FLAG paint.style = Paint.Style.FILL + if (isTransientTaskbar) { + paint.color = context.getColor(R.color.transient_taskbar_background) + + val res = context.resources + bottomMargin = res.getDimensionPixelSize(R.dimen.transient_taskbar_margin) + shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur) + keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance) + } + + setCornerRoundness(DEFAULT_ROUNDNESS) + } + + /** + * Sets the roundness of the round corner above Taskbar. No effect on transient Taskkbar. + * @param cornerRoundness 0 has no round corner, 1 has complete round corner. + */ + fun setCornerRoundness(cornerRoundness: Float) { + if (isTransientTaskbar && !transientBackgroundBounds.isEmpty) { + return + } + + leftCornerRadius = fullLeftCornerRadius * cornerRoundness + rightCornerRadius = fullRightCornerRadius * cornerRoundness + // Create the paths for the inverted rounded corners above the taskbar. Start with a filled // square, and then subtract out a circle from the appropriate corner. - val square = Path() + square.reset() square.addRect(0f, 0f, leftCornerRadius, leftCornerRadius, Path.Direction.CW) - val circle = Path() + circle.reset() circle.addCircle(leftCornerRadius, 0f, leftCornerRadius, Path.Direction.CW) invertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE) + square.reset() square.addRect(0f, 0f, rightCornerRadius, rightCornerRadius, Path.Direction.CW) circle.reset() @@ -58,18 +103,49 @@ class TaskbarBackgroundRenderer(context: TaskbarActivityContext) { */ fun draw(canvas: Canvas) { canvas.save() - canvas.translate(0f, canvas.height - backgroundHeight) + canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin) + if (!isTransientTaskbar || transientBackgroundBounds.isEmpty) { + // Draw the background behind taskbar content. + canvas.drawRect(0f, 0f, canvas.width.toFloat(), backgroundHeight, paint) - // Draw the background behind taskbar content. - canvas.drawRect(0f, 0f, canvas.width.toFloat(), backgroundHeight, paint) + // Draw the inverted rounded corners above the taskbar. + canvas.translate(0f, -leftCornerRadius) + canvas.drawPath(invertedLeftCornerPath, paint) + canvas.translate(0f, leftCornerRadius) + canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius) + canvas.drawPath(invertedRightCornerPath, paint) + } else { + // Approximates the stash/unstash animation to transform the background. + val scaleFactor = backgroundHeight / maxBackgroundHeight + val width = transientBackgroundBounds.width() + val widthScale = mapToRange(scaleFactor, 0f, 1f, 0.4f, 1f, Interpolators.LINEAR) + val newWidth = widthScale * width + val delta = width - newWidth + canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f)) - // Draw the inverted rounded corners above the taskbar. - canvas.translate(0f, -leftCornerRadius) - canvas.drawPath(invertedLeftCornerPath, paint) - canvas.translate(0f, leftCornerRadius) - canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius) - canvas.drawPath(invertedRightCornerPath, paint) + // Draw shadow. + val shadowAlpha = mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f, + Interpolators.LINEAR) + paint.setShadowLayer(shadowBlur, 0f, keyShadowDistance, + setColorAlphaBound(Color.BLACK, Math.round(shadowAlpha)) + ) + + // Draw background. + val radius = backgroundHeight / 2f; + + canvas.drawRoundRect( + transientBackgroundBounds.left + (delta / 2f), + translationYForSwipe, + transientBackgroundBounds.right - (delta / 2f), + backgroundHeight + translationYForSwipe, + radius, radius, paint + ) + } canvas.restore() } + + companion object { + const val DEFAULT_ROUNDNESS = 1f + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 2b80b753fb..bc41c2b520 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -21,7 +21,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; import com.android.systemui.shared.rotation.RotationButtonController; import java.io.PrintWriter; @@ -54,8 +56,11 @@ public class TaskbarControllers { public final TaskbarInsetsController taskbarInsetsController; public final VoiceInteractionWindowController voiceInteractionWindowController; public final TaskbarRecentAppsController taskbarRecentAppsController; + public final TaskbarTranslationController taskbarTranslationController; + public final TaskbarOverlayController taskbarOverlayController; @Nullable private LoggableTaskbarController[] mControllersToLog = null; + @Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null; /** Do not store this controller, as it may change at runtime. */ @NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT; @@ -65,6 +70,9 @@ public class TaskbarControllers { @Nullable private TaskbarSharedState mSharedState = null; + // Roundness property for round corner above taskbar . + private final AnimatedFloat mCornerRoundness = new AnimatedFloat(this::updateCornerRoundness); + public TaskbarControllers(TaskbarActivityContext taskbarActivityContext, TaskbarDragController taskbarDragController, TaskbarNavButtonController navButtonController, @@ -81,9 +89,11 @@ public class TaskbarControllers { TaskbarAutohideSuspendController taskbarAutoHideSuspendController, TaskbarPopupController taskbarPopupController, TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController, + TaskbarOverlayController taskbarOverlayController, TaskbarAllAppsController taskbarAllAppsController, TaskbarInsetsController taskbarInsetsController, VoiceInteractionWindowController voiceInteractionWindowController, + TaskbarTranslationController taskbarTranslationController, TaskbarRecentAppsController taskbarRecentAppsController) { this.taskbarActivityContext = taskbarActivityContext; this.taskbarDragController = taskbarDragController; @@ -101,9 +111,11 @@ public class TaskbarControllers { this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController; this.taskbarPopupController = taskbarPopupController; this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController; + this.taskbarOverlayController = taskbarOverlayController; this.taskbarAllAppsController = taskbarAllAppsController; this.taskbarInsetsController = taskbarInsetsController; this.voiceInteractionWindowController = voiceInteractionWindowController; + this.taskbarTranslationController = taskbarTranslationController; this.taskbarRecentAppsController = taskbarRecentAppsController; } @@ -129,11 +141,13 @@ public class TaskbarControllers { taskbarEduController.init(this); taskbarPopupController.init(this); taskbarForceVisibleImmersiveController.init(this); + taskbarOverlayController.init(this); taskbarAllAppsController.init(this, sharedState.allAppsVisible); navButtonController.init(this); taskbarInsetsController.init(this); voiceInteractionWindowController.init(this); taskbarRecentAppsController.init(this); + taskbarTranslationController.init(this); mControllersToLog = new LoggableTaskbarController[] { taskbarDragController, navButtonController, navbarButtonsViewController, @@ -141,8 +155,13 @@ public class TaskbarControllers { taskbarUnfoldAnimationController, taskbarKeyguardController, stashedHandleViewController, taskbarStashController, taskbarEduController, taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController, + voiceInteractionWindowController, taskbarTranslationController + }; + mBackgroundRendererControllers = new BackgroundRendererController[] { + taskbarDragLayerController, taskbarScrimViewController, voiceInteractionWindowController }; + mCornerRoundness.updateValue(TaskbarBackgroundRenderer.DEFAULT_ROUNDNESS); mAreAllControllersInitialized = true; for (Runnable postInitCallback : mPostInitCallbacks) { @@ -159,12 +178,14 @@ public class TaskbarControllers { public void onConfigurationChanged(@Config int configChanges) { navbarButtonsViewController.onConfigurationChanged(configChanges); + taskbarDragLayerController.onConfigurationChanged(); } /** * Cleans up all controllers. */ public void onDestroy() { + mAreAllControllersInitialized = false; mSharedState = null; navbarButtonsViewController.onDestroy(); @@ -178,13 +199,14 @@ public class TaskbarControllers { taskbarAutohideSuspendController.onDestroy(); taskbarPopupController.onDestroy(); taskbarForceVisibleImmersiveController.onDestroy(); - taskbarAllAppsController.onDestroy(); + taskbarOverlayController.onDestroy(); navButtonController.onDestroy(); taskbarInsetsController.onDestroy(); voiceInteractionWindowController.onDestroy(); taskbarRecentAppsController.onDestroy(); mControllersToLog = null; + mBackgroundRendererControllers = null; } /** @@ -218,6 +240,23 @@ public class TaskbarControllers { rotationButtonController.dumpLogs(prefix + "\t", pw); } + /** + * Returns a float property that animates roundness of the round corner above Taskbar. + */ + public AnimatedFloat getTaskbarCornerRoundness() { + return mCornerRoundness; + } + + private void updateCornerRoundness() { + if (mBackgroundRendererControllers == null) { + return; + } + + for (BackgroundRendererController controller : mBackgroundRendererControllers) { + controller.setCornerRoundness(mCornerRoundness.value); + } + } + @VisibleForTesting TaskbarActivityContext getTaskbarActivityContext() { // Used to mock @@ -227,4 +266,12 @@ public class TaskbarControllers { protected interface LoggableTaskbarController { void dumpLogs(String prefix, PrintWriter pw); } + + protected interface BackgroundRendererController { + /** + * Sets the roundness of the round corner above Taskbar. + * @param cornerRoundness 0 has no round corner, 1 has complete round corner. + */ + void setCornerRoundness(float cornerRoundness); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index 9a1e0642bb..d1fea7b069 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -15,13 +15,16 @@ */ package com.android.launcher3.taskbar; +import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT; +import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; +import android.annotation.NonNull; import android.content.ClipData; import android.content.ClipDescription; import android.content.Intent; @@ -49,7 +52,6 @@ import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.config.FeatureFlags; @@ -70,6 +72,7 @@ import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.ItemInfoMatcher; import com.android.quickstep.util.LogUtils; +import com.android.quickstep.util.MultiValueUpdateListener; import com.android.systemui.shared.recents.model.Task; import java.io.PrintWriter; @@ -83,7 +86,8 @@ import java.util.function.Predicate; public class TaskbarDragController extends DragController<BaseTaskbarContext> implements TaskbarControllers.LoggableTaskbarController { - private static boolean DEBUG_DRAG_SHADOW_SURFACE = false; + private static final boolean DEBUG_DRAG_SHADOW_SURFACE = false; + private static final int ANIM_DURATION_RETURN_ICON_TO_TASKBAR = 300; private final int mDragIconSize; private final int[] mTempXY = new int[2]; @@ -99,6 +103,8 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im // Animation for the drag shadow back into position after an unsuccessful drag private ValueAnimator mReturnAnimator; + private boolean mDisallowGlobalDrag; + private boolean mDisallowLongClick; public TaskbarDragController(BaseTaskbarContext activity) { super(activity); @@ -110,6 +116,14 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im mControllers = controllers; } + public void setDisallowGlobalDrag(boolean disallowGlobalDrag) { + mDisallowGlobalDrag = disallowGlobalDrag; + } + + public void setDisallowLongClick(boolean disallowLongClick) { + mDisallowLongClick = disallowLongClick; + } + /** * Attempts to start a system drag and drop operation for the given View, using its tag to * generate the ClipDescription and Intent. @@ -131,7 +145,7 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im View view, @Nullable DragPreviewProvider dragPreviewProvider, @Nullable Point iconShift) { - if (!(view instanceof BubbleTextView)) { + if (!(view instanceof BubbleTextView) || mDisallowLongClick) { return false; } TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onTaskbarItemLongClick"); @@ -193,8 +207,13 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get() && !shouldStartDrag(0)) { - // Immediately close the popup menu. - mDragView.setOnAnimationEndCallback(() -> callOnDragStart()); + mDragView.setOnAnimationEndCallback(() -> { + // Drag might be cancelled during the DragView animation, so check + // mIsPreDrag again. + if (mIsInPreDrag) { + callOnDragStart(); + } + }); } } @@ -288,11 +307,20 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im protected void callOnDragStart() { super.callOnDragStart(); // Pre-drag has ended, start the global system drag. - AbstractFloatingView.closeAllOpenViews(mActivity); + if (mDisallowGlobalDrag) { + AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS); + } else { + // stash the transient taskbar + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true); + + AbstractFloatingView.closeAllOpenViews(mActivity); + } + startSystemDrag((BubbleTextView) mDragObject.originalView); } private void startSystemDrag(BubbleTextView btv) { + if (mDisallowGlobalDrag) return; View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(btv) { @Override @@ -393,9 +421,14 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im if (dragEvent.getResult()) { maybeOnDragEnd(); } else { + // un-stash the transient taskbar in case drag and drop was canceled + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false); + // This will take care of calling maybeOnDragEnd() after the animation animateGlobalDragViewToOriginalPosition(btv, dragEvent); } + mActivity.getDragLayer().setOnDragListener(null); + return true; } return false; @@ -422,6 +455,45 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im } @Override + protected void endDrag() { + if (mDisallowGlobalDrag) { + // We need to explicitly set deferDragViewCleanupPostAnimation to true here so the + // super call doesn't remove it from the drag layer before the animation completes. + // This variable gets set in to false in super.dispatchDropComplete() because it + // (rightfully so, perhaps) thinks this drag operation has failed, and does its own + // internal cleanup. + // Another way to approach this would be to make all of overview a drop target and + // accept the drop as successful and then run the setupReturnDragAnimator to simulate + // drop failure to the user + mDragObject.deferDragViewCleanupPostAnimation = true; + + float fromX = mDragObject.x - mDragObject.xOffset; + float fromY = mDragObject.y - mDragObject.yOffset; + DragView dragView = mDragObject.dragView; + setupReturnDragAnimator(fromX, fromY, (View) mDragObject.originalView, + (x, y, scale, alpha) -> { + dragView.setTranslationX(x); + dragView.setTranslationY(y); + dragView.setScaleX(scale); + dragView.setScaleY(scale); + dragView.setAlpha(alpha); + }); + mReturnAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + callOnDragEnd(); + dragView.remove(); + dragView.clearAnimation(); + mReturnAnimator = null; + + } + }); + mReturnAnimator.start(); + } + super.endDrag(); + } + + @Override protected void callOnDragEnd() { super.callOnDragEnd(); maybeOnDragEnd(); @@ -432,56 +504,20 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im SurfaceControl dragSurface = dragEvent.getDragSurface(); // For top level icons, the target is the icon itself - View target = btv; - Object tag = btv.getTag(); - if (tag instanceof ItemInfo) { - ItemInfo item = (ItemInfo) tag; - TaskbarViewController taskbarViewController = mControllers.taskbarViewController; - if (item.container == CONTAINER_ALL_APPS || item.container == CONTAINER_PREDICTION) { - // Since all apps closes when the drag starts, target the all apps button instead. - target = taskbarViewController.getAllAppsButtonView(); - } else if (item.container >= 0) { - // Since folders close when the drag starts, target the folder icon instead. - Predicate<ItemInfo> matcher = ItemInfoMatcher.forFolderMatch( - ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id))); - target = taskbarViewController.getFirstIconMatch(matcher); - } else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) { - // Find first icon with same package/user as the deep shortcut. - Predicate<ItemInfo> packageUserMatcher = ItemInfoMatcher.ofPackages( - Collections.singleton(item.getTargetPackage()), item.user); - target = taskbarViewController.getFirstIconMatch(packageUserMatcher); - } - } - - // Finish any pending return animation before starting a new drag - if (mReturnAnimator != null) { - mReturnAnimator.end(); - } + View target = findTaskbarTargetForIconView(btv); float fromX = dragEvent.getX() - dragEvent.getOffsetX(); float fromY = dragEvent.getY() - dragEvent.getOffsetY(); - int[] toPosition = target.getLocationOnScreen(); - float toScale = (float) target.getWidth() / mDragIconSize; - float toAlpha = (target == btv) ? 1f : 0f; final ViewRootImpl viewRoot = target.getViewRootImpl(); SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); - mReturnAnimator = ValueAnimator.ofFloat(0f, 1f); - mReturnAnimator.setDuration(300); - mReturnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); - mReturnAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - float t = animation.getAnimatedFraction(); - float accelT = Interpolators.ACCEL_2.getInterpolation(t); - float scale = 1f - t * (1f - toScale); - float alpha = 1f - accelT * (1f - toAlpha); - tx.setPosition(dragSurface, Utilities.mapRange(t, fromX, toPosition[0]), - Utilities.mapRange(t, fromY, toPosition[1])); - tx.setScale(dragSurface, scale, scale); - tx.setAlpha(dragSurface, alpha); - tx.apply(); - } - }); + setupReturnDragAnimator(fromX, fromY, btv, + (x, y, scale, alpha) -> { + tx.setPosition(dragSurface, x, y); + tx.setScale(dragSurface, scale, scale); + tx.setAlpha(dragSurface, alpha); + tx.apply(); + }); + mReturnAnimator.addListener(new AnimatorListenerAdapter() { private boolean mCanceled = false; @@ -517,6 +553,68 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im mReturnAnimator.start(); } + private View findTaskbarTargetForIconView(@NonNull View iconView) { + Object tag = iconView.getTag(); + TaskbarViewController taskbarViewController = mControllers.taskbarViewController; + + if (tag instanceof ItemInfo) { + ItemInfo item = (ItemInfo) tag; + if (item.container == CONTAINER_ALL_APPS || item.container == CONTAINER_PREDICTION) { + if (mDisallowGlobalDrag) { + // We're dragging in taskbarAllApps, we don't have folders or shortcuts + return iconView; + } + // Since all apps closes when the drag starts, target the all apps button instead. + return taskbarViewController.getAllAppsButtonView(); + } else if (item.container >= 0) { + // Since folders close when the drag starts, target the folder icon instead. + Predicate<ItemInfo> matcher = ItemInfoMatcher.forFolderMatch( + ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id))); + return taskbarViewController.getFirstIconMatch(matcher); + } else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) { + // Find first icon with same package/user as the deep shortcut. + Predicate<ItemInfo> packageUserMatcher = ItemInfoMatcher.ofPackages( + Collections.singleton(item.getTargetPackage()), item.user); + return taskbarViewController.getFirstIconMatch(packageUserMatcher); + } + } + return iconView; + } + + private void setupReturnDragAnimator(float fromX, float fromY, View originalView, + TaskbarReturnPropertiesListener animListener) { + // Finish any pending return animation before starting a new return + if (mReturnAnimator != null) { + mReturnAnimator.end(); + } + + // For top level icons, the target is the icon itself + View target = findTaskbarTargetForIconView(originalView); + + int[] toPosition = target.getLocationOnScreen(); + float toScale = (float) target.getWidth() / mDragIconSize; + float toAlpha = (target == originalView) ? 1f : 0f; + MultiValueUpdateListener listener = new MultiValueUpdateListener() { + final FloatProp mDx = new FloatProp(fromX, toPosition[0], 0, + ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.FAST_OUT_SLOW_IN); + final FloatProp mDy = new FloatProp(fromY, toPosition[1], 0, + ANIM_DURATION_RETURN_ICON_TO_TASKBAR, + FAST_OUT_SLOW_IN); + final FloatProp mScale = new FloatProp(1f, toScale, 0, + ANIM_DURATION_RETURN_ICON_TO_TASKBAR, FAST_OUT_SLOW_IN); + final FloatProp mAlpha = new FloatProp(1f, toAlpha, 0, + ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.ACCEL_2); + @Override + public void onUpdate(float percent, boolean initOnly) { + animListener.updateDragShadow(mDx.value, mDy.value, mScale.value, mAlpha.value); + } + }; + mReturnAnimator = ValueAnimator.ofFloat(0f, 1f); + mReturnAnimator.setDuration(ANIM_DURATION_RETURN_ICON_TO_TASKBAR); + mReturnAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + mReturnAnimator.addUpdateListener(listener); + } + @Override protected float getX(MotionEvent ev) { // We will resize to fill the screen while dragging, so use screen coordinates. This ensures @@ -540,7 +638,7 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im @Override protected void exitDrag() { - if (mDragObject != null) { + if (mDragObject != null && !mDisallowGlobalDrag) { mActivity.getDragLayer().removeView(mDragObject.dragView); } } @@ -556,6 +654,10 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im return null; } + interface TaskbarReturnPropertiesListener { + void updateDragShadow(float x, float y, float scale, float alpha); + } + @Override public void dumpLogs(String prefix, PrintWriter pw) { pw.println(prefix + "TaskbarDragController:"); @@ -566,5 +668,7 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im pw.println(prefix + "\tmRegistrationY=" + mRegistrationY); pw.println(prefix + "\tmIsSystemDragInProgress=" + mIsSystemDragInProgress); pw.println(prefix + "\tisInternalDragInProgess=" + super.isDragging()); + pw.println(prefix + "\tmDisallowGlobalDrag=" + mDisallowGlobalDrag); + pw.println(prefix + "\tmDisallowLongClick=" + mDisallowLongClick); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java index 7e75779c62..d0059f7207 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java @@ -116,6 +116,22 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> { } @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (mControllerCallbacks != null) { + mControllerCallbacks.tryStashBasedOnMotionEvent(ev); + } + return super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (mControllerCallbacks != null) { + mControllerCallbacks.tryStashBasedOnMotionEvent(ev); + } + return super.onTouchEvent(ev); + } + + @Override public void onViewRemoved(View child) { super.onViewRemoved(child); if (mControllerCallbacks != null) { @@ -150,6 +166,23 @@ public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> { invalidate(); } + /** + * Sets the roundness of the round corner above Taskbar. + * @param cornerRoundness 0 has no round corner, 1 has complete round corner. + */ + protected void setCornerRoundness(float cornerRoundness) { + mBackgroundRenderer.setCornerRoundness(cornerRoundness); + invalidate(); + } + + /* + * Sets the translation of the background during the swipe up gesture. + */ + protected void setBackgroundTranslationYForSwipe(float translationY) { + mBackgroundRenderer.setTranslationYForSwipe(translationY); + invalidate(); + } + @Override public boolean dispatchTouchEvent(MotionEvent ev) { TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java index 025fe7a017..cd27a46a00 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java @@ -16,24 +16,31 @@ package com.android.launcher3.taskbar; import android.content.res.Resources; +import android.graphics.Point; import android.graphics.Rect; +import android.view.MotionEvent; import android.view.ViewTreeObserver; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.launcher3.anim.AnimatedFloat; +import com.android.launcher3.testing.shared.ResourceUtils; +import com.android.launcher3.util.DimensionUtils; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.TouchController; -import com.android.quickstep.AnimatedFloat; import java.io.PrintWriter; /** * Handles properties/data collection, then passes the results to TaskbarDragLayer to render. */ -public class TaskbarDragLayerController implements TaskbarControllers.LoggableTaskbarController { +public class TaskbarDragLayerController implements TaskbarControllers.LoggableTaskbarController, + TaskbarControllers.BackgroundRendererController { private final TaskbarActivityContext mActivity; private final TaskbarDragLayer mTaskbarDragLayer; private final int mFolderMargin; + private float mGestureHeightYThreshold; // Alpha properties for taskbar background. private final AnimatedFloat mBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha); @@ -60,6 +67,7 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa mTaskbarDragLayer = taskbarDragLayer; final Resources resources = mTaskbarDragLayer.getResources(); mFolderMargin = resources.getDimensionPixelSize(R.dimen.taskbar_folder_margin); + updateGestureHeight(); } public void init(TaskbarControllers controllers) { @@ -119,6 +127,19 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa return mBgOffset; } + private void updateGestureHeight() { + int gestureHeight = ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, + mActivity.getResources()); + mGestureHeightYThreshold = mActivity.getDeviceProfile().heightPx - gestureHeight; + } + + /** + * Make updates when configuration changes. + */ + public void onConfigurationChanged() { + updateGestureHeight(); + } + private void updateBackgroundAlpha() { final float bgNavbar = mBgNavbar.value; final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value @@ -129,12 +150,24 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa updateNavBarDarkIntensityMultiplier(); } + /** + * Sets the translation of the background during the swipe up gesture. + */ + public void setTranslationYForSwipe(float transY) { + mTaskbarDragLayer.setBackgroundTranslationYForSwipe(transY); + } + private void updateBackgroundOffset() { mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value); updateNavBarDarkIntensityMultiplier(); } + @Override + public void setCornerRoundness(float cornerRoundness) { + mTaskbarDragLayer.setCornerRoundness(cornerRoundness); + } + private void updateNavBarDarkIntensityMultiplier() { // Zero out the app-requested dark intensity when we're drawing our own background. float effectiveBgAlpha = mLastSetBackgroundAlpha * (1 - mBgOffset.value); @@ -155,6 +188,8 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa */ public class TaskbarDragLayerCallbacks { + private final int[] mTempOutLocation = new int[2]; + /** * Called to update the touchable insets. * @see ViewTreeObserver.InternalInsetsInfo#setTouchableInsets(int) @@ -164,10 +199,41 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa } /** + * Listens to TaskbarDragLayer touch events and responds accordingly. + */ + public void tryStashBasedOnMotionEvent(MotionEvent ev) { + if (!DisplayController.isTransientTaskbar(mActivity)) { + return; + } + if (mControllers.taskbarStashController.isStashed()) { + return; + } + + boolean stashTaskbar = false; + + MotionEvent screenCoordinates = MotionEvent.obtain(ev); + if (ev.getAction() == MotionEvent.ACTION_OUTSIDE) { + stashTaskbar = true; + } else if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mTaskbarDragLayer.getLocationOnScreen(mTempOutLocation); + screenCoordinates.offsetLocation(mTempOutLocation[0], mTempOutLocation[1]); + + if (!mControllers.taskbarViewController.isEventOverAnyItem(screenCoordinates) + && screenCoordinates.getY() < mGestureHeightYThreshold) { + stashTaskbar = true; + } + } + + if (stashTaskbar) { + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true); + } + } + + /** * Called when a child is removed from TaskbarDragLayer. */ public void onDragLayerViewRemoved() { - mActivity.maybeSetTaskbarWindowNotFullscreen(); + mActivity.onDragEndOrViewRemoved(); } /** @@ -177,9 +243,12 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa DeviceProfile deviceProfile = mActivity.getDeviceProfile(); if (TaskbarManager.isPhoneMode(deviceProfile)) { Resources resources = mActivity.getResources(); - return mActivity.isThreeButtonNav() ? - resources.getDimensionPixelSize(R.dimen.taskbar_size) : - resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size); + Point taskbarDimensions = + DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources, + TaskbarManager.isPhoneMode(deviceProfile)); + return taskbarDimensions.y == -1 ? + deviceProfile.getDisplayInfo().currentSize.y : + taskbarDimensions.y; } else { return deviceProfile.taskbarSize; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java index 454a2a4569..d3f1b2f51e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java @@ -15,69 +15,33 @@ */ package com.android.launcher3.taskbar; -import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.anim.Interpolators.ACCEL_2; -import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; -import static com.android.launcher3.anim.Interpolators.DEACCEL; -import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.Keyframe; -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.animation.TimeInterpolator; -import android.content.res.Resources; -import android.text.TextUtils; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; -import com.android.launcher3.icons.BitmapInfo; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.uioverrides.PredictedAppIcon; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; +import com.android.launcher3.util.DisplayController; + +import com.airbnb.lottie.LottieAnimationView; import java.io.PrintWriter; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; /** Handles the Taskbar Education flow. */ public class TaskbarEduController implements TaskbarControllers.LoggableTaskbarController { - private static final long WAVE_ANIM_DELAY = 250; - private static final long WAVE_ANIM_STAGGER = 50; - private static final long WAVE_ANIM_EACH_ICON_DURATION = 633; - private static final long WAVE_ANIM_SLOT_MACHINE_DURATION = 1085; - // The fraction of each icon's animation at which we reach the top point of the wave. - private static final float WAVE_ANIM_FRACTION_TOP = 0.4f; - // The fraction of each icon's animation at which we reach the bottom, before overshooting. - private static final float WAVE_ANIM_FRACTION_BOTTOM = 0.9f; - private static final TimeInterpolator WAVE_ANIM_TO_TOP_INTERPOLATOR = FAST_OUT_SLOW_IN; - private static final TimeInterpolator WAVE_ANIM_TO_BOTTOM_INTERPOLATOR = ACCEL_2; - private static final TimeInterpolator WAVE_ANIM_OVERSHOOT_INTERPOLATOR = DEACCEL; - private static final TimeInterpolator WAVE_ANIM_OVERSHOOT_RETURN_INTERPOLATOR = ACCEL_DEACCEL; - private static final float WAVE_ANIM_ICON_SCALE = 1.2f; - // How many icons to cycle through in the slot machine (+ the original icon at each end). - private static final int WAVE_ANIM_SLOT_MACHINE_NUM_ICONS = 3; - private final TaskbarActivityContext mActivity; - private final float mWaveAnimTranslationY; - private final float mWaveAnimTranslationYReturnOvershoot; // Initialized in init. TaskbarControllers mControllers; private TaskbarEduView mTaskbarEduView; - private Animator mAnim; + private TaskbarEduPagedView mPagedView; public TaskbarEduController(TaskbarActivityContext activity) { mActivity = activity; - - final Resources resources = activity.getResources(); - mWaveAnimTranslationY = resources.getDimension(R.dimen.taskbar_edu_wave_anim_trans_y); - mWaveAnimTranslationYReturnOvershoot = resources.getDimension( - R.dimen.taskbar_edu_wave_anim_trans_y_return_overshoot); } public void init(TaskbarControllers controllers) { @@ -85,126 +49,59 @@ public class TaskbarEduController implements TaskbarControllers.LoggableTaskbarC } void showEdu() { - mActivity.setTaskbarWindowFullscreen(true); - mActivity.getDragLayer().post(() -> { - mTaskbarEduView = (TaskbarEduView) mActivity.getLayoutInflater().inflate( - R.layout.taskbar_edu, mActivity.getDragLayer(), false); - mTaskbarEduView.init(new TaskbarEduCallbacks()); - mControllers.navbarButtonsViewController.setSlideInViewVisible(true); - mTaskbarEduView.setOnCloseBeginListener( - () -> mControllers.navbarButtonsViewController.setSlideInViewVisible(false)); - mTaskbarEduView.addOnCloseListener(() -> mTaskbarEduView = null); - mTaskbarEduView.show(); - startAnim(createWaveAnim()); - }); - } - - void hideEdu() { - if (mTaskbarEduView != null) { - mTaskbarEduView.close(true /* animate */); - } - } - - /** - * Starts the given animation, ending the previous animation first if it's still playing. - */ - private void startAnim(Animator anim) { - if (mAnim != null) { - mAnim.end(); - } - mAnim = anim; - mAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mAnim = null; - } - }); - mAnim.start(); - } - - /** - * Creates a staggered "wave" animation where each icon translates and scales up in succession. - */ - private Animator createWaveAnim() { - AnimatorSet waveAnim = new AnimatorSet(); - View[] icons = mControllers.taskbarViewController.getIconViews(); - for (int i = 0; i < icons.length; i++) { - View icon = icons[i]; - AnimatorSet iconAnim = new AnimatorSet(); - - Keyframe[] scaleKeyframes = new Keyframe[] { - Keyframe.ofFloat(0, 1f), - Keyframe.ofFloat(WAVE_ANIM_FRACTION_TOP, WAVE_ANIM_ICON_SCALE), - Keyframe.ofFloat(WAVE_ANIM_FRACTION_BOTTOM, 1f), - Keyframe.ofFloat(1f, 1f) - }; - scaleKeyframes[1].setInterpolator(WAVE_ANIM_TO_TOP_INTERPOLATOR); - scaleKeyframes[2].setInterpolator(WAVE_ANIM_TO_BOTTOM_INTERPOLATOR); - - Keyframe[] translationYKeyframes = new Keyframe[] { - Keyframe.ofFloat(0, 0f), - Keyframe.ofFloat(WAVE_ANIM_FRACTION_TOP, -mWaveAnimTranslationY), - Keyframe.ofFloat(WAVE_ANIM_FRACTION_BOTTOM, 0f), - // Half of the remaining fraction overshoots, then the other half returns to 0. - Keyframe.ofFloat( - WAVE_ANIM_FRACTION_BOTTOM + (1 - WAVE_ANIM_FRACTION_BOTTOM) / 2f, - mWaveAnimTranslationYReturnOvershoot), - Keyframe.ofFloat(1f, 0f) - }; - translationYKeyframes[1].setInterpolator(WAVE_ANIM_TO_TOP_INTERPOLATOR); - translationYKeyframes[2].setInterpolator(WAVE_ANIM_TO_BOTTOM_INTERPOLATOR); - translationYKeyframes[3].setInterpolator(WAVE_ANIM_OVERSHOOT_INTERPOLATOR); - translationYKeyframes[4].setInterpolator(WAVE_ANIM_OVERSHOOT_RETURN_INTERPOLATOR); - - iconAnim.play(ObjectAnimator.ofPropertyValuesHolder(icon, - PropertyValuesHolder.ofKeyframe(SCALE_PROPERTY, scaleKeyframes)) - .setDuration(WAVE_ANIM_EACH_ICON_DURATION)); - iconAnim.play(ObjectAnimator.ofPropertyValuesHolder(icon, - PropertyValuesHolder.ofKeyframe(View.TRANSLATION_Y, translationYKeyframes)) - .setDuration(WAVE_ANIM_EACH_ICON_DURATION)); - - if (icon instanceof PredictedAppIcon) { - // Play slot machine animation through random icons from AllAppsList. - PredictedAppIcon predictedAppIcon = (PredictedAppIcon) icon; - ItemInfo itemInfo = (ItemInfo) icon.getTag(); - List<BitmapInfo> iconsToAnimate = mControllers.uiController.getAppIconsForEdu() - .filter(appInfo -> !TextUtils.equals(appInfo.title, itemInfo.title)) - .map(appInfo -> appInfo.bitmap) - .filter(bitmap -> !bitmap.isNullOrLowRes()) - .collect(Collectors.toList()); - // Pick n icons at random. - Collections.shuffle(iconsToAnimate); - if (iconsToAnimate.size() > WAVE_ANIM_SLOT_MACHINE_NUM_ICONS) { - iconsToAnimate = iconsToAnimate.subList(0, WAVE_ANIM_SLOT_MACHINE_NUM_ICONS); - } - Animator slotMachineAnim = predictedAppIcon.createSlotMachineAnim(iconsToAnimate); - if (slotMachineAnim != null) { - iconAnim.play(slotMachineAnim.setDuration(WAVE_ANIM_SLOT_MACHINE_DURATION)); - } - } - - iconAnim.setStartDelay(WAVE_ANIM_STAGGER * i); - waveAnim.play(iconAnim); - } - waveAnim.setStartDelay(WAVE_ANIM_DELAY); - return waveAnim; + TaskbarOverlayController overlayController = mControllers.taskbarOverlayController; + TaskbarOverlayContext overlayContext = overlayController.requestWindow(); + LayoutInflater layoutInflater = overlayContext.getLayoutInflater(); + + mTaskbarEduView = (TaskbarEduView) layoutInflater.inflate( + R.layout.taskbar_edu, overlayContext.getDragLayer(), false); + mPagedView = mTaskbarEduView.findViewById(R.id.content); + layoutInflater.inflate( + DisplayController.isTransientTaskbar(overlayContext) + ? R.layout.taskbar_edu_pages_transient + : R.layout.taskbar_edu_pages_persistent, + mPagedView, + true); + + // Provide enough room for taskbar. + View startButton = mTaskbarEduView.findViewById(R.id.edu_start_button); + ViewGroup.MarginLayoutParams layoutParams = + (ViewGroup.MarginLayoutParams) startButton.getLayoutParams(); + DeviceProfile dp = overlayContext.getDeviceProfile(); + layoutParams.bottomMargin += DisplayController.isTransientTaskbar(overlayContext) + ? dp.taskbarSize + dp.transientTaskbarMargin + : dp.taskbarSize; + + mTaskbarEduView.init(new TaskbarEduCallbacks()); + + mControllers.navbarButtonsViewController.setSlideInViewVisible(true); + mTaskbarEduView.setOnCloseBeginListener( + () -> mControllers.navbarButtonsViewController.setSlideInViewVisible(false)); + mTaskbarEduView.addOnCloseListener(() -> mTaskbarEduView = null); + mTaskbarEduView.show(); } @Override public void dumpLogs(String prefix, PrintWriter pw) { pw.println(prefix + "TaskbarEduController:"); - pw.println(prefix + "\tisShowingEdu=" + (mTaskbarEduView != null)); - pw.println(prefix + "\tmWaveAnimTranslationY=" + mWaveAnimTranslationY); - pw.println(prefix + "\tmWaveAnimTranslationYReturnOvershoot=" - + mWaveAnimTranslationYReturnOvershoot); } /** * Callbacks for {@link TaskbarEduView} to interact with its controller. */ class TaskbarEduCallbacks { - void onPageChanged(int currentPage, int pageCount) { + void onPageChanged(int prevPage, int currentPage, int pageCount) { + // Reset previous pages' animation. + LottieAnimationView prevAnimation = mPagedView.getChildAt(prevPage) + .findViewById(R.id.animation); + prevAnimation.cancelAnimation(); + prevAnimation.setFrame(0); + + mPagedView.getChildAt(currentPage) + .<LottieAnimationView>findViewById(R.id.animation) + .playAnimation(); + if (currentPage == 0) { mTaskbarEduView.updateStartButton(R.string.taskbar_edu_close, v -> mTaskbarEduView.close(true /* animate */)); @@ -220,5 +117,17 @@ public class TaskbarEduController implements TaskbarControllers.LoggableTaskbarC v -> mTaskbarEduView.snapToPage(currentPage + 1)); } } + + int getIconLayoutBoundsWidth() { + return mControllers.taskbarViewController.getIconLayoutWidth(); + } + + int getOpenDuration() { + return mControllers.taskbarOverlayController.getOpenDuration(); + } + + int getCloseDuration() { + return mControllers.taskbarOverlayController.getCloseDuration(); + } } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java index 8e57ea62fc..6cd6512391 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java @@ -48,7 +48,7 @@ public class TaskbarEduPagedView extends PagedView<PageIndicatorDots> { void setControllerCallbacks(TaskbarEduCallbacks controllerCallbacks) { mControllerCallbacks = controllerCallbacks; - mControllerCallbacks.onPageChanged(getCurrentPage(), getPageCount()); + mControllerCallbacks.onPageChanged(getCurrentPage(), getCurrentPage(), getPageCount()); } @Override @@ -67,7 +67,7 @@ public class TaskbarEduPagedView extends PagedView<PageIndicatorDots> { @Override protected void notifyPageSwitchListener(int prevPage) { super.notifyPageSwitchListener(prevPage); - mControllerCallbacks.onPageChanged(getCurrentPage(), getPageCount()); + mControllerCallbacks.onPageChanged(prevPage, getCurrentPage(), getPageCount()); } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java index 89d67be685..5702b6bb5c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java @@ -15,7 +15,7 @@ */ package com.android.launcher3.taskbar; -import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE; +import static com.android.launcher3.anim.Interpolators.EMPHASIZED; import android.animation.PropertyValuesHolder; import android.content.Context; @@ -24,21 +24,23 @@ import android.provider.Settings; import android.util.AttributeSet; import android.util.Pair; import android.view.View; +import android.view.animation.Interpolator; import android.widget.Button; import com.android.launcher3.Insettable; import com.android.launcher3.R; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import com.android.launcher3.views.AbstractSlideInView; /** Education view about the Taskbar. */ -public class TaskbarEduView extends AbstractSlideInView<TaskbarActivityContext> +public class TaskbarEduView extends AbstractSlideInView<TaskbarOverlayContext> implements Insettable { - private static final int DEFAULT_OPEN_DURATION = 500; - private static final int DEFAULT_CLOSE_DURATION = 200; - private final Rect mInsets = new Rect(); + // Initialized in init. + private TaskbarEduController.TaskbarEduCallbacks mTaskbarEduCallbacks; + private Button mStartButton; private Button mEndButton; private TaskbarEduPagedView mPagedView; @@ -56,11 +58,17 @@ public class TaskbarEduView extends AbstractSlideInView<TaskbarActivityContext> if (mPagedView != null) { mPagedView.setControllerCallbacks(callbacks); } + mTaskbarEduCallbacks = callbacks; } @Override protected void handleClose(boolean animate) { - handleClose(animate, DEFAULT_CLOSE_DURATION); + handleClose(animate, mTaskbarEduCallbacks.getCloseDuration()); + } + + @Override + protected Interpolator getIdleInterpolator() { + return EMPHASIZED; } @Override @@ -101,6 +109,22 @@ public class TaskbarEduView extends AbstractSlideInView<TaskbarActivityContext> Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING, 0); } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int contentWidth = Math.min(getContentAreaWidth(), getMeasuredWidth()); + contentWidth = Math.max(contentWidth, mTaskbarEduCallbacks.getIconLayoutBoundsWidth()); + int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(contentWidth, MeasureSpec.EXACTLY); + + mContent.measure(contentAreaWidthSpec, MeasureSpec.UNSPECIFIED); + } + + private int getContentAreaWidth() { + return mTaskbarEduCallbacks.getIconLayoutBoundsWidth() + + getResources().getDimensionPixelSize(R.dimen.taskbar_edu_horizontal_margin) * 2; + } + /** Show the Education flow. */ public void show() { attachToContainer(); @@ -139,8 +163,8 @@ public class TaskbarEduView extends AbstractSlideInView<TaskbarActivityContext> mIsOpen = true; mOpenCloseAnimator.setValues( PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED)); - mOpenCloseAnimator.setInterpolator(AGGRESSIVE_EASE); - mOpenCloseAnimator.setDuration(DEFAULT_OPEN_DURATION).start(); + mOpenCloseAnimator.setInterpolator(EMPHASIZED); + mOpenCloseAnimator.setDuration(mTaskbarEduCallbacks.getOpenDuration()).start(); } void snapToPage(int page) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java index 6c793a6119..ffaee455d9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java @@ -30,13 +30,10 @@ import android.os.Looper; import android.view.MotionEvent; import android.view.View; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.compat.AccessibilityManagerCompat; -import com.android.launcher3.util.MultiValueAlpha; +import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.TouchController; -import com.android.quickstep.AnimatedFloat; - -import java.util.Optional; -import java.util.function.Consumer; /** * Controller for taskbar when force visible in immersive mode is set. @@ -54,8 +51,6 @@ public class TaskbarForceVisibleImmersiveController implements TouchController { private final Runnable mUndimmingRunnable = this::undimIcons; private final AnimatedFloat mIconAlphaForDimming = new AnimatedFloat( this::updateIconDimmingAlpha); - private final Consumer<MultiValueAlpha> mImmersiveModeAlphaUpdater = alpha -> alpha.getProperty( - ALPHA_INDEX_IMMERSIVE_MODE).setValue(mIconAlphaForDimming.value); private final View.AccessibilityDelegate mKidsModeAccessibilityDelegate = new View.AccessibilityDelegate() { @Override @@ -145,22 +140,20 @@ public class TaskbarForceVisibleImmersiveController implements TouchController { } private void updateIconDimmingAlpha() { - getBackButtonAlphaOptional().ifPresent(mImmersiveModeAlphaUpdater); - getHomeButtonAlphaOptional().ifPresent(mImmersiveModeAlphaUpdater); - } - - private Optional<MultiValueAlpha> getBackButtonAlphaOptional() { if (mControllers == null || mControllers.navbarButtonsViewController == null) { - return Optional.empty(); + return; } - return Optional.ofNullable(mControllers.navbarButtonsViewController.getBackButtonAlpha()); - } - private Optional<MultiValueAlpha> getHomeButtonAlphaOptional() { - if (mControllers == null || mControllers.navbarButtonsViewController == null) { - return Optional.empty(); + MultiPropertyFactory<View> ba = + mControllers.navbarButtonsViewController.getBackButtonAlpha(); + if (ba != null) { + ba.get(ALPHA_INDEX_IMMERSIVE_MODE).setValue(mIconAlphaForDimming.value); + } + MultiPropertyFactory<View> ha = + mControllers.navbarButtonsViewController.getHomeButtonAlpha(); + if (ba != null) { + ha.get(ALPHA_INDEX_IMMERSIVE_MODE).setValue(mIconAlphaForDimming.value); } - return Optional.ofNullable(mControllers.navbarButtonsViewController.getHomeButtonAlpha()); } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index 7b2b7eca7f..a48b88fc19 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -18,8 +18,8 @@ package com.android.launcher3.taskbar import android.graphics.Insets import android.graphics.Region import android.view.InsetsFrameProvider -import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES import android.view.InsetsState +import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES import android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT import android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR import android.view.ViewTreeObserver @@ -29,11 +29,11 @@ import android.view.WindowManager import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION import com.android.launcher3.AbstractFloatingView -import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS +import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY import com.android.launcher3.DeviceProfile +import com.android.launcher3.R import com.android.launcher3.anim.AlphaUpdateListener import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController -import com.android.quickstep.KtR import java.io.PrintWriter /** @@ -42,9 +42,8 @@ import java.io.PrintWriter class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTaskbarController { /** The bottom insets taskbar provides to the IME when IME is visible. */ - val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize( - KtR.dimen.taskbar_ime_size) - private val contentRegion: Region = Region() + val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(R.dimen.taskbar_ime_size) + private val touchableRegion: Region = Region() private val deviceProfileChangeListener = { _: DeviceProfile -> onTaskbarWindowHeightOrInsetsChanged() } @@ -77,38 +76,64 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask } fun onTaskbarWindowHeightOrInsetsChanged() { - var contentHeight = controllers.taskbarStashController.contentHeightToReportToApps - contentRegion.set(0, windowLayoutParams.height - contentHeight, + val touchableHeight = controllers.taskbarStashController.touchableHeight + touchableRegion.set(0, windowLayoutParams.height - touchableHeight, context.deviceProfile.widthPx, windowLayoutParams.height) - var tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps + val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps + val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps for (provider in windowLayoutParams.providedInsets) { - if (provider.type == ITYPE_EXTRA_NAVIGATION_BAR) { - provider.insetsSize = Insets.of(0, 0, 0, contentHeight) - } else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT - || provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES) { - provider.insetsSize = Insets.of(0, 0, 0, tappableHeight) + if (provider.type == ITYPE_EXTRA_NAVIGATION_BAR + || provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES) { + provider.insetsSize = getInsetsByNavMode(contentHeight) + } else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) { + provider.insetsSize = getInsetsByNavMode(tappableHeight) } } - val imeInsetsSize = Insets.of(0, 0, 0, taskbarHeightForIme) - // Use 0 insets for the VoiceInteractionWindow (assistant) when gesture nav is enabled. - val visInsetsSize = Insets.of(0, 0, 0, if (context.isGestureNav) 0 else tappableHeight) + val imeInsetsSize = getInsetsByNavMode(taskbarHeightForIme) val insetsSizeOverride = arrayOf( InsetsFrameProvider.InsetsSizeOverride( TYPE_INPUT_METHOD, imeInsetsSize ), + ) + // Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled. + val visInsetsSizeForGestureNavTappableElement = getInsetsByNavMode(0) + val insetsSizeOverrideForGestureNavTappableElement = arrayOf( + InsetsFrameProvider.InsetsSizeOverride( + TYPE_INPUT_METHOD, + imeInsetsSize + ), InsetsFrameProvider.InsetsSizeOverride( TYPE_VOICE_INTERACTION, - visInsetsSize - ) + visInsetsSizeForGestureNavTappableElement + ), ) for (provider in windowLayoutParams.providedInsets) { - provider.insetsSizeOverrides = insetsSizeOverride + if (context.isGestureNav && provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) { + provider.insetsSizeOverrides = insetsSizeOverrideForGestureNavTappableElement + } else { + provider.insetsSizeOverrides = insetsSizeOverride + } } } /** + * @return [Insets] where the [bottomInset] is either used as a bottom inset or + * right/left inset if using 3 button nav + */ + private fun getInsetsByNavMode(bottomInset: Int) : Insets { + val devicePortrait = !context.deviceProfile.isLandscape + if (!TaskbarManager.isPhoneButtonNavMode(context) || devicePortrait) { + // Taskbar or portrait phone mode + return Insets.of(0, 0, 0, bottomInset) + } + + // TODO(b/230394142): seascape + return Insets.of(0, 0, bottomInset, 0) + } + + /** * Sets {@param providesInsetsTypes} as the inset types provided by {@param params}. * @param params The window layout params. * @param providesInsetsTypes The inset types we would like this layout params to provide. @@ -134,7 +159,8 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) { // Let touches pass through us. insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION) - } else if (controllers.navbarButtonsViewController.isImeVisible) { + } else if (controllers.navbarButtonsViewController.isImeVisible + && controllers.taskbarStashController.isStashed()) { insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION) } else if (!controllers.uiController.isTaskbarTouchable) { // Let touches pass through us. @@ -142,8 +168,11 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask } else if (controllers.taskbarDragController.isSystemDragInProgress) { // Let touches pass through us. insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION) - } else if (AbstractFloatingView.hasOpenView(context, TYPE_TASKBAR_ALL_APPS)) { - // Let touches pass through us. + } else if (AbstractFloatingView.hasOpenView(context, TYPE_TASKBAR_OVERLAY_PROXY)) { + // Let touches pass through us if icons are hidden. + if (controllers.taskbarViewController.areIconsVisible()) { + insetsInfo.touchableRegion.set(touchableRegion) + } insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION) } else if (controllers.taskbarViewController.areIconsVisible() || AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL) @@ -154,7 +183,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTask if (context.isTaskbarWindowFullscreen) { TOUCHABLE_INSETS_FRAME } else { - insetsInfo.touchableRegion.set(contentRegion) + insetsInfo.touchableRegion.set(touchableRegion) TOUCHABLE_INSETS_REGION } ) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 58c689bc36..4ad3858de1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -35,11 +35,12 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.uioverrides.QuickstepLauncher; -import com.android.launcher3.util.MultiValueAlpha; -import com.android.quickstep.AnimatedFloat; +import com.android.launcher3.uioverrides.states.OverviewState; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.views.RecentsView; @@ -49,8 +50,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData; import java.io.PrintWriter; import java.util.HashMap; import java.util.StringJoiner; -import java.util.function.Consumer; -import java.util.function.Supplier; /** * Track LauncherState, RecentsAnimation, resumed state for task bar in one place here and animate @@ -65,19 +64,17 @@ import java.util.function.Supplier; public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1; public static final int FLAG_TRANSITION_STATE_RUNNING = 1 << 2; + private static final int FLAGS_LAUNCHER = FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING; /** Equivalent to an int with all 1s for binary operation purposes */ private static final int FLAGS_ALL = ~0; - private final AnimatedFloat mIconAlignmentForResumedState = - new AnimatedFloat(this::onIconAlignmentRatioChangedForAppAndHomeTransition); - private final AnimatedFloat mIconAlignmentForGestureState = - new AnimatedFloat(this::onIconAlignmentRatioChangedForAppAndHomeTransition); - private final AnimatedFloat mIconAlignmentForLauncherState = - new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition); + private final AnimatedFloat mIconAlignment = + new AnimatedFloat(this::onIconAlignmentRatioChanged); private TaskbarControllers mControllers; private AnimatedFloat mTaskbarBackgroundAlpha; - private MultiValueAlpha.AlphaProperty mIconAlphaForHome; + private AnimatedFloat mTaskbarCornerRoundness; + private MultiProperty mIconAlphaForHome; private QuickstepLauncher mLauncher; private Integer mPrevState; @@ -86,26 +83,15 @@ import java.util.function.Supplier; private @Nullable TaskBarRecentsAnimationListener mTaskBarRecentsAnimationListener; - private boolean mIsAnimatingToLauncherViaGesture; - private boolean mIsAnimatingToLauncherViaResume; + private boolean mIsAnimatingToLauncher; private boolean mShouldDelayLauncherStateAnim; // We skip any view synchronizations during init/destroy. private boolean mCanSyncViews; - private final Consumer<Float> mIconAlphaForHomeConsumer = alpha -> { - /* - * Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets - * should not be visible at the same time. - */ - mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1); - mLauncher.getHotseat().setQsbAlpha( - mLauncher.getDeviceProfile().isQsbInline && alpha > 0 ? 0 : 1); - }; - private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener = - dp -> mIconAlphaForHomeConsumer.accept(mIconAlphaForHome.getValue()); + dp -> updateIconAlphaForHome(mIconAlphaForHome.getValue()); private final StateManager.StateListener<LauncherState> mStateListener = new StateManager.StateListener<LauncherState>() { @@ -133,6 +119,13 @@ import java.util.function.Supplier; mLauncherState = finalState; updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false); applyState(); + boolean disallowGlobalDrag = finalState instanceof OverviewState; + boolean disallowLongClick = finalState == LauncherState.OVERVIEW_SPLIT_SELECT; + mControllers.taskbarDragController.setDisallowGlobalDrag(disallowGlobalDrag); + mControllers.taskbarDragController.setDisallowLongClick(disallowLongClick); + mControllers.taskbarAllAppsController.setDisallowGlobalDrag(disallowGlobalDrag); + mControllers.taskbarAllAppsController.setDisallowLongClick(disallowLongClick); + mControllers.taskbarPopupController.setHideSplitOptions(disallowGlobalDrag); } }; @@ -144,12 +137,12 @@ import java.util.function.Supplier; mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController .getTaskbarBackgroundAlpha(); - MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha(); - mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME); - mIconAlphaForHome.setConsumer(mIconAlphaForHomeConsumer); + mTaskbarCornerRoundness = mControllers.getTaskbarCornerRoundness(); + mIconAlphaForHome = mControllers.taskbarViewController + .getTaskbarIconAlpha().get(ALPHA_INDEX_HOME); - mIconAlignmentForResumedState.finishAnimation(); - onIconAlignmentRatioChangedForAppAndHomeTransition(); + mIconAlignment.finishAnimation(); + onIconAlignmentRatioChanged(); mLauncher.getStateManager().addStateListener(mStateListener); @@ -165,11 +158,8 @@ import java.util.function.Supplier; public void onDestroy() { mCanSyncViews = false; - mIconAlignmentForResumedState.finishAnimation(); - mIconAlignmentForGestureState.finishAnimation(); - mIconAlignmentForLauncherState.finishAnimation(); + mIconAlignment.finishAnimation(); - mIconAlphaForHome.setConsumer(null); mLauncher.getHotseat().setIconsAlpha(1f); mLauncher.getStateManager().removeStateListener(mStateListener); @@ -187,12 +177,19 @@ import java.util.function.Supplier; TaskbarStashController stashController = mControllers.taskbarStashController; stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, toState.isTaskbarStashed(mLauncher)); + if (DEBUG) { + Log.d(TAG, "createAnimToLauncher - FLAG_IN_APP: " + false); + } stashController.updateStateForFlag(FLAG_IN_APP, false); updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true); animatorSet.play(stashController.applyStateWithoutStart(duration)); animatorSet.play(applyState(duration, false)); + if (mTaskBarRecentsAnimationListener != null) { + mTaskBarRecentsAnimationListener.endGestureStateOverride( + !mLauncher.isInState(LauncherState.OVERVIEW)); + } mTaskBarRecentsAnimationListener = new TaskBarRecentsAnimationListener(callbacks); callbacks.addListener(mTaskBarRecentsAnimationListener); ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchListener(() -> @@ -201,7 +198,7 @@ import java.util.function.Supplier; } public boolean isAnimatingToLauncher() { - return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture; + return mIsAnimatingToLauncher; } public void setShouldDelayLauncherStateAnim(boolean shouldDelayLauncherStateAnim) { @@ -261,11 +258,19 @@ import java.util.function.Supplier; } private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) { + boolean goingToLauncher = isInLauncher(); + final float toAlignment = isIconAlignedWithHotseat() ? 1 : 0; + if (DEBUG) { + Log.d(TAG, "onStateChangeApplied - mState: " + getStateString(mState) + + ", changedFlags: " + getStateString(changedFlags) + + ", goingToLauncher: " + goingToLauncher + + ", mLauncherState: " + mLauncherState + + ", toAlignment: " + toAlignment); + } AnimatorSet animatorSet = new AnimatorSet(); // Add the state animation first to ensure FLAG_IN_STASHED_LAUNCHER_STATE is set and we can // determine whether goingToUnstashedLauncherStateChanged. - boolean wasGoingToUnstashedLauncherState = goingToUnstashedLauncherState(); if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_RUNNING)) { boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING); playStateTransitionAnim(animatorSet, duration, committed); @@ -276,95 +281,83 @@ import java.util.function.Supplier; applyState(0 /* duration */); } } - boolean goingToUnstashedLauncherStateChanged = wasGoingToUnstashedLauncherState - != goingToUnstashedLauncherState(); - - boolean launcherStateChangedDuringAnimToResumeAlignment = - mIconAlignmentForResumedState.isAnimating() && goingToUnstashedLauncherStateChanged; - if (hasAnyFlag(changedFlags, FLAG_RESUMED) - || launcherStateChangedDuringAnimToResumeAlignment) { - boolean isResumed = isResumed(); - // If launcher is resumed, we show the icons when going to an unstashed launcher state - // or launcher state is not changed (e.g. in overview, launcher is paused and resumed). - float toAlignmentForResumedState = isResumed && (goingToUnstashedLauncherState() - || !goingToUnstashedLauncherStateChanged) ? 1 : 0; - // If we're already animating to the value, just leave it be instead of restarting it. - if (!mIconAlignmentForResumedState.isAnimatingToValue(toAlignmentForResumedState)) { - ObjectAnimator resumeAlignAnim = mIconAlignmentForResumedState - .animateToValue(toAlignmentForResumedState) - .setDuration(duration); - if (DEBUG) { - Log.d(TAG, "mIconAlignmentForResumedState - " - + mIconAlignmentForResumedState.value - + " -> " + toAlignmentForResumedState + ": " + duration); - } - resumeAlignAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mIsAnimatingToLauncherViaResume = false; - } + if (hasAnyFlag(changedFlags, FLAGS_LAUNCHER)) { + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mIsAnimatingToLauncher = false; + } - @Override - public void onAnimationStart(Animator animation) { - mIsAnimatingToLauncherViaResume = isResumed; + @Override + public void onAnimationStart(Animator animation) { + mIsAnimatingToLauncher = goingToLauncher; - TaskbarStashController stashController = - mControllers.taskbarStashController; - stashController.updateStateForFlag(FLAG_IN_APP, !isResumed); - stashController.applyState(duration); + TaskbarStashController stashController = + mControllers.taskbarStashController; + if (DEBUG) { + Log.d(TAG, "onAnimationStart - FLAG_IN_APP: " + !goingToLauncher); } - }); - animatorSet.play(resumeAlignAnim); + stashController.updateStateForFlag(FLAG_IN_APP, !goingToLauncher); + stashController.applyState(duration); + } + }); + + if (goingToLauncher) { + // Handle closing open popups when going home/overview + AbstractFloatingView.closeAllOpenViews(mControllers.taskbarActivityContext); } } + float backgroundAlpha = + goingToLauncher && mLauncherState.isTaskbarAlignedWithHotseat(mLauncher) + ? 0 : 1; + // Don't animate if background has reached desired value. + if (mTaskbarBackgroundAlpha.isAnimating() + || mTaskbarBackgroundAlpha.value != backgroundAlpha) { + mTaskbarBackgroundAlpha.cancelAnimation(); + if (DEBUG) { + Log.d(TAG, "onStateChangeApplied - taskbarBackgroundAlpha - " + + mTaskbarBackgroundAlpha.value + + " -> " + backgroundAlpha + ": " + duration); + } + animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(backgroundAlpha) + .setDuration(duration)); + } - boolean launcherStateChangedDuringAnimToGestureAlignment = - mIconAlignmentForGestureState.isAnimating() && goingToUnstashedLauncherStateChanged; - if (hasAnyFlag(changedFlags, FLAG_RECENTS_ANIMATION_RUNNING) - || launcherStateChangedDuringAnimToGestureAlignment) { - boolean isRecentsAnimationRunning = isRecentsAnimationRunning(); - float toAlignmentForGestureState = isRecentsAnimationRunning - && goingToUnstashedLauncherState() ? 1 : 0; - // If we're already animating to the value, just leave it be instead of restarting it. - if (!mIconAlignmentForGestureState.isAnimatingToValue(toAlignmentForGestureState)) { - Animator gestureAlignAnim = mIconAlignmentForGestureState - .animateToValue(toAlignmentForGestureState); - if (isRecentsAnimationRunning) { - gestureAlignAnim.setDuration(duration); - } - if (DEBUG) { - Log.d(TAG, "mIconAlignmentForGestureState - " - + mIconAlignmentForGestureState.value - + " -> " + toAlignmentForGestureState + ": " + duration); - } - gestureAlignAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mIsAnimatingToLauncherViaGesture = false; - } - - @Override - public void onAnimationStart(Animator animation) { - mIsAnimatingToLauncherViaGesture = isRecentsAnimationRunning(); - } - }); - animatorSet.play(gestureAlignAnim); + float cornerRoundness = goingToLauncher ? 0 : 1; + // Don't animate if corner roundness has reached desired value. + if (mTaskbarCornerRoundness.isAnimating() + || mTaskbarCornerRoundness.value != cornerRoundness) { + mTaskbarCornerRoundness.cancelAnimation(); + if (DEBUG) { + Log.d(TAG, "onStateChangeApplied - taskbarCornerRoundness - " + + mTaskbarCornerRoundness.value + + " -> " + cornerRoundness + ": " + duration); } + animatorSet.play(mTaskbarCornerRoundness.animateToValue(cornerRoundness)); } - if (hasAnyFlag(changedFlags, FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING)) { - boolean goingToLauncher = hasAnyFlag(FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING); - if (goingToLauncher) { - // Handle closing open popups when going home/overview - AbstractFloatingView.closeAllOpenViews(mControllers.taskbarActivityContext); + if (mIconAlignment.isAnimatingToValue(toAlignment) + || mIconAlignment.isSettledOnValue(toAlignment)) { + // Already at desired value, but make sure we run the callback at the end. + animatorSet.addListener(AnimatorListeners.forEndCallback( + this::onIconAlignmentRatioChanged)); + } else { + mIconAlignment.cancelAnimation(); + ObjectAnimator iconAlignAnim = mIconAlignment + .animateToValue(toAlignment) + .setDuration(duration); + if (DEBUG) { + Log.d(TAG, "onStateChangeApplied - iconAlignment - " + + mIconAlignment.value + + " -> " + toAlignment + ": " + duration); } - animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(goingToLauncher ? 0 : 1) - .setDuration(duration)); + animatorSet.play(iconAlignAnim); } animatorSet.setInterpolator(EMPHASIZED); + if (start) { animatorSet.start(); } @@ -372,18 +365,36 @@ import java.util.function.Supplier; } /** Returns whether we're going to a state where taskbar icons should align with launcher. */ - private boolean goingToUnstashedLauncherState() { - return !mControllers.taskbarStashController.isInStashedLauncherState(); + public boolean goingToAlignedLauncherState() { + return mLauncherState.isTaskbarAlignedWithHotseat(mLauncher); + } + + /** + * Returns if icons should be aligned to hotseat in the current transition + */ + public boolean isIconAlignedWithHotseat() { + if (isInLauncher()) { + boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher); + boolean willStashVisually = isInStashedState + && mControllers.taskbarStashController.supportsVisualStashing(); + boolean isTaskbarAlignedWithHotseat = + mLauncherState.isTaskbarAlignedWithHotseat(mLauncher); + return isTaskbarAlignedWithHotseat && !willStashVisually; + } else { + return false; + } + } + + /** + * Returns if the current Launcher state has hotseat on top of other elemnets. + */ + public boolean isInHotseatOnTopStates() { + return mLauncherState != LauncherState.ALL_APPS; } private void playStateTransitionAnim(AnimatorSet animatorSet, long duration, boolean committed) { boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher); - boolean willStashVisually = - isInStashedState && mControllers.taskbarStashController.supportsVisualStashing(); - float toAlignment = - mLauncherState.isTaskbarAlignedWithHotseat(mLauncher) && !willStashVisually ? 1 : 0; - TaskbarStashController stashController = mControllers.taskbarStashController; stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, isInStashedState); Animator stashAnimator = stashController.applyStateWithoutStart(duration); @@ -400,61 +411,29 @@ import java.util.function.Supplier; @Override public void onAnimationStart(Animator animation) { if (mLauncher.getHotseat().getIconsAlpha() > 0) { - mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha()); + updateIconAlphaForHome(mLauncher.getHotseat().getIconsAlpha()); } } }); animatorSet.play(stashAnimator); } - if (mIconAlignmentForLauncherState.value == toAlignment) { - // Already at expected value, but make sure we run the callback at the end. - animatorSet.addListener(AnimatorListeners.forEndCallback( - this::onIconAlignmentRatioChangedForStateTransition)); - } - if (!mIconAlignmentForLauncherState.isAnimatingToValue(toAlignment)) { - // If we're already animating to the value, just leave it be instead of restarting it. - mIconAlignmentForLauncherState.finishAnimation(); - animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment) - .setDuration(duration)); - if (DEBUG) { - Log.d(TAG, "mIconAlignmentForLauncherState - " - + mIconAlignmentForLauncherState.value - + " -> " + toAlignment + ": " + duration); - } - animatorSet.setInterpolator(EMPHASIZED); - } - } - - private boolean isResumed() { - return (mState & FLAG_RESUMED) != 0; - } - - private boolean isRecentsAnimationRunning() { - return (mState & FLAG_RECENTS_ANIMATION_RUNNING) != 0; - } - - private void onIconAlignmentRatioChangedForStateTransition() { - if (!isResumed() && mTaskBarRecentsAnimationListener == null) { - return; - } - onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioForLauncherState); } - private void onIconAlignmentRatioChangedForAppAndHomeTransition() { - onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioBetweenAppAndHome); + private boolean isInLauncher() { + return (mState & FLAGS_LAUNCHER) != 0; } - private void onIconAlignmentRatioChanged(Supplier<AnimatedFloat> alignmentSupplier) { - if (mControllers == null) { - return; - } - AnimatedFloat animatedFloat = alignmentSupplier.get(); + private void onIconAlignmentRatioChanged() { float currentValue = mIconAlphaForHome.getValue(); - boolean taskbarWillBeVisible = animatedFloat.value < 1; + boolean taskbarWillBeVisible = mIconAlignment.value < 1; boolean firstFrameVisChanged = (taskbarWillBeVisible && Float.compare(currentValue, 1) != 0) || (!taskbarWillBeVisible && Float.compare(currentValue, 0) != 0); - updateIconAlignment(animatedFloat.value, animatedFloat.getEndValue()); + mControllers.taskbarViewController.setLauncherIconAlignment( + mIconAlignment.value, mLauncher.getDeviceProfile()); + mControllers.navbarButtonsViewController.updateTaskbarAlignment(mIconAlignment.value); + // Switch taskbar and hotseat in last frame + updateIconAlphaForHome(taskbarWillBeVisible ? 1 : 0); // Sync the first frame where we swap taskbar and hotseat. if (firstFrameVisChanged && mCanSyncViews && !Utilities.IS_RUNNING_IN_TEST_HARNESS) { @@ -464,26 +443,18 @@ import java.util.function.Supplier; } } - private void updateIconAlignment(float alignment, Float endAlignment) { - mControllers.taskbarViewController.setLauncherIconAlignment( - alignment, endAlignment, mLauncher.getDeviceProfile()); - - // Switch taskbar and hotseat in last frame - setTaskbarViewVisible(alignment < 1); - mControllers.navbarButtonsViewController.updateTaskbarAlignment(alignment); - } - - private AnimatedFloat getCurrentIconAlignmentRatioBetweenAppAndHome() { - return mIconAlignmentForResumedState.value > mIconAlignmentForGestureState.value - ? mIconAlignmentForResumedState : mIconAlignmentForGestureState; - } - - private AnimatedFloat getCurrentIconAlignmentRatioForLauncherState() { - return mIconAlignmentForLauncherState; - } - - private void setTaskbarViewVisible(boolean isVisible) { - mIconAlphaForHome.setValue(isVisible ? 1 : 0); + private void updateIconAlphaForHome(float alpha) { + mIconAlphaForHome.setValue(alpha); + boolean hotseatVisible = alpha == 0 + || (!mControllers.uiController.isHotseatIconOnTopWhenAligned() + && mIconAlignment.value > 0); + /* + * Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets + * should not be visible at the same time. + */ + mLauncher.getHotseat().setIconsAlpha(hotseatVisible ? 1 : 0); + mLauncher.getHotseat().setQsbAlpha( + mLauncher.getDeviceProfile().isQsbInline && !hotseatVisible ? 0 : 1); } private final class TaskBarRecentsAnimationListener implements @@ -515,11 +486,11 @@ import java.util.function.Supplier; updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, false); updateStateForFlag(FLAG_RESUMED, launcherResumed); applyState(); - // Set this last because applyState() might also animate it. - mIconAlignmentForResumedState.cancelAnimation(); - mIconAlignmentForResumedState.updateValue(launcherResumed ? 1 : 0); TaskbarStashController controller = mControllers.taskbarStashController; + if (DEBUG) { + Log.d(TAG, "endGestureStateOverride - FLAG_IN_APP: " + finishedToApp); + } controller.updateStateForFlag(FLAG_IN_APP, finishedToApp); controller.applyState(); } @@ -527,29 +498,24 @@ import java.util.function.Supplier; private static String getStateString(int flags) { StringJoiner str = new StringJoiner("|"); - str.add((flags & FLAG_RESUMED) != 0 ? "FLAG_RESUMED" : ""); - str.add((flags & FLAG_RECENTS_ANIMATION_RUNNING) != 0 - ? "FLAG_RECENTS_ANIMATION_RUNNING" : ""); - str.add((flags & FLAG_TRANSITION_STATE_RUNNING) != 0 - ? "FLAG_TRANSITION_STATE_RUNNING" : ""); + if ((flags & FLAG_RESUMED) != 0) { + str.add("FLAG_RESUMED"); + } + if ((flags & FLAG_RECENTS_ANIMATION_RUNNING) != 0) { + str.add("FLAG_RECENTS_ANIMATION_RUNNING"); + } + if ((flags & FLAG_TRANSITION_STATE_RUNNING) != 0) { + str.add("FLAG_TRANSITION_STATE_RUNNING"); + } return str.toString(); } protected void dumpLogs(String prefix, PrintWriter pw) { pw.println(prefix + "TaskbarLauncherStateController:"); - pw.println(String.format( - "%s\tmIconAlignmentForResumedState=%.2f", + "%s\tmIconAlignment=%.2f", prefix, - mIconAlignmentForResumedState.value)); - pw.println(String.format( - "%s\tmIconAlignmentForGestureState=%.2f", - prefix, - mIconAlignmentForGestureState.value)); - pw.println(String.format( - "%s\tmIconAlignmentForLauncherState=%.2f", - prefix, - mIconAlignmentForLauncherState.value)); + mIconAlignment.value)); pw.println(String.format( "%s\tmTaskbarBackgroundAlpha=%.2f", prefix, mTaskbarBackgroundAlpha.value)); pw.println(String.format( @@ -558,13 +524,9 @@ import java.util.function.Supplier; pw.println(String.format("%s\tmState=%s", prefix, getStateString(mState))); pw.println(String.format("%s\tmLauncherState=%s", prefix, mLauncherState)); pw.println(String.format( - "%s\tmIsAnimatingToLauncherViaGesture=%b", - prefix, - mIsAnimatingToLauncherViaGesture)); - pw.println(String.format( - "%s\tmIsAnimatingToLauncherViaResume=%b", + "%s\tmIsAnimatingToLauncher=%b", prefix, - mIsAnimatingToLauncherViaResume)); + mIsAnimatingToLauncher)); pw.println(String.format( "%s\tmShouldDelayLauncherStateAnim=%b", prefix, mShouldDelayLauncherStateAnim)); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index bc69088416..86e191151a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -32,6 +32,7 @@ import android.net.Uri; import android.os.Handler; import android.os.SystemProperties; import android.provider.Settings; +import android.util.Log; import android.view.Display; import androidx.annotation.NonNull; @@ -224,8 +225,13 @@ public class TaskbarManager { return; } mActivity = activity; - mUnfoldProgressProvider.setSourceProvider(getUnfoldTransitionProgressProviderForActivity( - activity)); + UnfoldTransitionProgressProvider unfoldTransitionProgressProvider = + getUnfoldTransitionProgressProviderForActivity(activity); + if (unfoldTransitionProgressProvider == null) { + Log.e("b/261320823", "UnfoldTransitionProgressProvider null in setActivity. " + + "Unfold animation for launcher will not work."); + } + mUnfoldProgressProvider.setSourceProvider(unfoldTransitionProgressProvider); if (mTaskbarActivityContext != null) { mTaskbarActivityContext.setUIController( @@ -314,6 +320,12 @@ public class TaskbarManager { } } + public void onLongPressHomeEnabled(boolean assistantLongPressEnabled) { + if (mNavButtonController != null) { + mNavButtonController.setAssistantLongPressEnabled(assistantLongPressEnabled); + } + } + /** * Sets the flag indicating setup UI is visible */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java index a395548f84..5bb958a713 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java @@ -67,6 +67,7 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa private long mLastScreenPinLongPress; private boolean mScreenPinned; + private boolean mAssistantLongPressEnabled; @Override public void dumpLogs(String prefix, PrintWriter pw) { @@ -251,6 +252,10 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa mStatsLogManager = null; } + public void setAssistantLongPressEnabled(boolean assistantLongPressEnabled) { + mAssistantLongPressEnabled = assistantLongPressEnabled; + } + private void logEvent(StatsLogManager.LauncherEvent event) { if (mStatsLogManager == null) { Log.w(TAG, "No stats log manager to log taskbar button event"); @@ -289,7 +294,7 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa } private void startAssistant() { - if (mScreenPinned) { + if (mScreenPinned || !mAssistantLongPressEnabled) { return; } Bundle args = new Bundle(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java index da6dab1e10..9b27c9d026 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java @@ -75,6 +75,7 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba // Initialized in init. private TaskbarControllers mControllers; + private boolean mHideSplitOptions; public TaskbarPopupController(TaskbarActivityContext context) { mContext = context; @@ -100,6 +101,10 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba mPopupDataProvider.setDeepShortcutMap(deepShortcutMapCopy); } + public void setHideSplitOptions(boolean hideSplitOptions) { + mHideSplitOptions = hideSplitOptions; + } + private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) { final PackageUserKey packageUserKey = new PackageUserKey(null, null); Predicate<ItemInfo> matcher = info -> !packageUserKey.updateFromItemInfo(info) @@ -186,11 +191,16 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba // TODO(b/227800345): Add "Split bottom" option when tablet is in portrait mode. private Stream<SystemShortcut.Factory> getSystemShortcuts() { // concat a Stream of split options with a Stream of APP_INFO + Stream<SystemShortcut.Factory> appInfo = Stream.of(APP_INFO); + if (mHideSplitOptions) { + return appInfo; + } + return Stream.concat( Utilities.getSplitPositionOptions(mContext.getDeviceProfile()) .stream() .map(this::createSplitShortcutFactory), - Stream.of(APP_INFO) + appInfo ); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java index 1d3757fca2..cdc6d59bf1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java @@ -69,4 +69,13 @@ public class TaskbarScrimView extends View { mRenderer.getPaint().setAlpha((int) (alpha * 255)); invalidate(); } + + /** + * Sets the roundness of the round corner above Taskbar. + * @param cornerRoundness 0 has no round corner, 1 has complete round corner. + */ + protected void setCornerRoundness(float cornerRoundness) { + mRenderer.setCornerRoundness(cornerRoundness); + invalidate(); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java index c3b0f57c2d..88767dd61d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java @@ -22,7 +22,7 @@ import android.animation.ObjectAnimator; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; -import com.android.quickstep.AnimatedFloat; +import com.android.launcher3.anim.AnimatedFloat; import com.android.quickstep.SystemUiProxy; import java.io.PrintWriter; @@ -30,7 +30,8 @@ import java.io.PrintWriter; /** * Handles properties/data collection, and passes the results to {@link TaskbarScrimView} to render. */ -public class TaskbarScrimViewController implements TaskbarControllers.LoggableTaskbarController { +public class TaskbarScrimViewController implements TaskbarControllers.LoggableTaskbarController, + TaskbarControllers.BackgroundRendererController { private static final float SCRIM_ALPHA = 0.6f; @@ -95,6 +96,11 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa } @Override + public void setCornerRoundness(float cornerRoundness) { + mScrimView.setCornerRoundness(cornerRoundness); + } + + @Override public void dumpLogs(String prefix, PrintWriter pw) { pw.println(prefix + "TaskbarScrimViewController:"); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 4b0adb192f..c269648f7d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -17,13 +17,20 @@ package com.android.launcher3.taskbar; import static android.view.HapticFeedbackConstants.LONG_PRESS; -import static com.android.launcher3.LauncherState.ALL_APPS; +import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; +import static com.android.launcher3.anim.Interpolators.INSTANT; +import static com.android.launcher3.config.FeatureFlags.FORCE_PERSISTENT_TASKBAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW; import static com.android.launcher3.taskbar.Utilities.appendFlag; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -37,15 +44,19 @@ import android.view.View; import android.view.ViewConfiguration; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; +import com.android.launcher3.Alarm; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.testing.shared.TestProtocol; -import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; -import com.android.quickstep.AnimatedFloat; +import com.android.launcher3.util.DisplayController; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.quickstep.SystemUiProxy; import java.io.PrintWriter; @@ -62,23 +73,24 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba public static final int FLAG_IN_APP = 1 << 0; public static final int FLAG_STASHED_IN_APP_MANUAL = 1 << 1; // long press, persisted - public static final int FLAG_STASHED_IN_APP_PINNED = 1 << 2; // app pinning + public static final int FLAG_STASHED_IN_SYSUI_STATE = 1 << 2; // app pinning, keyguard, etc. public static final int FLAG_STASHED_IN_APP_EMPTY = 1 << 3; // no hotseat icons public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 4; // setup wizard and AllSetActivity public static final int FLAG_STASHED_IN_APP_IME = 1 << 5; // IME is visible public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 6; - public static final int FLAG_STASHED_IN_APP_ALL_APPS = 1 << 7; // All apps is visible. + public static final int FLAG_STASHED_IN_TASKBAR_ALL_APPS = 1 << 7; // All apps is visible. public static final int FLAG_IN_SETUP = 1 << 8; // In the Setup Wizard public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 9; // phone screen gesture nav, stashed + public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 10; // Autohide (transient taskbar). // If any of these flags are enabled, isInApp should return true. private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP; // If we're in an app and any of these flags are enabled, taskbar should be stashed. private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL - | FLAG_STASHED_IN_APP_PINNED | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP - | FLAG_STASHED_IN_APP_IME | FLAG_STASHED_IN_APP_ALL_APPS | - FLAG_STASHED_SMALL_SCREEN; + | FLAG_STASHED_IN_SYSUI_STATE | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP + | FLAG_STASHED_IN_APP_IME | FLAG_STASHED_IN_TASKBAR_ALL_APPS + | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO; private static final int FLAGS_STASHED_IN_APP_IGNORING_IME = FLAGS_STASHED_IN_APP & ~FLAG_STASHED_IN_APP_IME; @@ -88,7 +100,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba // Currently any flag that causes us to stash in an app is included, except for IME or All Apps // since those cover the underlying app anyway and thus the app shouldn't change insets. private static final int FLAGS_REPORT_STASHED_INSETS_TO_APP = FLAGS_STASHED_IN_APP - & ~FLAG_STASHED_IN_APP_IME & ~FLAG_STASHED_IN_APP_ALL_APPS; + & ~FLAG_STASHED_IN_APP_IME & ~FLAG_STASHED_IN_TASKBAR_ALL_APPS; /** * How long to stash/unstash when manually invoked via long press. @@ -132,6 +144,9 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba */ private static final boolean DEFAULT_STASHED_PREF = false; + // Auto stashes when user has not interacted with the Taskbar after X ms. + private static final long NO_TOUCH_TIMEOUT_TO_STASH_MS = 5000; + private final TaskbarActivityContext mActivity; private final SharedPreferences mPrefs; private final int mStashedHeight; @@ -144,11 +159,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private AnimatedFloat mTaskbarBackgroundOffset; private AnimatedFloat mTaskbarImeBgAlpha; // TaskbarView icon properties. - private AlphaProperty mIconAlphaForStash; + private MultiProperty mIconAlphaForStash; private AnimatedFloat mIconScaleForStash; private AnimatedFloat mIconTranslationYForStash; // Stashed handle properties. - private AlphaProperty mTaskbarStashedHandleAlpha; + private MultiProperty mTaskbarStashedHandleAlpha; private AnimatedFloat mTaskbarStashedHandleHintScale; /** Whether we are currently visually stashed (might change based on launcher state). */ @@ -162,26 +177,36 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private boolean mEnableManualStashingDuringTests = false; + private final Alarm mTimeoutAlarm = new Alarm(); + private boolean mEnableBlockingTimeoutDuringTests = false; + // Evaluate whether the handle should be stashed private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder( flags -> { boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP); boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP); boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE); + boolean stashedInTaskbarAllApps = + hasAnyFlag(flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS); boolean stashedForSmallScreen = hasAnyFlag(flags, FLAG_STASHED_SMALL_SCREEN); return (inApp && stashedInApp) || (!inApp && stashedLauncherState) - || stashedForSmallScreen; + || stashedInTaskbarAllApps || stashedForSmallScreen; }); public TaskbarStashController(TaskbarActivityContext activity) { mActivity = activity; - mPrefs = Utilities.getPrefs(mActivity); + mPrefs = LauncherPrefs.getPrefs(mActivity); mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity); if (isPhoneMode()) { // DeviceProfile's taskbar vars aren't initialized w/ the flag off Resources resources = mActivity.getResources(); - mUnstashedHeight = resources.getDimensionPixelSize(R.dimen.taskbar_size); - mStashedHeight = resources.getDimensionPixelOffset(R.dimen.taskbar_stashed_size); + boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity); + mUnstashedHeight = resources.getDimensionPixelSize(isTransientTaskbar + ? R.dimen.transient_taskbar_size + : R.dimen.taskbar_size); + mStashedHeight = resources.getDimensionPixelSize(isTransientTaskbar + ? R.dimen.transient_taskbar_stashed_size + : R.dimen.taskbar_stashed_size); } else { mUnstashedHeight = mActivity.getDeviceProfile().taskbarSize; mStashedHeight = mActivity.getDeviceProfile().stashedTaskbarSize; @@ -197,24 +222,28 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba mTaskbarImeBgAlpha = dragLayerController.getImeBgTaskbar(); TaskbarViewController taskbarViewController = controllers.taskbarViewController; - mIconAlphaForStash = taskbarViewController.getTaskbarIconAlpha().getProperty( + mIconAlphaForStash = taskbarViewController.getTaskbarIconAlpha().get( TaskbarViewController.ALPHA_INDEX_STASH); mIconScaleForStash = taskbarViewController.getTaskbarIconScaleForStash(); mIconTranslationYForStash = taskbarViewController.getTaskbarIconTranslationYForStash(); StashedHandleViewController stashedHandleController = controllers.stashedHandleViewController; - mTaskbarStashedHandleAlpha = stashedHandleController.getStashedHandleAlpha().getProperty( + mTaskbarStashedHandleAlpha = stashedHandleController.getStashedHandleAlpha().get( StashedHandleViewController.ALPHA_INDEX_STASHED); mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale(); + boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity); // We use supportsVisualStashing() here instead of supportsManualStashing() because we want // it to work properly for tests that recreate taskbar. This check is here just to ensure // that taskbar unstashes when going to 3 button mode (supportsVisualStashing() false). boolean isManuallyStashedInApp = supportsVisualStashing() + && !isTransientTaskbar + && !FORCE_PERSISTENT_TASKBAR.get() && mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF); boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible; updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp); + updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, isTransientTaskbar); updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup); updateStateForFlag(FLAG_IN_SETUP, isInSetup); updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, isPhoneMode() @@ -239,19 +268,34 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba * Returns whether the user can manually stash the taskbar based on the current device state. */ protected boolean supportsManualStashing() { + if (FORCE_PERSISTENT_TASKBAR.get()) { + return false; + } return supportsVisualStashing() - && (!Utilities.IS_RUNNING_IN_TEST_HARNESS || mEnableManualStashingDuringTests); + && isInApp() + && (!Utilities.IS_RUNNING_IN_TEST_HARNESS || mEnableManualStashingDuringTests) + && !DisplayController.isTransientTaskbar(mActivity); } /** * Enables support for manual stashing. This should only be used to add this functionality * to Launcher specific tests. */ + @VisibleForTesting public void enableManualStashingDuringTests(boolean enableManualStashing) { mEnableManualStashingDuringTests = enableManualStashing; } /** + * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar + * testing. + */ + @VisibleForTesting + public void enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout) { + mEnableBlockingTimeoutDuringTests = enableBlockingTimeout; + } + + /** * Sets the flag indicating setup UI is visible */ protected void setSetupUIVisible(boolean isVisible) { @@ -317,22 +361,30 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } /** + * Returns the height that taskbar will be touchable. + */ + public int getTouchableHeight() { + return mIsStashed ? mStashedHeight : mUnstashedHeight; + } + + /** * Returns the height that taskbar will inset when inside apps. * @see WindowInsets.Type#navigationBars() * @see WindowInsets.Type#systemBars() */ public int getContentHeightToReportToApps() { - if (isPhoneMode() && !mActivity.isThreeButtonNav()) { + if ((isPhoneMode() && !mActivity.isThreeButtonNav()) + || DisplayController.isTransientTaskbar(mActivity)) { return getStashedHeight(); } if (supportsVisualStashing() && hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) { DeviceProfile dp = mActivity.getDeviceProfile(); - if (hasAnyFlag(FLAG_STASHED_IN_APP_SETUP) && dp.isTaskbarPresent && !dp.isLandscape) { + if (hasAnyFlag(FLAG_STASHED_IN_APP_SETUP) && dp.isTaskbarPresent) { // We always show the back button in SUW but in portrait the SUW layout may not - // be wide enough to support overlapping the nav bar with its content. For now, - // just inset by the bar height. - return mUnstashedHeight; + // be wide enough to support overlapping the nav bar with its content. + // We're sending different res values in portrait vs landscape + return mActivity.getResources().getDimensionPixelSize(R.dimen.taskbar_suw_insets); } boolean isAnimating = mAnimator != null && mAnimator.isStarted(); if (!mControllers.stashedHandleViewController.isStashedHandleVisible() @@ -345,6 +397,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } return mStashedHeight; } + return mUnstashedHeight; } @@ -362,6 +415,20 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } /** + * Stash or unstashes the transient taskbar. + */ + public void updateAndAnimateTransientTaskbar(boolean stash) { + if (!DisplayController.isTransientTaskbar(mActivity)) { + return; + } + + if (hasAnyFlag(FLAG_STASHED_IN_APP_AUTO) != stash) { + updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, stash); + applyState(); + } + } + + /** * Should be called when long pressing the nav region when taskbar is present. * @return Whether taskbar was stashed and now is unstashed. */ @@ -423,7 +490,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /* isStashed= */ false, placeholderDuration, /* startDelay= */ 0, - /* animateBg= */ false); + /* animateBg= */ false, + /* changedFlags=*/ 0); animation.play(mAnimator); } @@ -434,8 +502,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba * @param startDelay how many milliseconds to delay the animation after starting it. * @param animateBg whether the taskbar's background should be animated */ - private void createAnimToIsStashed( - boolean isStashed, long duration, long startDelay, boolean animateBg) { + private void createAnimToIsStashed(boolean isStashed, long duration, long startDelay, + boolean animateBg, int changedFlags) { if (mAnimator != null) { mAnimator.cancel(); } @@ -473,6 +541,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba final float firstHalfDurationScale; final float secondHalfDurationScale; + // If Hotseat is not the top element during animation to/from Launcher, fade in/out a + // already stashed Taskbar. + boolean skipStashAnimation = !mControllers.uiController.isHotseatIconOnTopWhenAligned() + && hasAnyFlag(changedFlags, FLAG_IN_APP); if (isStashed) { firstHalfDurationScale = 0.75f; secondHalfDurationScale = 0.5f; @@ -493,6 +565,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfAnimatorSet.playTogether( mTaskbarStashedHandleAlpha.animateToValue(1) ); + + if (skipStashAnimation) { + fullLengthAnimatorSet.setInterpolator(INSTANT); + firstHalfAnimatorSet.setInterpolator(INSTANT); + } } else { firstHalfDurationScale = 0.5f; secondHalfDurationScale = 0.75f; @@ -513,6 +590,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba secondHalfAnimatorSet.playTogether( mIconAlphaForStash.animateToValue(1) ); + + if (skipStashAnimation) { + fullLengthAnimatorSet.setInterpolator(FINAL_FRAME); + secondHalfAnimatorSet.setInterpolator(FINAL_FRAME); + } } fullLengthAnimatorSet.play(mControllers.stashedHandleViewController @@ -534,11 +616,17 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba public void onAnimationStart(Animator animation) { mIsStashed = isStashed; onIsStashedChanged(mIsStashed); + + cancelTimeoutIfExists(); } @Override public void onAnimationEnd(Animator animation) { mAnimator = null; + + if (!mIsStashed) { + tryStartTaskbarTimeout(); + } } }); } @@ -635,34 +723,26 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba // Only update the following flags when system gesture is not in progress. boolean shouldStashForIme = shouldStashForIme(); - maybeResetStashedInAppAllApps( - hasAnyFlag(FLAG_STASHED_IN_APP_IME) == shouldStashForIme); + updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false); if (hasAnyFlag(FLAG_STASHED_IN_APP_IME) != shouldStashForIme) { updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme); applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme()); + } else { + applyState(mControllers.taskbarOverlayController.getCloseDuration()); } } /** - * Reset stashed in all apps only if no system gesture is in progress. + * Resets the flag if no system gesture is in progress. * <p> * Otherwise, the reset should be deferred until after the gesture is finished. * * @see #setSystemGestureInProgress */ - public void maybeResetStashedInAppAllApps() { - maybeResetStashedInAppAllApps(true); - } - - private void maybeResetStashedInAppAllApps(boolean applyState) { - if (mIsSystemGestureInProgress) { - return; - } - - updateStateForFlag(FLAG_STASHED_IN_APP_ALL_APPS, false); - if (applyState) { - applyState(ALL_APPS.getTransitionDuration( - mControllers.taskbarActivityContext, false /* isToState */)); + public void resetFlagIfNoGestureInProgress(int flag) { + if (!mIsSystemGestureInProgress) { + updateStateForFlag(flag, false); + applyState(mControllers.taskbarOverlayController.getCloseDuration()); } } @@ -685,12 +765,18 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba long animDuration = TASKBAR_STASH_DURATION; long startDelay = 0; - updateStateForFlag(FLAG_STASHED_IN_APP_PINNED, - hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING)); + updateStateForFlag(FLAG_STASHED_IN_SYSUI_STATE, hasAnyFlag(systemUiStateFlags, + SYSUI_STATE_SCREEN_PINNING + | SYSUI_STATE_BOUNCER_SHOWING + | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING + | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED + | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED + | SYSUI_STATE_QUICK_SETTINGS_EXPANDED)); // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress. mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING); mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING); + if (!mIsSystemGestureInProgress) { updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme()); animDuration = TASKBAR_STASH_DURATION_FOR_IME; @@ -700,8 +786,20 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba applyState(skipAnim ? 0 : animDuration, skipAnim ? 0 : startDelay); } + /** + * We stash when IME or IME switcher is showing AND NOT + * * in small screen AND + * * 3 button nav AND + * * landscape (or seascape) + * We do not stash if taskbar is transient + */ private boolean shouldStashForIme() { - return mIsImeShowing || mIsImeSwitcherShowing; + if (DisplayController.isTransientTaskbar(mActivity)) { + return false; + } + return (mIsImeShowing || mIsImeSwitcherShowing) && + !(isPhoneMode() && mActivity.isThreeButtonNav() + && mActivity.getDeviceProfile().isLandscape); } /** @@ -756,6 +854,54 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba mControllers.rotationButtonController.onTaskbarStateChange(visible, stashed); } + /** + * Cancels a timeout if any exists. + */ + public void cancelTimeoutIfExists() { + if (mTimeoutAlarm.alarmPending()) { + mTimeoutAlarm.cancelAlarm(); + } + } + + /** + * Updates the status of the taskbar timeout. + * @param isAutohideSuspended If true, cancels any existing timeout + * If false, attempts to re/start the timeout + */ + public void updateTaskbarTimeout(boolean isAutohideSuspended) { + if (!DisplayController.isTransientTaskbar(mActivity)) { + return; + } + if (isAutohideSuspended) { + cancelTimeoutIfExists(); + } else { + tryStartTaskbarTimeout(); + } + } + + /** + * Attempts to start timer to auto hide the taskbar based on time. + */ + public void tryStartTaskbarTimeout() { + if (!DisplayController.isTransientTaskbar(mActivity) + || mIsStashed + || mEnableBlockingTimeoutDuringTests) { + return; + } + + cancelTimeoutIfExists(); + + mTimeoutAlarm.setOnAlarmListener(this::onTaskbarTimeout); + mTimeoutAlarm.setAlarm(NO_TOUCH_TIMEOUT_TO_STASH_MS); + } + + private void onTaskbarTimeout(Alarm alarm) { + if (mControllers.taskbarAutohideSuspendController.isSuspended()) { + return; + } + updateAndAnimateTransientTaskbar(true); + } + @Override public void dumpLogs(String prefix, PrintWriter pw) { pw.println(prefix + "TaskbarStashController:"); @@ -771,23 +917,25 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } private static String getStateString(int flags) { - StringJoiner str = new StringJoiner("|"); - appendFlag(str, flags, FLAGS_IN_APP, "FLAG_IN_APP"); - appendFlag(str, flags, FLAG_STASHED_IN_APP_MANUAL, "FLAG_STASHED_IN_APP_MANUAL"); - appendFlag(str, flags, FLAG_STASHED_IN_APP_PINNED, "FLAG_STASHED_IN_APP_PINNED"); - appendFlag(str, flags, FLAG_STASHED_IN_APP_EMPTY, "FLAG_STASHED_IN_APP_EMPTY"); - appendFlag(str, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP"); - appendFlag(str, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME"); - appendFlag(str, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE"); - appendFlag(str, flags, FLAG_STASHED_IN_APP_ALL_APPS, "FLAG_STASHED_IN_APP_ALL_APPS"); - appendFlag(str, flags, FLAG_IN_SETUP, "FLAG_IN_SETUP"); - return str.toString(); + StringJoiner sj = new StringJoiner("|"); + appendFlag(sj, flags, FLAGS_IN_APP, "FLAG_IN_APP"); + appendFlag(sj, flags, FLAG_STASHED_IN_APP_MANUAL, "FLAG_STASHED_IN_APP_MANUAL"); + appendFlag(sj, flags, FLAG_STASHED_IN_SYSUI_STATE, "FLAG_STASHED_IN_SYSUI_STATE"); + appendFlag(sj, flags, FLAG_STASHED_IN_APP_EMPTY, "FLAG_STASHED_IN_APP_EMPTY"); + appendFlag(sj, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP"); + appendFlag(sj, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME"); + appendFlag(sj, flags, FLAG_IN_STASHED_LAUNCHER_STATE, "FLAG_IN_STASHED_LAUNCHER_STATE"); + appendFlag(sj, flags, FLAG_STASHED_IN_TASKBAR_ALL_APPS, "FLAG_STASHED_IN_TASKBAR_ALL_APPS"); + appendFlag(sj, flags, FLAG_IN_SETUP, "FLAG_IN_SETUP"); + appendFlag(sj, flags, FLAG_STASHED_IN_APP_AUTO, "FLAG_STASHED_IN_APP_AUTO"); + return sj.toString(); } private class StatePropertyHolder { private final IntPredicate mStashCondition; private boolean mIsStashed; + private boolean mIsHotseatIconOnTopWhenAligned; private int mPrevFlags; StatePropertyHolder(IntPredicate stashCondition) { @@ -817,7 +965,13 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba mPrevFlags = flags; } boolean isStashed = mStashCondition.test(flags); - if (mIsStashed != isStashed) { + boolean isHotseatIconOnTopWhenAligned = + mControllers.uiController.isHotseatIconOnTopWhenAligned(); + // If an animation has started and mIsHotseatIconOnTopWhenAligned is changed, we need + // to restart the animation with new parameters. + if (mIsStashed != isStashed + || (mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned + && mAnimator != null && mAnimator.isStarted())) { if (TestProtocol.sDebugTracing) { Log.d(TestProtocol.TASKBAR_IN_APP_STATE, String.format( "setState: mIsStashed=%b, isStashed=%b, duration=%d, start=:%b", @@ -827,9 +981,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba start)); } mIsStashed = isStashed; + mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned; // This sets mAnimator. - createAnimToIsStashed(mIsStashed, duration, startDelay, /* animateBg= */ true); + createAnimToIsStashed( + mIsStashed, duration, startDelay, /* animateBg= */ true, changedFlags); if (start) { mAnimator.start(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java new file mode 100644 index 0000000000..5dba444ada --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar; + +import static com.android.launcher3.anim.AnimatedFloat.VALUE; +import static com.android.launcher3.anim.AnimatorListeners.forEndCallback; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; + +import androidx.annotation.Nullable; +import androidx.dynamicanimation.animation.SpringForce; + +import com.android.launcher3.anim.AnimatedFloat; +import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.SpringAnimationBuilder; +import com.android.launcher3.util.DisplayController; + +import java.io.PrintWriter; + +/** + * Class responsible for translating the transient taskbar UI during a swipe gesture. + * + * The translation is controlled, in priority order: + * - animation to home + * - a spring animation + * - controlled by user + * + * The spring animation will play start once the user lets go or when user pauses to go to overview. + * When the user goes home, the stash animation will play. + */ +public class TaskbarTranslationController implements TaskbarControllers.LoggableTaskbarController { + + private final TaskbarActivityContext mContext; + private TaskbarControllers mControllers; + private final AnimatedFloat mTranslationYForSwipe = new AnimatedFloat( + this::updateTranslationYForSwipe); + + private boolean mHasSprungOnceThisGesture; + private @Nullable ValueAnimator mSpringBounce; + private boolean mGestureEnded; + private boolean mAnimationToHomeRunning; + + private final boolean mIsTransientTaskbar; + + private final TransitionCallback mCallback; + + public TaskbarTranslationController(TaskbarActivityContext context) { + mContext = context; + mIsTransientTaskbar = DisplayController.isTransientTaskbar(mContext); + mCallback = new TransitionCallback(); + } + + /** + * Initialization method. + */ + public void init(TaskbarControllers controllers) { + mControllers = controllers; + } + + /** + * Called to cancel any existing animations. + */ + public void cancelAnimationIfExists() { + if (mSpringBounce != null) { + mSpringBounce.cancel(); + mSpringBounce = null; + } + reset(); + } + + private void updateTranslationYForSwipe() { + if (!mIsTransientTaskbar) { + return; + } + + float transY = mTranslationYForSwipe.value; + mControllers.stashedHandleViewController.setTranslationYForSwipe(transY); + mControllers.taskbarViewController.setTranslationYForSwipe(transY); + mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY); + } + + /** + * Starts a spring aniamtion to set the views back to the resting state. + */ + public void startSpring() { + if (mHasSprungOnceThisGesture || mAnimationToHomeRunning) { + return; + } + mSpringBounce = new SpringAnimationBuilder(mContext) + .setStartValue(mTranslationYForSwipe.value) + .setEndValue(0) + .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY) + .setStiffness(SpringForce.STIFFNESS_LOW) + .build(mTranslationYForSwipe, VALUE); + mSpringBounce.addListener(forEndCallback(() -> { + if (mGestureEnded) { + reset(); + } + })); + mSpringBounce.start(); + mHasSprungOnceThisGesture = true; + } + + private void reset() { + mGestureEnded = false; + mHasSprungOnceThisGesture = false; + } + + /** + * Returns a callback to help monitor the swipe gesture. + */ + public TransitionCallback getTransitionCallback() { + return mCallback; + } + + /** + * Returns an animation to reset the taskbar translation for animation back to launcher. + */ + public ObjectAnimator createAnimToLauncher(long duration) { + ObjectAnimator animator = ObjectAnimator.ofFloat(mTranslationYForSwipe, VALUE, 0); + animator.setInterpolator(Interpolators.LINEAR); + animator.setDuration(duration); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + cancelAnimationIfExists(); + mAnimationToHomeRunning = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + mAnimationToHomeRunning = false; + reset(); + } + }); + return animator; + } + + /** + * Helper class to communicate to/from the input consumer. + */ + public class TransitionCallback { + + /** + * Called when there is movement to move the taskbar. + */ + public void onActionMove(float dY) { + if (mAnimationToHomeRunning + || (mHasSprungOnceThisGesture && !mGestureEnded)) { + return; + } + + mTranslationYForSwipe.updateValue(dY); + } + + /** + * Called when swipe gesture has ended. + */ + public void onActionEnd() { + if (mHasSprungOnceThisGesture) { + reset(); + } else { + mGestureEnded = true; + startSpring(); + } + } + } + + @Override + public void dumpLogs(String prefix, PrintWriter pw) { + pw.println(prefix + "TaskbarTranslationController:"); + + pw.println(prefix + "\tmTranslationYForSwipe=" + mTranslationYForSwipe.value); + pw.println(prefix + "\tmHasSprungOnceThisGesture=" + mHasSprungOnceThisGesture); + pw.println(prefix + "\tmAnimationToHomeRunning=" + mAnimationToHomeRunning); + pw.println(prefix + "\tmGestureEnded=" + mGestureEnded); + pw.println(prefix + "\tmSpringBounce is running=" + (mSpringBounce != null + && mSpringBounce.isRunning())); + } +} + diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 114bfecb6e..7b0374614c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -15,15 +15,23 @@ */ package com.android.launcher3.taskbar; +import android.content.Intent; +import android.graphics.drawable.BitmapDrawable; +import android.view.MotionEvent; import android.view.View; import androidx.annotation.CallSuper; +import androidx.annotation.Nullable; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; +import com.android.launcher3.util.DisplayController; +import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.recents.model.Task; import java.io.PrintWriter; -import java.util.stream.Stream; +import java.util.function.Consumer; /** * Base class for providing different taskbar UI @@ -60,10 +68,6 @@ public class TaskbarUIController { protected void onStashedInAppChanged() { } - public Stream<ItemInfoWithIcon> getAppIconsForEdu() { - return Stream.empty(); - } - /** Called when an icon is launched. */ public void onTaskbarIconLaunched(ItemInfo item) { } @@ -80,10 +84,13 @@ public class TaskbarUIController { } /** - * Manually closes the all apps window. + * Manually closes the overlay window. */ - public void hideAllApps() { - mControllers.taskbarAllAppsController.hide(); + public void hideOverlayWindow() { + if (!DisplayController.isTransientTaskbar(mControllers.taskbarActivityContext) + || mControllers.taskbarAllAppsController.isOpen()) { + mControllers.taskbarOverlayController.hideWindow(); + } } /** @@ -97,6 +104,50 @@ public class TaskbarUIController { } } + /** + * Returns {@code true} iff taskbar is stashed. + */ + public boolean isTaskbarStashed() { + return mControllers.taskbarStashController.isStashed(); + } + + /** + * Returns {@code true} iff taskbar All Apps is open. + */ + public boolean isTaskbarAllAppsOpen() { + return mControllers.taskbarAllAppsController.isOpen(); + } + + /** + * Called at the end of the swipe gesture on Transient taskbar. + */ + public void startTranslationSpring() { + mControllers.taskbarActivityContext.startTranslationSpring(); + } + + /* + * @param ev MotionEvent in screen coordinates. + * @return Whether any Taskbar item could handle the given MotionEvent if given the chance. + */ + public boolean isEventOverAnyTaskbarItem(MotionEvent ev) { + return mControllers.taskbarViewController.isEventOverAnyItem(ev) + || mControllers.navbarButtonsViewController.isEventOverAnyItem(ev); + } + + /** + * Returns true if icons should be aligned to hotseat in the current transition. + */ + public boolean isIconAlignedWithHotseat() { + return false; + } + + /** + * Returns true if hotseat icons are on top of view hierarchy when aligned in the current state. + */ + public boolean isHotseatIconOnTopWhenAligned() { + return true; + } + @CallSuper protected void dumpLogs(String prefix, PrintWriter pw) { pw.println(String.format( @@ -104,4 +155,45 @@ public class TaskbarUIController { prefix, getClass().getSimpleName())); } + + /** + * Returns RecentsView. Overwritten in LauncherTaskbarUIController and + * FallbackTaskbarUIController with Launcher-specific implementations. Returns null for other + * UI controllers (like DesktopTaskbarUIController) that don't have a RecentsView. + */ + public @Nullable RecentsView getRecentsView() { + return null; + } + + /** + * Uses the clicked Taskbar icon to launch a second app for splitscreen. + */ + public void triggerSecondAppForSplit(ItemInfoWithIcon info, Intent intent, View startingView) { + RecentsView recents = getRecentsView(); + recents.findLastActiveTaskAndDoSplitOperation( + info.getTargetComponent(), + (Consumer<Task>) foundTask -> { + if (foundTask != null) { + TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id); + // There is already a running app of this type, use that as second app. + recents.confirmSplitSelect( + foundTaskView, + foundTaskView.getTask(), + foundTaskView.getIconView().getDrawable(), + foundTaskView.getThumbnail(), + foundTaskView.getThumbnail().getThumbnail(), + null /* intent */); + } else { + // No running app of that type, create a new instance as second app. + recents.confirmSplitSelect( + null /* containerTaskView */, + null /* task */, + new BitmapDrawable(info.bitmap.icon), + startingView, + null /* thumbnail */, + intent); + } + } + ); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java index 64a4fa79df..4c937a7f9b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java @@ -15,13 +15,13 @@ */ package com.android.launcher3.taskbar; -import android.view.IWindowManager; import android.view.View; import android.view.WindowManager; import com.android.quickstep.util.LauncherViewsMoveFromCenterTranslationApplier; import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator; import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener; +import com.android.systemui.unfold.updates.RotationChangeProvider; import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider; import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider; @@ -41,16 +41,20 @@ public class TaskbarUnfoldAnimationController implements public TaskbarUnfoldAnimationController(BaseTaskbarContext context, ScopedUnfoldTransitionProgressProvider source, - WindowManager windowManager, IWindowManager iWindowManager) { + WindowManager windowManager, + RotationChangeProvider rotationChangeProvider) { mScopedUnfoldTransitionProgressProvider = source; mNaturalUnfoldTransitionProgressProvider = - new NaturalRotationUnfoldProgressProvider(context, iWindowManager, source); + new NaturalRotationUnfoldProgressProvider(context, + rotationChangeProvider, + source); mMoveFromCenterAnimator = new UnfoldMoveFromCenterAnimator(windowManager, new LauncherViewsMoveFromCenterTranslationApplier()); } /** * Initializes the controller + * * @param taskbarControllers references to all other taskbar controllers */ public void init(TaskbarControllers taskbarControllers) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index bb82d19734..2fcd64b5e6 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -16,17 +16,14 @@ package com.android.launcher3.taskbar; import android.content.Context; -import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Rect; -import android.os.SystemProperties; import android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.LayoutRes; @@ -45,9 +42,9 @@ import com.android.launcher3.icons.ThemedIconDrawable; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.LauncherBindableItemsContainer; import com.android.launcher3.views.ActivityContext; -import com.android.launcher3.views.AllAppsButton; import com.android.launcher3.views.DoubleShadowBubbleTextView; import java.util.function.Predicate; @@ -62,10 +59,11 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar public int mThemeIconsBackground; private final int[] mTempOutLocation = new int[2]; - private final Rect mIconLayoutBounds = new Rect(); + private final Rect mIconLayoutBounds; private final int mIconTouchSize; private final int mItemMarginLeftRight; private final int mItemPadding; + private final boolean mIsRtl; private final TaskbarActivityContext mActivityContext; @@ -81,16 +79,10 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar private @Nullable FolderIcon mLeaveBehindFolderIcon; // Only non-null when device supports having an All Apps button. - private @Nullable AllAppsButton mAllAppsButton; + private @Nullable View mAllAppsButton; private View mQsb; - // Only non-null when device supports having a floating task. - private @Nullable BubbleTextView mFloatingTaskButton; - private @Nullable Intent mFloatingTaskIntent; - private static final boolean FLOATING_TASKS_ENABLED = - SystemProperties.getBoolean("persist.wm.debug.floating_tasks", false); - public TaskbarView(@NonNull Context context) { this(context, null); } @@ -108,13 +100,16 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mActivityContext = ActivityContext.lookupContext(context); - + mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds(); Resources resources = getResources(); - mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size); + mIsRtl = Utilities.isRtl(resources); int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing); int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx; + mIconTouchSize = Math.max(actualIconSize, + resources.getDimensionPixelSize(R.dimen.taskbar_icon_min_touch_size)); + // We layout the icons to be of mIconTouchSize in width and height mItemMarginLeftRight = actualMargin - (mIconTouchSize - actualIconSize) / 2; mItemPadding = (mIconTouchSize - actualIconSize) / 2; @@ -125,27 +120,18 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar mThemeIconsBackground = calculateThemeIconsBackground(); if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { - mAllAppsButton = new AllAppsButton(context); - mAllAppsButton.setLayoutParams( - new ViewGroup.LayoutParams(mIconTouchSize, mIconTouchSize)); + mAllAppsButton = LayoutInflater.from(context) + .inflate(R.layout.taskbar_all_apps_button, this, false); mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding); + mAllAppsButton.setScaleX(mIsRtl ? -1 : 1); + if (mActivityContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) { + mAllAppsButton.setVisibility(GONE); + } } // TODO: Disable touch events on QSB otherwise it can crash. mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false); - if (FLOATING_TASKS_ENABLED) { - mFloatingTaskIntent = FloatingTaskIntentResolver.getIntent(context); - if (mFloatingTaskIntent != null) { - mFloatingTaskButton = new LaunchFloatingTaskButton(context); - mFloatingTaskButton.setLayoutParams( - new ViewGroup.LayoutParams(mIconTouchSize, mIconTouchSize)); - mFloatingTaskButton.setPadding(mItemPadding, mItemPadding, mItemPadding, - mItemPadding); - } else { - Log.d(TAG, "Floating tasks is enabled but no intent was found!"); - } - } } private int getColorWithGivenLuminance(int color, float luminance) { @@ -173,10 +159,6 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar if (mAllAppsButton != null) { mAllAppsButton.setOnClickListener(mControllerCallbacks.getAllAppsButtonClickListener()); } - if (mFloatingTaskButton != null) { - mFloatingTaskButton.setOnClickListener( - mControllerCallbacks.getFloatingTaskButtonListener(mFloatingTaskIntent)); - } } private void removeAndRecycle(View view) { @@ -201,9 +183,6 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } removeView(mQsb); - if (mFloatingTaskButton != null) { - removeView(mFloatingTaskButton); - } for (int i = 0; i < hotseatItemInfos.length; i++) { ItemInfo hotseatItemInfo = hotseatItemInfos[i]; @@ -277,20 +256,15 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } if (mAllAppsButton != null) { - int index = Utilities.isRtl(getResources()) ? 0 : getChildCount(); + int index = mIsRtl ? getChildCount() : 0; addView(mAllAppsButton, index); } if (mActivityContext.getDeviceProfile().isQsbInline) { - addView(mQsb, Utilities.isRtl(getResources()) ? getChildCount() : 0); + addView(mQsb, mIsRtl ? getChildCount() : 0); // Always set QSB to invisible after re-adding. mQsb.setVisibility(View.INVISIBLE); } - if (mFloatingTaskButton != null) { - int index = Utilities.isRtl(getResources()) ? 0 : getChildCount(); - addView(mFloatingTaskButton, index); - } - mThemeIconsBackground = calculateThemeIconsBackground(); setThemedIconsBackgroundColor(mThemeIconsBackground); } @@ -321,12 +295,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int count = getChildCount(); - int countExcludingQsb = count; DeviceProfile deviceProfile = mActivityContext.getDeviceProfile(); - if (deviceProfile.isQsbInline) { - countExcludingQsb--; - } - int spaceNeeded = countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize); + int spaceNeeded = getIconLayoutWidth(); int navSpaceNeeded = deviceProfile.hotseatBarEndOffset; boolean layoutRtl = isLayoutRtl(); int iconEnd = right - (right - left - spaceNeeded) / 2; @@ -377,12 +347,22 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + mControllerCallbacks.onInterceptTouchEvent(ev); + return super.onInterceptTouchEvent(ev); + } + + @Override public boolean onTouchEvent(MotionEvent event) { if (!mTouchEnabled) { return true; } - if (mIconLayoutBounds.left <= event.getX() && event.getX() <= mIconLayoutBounds.right) { - // Don't allow long pressing between icons, or above/below them. + if (mIconLayoutBounds.left <= event.getX() + && event.getX() <= mIconLayoutBounds.right + && !DisplayController.isTransientTaskbar(mActivityContext)) { + // Don't allow long pressing between icons, or above/below them + // unless its transient taskbar. + mControllerCallbacks.clearTouchInProgress(); return true; } if (mControllerCallbacks.onTouchEvent(event)) { @@ -399,6 +379,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar public void setTouchesEnabled(boolean touchEnabled) { this.mTouchEnabled = touchEnabled; + mControllerCallbacks.clearTouchInProgress(); } /** @@ -417,6 +398,18 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } /** + * Returns the space used by the icons + */ + public int getIconLayoutWidth() { + int countExcludingQsb = getChildCount(); + DeviceProfile deviceProfile = mActivityContext.getDeviceProfile(); + if (deviceProfile.isQsbInline) { + countExcludingQsb--; + } + return countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize); + } + + /** * Returns the app icons currently shown in the taskbar. */ public View[] getIconViews() { @@ -431,6 +424,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar /** * Returns the all apps button in the taskbar. */ + @Nullable public View getAllAppsButtonView() { return mAllAppsButton; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 00d5083dd3..168c353273 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -17,20 +17,25 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; +import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.launcher3.anim.AnimatedFloat.VALUE; +import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP; import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode; -import static com.android.quickstep.AnimatedFloat.VALUE; +import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE; +import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL; import android.annotation.NonNull; -import android.content.Intent; import android.graphics.Rect; import android.util.FloatProperty; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import android.view.animation.Interpolator; +import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import androidx.core.view.OneShotPreDrawListener; @@ -40,6 +45,7 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AlphaUpdateListener; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; @@ -47,12 +53,13 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.icons.ThemedIconDrawable; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.touch.SingleAxisSwipeDetector; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.HorizontalInsettableView; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LauncherBindableItemsContainer; +import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.MultiValueAlpha; -import com.android.quickstep.AnimatedFloat; -import com.android.quickstep.SystemUiProxy; import java.io.PrintWriter; import java.util.function.Predicate; @@ -86,12 +93,18 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar this::updateTranslationY); private AnimatedFloat mTaskbarNavButtonTranslationY; private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay; + private float mTaskbarIconTranslationYForSwipe; + + private final int mTaskbarBottomMargin; private final AnimatedFloat mThemeIconsBackground = new AnimatedFloat( this::updateIconsBackground); private final TaskbarModelCallbacks mModelCallbacks; + // Captures swipe down action to close transient taskbar. + protected @Nullable SingleAxisSwipeDetector mSwipeDownDetector; + // Initialized in init. private TaskbarControllers mControllers; @@ -101,6 +114,10 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar private Runnable mOnControllerPreCreateCallback = NO_OP; private int mThemeIconsColor; + private boolean mIsHotseatIconOnTopWhenAligned; + + private final DeviceProfile.OnDeviceProfileChangeListener mDeviceProfileChangeListener = + dp -> commitRunningAppsToUI(); public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) { mActivity = activity; @@ -108,6 +125,34 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, NUM_ALPHA_CHANNELS); mTaskbarIconAlpha.setUpdateVisibility(true); mModelCallbacks = new TaskbarModelCallbacks(activity, mTaskbarView); + mTaskbarBottomMargin = DisplayController.isTransientTaskbar(activity) + ? activity.getResources().getDimensionPixelSize(R.dimen.transient_taskbar_margin) + : 0; + + if (DisplayController.isTransientTaskbar(mActivity)) { + mSwipeDownDetector = new SingleAxisSwipeDetector(activity, + new SingleAxisSwipeDetector.Listener() { + private float mLastDisplacement; + + @Override + public boolean onDrag(float displacement) { + mLastDisplacement = displacement; + return false; + } + + @Override + public void onDragEnd(float velocity) { + if (mLastDisplacement > 0) { + mControllers.taskbarStashController + .updateAndAnimateTransientTaskbar(true); + } + } + + @Override + public void onDragStart(boolean start, float startDisplacement) {} + }, VERTICAL); + mSwipeDownDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false); + } } public void init(TaskbarControllers controllers) { @@ -129,10 +174,13 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar controllers.navbarButtonsViewController.getTaskbarNavButtonTranslationY(); mTaskbarNavButtonTranslationYForInAppDisplay = controllers.navbarButtonsViewController .getTaskbarNavButtonTranslationYForInAppDisplay(); + + mActivity.addOnDeviceProfileChangeListener(mDeviceProfileChangeListener); } public void onDestroy() { LauncherAppState.getInstance(mActivity).getModel().removeCallbacks(mModelCallbacks); + mActivity.removeOnDeviceProfileChangeListener(mDeviceProfileChangeListener); mModelCallbacks.unregisterListeners(); } @@ -140,7 +188,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar return mTaskbarView.areIconsVisible(); } - public MultiValueAlpha getTaskbarIconAlpha() { + public MultiPropertyFactory<View> getTaskbarIconAlpha() { return mTaskbarIconAlpha; } @@ -148,14 +196,15 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar * Should be called when the IME visibility changes, so we can make Taskbar not steal touches. */ public void setImeIsVisible(boolean isImeVisible) { - mTaskbarView.setTouchesEnabled(!isImeVisible); + mTaskbarView.setTouchesEnabled(!isImeVisible + || DisplayController.isTransientTaskbar(mActivity)); } /** * Should be called when the IME switcher visibility changes. */ public void setIsImeSwitcherVisible(boolean isImeSwitcherVisible) { - mTaskbarIconAlpha.getProperty(ALPHA_INDEX_IME_BUTTON_NAV).setValue( + mTaskbarIconAlpha.get(ALPHA_INDEX_IME_BUTTON_NAV).setValue( isImeSwitcherVisible ? 0 : 1); } @@ -164,7 +213,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar */ public void setRecentsButtonDisabled(boolean isDisabled) { // TODO: check TaskbarStashController#supportsStashing(), to stash instead of setting alpha. - mTaskbarIconAlpha.getProperty(ALPHA_INDEX_RECENTS_DISABLED).setValue(isDisabled ? 0 : 1); + mTaskbarIconAlpha.get(ALPHA_INDEX_RECENTS_DISABLED).setValue(isDisabled ? 0 : 1); } /** @@ -187,10 +236,15 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar return mTaskbarView.getIconLayoutBounds(); } + public int getIconLayoutWidth() { + return mTaskbarView.getIconLayoutWidth(); + } + public View[] getIconViews() { return mTaskbarView.getIconViews(); } + @Nullable public View getAllAppsButtonView() { return mTaskbarView.getAllAppsButtonView(); } @@ -212,9 +266,18 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar mTaskbarView.setScaleY(scale); } + /** + * Sets the translation of the TaskbarView during the swipe up gesture. + */ + public void setTranslationYForSwipe(float transY) { + mTaskbarIconTranslationYForSwipe = transY; + updateTranslationY(); + } + private void updateTranslationY() { mTaskbarView.setTranslationY(mTaskbarIconTranslationYForHome.value - + mTaskbarIconTranslationYForStash.value); + + mTaskbarIconTranslationYForStash.value + + mTaskbarIconTranslationYForSwipe); } private void updateIconsBackground() { @@ -232,10 +295,14 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar * 0 => not aligned * 1 => fully aligned */ - public void setLauncherIconAlignment(float alignmentRatio, Float endAlignment, - DeviceProfile launcherDp) { - if (mIconAlignControllerLazy == null) { - mIconAlignControllerLazy = createIconAlignmentController(launcherDp, endAlignment); + public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) { + boolean isHotseatIconOnTopWhenAligned = + mControllers.uiController.isHotseatIconOnTopWhenAligned(); + // When mIsHotseatIconOnTopWhenAligned changes, animation needs to be re-created. + if (mIconAlignControllerLazy == null + || mIsHotseatIconOnTopWhenAligned != isHotseatIconOnTopWhenAligned) { + mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned; + mIconAlignControllerLazy = createIconAlignmentController(launcherDp); } mIconAlignControllerLazy.setPlayFraction(alignmentRatio); if (alignmentRatio <= 0 || alignmentRatio >= 1) { @@ -247,8 +314,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar /** * Creates an animation for aligning the taskbar icons with the provided Launcher device profile */ - private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp, - Float endAlignment) { + private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) { mOnControllerPreCreateCallback.run(); PendingAnimation setter = new PendingAnimation(100); DeviceProfile taskbarDp = mActivity.getDeviceProfile(); @@ -260,10 +326,15 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar borderSpacing, launcherDp.numShownHotseatIcons); + boolean isToHome = mControllers.uiController.isIconAlignedWithHotseat(); + // If Hotseat is not the top element, Taskbar should maintain in-app state as it fades out, + // or fade in while already in in-app state. + Interpolator interpolator = mIsHotseatIconOnTopWhenAligned ? LINEAR : FINAL_FRAME; + int offsetY = launcherDp.getTaskbarOffsetY(); - setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, LINEAR); - setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, LINEAR); - setter.setFloat(mTaskbarNavButtonTranslationYForInAppDisplay, VALUE, offsetY, LINEAR); + setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, interpolator); + setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, interpolator); + setter.setFloat(mTaskbarNavButtonTranslationYForInAppDisplay, VALUE, offsetY, interpolator); if (Utilities.isDarkTheme(mTaskbarView.getContext())) { setter.addFloat(mThemeIconsBackground, VALUE, 0f, 1f, LINEAR); @@ -274,27 +345,24 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight( anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight)); - boolean isToHome = endAlignment != null && endAlignment == 1; for (int i = 0; i < mTaskbarView.getChildCount(); i++) { View child = mTaskbarView.getChildAt(i); int positionInHotseat; - if (FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() - && child == mTaskbarView.getAllAppsButtonView()) { - // Note that there is no All Apps button in the hotseat, this position is only used - // as its convenient for animation purposes. - positionInHotseat = Utilities.isRtl(child.getResources()) - ? -1 - : taskbarDp.numShownHotseatIcons; + boolean isAllAppsButton = FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get() + && child == mTaskbarView.getAllAppsButtonView(); + if (!mIsHotseatIconOnTopWhenAligned) { + // When going to home, the EMPHASIZED interpolator in TaskbarLauncherStateController + // plays iconAlignment to 1 really fast, therefore moving the fading towards the end + // to avoid icons disappearing rather than fading out visually. + setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f)); + } else if ((isAllAppsButton && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get())) { + setter.setViewAlpha(child, 0, + isToHome + ? Interpolators.clampToProgress(LINEAR, 0f, 0.17f) + : Interpolators.clampToProgress(LINEAR, 0.72f, 0.84f)); + } - if (!FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { - setter.setViewAlpha(child, 0, - isToHome - ? Interpolators.clampToProgress(LINEAR, 0f, 0.17f) - : Interpolators.clampToProgress(LINEAR, 0.72f, 0.84f)); - } - } else if (child.getTag() instanceof ItemInfo) { - positionInHotseat = ((ItemInfo) child.getTag()).screenId; - } else if (child == mTaskbarView.getQsb()) { + if (child == mTaskbarView.getQsb()) { boolean isRtl = Utilities.isRtl(child.getResources()); float hotseatIconCenter = isRtl ? launcherDp.widthPx - hotseatPadding.right + borderSpacing @@ -305,24 +373,38 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar (launcherDp.hotseatQsbWidth - taskbarDp.iconSizePx) / 2f; setter.addFloat(child, ICON_TRANSLATE_X, isRtl ? -halfQsbIconWidthDiff : halfQsbIconWidthDiff, - hotseatIconCenter - childCenter, LINEAR); + hotseatIconCenter - childCenter, interpolator); float scale = ((float) taskbarDp.iconSizePx) / launcherDp.hotseatQsbVisualHeight; - setter.addFloat(child, SCALE_PROPERTY, scale, 1f, LINEAR); + setter.addFloat(child, SCALE_PROPERTY, scale, 1f, interpolator); - setter.addFloat(child, VIEW_ALPHA, 0f, 1f, - isToHome - ? Interpolators.clampToProgress(LINEAR, 0f, 0.35f) - : Interpolators.clampToProgress(LINEAR, 0.84f, 1f)); + setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator); + + if (mIsHotseatIconOnTopWhenAligned) { + setter.addFloat(child, VIEW_ALPHA, 0f, 1f, + isToHome + ? Interpolators.clampToProgress(LINEAR, 0f, 0.35f) + : Interpolators.clampToProgress(LINEAR, 0.84f, 1f)); + } setter.addOnFrameListener(animator -> AlphaUpdateListener.updateVisibility(child)); float qsbInsetFraction = halfQsbIconWidthDiff / launcherDp.hotseatQsbWidth; - if (child instanceof HorizontalInsettableView) { + if (child instanceof HorizontalInsettableView) { setter.addFloat((HorizontalInsettableView) child, HorizontalInsettableView.HORIZONTAL_INSETS, qsbInsetFraction, 0, - LINEAR); + interpolator); } continue; + } + + if (isAllAppsButton) { + // Note that there is no All Apps button in the hotseat, this position is only used + // as its convenient for animation purposes. + positionInHotseat = Utilities.isRtl(child.getResources()) + ? taskbarDp.numShownHotseatIcons + : -1; + } else if (child.getTag() instanceof ItemInfo) { + positionInHotseat = ((ItemInfo) child.getTag()).screenId; } else { Log.w(TAG, "Unsupported view found in createIconAlignmentController, v=" + child); continue; @@ -333,9 +415,11 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar + hotseatCellSize / 2f; float childCenter = (child.getLeft() + child.getRight()) / 2f; - setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR); + setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, interpolator); - setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR); + setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, interpolator); + + setter.setFloat(child, SCALE_PROPERTY, scaleUp, interpolator); } AnimatorPlaybackController controller = setter.createPlaybackController(); @@ -344,8 +428,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar } public void onRotationChanged(DeviceProfile deviceProfile) { - if (mControllers.taskbarStashController.isInApp()) { - // We only translate on rotation when on home + if (!mControllers.uiController.isIconAlignedWithHotseat()) { + // We only translate on rotation when icon is aligned with hotseat return; } mActivity.setTaskbarWindowHeight( @@ -418,6 +502,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar private float mDownX, mDownY; private boolean mCanceledStashHint; + private boolean mTouchInProgress; + public View.OnClickListener getIconOnClickListener() { return mActivity.getItemOnClickListener(); } @@ -429,13 +515,6 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar }; } - public View.OnClickListener getFloatingTaskButtonListener(@NonNull Intent intent) { - return v -> { - SystemUiProxy proxy = SystemUiProxy.INSTANCE.get(v.getContext()); - proxy.showFloatingTask(intent); - }; - } - public View.OnLongClickListener getIconOnLongClickListener() { return mControllers.taskbarDragController::startDragOnLongClick; } @@ -446,37 +525,75 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar } /** + * Simply listens to all intercept touch events passed to TaskbarView. + */ + public void onInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mTouchInProgress = true; + } + + if (mTouchInProgress && mSwipeDownDetector != null) { + mSwipeDownDetector.onTouchEvent(ev); + } + + if (ev.getAction() == MotionEvent.ACTION_UP + || ev.getAction() == MotionEvent.ACTION_CANCEL) { + clearTouchInProgress(); + } + } + + /** * Get the first chance to handle TaskbarView#onTouchEvent, and return whether we want to * consume the touch so TaskbarView treats it as an ACTION_CANCEL. */ public boolean onTouchEvent(MotionEvent motionEvent) { + boolean shouldConsumeTouch = false; + boolean clearTouchInProgress = false; + final float x = motionEvent.getRawX(); final float y = motionEvent.getRawY(); switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: + mTouchInProgress = true; mDownX = x; mDownY = y; mControllers.taskbarStashController.startStashHint(/* animateForward = */ true); mCanceledStashHint = false; break; case MotionEvent.ACTION_MOVE: - if (!mCanceledStashHint + if (mTouchInProgress + && !mCanceledStashHint && squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop) { mControllers.taskbarStashController.startStashHint( /* animateForward= */ false); mCanceledStashHint = true; - return true; + shouldConsumeTouch = true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - if (!mCanceledStashHint) { + if (mTouchInProgress && !mCanceledStashHint) { mControllers.taskbarStashController.startStashHint( /* animateForward= */ false); } + clearTouchInProgress = true; break; } - return false; + + if (mTouchInProgress && mSwipeDownDetector != null) { + mSwipeDownDetector.onTouchEvent(motionEvent); + } + if (clearTouchInProgress) { + clearTouchInProgress(); + } + return shouldConsumeTouch; + } + + /** + * Ensures that we do not pass any more touch events to the SwipeDetector. + */ + public void clearTouchInProgress() { + mTouchInProgress = false; } } diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt index 076900cd39..a033507b8e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt @@ -14,7 +14,8 @@ private const val STASHED_HANDLE_FADE_DURATION = 180L * Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. */ class VoiceInteractionWindowController(val context: TaskbarActivityContext) - : TaskbarControllers.LoggableTaskbarController { + : TaskbarControllers.LoggableTaskbarController, + TaskbarControllers.BackgroundRendererController { private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context) @@ -63,11 +64,11 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext) // Fade out taskbar icons and stashed handle. val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f val fadeTaskbarIcons = controllers.taskbarViewController.taskbarIconAlpha - .getProperty(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED) + .get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED) .animateToValue(taskbarIconAlpha) .setDuration(TASKBAR_ICONS_FADE_DURATION) val fadeStashedHandle = controllers.stashedHandleViewController.stashedHandleAlpha - .getProperty(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED) + .get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED) .animateToValue(taskbarIconAlpha) .setDuration(STASHED_HANDLE_FADE_DURATION) fadeTaskbarIcons.start() @@ -111,6 +112,11 @@ class VoiceInteractionWindowController(val context: TaskbarActivityContext) } } + override fun setCornerRoundness(cornerRoundness: Float) { + taskbarBackgroundRenderer.setCornerRoundness(cornerRoundness) + separateWindowForTaskbarBackground.invalidate() + } + override fun dumpLogs(prefix: String, pw: PrintWriter) { pw.println(prefix + "VoiceInteractionWindowController:") pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible") diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java index 51fa4d9f3a..eeca329e80 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java @@ -17,17 +17,17 @@ package com.android.launcher3.taskbar.allapps; import android.content.Context; import android.util.AttributeSet; +import android.view.View; import android.view.WindowInsets; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; import com.android.launcher3.allapps.ActivityAllAppsContainerView; -import com.android.launcher3.allapps.AllAppsGridAdapter; -import com.android.launcher3.allapps.AlphabeticalAppsList; -import com.android.launcher3.allapps.BaseAdapterProvider; -import com.android.launcher3.allapps.BaseAllAppsAdapter; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; /** All apps container accessible from taskbar. */ public class TaskbarAllAppsContainerView extends - ActivityAllAppsContainerView<TaskbarAllAppsContext> { + ActivityAllAppsContainerView<TaskbarOverlayContext> { public TaskbarAllAppsContainerView(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -44,10 +44,33 @@ public class TaskbarAllAppsContainerView extends } @Override - protected BaseAllAppsAdapter<TaskbarAllAppsContext> createAdapter( - AlphabeticalAppsList<TaskbarAllAppsContext> appsList, - BaseAdapterProvider[] adapterProviders) { - return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList, - adapterProviders); + protected View inflateSearchBox() { + // Remove top padding of header, since we do not have any search + mHeader.setPadding(mHeader.getPaddingLeft(), 0, + mHeader.getPaddingRight(), mHeader.getPaddingBottom()); + + TaskbarAllAppsFallbackSearchContainer searchView = + new TaskbarAllAppsFallbackSearchContainer(getContext(), null); + searchView.setId(R.id.search_container_all_apps); + searchView.setVisibility(GONE); + return searchView; + } + + @Override + protected boolean isSearchSupported() { + return false; + } + + @Override + protected void updateBackground(DeviceProfile deviceProfile) { + super.updateBackground(deviceProfile); + // TODO(b/240670050): Remove this and add header protection for the taskbar entrypoint. + mBottomSheetBackground.setBackgroundResource(R.drawable.bg_rounded_corner_bottom_sheet); + } + + @Override + public boolean isInAllApps() { + // All apps is always open + return true; } } diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java deleted file mode 100644 index 0372f67b75..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2022 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.launcher3.taskbar.allapps; - -import static android.view.KeyEvent.ACTION_UP; -import static android.view.KeyEvent.KEYCODE_BACK; -import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; - -import android.content.Context; -import android.graphics.Insets; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewTreeObserver; -import android.view.ViewTreeObserver.OnComputeInternalInsetsListener; -import android.view.WindowInsets; - -import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.allapps.ActivityAllAppsContainerView; -import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider; -import com.android.launcher3.allapps.search.SearchAdapterProvider; -import com.android.launcher3.dot.DotInfo; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.popup.PopupDataProvider; -import com.android.launcher3.taskbar.BaseTaskbarContext; -import com.android.launcher3.taskbar.TaskbarActivityContext; -import com.android.launcher3.taskbar.TaskbarControllers; -import com.android.launcher3.taskbar.TaskbarDragController; -import com.android.launcher3.taskbar.TaskbarStashController; -import com.android.launcher3.testing.TestLogging; -import com.android.launcher3.testing.shared.TestProtocol; -import com.android.launcher3.util.OnboardingPrefs; -import com.android.launcher3.util.TouchController; -import com.android.launcher3.views.BaseDragLayer; - -/** - * Window context for the taskbar all apps overlay. - * <p> - * All apps has its own window and needs a window context. Some properties are delegated to the - * {@link TaskbarActivityContext} such as {@link DeviceProfile} and {@link PopupDataProvider}. - */ -class TaskbarAllAppsContext extends BaseTaskbarContext { - private final TaskbarActivityContext mTaskbarContext; - private final OnboardingPrefs<TaskbarAllAppsContext> mOnboardingPrefs; - - private final TaskbarAllAppsController mWindowController; - private final TaskbarAllAppsViewController mAllAppsViewController; - private final TaskbarDragController mDragController; - private final TaskbarAllAppsDragLayer mDragLayer; - private final TaskbarAllAppsContainerView mAppsView; - - // We automatically stash taskbar when all apps is opened in gesture navigation mode. - private final boolean mWillTaskbarBeVisuallyStashed; - private final int mStashedTaskbarHeight; - - TaskbarAllAppsContext( - TaskbarActivityContext taskbarContext, - TaskbarAllAppsController windowController, - TaskbarControllers taskbarControllers) { - super(taskbarContext.createWindowContext(TYPE_APPLICATION_OVERLAY, null)); - mTaskbarContext = taskbarContext; - mWindowController = windowController; - mDragController = new TaskbarDragController(this); - mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this)); - - mDragLayer = new TaskbarAllAppsDragLayer(this); - TaskbarAllAppsSlideInView slideInView = (TaskbarAllAppsSlideInView) mLayoutInflater.inflate( - R.layout.taskbar_all_apps, mDragLayer, false); - mAllAppsViewController = new TaskbarAllAppsViewController( - this, - slideInView, - windowController, - taskbarControllers); - mAppsView = slideInView.getAppsView(); - - TaskbarStashController taskbarStashController = taskbarControllers.taskbarStashController; - mWillTaskbarBeVisuallyStashed = taskbarStashController.supportsVisualStashing(); - mStashedTaskbarHeight = taskbarStashController.getStashedHeight(); - } - - TaskbarAllAppsViewController getAllAppsViewController() { - return mAllAppsViewController; - } - - @Override - public DeviceProfile getDeviceProfile() { - return mWindowController.getDeviceProfile(); - } - - @Override - public TaskbarDragController getDragController() { - return mDragController; - } - - @Override - public TaskbarAllAppsDragLayer getDragLayer() { - return mDragLayer; - } - - @Override - public TaskbarAllAppsContainerView getAppsView() { - return mAppsView; - } - - @Override - public OnboardingPrefs<TaskbarAllAppsContext> getOnboardingPrefs() { - return mOnboardingPrefs; - } - - @Override - public boolean isBindingItems() { - return mTaskbarContext.isBindingItems(); - } - - @Override - public View.OnClickListener getItemOnClickListener() { - return mTaskbarContext.getItemOnClickListener(); - } - - @Override - public PopupDataProvider getPopupDataProvider() { - return mTaskbarContext.getPopupDataProvider(); - } - - @Override - public DotInfo getDotInfoForItem(ItemInfo info) { - return mTaskbarContext.getDotInfoForItem(info); - } - - @Override - public void onDragStart() {} - - @Override - public void onDragEnd() { - mWindowController.maybeCloseWindow(); - } - - @Override - public void onPopupVisibilityChanged(boolean isVisible) {} - - @Override - public SearchAdapterProvider<?> createSearchAdapterProvider( - ActivityAllAppsContainerView<?> appsView) { - return new DefaultSearchAdapterProvider(this); - } - - /** Root drag layer for this context. */ - private static class TaskbarAllAppsDragLayer extends - BaseDragLayer<TaskbarAllAppsContext> implements OnComputeInternalInsetsListener { - - private TaskbarAllAppsDragLayer(Context context) { - super(context, null, 1); - setClipChildren(false); - recreateControllers(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - getViewTreeObserver().addOnComputeInternalInsetsListener(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - getViewTreeObserver().removeOnComputeInternalInsetsListener(this); - } - - @Override - public void recreateControllers() { - mControllers = new TouchController[]{mActivity.mDragController}; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev); - return super.dispatchTouchEvent(ev); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent event) { - if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) { - AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity); - if (topView != null && topView.onBackPressed()) { - return true; - } - } - return super.dispatchKeyEvent(event); - } - - @Override - public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) { - if (mActivity.mDragController.isSystemDragInProgress()) { - inoutInfo.touchableRegion.setEmpty(); - inoutInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); - } - } - - @Override - public WindowInsets onApplyWindowInsets(WindowInsets insets) { - return updateInsetsDueToStashing(insets); - } - - /** - * Taskbar automatically stashes when opening all apps, but we don't report the insets as - * changing to avoid moving the underlying app. But internally, the apps view should still - * layout according to the stashed insets rather than the unstashed insets. So this method - * does two things: - * 1) Sets navigationBars bottom inset to stashedHeight. - * 2) Sets tappableInsets bottom inset to 0. - */ - private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) { - if (!mActivity.mWillTaskbarBeVisuallyStashed) { - return oldInsets; - } - WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets); - - Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars()); - Insets newNavInsets = Insets.of(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right, - mActivity.mStashedTaskbarHeight); - updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets); - - Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement()); - Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top, - oldTappableInsets.right, 0); - updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets); - - return updatedInsetsBuilder.build(); - } - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java index 1671a0f1d7..7a34869e2a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java @@ -15,34 +15,18 @@ */ package com.android.launcher3.taskbar.allapps; -import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; - -import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; -import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE; - -import android.content.Context; -import android.graphics.PixelFormat; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; - import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; -import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; import com.android.launcher3.appprediction.PredictionRowView; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; -import com.android.systemui.shared.system.TaskStackChangeListener; -import com.android.systemui.shared.system.TaskStackChangeListeners; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import java.util.List; -import java.util.Optional; /** * Handles the all apps overlay window initialization, updates, and its data. @@ -57,35 +41,16 @@ import java.util.Optional; */ public final class TaskbarAllAppsController { - private static final String WINDOW_TITLE = "Taskbar All Apps"; - - private final TaskbarActivityContext mTaskbarContext; - private final TaskbarAllAppsProxyView mProxyView; - private final LayoutParams mLayoutParams; - - private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { - @Override - public void onTaskStackChanged() { - mProxyView.close(false); - } - }; - - private DeviceProfile mDeviceProfile; private TaskbarControllers mControllers; - /** Window context for all apps if it is open. */ - private @Nullable TaskbarAllAppsContext mAllAppsContext; + private @Nullable TaskbarAllAppsSlideInView mSlideInView; + private @Nullable TaskbarAllAppsContainerView mAppsView; // Application data models. private AppInfo[] mApps; private int mAppsModelFlags; private List<ItemInfo> mPredictedApps; - - public TaskbarAllAppsController(TaskbarActivityContext context, DeviceProfile dp) { - mDeviceProfile = dp; - mTaskbarContext = context; - mProxyView = new TaskbarAllAppsProxyView(mTaskbarContext); - mLayoutParams = createLayoutParams(); - } + private boolean mDisallowGlobalDrag; + private boolean mDisallowLongClick; /** Initialize the controller. */ public void init(TaskbarControllers controllers, boolean allAppsVisible) { @@ -111,11 +76,19 @@ public final class TaskbarAllAppsController { mApps = apps; mAppsModelFlags = flags; - if (mAllAppsContext != null) { - mAllAppsContext.getAppsView().getAppsStore().setApps(mApps, mAppsModelFlags); + if (mAppsView != null) { + mAppsView.getAppsStore().setApps(mApps, mAppsModelFlags); } } + public void setDisallowGlobalDrag(boolean disableDragForOverviewState) { + mDisallowGlobalDrag = disableDragForOverviewState; + } + + public void setDisallowLongClick(boolean disallowLongClick) { + mDisallowLongClick = disallowLongClick; + } + /** Updates the current predictions. */ public void setPredictedApps(List<ItemInfo> predictedApps) { if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) { @@ -123,8 +96,8 @@ public final class TaskbarAllAppsController { } mPredictedApps = predictedApps; - if (mAllAppsContext != null) { - mAllAppsContext.getAppsView().getFloatingHeaderView() + if (mAppsView != null) { + mAppsView.getFloatingHeaderView() .findFixedRowByType(PredictionRowView.class) .setPredictedApps(mPredictedApps); } @@ -135,121 +108,49 @@ public final class TaskbarAllAppsController { show(true); } + /** Returns {@code true} if All Apps is open. */ + public boolean isOpen() { + return mSlideInView != null && mSlideInView.isOpen(); + } + private void show(boolean animate) { - if (mProxyView.isOpen()) { + if (mAppsView != null) { return; } - mProxyView.show(); // mControllers and getSharedState should never be null here. Do not handle null-pointer // to catch invalid states. mControllers.getSharedState().allAppsVisible = true; - mAllAppsContext = new TaskbarAllAppsContext(mTaskbarContext, this, mControllers); - mAllAppsContext.getDragController().init(mControllers); - TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener); - Optional.ofNullable(mAllAppsContext.getSystemService(WindowManager.class)) - .ifPresent(m -> m.addView(mAllAppsContext.getDragLayer(), mLayoutParams)); + TaskbarOverlayContext overlayContext = + mControllers.taskbarOverlayController.requestWindow(); + mSlideInView = (TaskbarAllAppsSlideInView) overlayContext.getLayoutInflater().inflate( + R.layout.taskbar_all_apps, overlayContext.getDragLayer(), false); + mSlideInView.addOnCloseListener(() -> { + mControllers.getSharedState().allAppsVisible = false; + mSlideInView = null; + mAppsView = null; + }); + TaskbarAllAppsViewController viewController = new TaskbarAllAppsViewController( + overlayContext, mSlideInView, mControllers); - mAllAppsContext.getAppsView().getAppsStore().setApps(mApps, mAppsModelFlags); - mAllAppsContext.getAppsView().getFloatingHeaderView() + viewController.show(animate); + mAppsView = overlayContext.getAppsView(); + mAppsView.getAppsStore().setApps(mApps, mAppsModelFlags); + mAppsView.getFloatingHeaderView() .findFixedRowByType(PredictionRowView.class) .setPredictedApps(mPredictedApps); - mAllAppsContext.getAllAppsViewController().show(animate); + // 1 alternative that would be more work: + // Create a shared drag layer between taskbar and taskbarAllApps so that when dragging + // starts and taskbarAllApps can close, but the drag layer that the view is being dragged in + // doesn't also close + overlayContext.getDragController().setDisallowGlobalDrag(mDisallowGlobalDrag); + overlayContext.getDragController().setDisallowLongClick(mDisallowLongClick); } - /** Closes the {@link TaskbarAllAppsContainerView}. */ - public void hide() { - mProxyView.close(true); - } - /** - * Removes the all apps window from the hierarchy, if all floating views are closed and there is - * no system drag operation in progress. - * <p> - * This method should be called after an exit animation finishes, if applicable. - */ - void maybeCloseWindow() { - if (mAllAppsContext != null && (AbstractFloatingView.hasOpenView(mAllAppsContext, TYPE_ALL) - || mAllAppsContext.getDragController().isSystemDragInProgress())) { - return; - } - mProxyView.close(false); - // mControllers and getSharedState should never be null here. Do not handle null-pointer - // to catch invalid states. - mControllers.getSharedState().allAppsVisible = false; - onDestroy(); - } - - /** Destroys the controller and any All Apps window if present. */ - public void onDestroy() { - TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener); - Optional.ofNullable(mAllAppsContext) - .map(c -> c.getSystemService(WindowManager.class)) - .ifPresent(m -> m.removeViewImmediate(mAllAppsContext.getDragLayer())); - mAllAppsContext = null; - } - - /** Updates {@link DeviceProfile} instance for Taskbar's All Apps window. */ - public void updateDeviceProfile(DeviceProfile dp) { - mDeviceProfile = dp; - Optional.ofNullable(mAllAppsContext).ifPresent(c -> { - AbstractFloatingView.closeAllOpenViewsExcept(c, false, TYPE_REBIND_SAFE); - c.dispatchDeviceProfileChanged(); - }); - } - - DeviceProfile getDeviceProfile() { - return mDeviceProfile; - } - - private LayoutParams createLayoutParams() { - LayoutParams layoutParams = new LayoutParams( - TYPE_APPLICATION_OVERLAY, - WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - layoutParams.setTitle(WINDOW_TITLE); - layoutParams.gravity = Gravity.BOTTOM; - layoutParams.packageName = mTaskbarContext.getPackageName(); - layoutParams.setFitInsetsTypes(0); // Handled by container view. - layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - layoutParams.setSystemApplicationOverlay(true); - return layoutParams; - } - - /** - * Proxy view connecting taskbar drag layer to the all apps window. - * <p> - * The all apps view is in a separate window and has its own drag layer, but this proxy lets it - * behave as though its in the taskbar drag layer. For instance, when the taskbar closes all - * {@link AbstractFloatingView} instances, the all apps window will also close. - */ - private class TaskbarAllAppsProxyView extends AbstractFloatingView { - - private TaskbarAllAppsProxyView(Context context) { - super(context, null); - } - - private void show() { - mIsOpen = true; - mTaskbarContext.getDragLayer().addView(this); - } - - @Override - protected void handleClose(boolean animate) { - mTaskbarContext.getDragLayer().removeView(this); - Optional.ofNullable(mAllAppsContext) - .map(TaskbarAllAppsContext::getAllAppsViewController) - .ifPresent(v -> v.close(animate)); - } - - @Override - protected boolean isOfType(int type) { - return (type & TYPE_TASKBAR_ALL_APPS) != 0; - } - - @Override - public boolean onControllerInterceptTouchEvent(MotionEvent ev) { - return false; - } + @VisibleForTesting + public int getTaskbarAllAppsTopPadding() { + // Allow null-pointer since this should only be null if the apps view is not showing. + return mAppsView.getActiveRecyclerView().getClipBounds().top; } } diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java index 9d48c8de89..8502752652 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.taskbar.allapps; -import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.anim.Interpolators.EMPHASIZED; import android.animation.PropertyValuesHolder; @@ -28,14 +27,19 @@ import android.view.animation.Interpolator; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.R; +import com.android.launcher3.taskbar.allapps.TaskbarAllAppsViewController.TaskbarAllAppsCallbacks; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import com.android.launcher3.views.AbstractSlideInView; /** Wrapper for taskbar all apps with slide-in behavior. */ -public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllAppsContext> +public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverlayContext> implements Insettable, DeviceProfile.OnDeviceProfileChangeListener { private TaskbarAllAppsContainerView mAppsView; private float mShiftRange; + // Initialized in init. + private TaskbarAllAppsCallbacks mAllAppsCallbacks; + public TaskbarAllAppsSlideInView(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -45,6 +49,10 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllApp super(context, attrs, defStyleAttr); } + void init(TaskbarAllAppsCallbacks callbacks) { + mAllAppsCallbacks = callbacks; + } + /** Opens the all apps view. */ void show(boolean animate) { if (mIsOpen || mOpenCloseAnimator.isRunning()) { @@ -57,8 +65,7 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllApp mOpenCloseAnimator.setValues( PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED)); mOpenCloseAnimator.setInterpolator(EMPHASIZED); - mOpenCloseAnimator.setDuration( - ALL_APPS.getTransitionDuration(mActivityContext, true /* isToState */)).start(); + mOpenCloseAnimator.setDuration(mAllAppsCallbacks.getOpenDuration()).start(); } else { mTranslationShift = TRANSLATION_SHIFT_OPENED; } @@ -71,8 +78,7 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllApp @Override protected void handleClose(boolean animate) { - handleClose(animate, - ALL_APPS.getTransitionDuration(mActivityContext, false /* isToState */)); + handleClose(animate, mAllAppsCallbacks.getCloseDuration()); } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java index b0d3528e2c..7a3b3e8c7b 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java @@ -15,8 +15,8 @@ */ package com.android.launcher3.taskbar.allapps; -import static com.android.launcher3.LauncherState.ALL_APPS; -import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_ALL_APPS; +import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_TASKBAR_ALL_APPS; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT; import com.android.launcher3.AbstractFloatingView; @@ -25,6 +25,9 @@ import com.android.launcher3.appprediction.PredictionRowView; import com.android.launcher3.taskbar.NavbarButtonsViewController; import com.android.launcher3.taskbar.TaskbarControllers; import com.android.launcher3.taskbar.TaskbarStashController; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; +import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; +import com.android.launcher3.util.DisplayController; /** * Handles the {@link TaskbarAllAppsContainerView} behavior and synchronizes its transitions with @@ -32,16 +35,16 @@ import com.android.launcher3.taskbar.TaskbarStashController; */ final class TaskbarAllAppsViewController { - private final TaskbarAllAppsContext mContext; + private final TaskbarOverlayContext mContext; private final TaskbarAllAppsSlideInView mSlideInView; private final TaskbarAllAppsContainerView mAppsView; private final TaskbarStashController mTaskbarStashController; private final NavbarButtonsViewController mNavbarButtonsViewController; + private final TaskbarOverlayController mOverlayController; TaskbarAllAppsViewController( - TaskbarAllAppsContext context, + TaskbarOverlayContext context, TaskbarAllAppsSlideInView slideInView, - TaskbarAllAppsController windowController, TaskbarControllers taskbarControllers) { mContext = context; @@ -49,11 +52,12 @@ final class TaskbarAllAppsViewController { mAppsView = mSlideInView.getAppsView(); mTaskbarStashController = taskbarControllers.taskbarStashController; mNavbarButtonsViewController = taskbarControllers.navbarButtonsViewController; + mOverlayController = taskbarControllers.taskbarOverlayController; + mSlideInView.init(new TaskbarAllAppsCallbacks()); setUpIconLongClick(); setUpAppDivider(); setUpTaskbarStashing(); - mSlideInView.addOnCloseListener(windowController::maybeCloseWindow); } /** Starts the {@link TaskbarAllAppsSlideInView} enter transition. */ @@ -84,17 +88,34 @@ final class TaskbarAllAppsViewController { } private void setUpTaskbarStashing() { - mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_APP_ALL_APPS, true); - mTaskbarStashController.applyState( - ALL_APPS.getTransitionDuration(mContext, true /* isToState */)); + mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, true); + mTaskbarStashController.applyState(mOverlayController.getOpenDuration()); + mNavbarButtonsViewController.setSlideInViewVisible(true); mSlideInView.setOnCloseBeginListener(() -> { mNavbarButtonsViewController.setSlideInViewVisible(false); AbstractFloatingView.closeOpenContainer( mContext, AbstractFloatingView.TYPE_ACTION_POPUP); - // Post in case view is closing due to gesture navigation. If a gesture is in progress, - // wait to unstash until after the gesture is finished. - mSlideInView.post(mTaskbarStashController::maybeResetStashedInAppAllApps); + + if (DisplayController.isTransientTaskbar(mContext)) { + mTaskbarStashController.updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false); + mTaskbarStashController.applyState(mOverlayController.getCloseDuration()); + } else { + // Post in case view is closing due to gesture navigation. If a gesture is in + // progress, wait to unstash until after the gesture is finished. + MAIN_EXECUTOR.post(() -> mTaskbarStashController.resetFlagIfNoGestureInProgress( + FLAG_STASHED_IN_TASKBAR_ALL_APPS)); + } }); } + + class TaskbarAllAppsCallbacks { + int getOpenDuration() { + return mOverlayController.getOpenDuration(); + } + + int getCloseDuration() { + return mOverlayController.getCloseDuration(); + } + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt new file mode 100644 index 0000000000..68ea27a8ec --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.navbutton + +import android.content.res.Resources +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.LinearLayout +import com.android.launcher3.R +import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter + +/** + * Meant to be a simple container for data subclasses will need + * + * Assumes that the 3 navigation buttons (back/home/recents) have already been added to + * [navButtonContainer] + * + * @property navButtonContainer ViewGroup that holds the 3 navigation buttons. + * @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME dismiss). + * @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y). + */ +abstract class AbstractNavButtonLayoutter( + val resources: Resources, + val navButtonContainer: LinearLayout, + protected val endContextualContainer: ViewGroup, + protected val startContextualContainer: ViewGroup +) : NavButtonLayoutter { + protected val homeButton: ImageView = navButtonContainer + .findViewById(R.id.home) + protected val recentsButton: ImageView = navButtonContainer + .findViewById(R.id.recent_apps) + protected val backButton: ImageView = navButtonContainer + .findViewById(R.id.back) +} + diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt new file mode 100644 index 0000000000..c67ab7964e --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.navbutton + +import android.content.res.Resources +import android.graphics.Color +import android.graphics.drawable.PaintDrawable +import android.view.Gravity +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.LinearLayout +import com.android.launcher3.DeviceProfile +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_ICON_SIZE_KIDS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DRAWABLE_SYSBAR_BACK_KIDS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DRAWABLE_SYSBAR_HOME_KIDS + +class KidsNavLayoutter( + resources: Resources, + navBarContainer: LinearLayout, + endContextualContainer: ViewGroup, + startContextualContainer: ViewGroup +) : AbstractNavButtonLayoutter( + resources, + navBarContainer, + endContextualContainer, + startContextualContainer +) { + + override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) { + val iconSize: Int = resources.getDimensionPixelSize( + DIMEN_TASKBAR_ICON_SIZE_KIDS) + val buttonWidth: Int = resources.getDimensionPixelSize( + DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS) + val buttonHeight: Int = resources.getDimensionPixelSize( + DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS) + val buttonRadius: Int = resources.getDimensionPixelSize( + DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS) + val paddingLeft = (buttonWidth - iconSize) / 2 + val paddingTop = (buttonHeight - iconSize) / 2 + + // Update icons + backButton.setImageDrawable( + backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS)) + backButton.scaleType = ImageView.ScaleType.FIT_CENTER + backButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop) + homeButton.setImageDrawable( + homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS)) + homeButton.scaleType = ImageView.ScaleType.FIT_CENTER + homeButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop) + + // Home button layout + val homeLayoutparams = LinearLayout.LayoutParams( + buttonWidth, + buttonHeight + ) + val homeButtonLeftMargin: Int = resources.getDimensionPixelSize( + DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS) + homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0) + homeButton.layoutParams = homeLayoutparams + + // Back button layout + val backLayoutParams = LinearLayout.LayoutParams( + buttonWidth, + buttonHeight + ) + val backButtonLeftMargin: Int = resources.getDimensionPixelSize( + DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS) + backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0) + backButton.layoutParams = backLayoutParams + + // Button backgrounds + val whiteWith10PctAlpha = Color.argb(0.1f, 1f, 1f, 1f) + val buttonBackground = PaintDrawable(whiteWith10PctAlpha) + buttonBackground.setCornerRadius(buttonRadius.toFloat()) + homeButton.background = buttonBackground + backButton.background = buttonBackground + + // Update alignment within taskbar + val navButtonsLayoutParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams + navButtonsLayoutParams.apply { + marginStart = navButtonsLayoutParams.marginEnd / 2 + marginEnd = navButtonsLayoutParams.marginStart + gravity = Gravity.CENTER + } + navButtonContainer.requestLayout() + + homeButton.onLongClickListener = null + } +}
\ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/LayoutResourceHelper.java b/quickstep/src/com/android/launcher3/taskbar/navbutton/LayoutResourceHelper.java new file mode 100644 index 0000000000..0d9b855c91 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/LayoutResourceHelper.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.navbutton; + +import android.annotation.DimenRes; +import android.annotation.DrawableRes; +import android.annotation.IdRes; + +import com.android.launcher3.R; + +/** + * A class for retrieving resources in Kotlin. + * + * This class should be removed once the build system supports resources loading in Kotlin. + */ +public final class LayoutResourceHelper { + + // -------------------------- + // Kids Nav Layout + @DimenRes + public static final int DIMEN_TASKBAR_ICON_SIZE_KIDS = R.dimen.taskbar_icon_size_kids; + @DrawableRes + public static final int DRAWABLE_SYSBAR_BACK_KIDS = R.drawable.ic_sysbar_back_kids; + @DrawableRes + public static final int DRAWABLE_SYSBAR_HOME_KIDS = R.drawable.ic_sysbar_home_kids; + @DimenRes + public static final int DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS = + R.dimen.taskbar_home_button_left_margin_kids; + @DimenRes + public static final int DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS = + R.dimen.taskbar_back_button_left_margin_kids; + @DimenRes + public static final int DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS = + R.dimen.taskbar_nav_buttons_width_kids; + @DimenRes + public static final int DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS = + R.dimen.taskbar_nav_buttons_height_kids; + @DimenRes + public static final int DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS = + R.dimen.taskbar_nav_buttons_corner_radius_kids; + + // -------------------------- + // Nav Layout Factory + @IdRes + public static final int ID_START_CONTEXTUAL_BUTTONS = R.id.start_contextual_buttons; + @IdRes + public static final int ID_END_CONTEXTUAL_BUTTONS = R.id.end_contextual_buttons; + @IdRes + public static final int ID_END_NAV_BUTTONS = R.id.end_nav_buttons; + + private LayoutResourceHelper() { + + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt new file mode 100644 index 0000000000..db0a2d8d44 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.navbutton + +import android.content.res.Resources +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.LinearLayout +import com.android.launcher3.DeviceProfile +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS +import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS +import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.Companion +import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter + +/** + * Select the correct layout for nav buttons + * + * Since layouts are done dynamically for the nav buttons on Taskbar, this + * class returns a corresponding [NavButtonLayoutter] via + * [Companion.getUiLayoutter] + * that can help position the buttons based on the current [DeviceProfile] + */ +class NavButtonLayoutFactory { + companion object { + /** + * Get the correct instance of [NavButtonLayoutter] + * + * No layouts supported for configurations where: + * * taskbar isn't showing AND + * * the device is not in [phoneMode] + * OR + * * phone is showing + * * device is using gesture navigation + * + * @param navButtonsView ViewGroup that contains start, end, nav button ViewGroups + * @param isKidsMode no-op when taskbar is hidden/not showing + * @param isInSetup no-op when taskbar is hidden/not showing + * @param phoneMode refers to the device using the taskbar window on phones + * @param isThreeButtonNav are no-ops when taskbar is present/showing + */ + fun getUiLayoutter(deviceProfile: DeviceProfile, + navButtonsView: FrameLayout, + resources: Resources, + isKidsMode: Boolean, + isInSetup: Boolean, + isThreeButtonNav: Boolean, + phoneMode: Boolean): + NavButtonLayoutter { + val navButtonContainer = + navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS) + val endContextualContainer = + navButtonsView.findViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS) + val startContextualContainer = + navButtonsView.findViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS) + val isPhoneNavMode = phoneMode && isThreeButtonNav + return when { + isPhoneNavMode -> { + if (!deviceProfile.isLandscape) { + PhonePortraitNavLayoutter(resources, navButtonContainer, + endContextualContainer, startContextualContainer) + } else { + PhoneLandscapeNavLayoutter(resources, navButtonContainer, + endContextualContainer, startContextualContainer) + } + } + deviceProfile.isTaskbarPresent -> { + return when { + isInSetup -> { + SetupNavLayoutter(resources, navButtonContainer, endContextualContainer, + startContextualContainer) + } + isKidsMode -> { + KidsNavLayoutter(resources, navButtonContainer, endContextualContainer, + startContextualContainer) + } + else -> + TaskbarNavLayoutter(resources, navButtonContainer, endContextualContainer, + startContextualContainer) + } + } + else -> error("No layoutter found") + } + } + } + + /** Lays out and provides access to the home, recents, and back buttons for various mischief */ + interface NavButtonLayoutter { + fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) + } +}
\ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt new file mode 100644 index 0000000000..a89476e15a --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.navbutton + +import android.content.res.Resources +import android.view.Gravity +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.LinearLayout +import androidx.core.view.children +import com.android.launcher3.DeviceProfile +import com.android.launcher3.R +import com.android.launcher3.taskbar.TaskbarManager +import com.android.launcher3.util.DimensionUtils + +class PhoneLandscapeNavLayoutter( + resources: Resources, + navBarContainer: LinearLayout, + endContextualContainer: ViewGroup, + startContextualContainer: ViewGroup +) : AbstractNavButtonLayoutter( + resources, + navBarContainer, + endContextualContainer, + startContextualContainer +) { + + override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) { + // TODO(b/230395757): Polish pending, this is just to make it usable + val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams + val endStartMargins = + resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) + val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources, + TaskbarManager.isPhoneMode(dp)) + navButtonContainer.removeAllViews() + navButtonContainer.orientation = LinearLayout.VERTICAL + + navContainerParams.apply { + width = taskbarDimensions.x + height = ViewGroup.LayoutParams.MATCH_PARENT + gravity = Gravity.CENTER + topMargin = endStartMargins + bottomMargin = endStartMargins + marginEnd = 0 + marginStart = 0 + } + + // Swap recents and back button + navButtonContainer.addView(recentsButton) + navButtonContainer.addView(homeButton) + navButtonContainer.addView(backButton) + + navButtonContainer.layoutParams = navContainerParams + + // Add the spaces in between the nav buttons + val spaceInBetween: Int = + resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone) + navButtonContainer.children.forEachIndexed { i, navButton -> + val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams + buttonLayoutParams.weight = 1f + when (i) { + 0 -> { + buttonLayoutParams.bottomMargin = spaceInBetween / 2 + } + navButtonContainer.childCount - 1 -> { + buttonLayoutParams.topMargin = spaceInBetween / 2 + } + else -> { + buttonLayoutParams.bottomMargin = spaceInBetween / 2 + buttonLayoutParams.topMargin = spaceInBetween / 2 + } + } + } + } +}
\ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt new file mode 100644 index 0000000000..275f59faef --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.navbutton + +import android.content.res.Resources +import android.view.Gravity +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.LinearLayout +import com.android.launcher3.DeviceProfile +import com.android.launcher3.R +import com.android.launcher3.taskbar.TaskbarManager +import com.android.launcher3.util.DimensionUtils + +class PhonePortraitNavLayoutter(resources: Resources, navBarContainer: LinearLayout, + endContextualContainer: ViewGroup, + startContextualContainer: ViewGroup) : + AbstractNavButtonLayoutter(resources, navBarContainer, endContextualContainer, + startContextualContainer) { + + override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) { + // TODO(b/230395757): Polish pending, this is just to make it usable + val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams + val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources, + TaskbarManager.isPhoneMode(dp)) + val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) + navContainerParams.width = taskbarDimensions.x + navContainerParams.height = ViewGroup.LayoutParams.MATCH_PARENT + navContainerParams.gravity = Gravity.CENTER_VERTICAL + + // Ensure order of buttons is correct + navButtonContainer.removeAllViews() + navButtonContainer.orientation = LinearLayout.HORIZONTAL + navContainerParams.topMargin = 0 + navContainerParams.bottomMargin = 0 + navContainerParams.marginEnd = endStartMargins + navContainerParams.marginStart = endStartMargins + // Swap recents and back button in case we were landscape prior to this + navButtonContainer.addView(backButton) + navButtonContainer.addView(homeButton) + navButtonContainer.addView(recentsButton) + + navButtonContainer.layoutParams = navContainerParams + + // Add the spaces in between the nav buttons + val spaceInBetween = + resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone) + for (i in 0 until navButtonContainer.childCount) { + val navButton = navButtonContainer.getChildAt(i) + val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams + buttonLayoutParams.weight = 1f + when (i) { + 0 -> { + // First button + buttonLayoutParams.marginEnd = spaceInBetween / 2 + } + navButtonContainer.childCount - 1 -> { + // Last button + buttonLayoutParams.marginStart = spaceInBetween / 2 + } + else -> { + // other buttons + buttonLayoutParams.marginStart = spaceInBetween / 2 + buttonLayoutParams.marginEnd = spaceInBetween / 2 + } + } + } + } +}
\ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt new file mode 100644 index 0000000000..afe70d6c21 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.navbutton + +import android.content.res.Resources +import android.view.Gravity +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.LinearLayout +import com.android.launcher3.DeviceProfile + +class SetupNavLayoutter( + resources: Resources, + navButtonContainer: LinearLayout, + endContextualContainer: ViewGroup, + startContextualContainer: ViewGroup +) : AbstractNavButtonLayoutter( + resources, + navButtonContainer, + endContextualContainer, + startContextualContainer +) { + + override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) { + // Since setup wizard only has back button enabled, it looks strange to be + // end-aligned, so start-align instead. + val navButtonsLayoutParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams + navButtonsLayoutParams.apply { + marginStart = navButtonsLayoutParams.marginEnd + marginEnd = 0 + gravity = Gravity.START + } + navButtonContainer.requestLayout() + } +}
\ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt new file mode 100644 index 0000000000..b2ca2afa04 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.navbutton + +import android.content.res.Resources +import android.view.Gravity +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.LinearLayout +import com.android.launcher3.DeviceProfile +import com.android.launcher3.R + +/** + * Layoutter for showing 3 button navigation on large screen + */ +class TaskbarNavLayoutter( + resources: Resources, + navBarContainer: LinearLayout, + endContextualContainer: ViewGroup, + startContextualContainer: ViewGroup +) : AbstractNavButtonLayoutter( + resources, + navBarContainer, + endContextualContainer, + startContextualContainer +) { + + override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) { + // Add spacing after the end of the last nav button + val navButtonParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams + var navMarginEnd = resources.getDimension(dp.inv.inlineNavButtonsEndSpacing).toInt() + val contextualWidth = endContextualContainer.width + // If contextual buttons are showing, we check if the end margin is enough for the + // contextual button to be showing - if not, move the nav buttons over a smidge + if (isContextualButtonShowing && navMarginEnd < contextualWidth) { + // Additional spacing, eat up half of space between last icon and nav button + navMarginEnd += resources.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing) / 2 + } + + navButtonParams.apply { + gravity = Gravity.END + width = FrameLayout.LayoutParams.WRAP_CONTENT + height = ViewGroup.LayoutParams.MATCH_PARENT + marginEnd = navMarginEnd + } + navButtonContainer.orientation = LinearLayout.HORIZONTAL + navButtonContainer.layoutParams = navButtonParams + + // Add the spaces in between the nav buttons + val spaceInBetween = resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween) + for (i in 0 until navButtonContainer.childCount) { + val navButton = navButtonContainer.getChildAt(i) + val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams + buttonLayoutParams.weight = 0f + when (i) { + 0 -> { + buttonLayoutParams.marginEnd = spaceInBetween / 2 + } + navButtonContainer.childCount - 1 -> { + buttonLayoutParams.marginStart = spaceInBetween / 2 + } + else -> { + buttonLayoutParams.marginStart = spaceInBetween / 2 + buttonLayoutParams.marginEnd = spaceInBetween / 2 + } + } + } + } +}
\ No newline at end of file diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java new file mode 100644 index 0000000000..38b6dfd39b --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.overlay; + +import android.content.Context; +import android.view.View; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.LauncherPrefs; +import com.android.launcher3.R; +import com.android.launcher3.dot.DotInfo; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.popup.PopupDataProvider; +import com.android.launcher3.taskbar.BaseTaskbarContext; +import com.android.launcher3.taskbar.TaskbarActivityContext; +import com.android.launcher3.taskbar.TaskbarControllers; +import com.android.launcher3.taskbar.TaskbarDragController; +import com.android.launcher3.taskbar.TaskbarStashController; +import com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView; +import com.android.launcher3.util.OnboardingPrefs; + +/** + * Window context for the taskbar overlays such as All Apps and EDU. + * <p> + * Overlays have their own window and need a window context. Some properties are delegated to the + * {@link TaskbarActivityContext} such as {@link PopupDataProvider}. + */ +public class TaskbarOverlayContext extends BaseTaskbarContext { + private final TaskbarActivityContext mTaskbarContext; + private final OnboardingPrefs<TaskbarOverlayContext> mOnboardingPrefs; + + private final TaskbarOverlayController mOverlayController; + private final TaskbarDragController mDragController; + private final TaskbarOverlayDragLayer mDragLayer; + + // We automatically stash taskbar when All Apps is opened in gesture navigation mode. + private final boolean mWillTaskbarBeVisuallyStashed; + private final int mStashedTaskbarHeight; + + public TaskbarOverlayContext( + Context windowContext, + TaskbarActivityContext taskbarContext, + TaskbarControllers controllers) { + super(windowContext); + mTaskbarContext = taskbarContext; + mOverlayController = controllers.taskbarOverlayController; + mDragController = new TaskbarDragController(this); + mDragController.init(controllers); + mOnboardingPrefs = new OnboardingPrefs<>(this, LauncherPrefs.getPrefs(this)); + mDragLayer = new TaskbarOverlayDragLayer(this); + + TaskbarStashController taskbarStashController = controllers.taskbarStashController; + mWillTaskbarBeVisuallyStashed = taskbarStashController.supportsVisualStashing(); + mStashedTaskbarHeight = taskbarStashController.getStashedHeight(); + } + + boolean willTaskbarBeVisuallyStashed() { + return mWillTaskbarBeVisuallyStashed; + } + + int getStashedTaskbarHeight() { + return mStashedTaskbarHeight; + } + + public TaskbarOverlayController getOverlayController() { + return mOverlayController; + } + + @Override + public DeviceProfile getDeviceProfile() { + return mOverlayController.getLauncherDeviceProfile(); + } + + @Override + public TaskbarDragController getDragController() { + return mDragController; + } + + @Override + public TaskbarOverlayDragLayer getDragLayer() { + return mDragLayer; + } + + @Override + public TaskbarAllAppsContainerView getAppsView() { + return mDragLayer.findViewById(R.id.apps_view); + } + + @Override + public OnboardingPrefs<TaskbarOverlayContext> getOnboardingPrefs() { + return mOnboardingPrefs; + } + + @Override + public boolean isBindingItems() { + return mTaskbarContext.isBindingItems(); + } + + @Override + public View.OnClickListener getItemOnClickListener() { + return mTaskbarContext.getItemOnClickListener(); + } + + @Override + public PopupDataProvider getPopupDataProvider() { + return mTaskbarContext.getPopupDataProvider(); + } + + @Override + public DotInfo getDotInfoForItem(ItemInfo info) { + return mTaskbarContext.getDotInfoForItem(info); + } + + @Override + public void onDragStart() {} + + @Override + public void onDragEnd() { + mOverlayController.maybeCloseWindow(); + } + + @Override + public void onPopupVisibilityChanged(boolean isVisible) {} +} diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java new file mode 100644 index 0000000000..476e0a8bab --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.overlay; + +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + +import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; +import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE; +import static com.android.launcher3.LauncherState.ALL_APPS; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; + +import androidx.annotation.Nullable; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.taskbar.TaskbarActivityContext; +import com.android.launcher3.taskbar.TaskbarControllers; +import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.shared.system.TaskStackChangeListeners; + +import java.util.Optional; + +/** + * Handles the Taskbar overlay window lifecycle. + * <p> + * Overlays need to be inflated in a separate window so that have the correct hierarchy. For + * instance, they need to be below the notification tray. If there are multiple overlays open, the + * same window is used. + */ +public final class TaskbarOverlayController { + + private static final String WINDOW_TITLE = "Taskbar Overlay"; + + private final TaskbarActivityContext mTaskbarContext; + private final Context mWindowContext; + private final TaskbarOverlayProxyView mProxyView; + private final LayoutParams mLayoutParams; + + private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() { + @Override + public void onTaskStackChanged() { + mProxyView.close(false); + } + + @Override + public void onTaskMovedToFront(int taskId) { + mProxyView.close(false); + } + }; + + private DeviceProfile mLauncherDeviceProfile; + private @Nullable TaskbarOverlayContext mOverlayContext; + private TaskbarControllers mControllers; // Initialized in init. + + public TaskbarOverlayController( + TaskbarActivityContext taskbarContext, DeviceProfile launcherDeviceProfile) { + mTaskbarContext = taskbarContext; + mWindowContext = mTaskbarContext.createWindowContext(TYPE_APPLICATION_OVERLAY, null); + mProxyView = new TaskbarOverlayProxyView(); + mLayoutParams = createLayoutParams(); + mLauncherDeviceProfile = launcherDeviceProfile; + } + + /** Initialize the controller. */ + public void init(TaskbarControllers controllers) { + mControllers = controllers; + } + + /** + * Creates a window for Taskbar overlays, if it does not already exist. Returns the window + * context for the current overlay window. + */ + public TaskbarOverlayContext requestWindow() { + if (mOverlayContext == null) { + mOverlayContext = new TaskbarOverlayContext( + mWindowContext, mTaskbarContext, mControllers); + } + + if (!mProxyView.isOpen()) { + mProxyView.show(); + Optional.ofNullable(mOverlayContext.getSystemService(WindowManager.class)) + .ifPresent(m -> m.addView(mOverlayContext.getDragLayer(), mLayoutParams)); + TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener); + } + + return mOverlayContext; + } + + /** Hides the current overlay window with animation. */ + public void hideWindow() { + mProxyView.close(true); + } + + /** + * Removes the overlay window from the hierarchy, if all floating views are closed and there is + * no system drag operation in progress. + * <p> + * This method should be called after an exit animation finishes, if applicable. + */ + @SuppressLint("WrongConstant") + void maybeCloseWindow() { + if (mOverlayContext != null && (AbstractFloatingView.hasOpenView(mOverlayContext, TYPE_ALL) + || mOverlayContext.getDragController().isSystemDragInProgress())) { + return; + } + mProxyView.close(false); + onDestroy(); + } + + /** Destroys the controller and any overlay window if present. */ + public void onDestroy() { + TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener); + Optional.ofNullable(mOverlayContext) + .map(c -> c.getSystemService(WindowManager.class)) + .ifPresent(m -> m.removeViewImmediate(mOverlayContext.getDragLayer())); + mOverlayContext = null; + } + + /** The current device profile for the overlay window. */ + public DeviceProfile getLauncherDeviceProfile() { + return mLauncherDeviceProfile; + } + + /** Updates {@link DeviceProfile} instance for Taskbar's overlay window. */ + public void updateLauncherDeviceProfile(DeviceProfile dp) { + mLauncherDeviceProfile = dp; + Optional.ofNullable(mOverlayContext).ifPresent(c -> { + AbstractFloatingView.closeAllOpenViewsExcept(c, false, TYPE_REBIND_SAFE); + c.dispatchDeviceProfileChanged(); + }); + } + + /** The default open duration for overlays. */ + public int getOpenDuration() { + return ALL_APPS.getTransitionDuration(mTaskbarContext, true); + } + + /** The default close duration for overlays. */ + public int getCloseDuration() { + return ALL_APPS.getTransitionDuration(mTaskbarContext, false); + } + + @SuppressLint("WrongConstant") + private LayoutParams createLayoutParams() { + LayoutParams layoutParams = new LayoutParams( + TYPE_APPLICATION_OVERLAY, + LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + layoutParams.setTitle(WINDOW_TITLE); + layoutParams.gravity = Gravity.BOTTOM; + layoutParams.packageName = mTaskbarContext.getPackageName(); + layoutParams.setFitInsetsTypes(0); // Handled by container view. + layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + layoutParams.setSystemApplicationOverlay(true); + return layoutParams; + } + + /** + * Proxy view connecting taskbar drag layer to the overlay window. + * + * Overlays are in a separate window and has its own drag layer, but this proxy lets its views + * behave as though they are in the taskbar drag layer. For instance, when the taskbar closes + * all {@link AbstractFloatingView} instances, the overlay window will also close. + */ + private class TaskbarOverlayProxyView extends AbstractFloatingView { + + private TaskbarOverlayProxyView() { + super(mTaskbarContext, null); + } + + private void show() { + mIsOpen = true; + mTaskbarContext.getDragLayer().addView(this); + } + + @Override + protected void handleClose(boolean animate) { + mTaskbarContext.getDragLayer().removeView(this); + Optional.ofNullable(mOverlayContext).ifPresent(c -> closeAllOpenViews(c, animate)); + } + + @Override + protected boolean isOfType(int type) { + return (type & TYPE_TASKBAR_OVERLAY_PROXY) != 0; + } + + @Override + public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + return false; + } + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java new file mode 100644 index 0000000000..044afd6725 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 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.launcher3.taskbar.overlay; + +import static android.view.KeyEvent.ACTION_UP; +import static android.view.KeyEvent.KEYCODE_BACK; +import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; + +import android.content.Context; +import android.graphics.Insets; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.WindowInsets; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.testing.TestLogging; +import com.android.launcher3.testing.shared.TestProtocol; +import com.android.launcher3.util.TouchController; +import com.android.launcher3.views.BaseDragLayer; + +/** Root drag layer for the Taskbar overlay window. */ +public class TaskbarOverlayDragLayer extends + BaseDragLayer<TaskbarOverlayContext> implements + ViewTreeObserver.OnComputeInternalInsetsListener { + + TaskbarOverlayDragLayer(Context context) { + super(context, null, 1); + setClipChildren(false); + recreateControllers(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + getViewTreeObserver().addOnComputeInternalInsetsListener(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + getViewTreeObserver().removeOnComputeInternalInsetsListener(this); + } + + @Override + public void recreateControllers() { + mControllers = new TouchController[]{mActivity.getDragController()}; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev); + return super.dispatchTouchEvent(ev); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) { + AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity); + if (topView != null && topView.onBackPressed()) { + return true; + } + } + return super.dispatchKeyEvent(event); + } + + @Override + public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) { + if (mActivity.getDragController().isSystemDragInProgress()) { + inoutInfo.touchableRegion.setEmpty(); + inoutInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); + } + } + + @Override + public WindowInsets onApplyWindowInsets(WindowInsets insets) { + return updateInsetsDueToStashing(insets); + } + + @Override + public void onViewRemoved(View child) { + super.onViewRemoved(child); + mActivity.getOverlayController().maybeCloseWindow(); + } + + /** + * Taskbar automatically stashes when opening all apps, but we don't report the insets as + * changing to avoid moving the underlying app. But internally, the apps view should still + * layout according to the stashed insets rather than the unstashed insets. So this method + * does two things: + * 1) Sets navigationBars bottom inset to stashedHeight. + * 2) Sets tappableInsets bottom inset to 0. + */ + private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) { + if (!mActivity.willTaskbarBeVisuallyStashed()) { + return oldInsets; + } + WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets); + + Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars()); + Insets newNavInsets = Insets.of(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right, + mActivity.getStashedTaskbarHeight()); + updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets); + + Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement()); + Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top, + oldTappableInsets.right, 0); + updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets); + + return updatedInsetsBuilder.build(); + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java index f450496b3b..ca7ce746b6 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java @@ -21,6 +21,9 @@ import android.content.pm.ShortcutInfo; import com.android.launcher3.Utilities; +/** + * A wrapper for the hidden API calls + */ public class ApiWrapper { public static final boolean TASKBAR_DRAWN_IN_PROCESS = true; diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java index 5f3a990750..bf0f8f72e9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java +++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java @@ -49,6 +49,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatorListeners; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.icons.IconNormalizer; @@ -271,7 +272,7 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView { mIsPinned = true; applyFromWorkspaceItem(info); setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE); - ((CellLayout.LayoutParams) getLayoutParams()).canReorder = true; + ((CellLayoutLayoutParams) getLayoutParams()).canReorder = true; invalidate(); } @@ -280,7 +281,7 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView { */ public void finishBinding(OnLongClickListener longClickListener) { setOnLongClickListener(longClickListener); - ((CellLayout.LayoutParams) getLayoutParams()).canReorder = false; + ((CellLayoutLayoutParams) getLayoutParams()).canReorder = false; setTextVisibility(false); verifyHighRes(); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java new file mode 100644 index 0000000000..6659fa0ee7 --- /dev/null +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2022 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.launcher3.uioverrides; + +import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID; + +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.os.Looper; + +import androidx.annotation.NonNull; + +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; +import com.android.launcher3.widget.LauncherWidgetHolder; + +import java.util.function.IntConsumer; + +/** + * {@link AppWidgetHost} that is used to receive the changes to the widgets without + * storing any {@code Activity} info like that of the launcher. + */ +final class QuickstepAppWidgetHost extends AppWidgetHost { + private final @NonNull Context mContext; + private final @NonNull IntConsumer mAppWidgetRemovedCallback; + private final @NonNull LauncherWidgetHolder.ProviderChangedListener mProvidersChangedListener; + + QuickstepAppWidgetHost(@NonNull Context context, @NonNull IntConsumer appWidgetRemovedCallback, + @NonNull LauncherWidgetHolder.ProviderChangedListener listener, + @NonNull Looper looper) { + super(context, APPWIDGET_HOST_ID, null, looper); + mContext = context; + mAppWidgetRemovedCallback = appWidgetRemovedCallback; + mProvidersChangedListener = listener; + } + + @Override + protected void onProvidersChanged() { + mProvidersChangedListener.notifyWidgetProvidersChanged(); + } + + @Override + public void onAppWidgetRemoved(int appWidgetId) { + mAppWidgetRemovedCallback.accept(appWidgetId); + } + + @Override + protected void onProviderChanged(int appWidgetId, @NonNull AppWidgetProviderInfo appWidget) { + LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo.fromProviderInfo( + mContext, appWidget); + super.onProviderChanged(appWidgetId, info); + // The super method updates the dimensions of the providerInfo. Update the + // launcher spans accordingly. + info.initSpans(mContext, LauncherAppState.getIDP(mContext)); + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 192ac6251e..9be569e895 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2022 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. @@ -29,7 +29,6 @@ import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; import static com.android.launcher3.anim.Interpolators.EMPHASIZED; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE; import static com.android.launcher3.config.FeatureFlags.ENABLE_WIDGET_PICKER_DEPTH; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; @@ -46,7 +45,6 @@ import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; -import static com.android.quickstep.util.BaseDepthController.WIDGET_DEPTH; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; import android.animation.AnimatorSet; @@ -60,17 +58,23 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.hardware.SensorManager; import android.hardware.devicestate.DeviceStateManager; +import android.media.permission.SafeCloseable; import android.os.Bundle; import android.os.CancellationSignal; import android.os.IBinder; import android.os.SystemProperties; +import android.util.Log; import android.view.Display; import android.view.HapticFeedbackConstants; +import android.view.RemoteAnimationTarget; import android.view.View; +import android.view.WindowManagerGlobal; import android.window.SplashScreen; +import androidx.annotation.BinderThread; import androidx.annotation.Nullable; +import com.android.app.viewcapture.ViewCapture; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherSettings.Favorites; @@ -96,10 +100,12 @@ import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.proxy.ProxyActivityStarter; import com.android.launcher3.proxy.StartActivityParams; import com.android.launcher3.statehandlers.DepthController; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.taskbar.TaskbarManager; +import com.android.launcher3.uioverrides.QuickstepWidgetHolder.QuickstepHolderFactory; import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory; import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController; import com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController; @@ -118,10 +124,9 @@ import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.util.PendingRequestArgs; import com.android.launcher3.util.PendingSplitSelectInfo; import com.android.launcher3.util.RunnableList; -import com.android.launcher3.util.SafeCloseable; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.launcher3.util.TouchController; -import com.android.launcher3.widget.LauncherAppWidgetHost; +import com.android.launcher3.widget.LauncherWidgetHolder; import com.android.quickstep.OverviewCommandHelper; import com.android.quickstep.RecentsModel; import com.android.quickstep.SystemUiProxy; @@ -133,19 +138,22 @@ import com.android.quickstep.util.QuickstepOnboardingPrefs; import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.util.SplitSelectStateController; +import com.android.quickstep.util.SplitToWorkspaceController; +import com.android.quickstep.util.SplitWithKeyboardShortcutController; import com.android.quickstep.util.TISBindHelper; -import com.android.quickstep.util.ViewCapture; +import com.android.quickstep.views.DesktopTaskView; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.unfold.UnfoldSharedComponent; import com.android.systemui.unfold.UnfoldTransitionFactory; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig; import com.android.systemui.unfold.config.UnfoldTransitionConfig; import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider; import com.android.systemui.unfold.system.DeviceStateManagerFoldProvider; +import com.android.systemui.unfold.updates.RotationChangeProvider; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -165,6 +173,7 @@ public class QuickstepLauncher extends Launcher { private FixedContainerItems mAllAppsPredictions; private HotseatPredictionController mHotseatPredictionController; private DepthController mDepthController; + private DesktopVisibilityController mDesktopVisibilityController; private QuickstepTransitionManager mAppTransitionManager; private OverviewActionsView mActionsView; private TISBindHelper mTISBindHelper; @@ -174,7 +183,13 @@ public class QuickstepLauncher extends Launcher { // Will be updated when dragging from taskbar. private @Nullable DragOptions mNextWorkspaceDragOptions = null; private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider; + private @Nullable RotationChangeProvider mRotationChangeProvider; private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController; + + private SplitSelectStateController mSplitSelectStateController; + private SplitWithKeyboardShortcutController mSplitWithKeyboardShortcutController; + private SplitToWorkspaceController mSplitToWorkspaceController; + /** * If Launcher restarted while in the middle of an Overview split select, it needs this data to * recover. In all other cases this will remain null. @@ -183,16 +198,22 @@ public class QuickstepLauncher extends Launcher { private SafeCloseable mViewCapture; + private boolean mEnableWidgetDepth; + @Override protected void setupViews() { super.setupViews(); mActionsView = findViewById(R.id.overview_actions_view); - RecentsView overviewPanel = (RecentsView) getOverviewPanel(); - SplitSelectStateController controller = + RecentsView overviewPanel = getOverviewPanel(); + mSplitSelectStateController = new SplitSelectStateController(this, mHandler, getStateManager(), getDepthController(), getStatsLogManager()); - overviewPanel.init(mActionsView, controller); + overviewPanel.init(mActionsView, mSplitSelectStateController); + mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(this, + mSplitSelectStateController); + mSplitToWorkspaceController = new SplitToWorkspaceController(this, + mSplitSelectStateController); mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize()); mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this)); @@ -202,7 +223,13 @@ public class QuickstepLauncher extends Launcher { mTISBindHelper = new TISBindHelper(this, this::onTISConnected); mDepthController = new DepthController(this); + mDesktopVisibilityController = new DesktopVisibilityController(this); mHotseatPredictionController = new HotseatPredictionController(this); + + mEnableWidgetDepth = ENABLE_WIDGET_PICKER_DEPTH.get() + && SystemProperties.getBoolean("ro.launcher.depth.widget", true); + getWorkspace().addOverlayCallback(progress -> + onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX)); } @Override @@ -311,6 +338,17 @@ public class QuickstepLauncher extends Launcher { super.showAllAppsFromIntent(alreadyOnHome); } + protected void onItemClicked(View view) { + if (!mSplitToWorkspaceController.handleSecondAppSelectionForSplit(view)) { + QuickstepLauncher.super.getItemOnClickListener().onClick(view); + } + } + + @Override + public View.OnClickListener getItemOnClickListener() { + return this::onItemClicked; + } + @Override public Stream<SystemShortcut.Factory> getSupportedShortcuts() { Stream<SystemShortcut.Factory> base = Stream.of(WellbeingModel.SHORTCUT_FACTORY); @@ -392,7 +430,8 @@ public class QuickstepLauncher extends Launcher { super.onDestroy(); mHotseatPredictionController.destroy(); - mViewCapture.close(); + mSplitWithKeyboardShortcutController.onDestroy(); + if (mViewCapture != null) mViewCapture.close(); } @Override @@ -477,10 +516,13 @@ public class QuickstepLauncher extends Launcher { return new QuickstepAtomicAnimationFactory(this); } - protected LauncherAppWidgetHost createAppWidgetHost() { - LauncherAppWidgetHost appWidgetHost = super.createAppWidgetHost(); - appWidgetHost.setInteractionHandler(new QuickstepInteractionHandler(this)); - return appWidgetHost; + @Override + protected LauncherWidgetHolder createAppWidgetHolder() { + final QuickstepHolderFactory factory = + (QuickstepHolderFactory) LauncherWidgetHolder.HolderFactory.newFactory(this); + return factory.newInstance(this, + appWidgetId -> getWorkspace().removeWidget(appWidgetId), + new QuickstepInteractionHandler(this)); } @Override @@ -492,7 +534,9 @@ public class QuickstepLauncher extends Launcher { } addMultiWindowModeChangedListener(mDepthController); initUnfoldTransitionProgressProvider(); - mViewCapture = ViewCapture.INSTANCE.get(this).startCapture(getWindow()); + if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { + mViewCapture = ViewCapture.getInstance().startCapture(getWindow()); + } } @Override @@ -559,21 +603,8 @@ public class QuickstepLauncher extends Launcher { @Override protected void onScreenOff() { super.onScreenOff(); - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - RecentsView recentsView = getOverviewPanel(); - recentsView.finishRecentsAnimation(true /* toRecents */, null); - } - } - - /** - * {@code LauncherOverlayCallbacks} scroll amount. - * Indicates transition progress to -1 screen. - * @param progress From 0 to 1. - */ - @Override - public void onScrollChanged(float progress) { - super.onScrollChanged(progress); - onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX); + RecentsView recentsView = getOverviewPanel(); + recentsView.finishRecentsAnimation(true /* toRecents */, null); } @Override @@ -586,12 +617,9 @@ public class QuickstepLauncher extends Launcher { public void onWidgetsTransition(float progress) { super.onWidgetsTransition(progress); onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX); - // Change of wallpaper depth in widget picker is disabled for tests as it causes flakiness - // on very slow cuttlefish devices. - if (ENABLE_WIDGET_PICKER_DEPTH.get() && !Utilities.IS_RUNNING_IN_TEST_HARNESS) { - WIDGET_DEPTH.set(getDepthController(), - Utilities.mapToRange(progress, 0f, 1f, 0f, getDeviceProfile().bottomSheetDepth, - EMPHASIZED)); + if (mEnableWidgetDepth) { + getDepthController().widgetDepth.setValue(Utilities.mapToRange( + progress, 0f, 1f, 0f, getDeviceProfile().bottomSheetDepth, EMPHASIZED)); } } @@ -637,6 +665,20 @@ public class QuickstepLauncher extends Launcher { } @Override + public void setResumed() { + if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) { + DesktopVisibilityController controller = mDesktopVisibilityController; + if (controller != null && controller.areFreeformTasksVisible()) { + // Return early to skip setting activity to appear as resumed + // TODO(b/255649902): shouldn't be needed when we have a separate launcher state + // for desktop that we can use to control other parts of launcher + return; + } + } + super.setResumed(); + } + + @Override protected void onDeferredResumed() { super.onDeferredResumed(); handlePendingActivityRequest(); @@ -667,8 +709,8 @@ public class QuickstepLauncher extends Launcher { private void initUnfoldTransitionProgressProvider() { final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig(); if (config.isEnabled()) { - mUnfoldTransitionProgressProvider = - UnfoldTransitionFactory.createUnfoldTransitionProgressProvider( + UnfoldSharedComponent unfoldComponent = + UnfoldTransitionFactory.createUnfoldSharedComponent( /* context= */ this, config, ProxyScreenStatusProvider.INSTANCE, @@ -680,14 +722,23 @@ public class QuickstepLauncher extends Launcher { getMainThreadHandler(), getMainExecutor(), /* backgroundExecutor= */ THREAD_POOL_EXECUTOR, - /* tracingTagPrefix= */ "launcher" + /* tracingTagPrefix= */ "launcher", + WindowManagerGlobal.getWindowManagerService() ); + mUnfoldTransitionProgressProvider = unfoldComponent.getUnfoldTransitionProvider() + .orElseThrow(() -> new IllegalStateException( + "Trying to create UnfoldTransitionProgressProvider when the " + + "transition is disabled")); + + mRotationChangeProvider = unfoldComponent.getRotationChangeProvider(); mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController( - this, + /* launcher= */ this, getWindowManager(), - mUnfoldTransitionProgressProvider + mUnfoldTransitionProgressProvider, + mRotationChangeProvider ); + Log.d("b/261320823", "initUnfoldTransitionProgressProvider completed"); } } @@ -699,6 +750,10 @@ public class QuickstepLauncher extends Launcher { return mTaskbarUIController; } + public SplitSelectStateController getSplitSelectStateController() { + return mSplitSelectStateController; + } + public <T extends OverviewActionsView> T getActionsView() { return (T) mActionsView; } @@ -720,6 +775,10 @@ public class QuickstepLauncher extends Launcher { return mDepthController; } + public DesktopVisibilityController getDesktopVisibilityController() { + return mDesktopVisibilityController; + } + @Nullable public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() { return mUnfoldTransitionProgressProvider; @@ -749,8 +808,8 @@ public class QuickstepLauncher extends Launcher { QuickstepTransitionManager appTransitionManager = getAppTransitionManager(); appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() { @Override - public AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { + public AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets) { // On the first call clear the reference. signal.cancel(); @@ -812,6 +871,12 @@ public class QuickstepLauncher extends Launcher { return activityOptions; } + @Override + @BinderThread + public void enterStageSplitFromRunningApp(boolean leftOrTop) { + mSplitWithKeyboardShortcutController.enterStageSplit(leftOrTop); + } + /** * Adds a new launch cookie for the activity launch if supported. * @@ -872,7 +937,11 @@ public class QuickstepLauncher extends Launcher { // When changing screens, force moving to rest state similar to StatefulActivity.onStop, as // StatefulActivity isn't called consistently. if ((flags & CHANGE_ACTIVE_SCREEN) != 0) { - getStateManager().moveToRestState(); + // Do not animate moving to rest state, as it can clash with Launcher#onIdpChanged + // where reapplyUi calls StateManager's reapplyState during the state change animation, + // and cancel the state change unexpectedly. The screen will be off during screen + // transition, hiding the unanimated transition. + getStateManager().moveToRestState(/* isAnimated = */false); } if ((flags & CHANGE_NAVIGATION_MODE) != 0) { diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java new file mode 100644 index 0000000000..a8edd511f6 --- /dev/null +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java @@ -0,0 +1,270 @@ +/** + * Copyright (C) 2022 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.launcher3.uioverrides; + +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; + +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetHostView; +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.util.SparseArray; +import android.widget.RemoteViews; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.UiThread; +import androidx.annotation.WorkerThread; + +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.model.WidgetsModel; +import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.LauncherAppWidgetHostView; +import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; +import com.android.launcher3.widget.LauncherWidgetHolder; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.function.Consumer; +import java.util.function.IntConsumer; + +/** + * {@link LauncherWidgetHolder} that puts the app widget host in the background + */ +public final class QuickstepWidgetHolder extends LauncherWidgetHolder { + private static final List<QuickstepWidgetHolder> sHolders = new ArrayList<>(); + private static final SparseArray<QuickstepWidgetHolderListener> sListeners = + new SparseArray<>(); + + private static AppWidgetHost sWidgetHost = null; + + private final @Nullable RemoteViews.InteractionHandler mInteractionHandler; + + private final @NonNull IntConsumer mAppWidgetRemovedCallback; + + private final ArrayList<ProviderChangedListener> mProviderChangedListeners = new ArrayList<>(); + + @Thunk + QuickstepWidgetHolder(@NonNull Context context, + @Nullable IntConsumer appWidgetRemovedCallback, + @Nullable RemoteViews.InteractionHandler interactionHandler) { + super(context, appWidgetRemovedCallback); + mAppWidgetRemovedCallback = appWidgetRemovedCallback != null ? appWidgetRemovedCallback + : i -> {}; + mInteractionHandler = interactionHandler; + sHolders.add(this); + } + + @Override + @NonNull + protected AppWidgetHost createHost(@NonNull Context context, + @Nullable IntConsumer appWidgetRemovedCallback) { + if (sWidgetHost == null) { + sWidgetHost = new QuickstepAppWidgetHost(context.getApplicationContext(), + i -> MAIN_EXECUTOR.execute(() -> + sHolders.forEach(h -> h.mAppWidgetRemovedCallback.accept(i))), + () -> MAIN_EXECUTOR.execute(() -> + sHolders.forEach(h -> h.mProviderChangedListeners.forEach( + ProviderChangedListener::notifyWidgetProvidersChanged))), + UI_HELPER_EXECUTOR.getLooper()); + if (!WidgetsModel.GO_DISABLE_WIDGETS) { + sWidgetHost.startListening(); + } + } + return sWidgetHost; + } + + /** + * Delete the specified app widget from the host + * @param appWidgetId The ID of the app widget to be deleted + */ + @Override + public void deleteAppWidgetId(int appWidgetId) { + super.deleteAppWidgetId(appWidgetId); + sListeners.remove(appWidgetId); + } + + /** + * Called when the launcher is destroyed + */ + @Override + public void destroy() { + sHolders.remove(this); + } + + /** + * Add a listener that is triggered when the providers of the widgets are changed + * @param listener The listener that notifies when the providers changed + */ + @Override + public void addProviderChangeListener( + @NonNull LauncherWidgetHolder.ProviderChangedListener listener) { + mProviderChangedListeners.add(listener); + } + + /** + * Remove the specified listener from the host + * @param listener The listener that is to be removed from the host + */ + @Override + public void removeProviderChangeListener( + LauncherWidgetHolder.ProviderChangedListener listener) { + mProviderChangedListeners.remove(listener); + } + + /** + * Stop the host from updating the widget views + */ + @Override + public void stopListening() { + if (WidgetsModel.GO_DISABLE_WIDGETS) { + return; + } + + sWidgetHost.setAppWidgetHidden(); + setListeningFlag(false); + } + + /** + * Create a view for the specified app widget + * @param context The activity context for which the view is created + * @param appWidgetId The ID of the widget + * @param appWidget The {@link LauncherAppWidgetProviderInfo} of the widget + * @return A view for the widget + */ + @NonNull + @Override + public LauncherAppWidgetHostView createView(@NonNull Context context, int appWidgetId, + @NonNull LauncherAppWidgetProviderInfo appWidget) { + LauncherAppWidgetHostView widgetView = getPendingView(appWidgetId); + if (widgetView != null) { + removePendingView(appWidgetId); + } else { + widgetView = new LauncherAppWidgetHostView(context); + } + widgetView.setInteractionHandler(mInteractionHandler); + widgetView.setAppWidget(appWidgetId, appWidget); + + QuickstepWidgetHolderListener listener = sListeners.get(appWidgetId); + if (listener == null) { + listener = new QuickstepWidgetHolderListener(this, widgetView); + sWidgetHost.setListener(appWidgetId, listener); + sListeners.put(appWidgetId, listener); + } else { + listener.resetView(this, widgetView); + } + + return widgetView; + } + + /** + * Clears all the views from the host + */ + @Override + public void clearViews() { + for (int i = sListeners.size() - 1; i >= 0; i--) { + sListeners.valueAt(i).mView.remove(this); + } + } + + private static class QuickstepWidgetHolderListener + implements AppWidgetHost.AppWidgetHostListener { + @NonNull + private final Map<QuickstepWidgetHolder, AppWidgetHostView> mView = new WeakHashMap<>(); + + @Nullable + private RemoteViews mRemoteViews = null; + + QuickstepWidgetHolderListener(@NonNull QuickstepWidgetHolder holder, + @NonNull LauncherAppWidgetHostView view) { + mView.put(holder, view); + } + + @UiThread + public void resetView(@NonNull QuickstepWidgetHolder holder, + @NonNull AppWidgetHostView view) { + mView.put(holder, view); + view.updateAppWidget(mRemoteViews); + } + + @Override + @WorkerThread + public void onUpdateProviderInfo(@Nullable AppWidgetProviderInfo info) { + mRemoteViews = null; + executeOnMainExecutor(v -> v.onUpdateProviderInfo(info)); + } + + @Override + @WorkerThread + public void updateAppWidget(@Nullable RemoteViews views) { + mRemoteViews = views; + executeOnMainExecutor(v -> v.updateAppWidget(mRemoteViews)); + } + + @Override + @WorkerThread + public void onViewDataChanged(int viewId) { + executeOnMainExecutor(v -> v.onViewDataChanged(viewId)); + } + + private void executeOnMainExecutor(Consumer<AppWidgetHostView> consumer) { + MAIN_EXECUTOR.execute(() -> mView.values().forEach(consumer)); + } + } + + /** + * {@code HolderFactory} subclass that takes an interaction handler as one of the parameters + * when creating a new instance. + */ + public static class QuickstepHolderFactory extends HolderFactory { + + @SuppressWarnings("unused") + public QuickstepHolderFactory(Context context) { } + + @Override + public LauncherWidgetHolder newInstance(@NonNull Context context, + @Nullable IntConsumer appWidgetRemovedCallback) { + return newInstance(context, appWidgetRemovedCallback, null); + } + + /** + * @param context The context of the caller + * @param appWidgetRemovedCallback The callback that is called when widgets are removed + * @param interactionHandler The interaction handler when the widgets are clicked + * @return A new {@link LauncherWidgetHolder} instance + */ + public LauncherWidgetHolder newInstance(@NonNull Context context, + @Nullable IntConsumer appWidgetRemovedCallback, + @Nullable RemoteViews.InteractionHandler interactionHandler) { + + if (!FeatureFlags.ENABLE_WIDGET_HOST_IN_BACKGROUND.get()) { + return new LauncherWidgetHolder(context, appWidgetRemovedCallback) { + @Override + protected AppWidgetHost createHost(Context context, + @Nullable IntConsumer appWidgetRemovedCallback) { + AppWidgetHost host = super.createHost(context, appWidgetRemovedCallback); + host.setInteractionHandler(interactionHandler); + return host; + } + }; + } + return new QuickstepWidgetHolder(context, appWidgetRemovedCallback, interactionHandler); + } + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 910b99b36a..e8e83288cd 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -20,6 +20,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS; import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE; +import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA; import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS; import static com.android.quickstep.views.RecentsView.TASK_MODALNESS; @@ -31,17 +32,18 @@ import android.animation.AnimatorSet; import android.annotation.TargetApi; import android.os.Build; import android.util.FloatProperty; +import android.util.Log; import android.util.Pair; import androidx.annotation.NonNull; import com.android.launcher3.LauncherState; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.PagedOrientationHandler; -import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.util.AnimUtils; import com.android.quickstep.util.SplitAnimationTimings; import com.android.quickstep.views.ClearAllButton; @@ -88,6 +90,13 @@ public final class RecentsViewStateController extends // While animating into recents, update the visible task data as needed builder.addOnFrameCallback(() -> mRecentsView.loadVisibleTaskData(FLAG_UPDATE_ALL)); mRecentsView.updateEmptyMessage(); + // TODO(b/246283207): Remove logging once root cause of flake detected. + if (Utilities.IS_RUNNING_IN_TEST_HARNESS) { + Log.d("b/246283207", "RecentsView#setStateWithAnimationInternal getCurrentPage(): " + + mRecentsView.getCurrentPage() + + ", getScrollForPage(getCurrentPage())): " + + mRecentsView.getScrollForPage(mRecentsView.getCurrentPage())); + } } else { builder.addListener( AnimatorListeners.forSuccessCallback(mRecentsView::resetTaskVisuals)); @@ -155,7 +164,7 @@ public final class RecentsViewStateController extends clearAllButtonAlpha, LINEAR); float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0; propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(), - MultiValueAlpha.VALUE, overviewButtonAlpha, config.getInterpolator( + MULTI_PROPERTY_VALUE, overviewButtonAlpha, config.getInterpolator( ANIM_OVERVIEW_ACTIONS_FADE, LINEAR)); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java index 5afeca7e3b..faa900b714 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java +++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java @@ -18,11 +18,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.SharedPreferences; -import com.android.launcher3.Utilities; -import com.android.systemui.shared.plugins.PluginEnabler; - import androidx.preference.PreferenceDataStore; +import com.android.launcher3.LauncherPrefs; +import com.android.systemui.shared.plugins.PluginEnabler; + public class PluginEnablerImpl extends PreferenceDataStore implements PluginEnabler { private static final String PREFIX_PLUGIN_ENABLED = "PLUGIN_ENABLED_"; @@ -30,7 +30,7 @@ public class PluginEnablerImpl extends PreferenceDataStore implements PluginEnab final private SharedPreferences mSharedPrefs; public PluginEnablerImpl(Context context) { - mSharedPrefs = Utilities.getDevicePrefs(context); + mSharedPrefs = LauncherPrefs.getDevicePrefs(context); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java index fe0bca6646..e3d386cae6 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java +++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java @@ -28,9 +28,9 @@ import com.android.launcher3.Utilities; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.systemui.plugins.Plugin; import com.android.systemui.plugins.PluginListener; +import com.android.systemui.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginActionManager; import com.android.systemui.shared.plugins.PluginInstance; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManagerImpl; import com.android.systemui.shared.plugins.PluginPrefs; import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager; diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index fd184c63a4..2a42175b5b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -20,12 +20,11 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAP import android.content.Context; -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.util.Themes; +import com.android.launcher3.views.ActivityContext; /** * Definition for AllApps state @@ -40,7 +39,7 @@ public class AllAppsState extends LauncherState { } @Override - public <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable> + public <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext> int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState) { return isToState ? context.getDeviceProfile().allAppsOpenDuration @@ -78,7 +77,7 @@ public class AllAppsState extends LauncherState { } @Override - protected <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable> + protected <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext> float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) { if (context.getDeviceProfile().isTablet) { return context.getDeviceProfile().bottomSheetDepth; diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index 4150d40bea..733c6a8b48 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -26,6 +26,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsTransitionController; +import com.android.launcher3.config.FeatureFlags; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; @@ -96,7 +97,7 @@ public class BackgroundAppState extends OverviewState { @Override public int getWorkspaceScrimColor(Launcher launcher) { DeviceProfile dp = launcher.getDeviceProfile(); - if (dp.isTaskbarPresentInApps) { + if (dp.isTaskbarPresentInApps && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) { return launcher.getColor(R.color.taskbar_background); } return Color.TRANSPARENT; diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index 6f07568cf5..d075750330 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -26,6 +26,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.Themes; import com.android.quickstep.util.LayoutUtils; @@ -104,7 +105,12 @@ public class OverviewState extends LauncherState { @Override public boolean isTaskbarStashed(Launcher launcher) { - return true; + return !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get(); + } + + @Override + public boolean isTaskbarAlignedWithHotseat(Launcher launcher) { + return !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get(); } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java index bcd722f4e3..5eeeb36981 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java @@ -113,19 +113,19 @@ public class QuickstepAtomicAnimationFactory extends config.setInterpolator(ANIM_OVERVIEW_FADE, FINAL_FRAME); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, EMPHASIZED_DECELERATE); config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME); + + // Scroll RecentsView to page 0 as it goes offscreen, if necessary. + int numPagesToScroll = overview.getNextPage() - DEFAULT_PAGE; + long scrollDuration = Math.min(MAX_PAGE_SCROLL_DURATION, + numPagesToScroll * PER_PAGE_SCROLL_DURATION); + config.duration = Math.max(config.duration, scrollDuration); + overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration)); } else { config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL_DEACCEL); config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f)); config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7); } - // Scroll RecentsView to page 0 as it goes offscreen, if necessary. - int numPagesToScroll = overview.getNextPage() - DEFAULT_PAGE; - long scrollDuration = Math.min(MAX_PAGE_SCROLL_DURATION, - numPagesToScroll * PER_PAGE_SCROLL_DURATION); - config.duration = Math.max(config.duration, scrollDuration); - overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration)); - Workspace<?> workspace = mActivity.getWorkspace(); // Start from a higher workspace scale, but only if we're invisible so we don't jump. boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE; @@ -197,7 +197,8 @@ public class QuickstepAtomicAnimationFactory extends config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, timings.getActionsFadeStartOffset(), timings.getActionsFadeEndOffset())); - } else if (fromState == NORMAL && toState == OVERVIEW_SPLIT_SELECT) { + } else if ((fromState == NORMAL || fromState == ALL_APPS) + && toState == OVERVIEW_SPLIT_SELECT) { // Splitting from Home is currently only available on tablets SplitAnimationTimings timings = SplitAnimationTimings.TABLET_HOME_TO_SPLIT; config.setInterpolator(ANIM_SCRIM_FADE, clampToProgress(LINEAR, diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index 30bb892c9a..40dfd82f5d 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java @@ -25,7 +25,6 @@ import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PULL_BACK_TRANSLATION; import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -139,9 +138,7 @@ public class NavBarToHomeTouchController implements TouchController, AnimatorControllerWithResistance.createRecentsResistanceFromOverviewAnim(mLauncher, builder); - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - builder.addOnFrameCallback(recentsView::redrawLiveTile); - } + builder.addOnFrameCallback(recentsView::redrawLiveTile); AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_TASK_MENU); } else if (mStartState == ALL_APPS) { @@ -182,11 +179,9 @@ public class NavBarToHomeTouchController implements TouchController, boolean success = interpolatedProgress >= SUCCESS_TRANSITION_PROGRESS || (velocity < 0 && fling); if (success) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - RecentsView recentsView = mLauncher.getOverviewPanel(); - recentsView.switchToScreenshot(null, - () -> recentsView.finishRecentsAnimation(true /* toRecents */, null)); - } + RecentsView recentsView = mLauncher.getOverviewPanel(); + recentsView.switchToScreenshot(null, + () -> recentsView.finishRecentsAnimation(true /* toRecents */, null)); if (mStartState.overviewUi) { new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState)) .animateWithVelocity(velocity); diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java index 918b3c1bf8..b5afda388a 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -25,7 +25,8 @@ import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; -import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC; +import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import android.animation.ObjectAnimator; @@ -41,11 +42,11 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.uioverrides.QuickstepLauncher; +import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.OverviewToHomeAnim; -import com.android.quickstep.util.VibratorWrapper; import com.android.quickstep.views.RecentsView; /** @@ -86,6 +87,11 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch @Override protected boolean canInterceptTouch(MotionEvent ev) { mDidTouchStartInNavBar = (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0; + boolean isOneHandedModeActive = (SystemUiProxy.INSTANCE.get(mLauncher) + .getLastSystemUiStateFlags() & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0; + // Reset touch slop multiplier to default 1.0f if one-handed-mode is not active + mDetector.setTouchSlopMultiplier( + isOneHandedModeActive ? ONE_HANDED_ACTIVATED_SLOP_MULTIPLIER : 1f /* default */); return super.canInterceptTouch(ev) && !mLauncher.isInState(HINT_STATE); } @@ -277,14 +283,4 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch private float dpiFromPx(float pixels) { return Utilities.dpiFromPx(pixels, mLauncher.getResources().getDisplayMetrics().densityDpi); } - - @Override - public void onOneHandedModeStateChanged(boolean activated) { - if (activated) { - mDetector.setTouchSlopMultiplier(ONE_HANDED_ACTIVATED_SLOP_MULTIPLIER); - } else { - // Reset touch slop multiplier to default 1.0f - mDetector.setTouchSlopMultiplier(1f /* default */); - } - } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index 922679b5f4..e0cb0b4ddb 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -41,8 +41,8 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM; import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT; import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP; +import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs; -import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET; import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA; import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS; @@ -62,6 +62,7 @@ import android.view.animation.Interpolator; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.states.StateAnimationConfig; @@ -69,12 +70,11 @@ import com.android.launcher3.touch.BaseSwipeDetector; import com.android.launcher3.touch.BothAxesSwipeDetector; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.TouchController; -import com.android.quickstep.AnimatedFloat; +import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.MotionPauseDetector; -import com.android.quickstep.util.VibratorWrapper; import com.android.quickstep.util.WorkspaceRevealAnim; import com.android.quickstep.views.LauncherRecentsView; import com.android.quickstep.views.RecentsView; diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index 9efbc34a17..8368f9ca03 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -186,12 +186,17 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr case MotionEvent.ACTION_DOWN: InteractionJankMonitorWrapper.begin( mLauncher.getRootView(), InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS); + InteractionJankMonitorWrapper.begin( + mLauncher.getRootView(), + InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: InteractionJankMonitorWrapper.cancel( InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS); + InteractionJankMonitorWrapper.cancel( + InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE); break; } return super.onControllerInterceptTouchEvent(ev); @@ -204,6 +209,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr if (newToState != ALL_APPS) { InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS); } + if (newToState != NORMAL) { + InteractionJankMonitorWrapper.cancel( + InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE); + } } @Override @@ -211,6 +220,9 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr super.onReachedFinalState(toState); if (toState == ALL_APPS) { InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS); + } else if (toState == NORMAL) { + InteractionJankMonitorWrapper.end( + InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE); } } @@ -218,5 +230,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr protected void clearState() { super.clearState(); InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS); + InteractionJankMonitorWrapper.cancel( + InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE); } } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java index c49848a5b4..eddc50c64f 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java @@ -41,8 +41,9 @@ import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.FlingBlockCheck; import com.android.launcher3.util.TouchController; +import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.views.BaseDragLayer; -import com.android.quickstep.util.VibratorWrapper; +import com.android.quickstep.util.VibrationConstants; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; @@ -61,7 +62,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity> Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1; public static final float TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE = 1f; public static final VibrationEffect TASK_DISMISS_VIBRATION_FALLBACK = - VibratorWrapper.EFFECT_TEXTURE_TICK; + VibrationConstants.EFFECT_TEXTURE_TICK; protected final T mActivity; private final SingleAxisSwipeDetector mDetector; diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index f3630c187b..8409475e4c 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -15,6 +15,7 @@ */ package com.android.quickstep; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; @@ -26,7 +27,7 @@ import static com.android.launcher3.PagedView.INVALID_PAGE; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_REVISED_THRESHOLDS; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE; @@ -37,6 +38,7 @@ import static com.android.launcher3.uioverrides.QuickstepLauncher.ENABLE_PIP_KEE import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK; +import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs; import static com.android.quickstep.GestureState.GestureEndTarget.HOME; import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK; @@ -48,12 +50,10 @@ import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_CANCELE import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED; import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION; -import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION; +import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET; -import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -65,6 +65,7 @@ import android.app.ActivityManager; import android.app.WindowConfiguration; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.Rect; @@ -74,8 +75,10 @@ import android.os.IBinder; import android.os.SystemClock; import android.util.Log; import android.view.MotionEvent; +import android.view.RemoteAnimationTarget; import android.view.View; import android.view.View.OnApplyWindowInsetsListener; +import android.view.ViewGroup; import android.view.ViewTreeObserver.OnDrawListener; import android.view.ViewTreeObserver.OnScrollChangedListener; import android.view.WindowInsets; @@ -93,14 +96,18 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; +import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulActivity; +import com.android.launcher3.taskbar.TaskbarUIController; import com.android.launcher3.tracing.InputConsumerProto; import com.android.launcher3.tracing.SwipeHandlerProto; import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.TraceHelper; +import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.util.WindowBounds; import com.android.quickstep.BaseActivityInterface.AnimationFactory; import com.android.quickstep.GestureState.GestureEndTarget; @@ -116,10 +123,10 @@ import com.android.quickstep.util.ProtoTracer; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.StaggeredWorkspaceAnim; +import com.android.quickstep.util.SurfaceTransaction; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.SwipePipToHomeAnimator; import com.android.quickstep.util.TaskViewSimulator; -import com.android.quickstep.util.VibratorWrapper; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; @@ -127,13 +134,15 @@ import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; +import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.startingsurface.SplashScreenExitAnimationUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.Optional; import java.util.function.Consumer; /** @@ -249,6 +258,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private static final float MAX_QUICK_SWITCH_RECENTS_SCALE_PROGRESS = 0.07f; + // Controls task thumbnail splash's reveal animation after landing on a task from quickswitch. + // These values match WindowManager/Shell starting_window_app_reveal_* config values. + private static final int SPLASH_FADE_OUT_DURATION = 133; + private static final int SPLASH_APP_REVEAL_DELAY = 83; + private static final int SPLASH_APP_REVEAL_DURATION = 266; + private static final int SPLASH_ANIMATION_DURATION = 349; + /** * Used as the page index for logging when we return to the last task at the end of the gesture. */ @@ -277,7 +293,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private boolean mWasLauncherAlreadyVisible; - private boolean mPassedOverviewThreshold; private boolean mGestureStarted; private boolean mLogDirectionUpOrLeft = true; private PointF mDownPos; @@ -286,6 +301,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; + private final int mSplashMainWindowShiftLength; + private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch; private SwipePipToHomeAnimator mSwipePipToHomeAnimator; @@ -298,6 +315,18 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, // Interpolate RecentsView scale from start of quick switch scroll until this scroll threshold private final float mQuickSwitchScaleScrollThreshold; + private final int mTaskbarAppWindowThreshold; + private final int mTaskbarHomeOverviewThreshold; + private final int mTaskbarCatchUpThreshold; + private final boolean mTaskbarAlreadyOpen; + private final boolean mIsTaskbarAllAppsOpen; + private final boolean mIsTransientTaskbar; + // May be set to false when mIsTransientTaskbar is true. + private boolean mCanSlowSwipeGoHome = true; + + @Nullable + private RemoteAnimationTargets.ReleaseCheck mSwipePipToHomeReleaseCheck = null; + public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs, boolean continuingLastGesture, @@ -318,11 +347,32 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mTaskAnimationManager = taskAnimationManager; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; - mQuickSwitchScaleScrollThreshold = context.getResources().getDimension( - R.dimen.quick_switch_scaling_scroll_threshold); - initAfterSubclassConstructor(); + Resources res = context.getResources(); + mQuickSwitchScaleScrollThreshold = res + .getDimension(R.dimen.quick_switch_scaling_scroll_threshold); + + mSplashMainWindowShiftLength = -res + .getDimensionPixelSize(R.dimen.starting_surface_exit_animation_window_shift_length); + + initTransitionEndpoints(mRemoteTargetHandles[0].getTaskViewSimulator() + .getOrientationState().getLauncherDeviceProfile()); initStateCallbacks(); + + mIsTransientTaskbar = mDp.isTaskbarPresent + && DisplayController.isTransientTaskbar(mActivity); + TaskbarUIController controller = mActivityInterface.getTaskbarController(); + mTaskbarAlreadyOpen = controller != null && !controller.isTaskbarStashed(); + mIsTaskbarAllAppsOpen = controller != null && controller.isTaskbarAllAppsOpen(); + mTaskbarAppWindowThreshold = res + .getDimensionPixelSize(ENABLE_TASKBAR_REVISED_THRESHOLDS.get() + ? R.dimen.taskbar_app_window_threshold_v2 + : R.dimen.taskbar_app_window_threshold); + mTaskbarHomeOverviewThreshold = res.getDimensionPixelSize( + ENABLE_TASKBAR_REVISED_THRESHOLDS.get() + ? R.dimen.taskbar_home_overview_threshold_v2 + : R.dimen.taskbar_home_overview_threshold); + mTaskbarCatchUpThreshold = res.getDimensionPixelSize(R.dimen.taskbar_catch_up_threshold); } @Nullable @@ -400,12 +450,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, this::resetStateForAnimationCancel); mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_FINISH_WITH_NO_END, this::resetStateForAnimationCancel); - - if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { - mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT - | STATE_SCREENSHOT_VIEW_SHOWN | STATE_CAPTURE_SCREENSHOT, - (b) -> mRecentsView.setRunningTaskHidden(!b)); - } } protected boolean onActivityInit(Boolean alreadyOnHome) { @@ -583,14 +627,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } private void onDeferredActivityLaunch() { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - mActivityInterface.switchRunningTaskViewToScreenshot( - null, () -> { - mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); - }); - } else { - mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); - } + mActivityInterface.switchRunningTaskViewToScreenshot( + null, () -> { + mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */); + }); } private void setupRecentsViewUi() { @@ -637,6 +677,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, public void onMotionPauseDetected() { mHasMotionEverBeenPaused = true; maybeUpdateRecentsAttachedState(true/* animate */, true/* moveFocusedTask */); + Optional.ofNullable(mActivityInterface.getTaskbarController()) + .ifPresent(TaskbarUIController::startTranslationSpring); performHapticFeedback(); } @@ -668,7 +710,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (!mDeviceState.isFullyGesturalNavMode() || mRecentsView == null) { return; } - RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationTargets != null + RemoteAnimationTarget runningTaskTarget = mRecentsAnimationTargets != null ? mRecentsAnimationTargets.findTask(mGestureState.getRunningTaskId()) : null; final boolean recentsAttachedToAppWindow; @@ -708,6 +750,15 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } } + /** + * Returns threshold that needs to be met in order for motion pause to be allowed. + */ + public float getThresholdToAllowMotionPause() { + return mIsTransientTaskbar + ? mTaskbarHomeOverviewThreshold + : 0; + } + public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) { setIsLikelyToStartNewTask(isLikelyToStartNewTask, true /* animate */); } @@ -770,14 +821,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, @UiThread @Override public void updateFinalShift() { - final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; - if (passed != mPassedOverviewThreshold) { - mPassedOverviewThreshold = passed; - if (mDeviceState.isTwoButtonNavMode() && !mGestureState.isHandlingAtomicEvent()) { - performHapticFeedback(); - } - } - updateSysUiFlags(mCurrentShift.value); applyScrollAndTransform(); @@ -829,11 +872,14 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(mContext, targets); mRecentsAnimationController = controller; mRecentsAnimationTargets = targets; + mSwipePipToHomeReleaseCheck = new RemoteAnimationTargets.ReleaseCheck(); + mSwipePipToHomeReleaseCheck.setCanRelease(true); + mRecentsAnimationTargets.addReleaseCheck(mSwipePipToHomeReleaseCheck); // Only initialize the device profile, if it has not been initialized before, as in some // configurations targets.homeContentInsets may not be correct. if (mActivity == null) { - RemoteAnimationTargetCompat primaryTaskTarget = targets.apps[0]; + RemoteAnimationTarget primaryTaskTarget = targets.apps[0]; // orientation state is independent of which remote target handle we use since both // should be pointing to the same one. Just choose index 0 for now since that works for // both split and non-split @@ -862,8 +908,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED, this::startInterceptingTouchesForGesture); mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED); - - mPassedOverviewThreshold = false; } @Override @@ -905,6 +949,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */); InteractionJankMonitorWrapper.begin(mRecentsView, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME); + InteractionJankMonitorWrapper.begin(mRecentsView, + InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS); rv.post(() -> rv.getViewTreeObserver().removeOnDrawListener(this)); } @@ -912,12 +958,34 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } notifyGestureStartedAsync(); setIsLikelyToStartNewTask(isLikelyToStartNewTask, false /* animate */); + + if (mIsTransientTaskbar && !mTaskbarAlreadyOpen && !isLikelyToStartNewTask) { + setClampScrollOffset(true); + } mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED); mGestureStarted = true; - SystemUiProxy.INSTANCE.get(mContext).notifySwipeUpGestureStarted(); } /** + * Sets whether or not we should clamp the scroll offset. + * This is used to avoid x-axis movement when swiping up transient taskbar. + * @param clampScrollOffset When true, we clamp the scroll to 0 before the clamp threshold is + * met. + */ + private void setClampScrollOffset(boolean clampScrollOffset) { + if (!mIsTransientTaskbar) { + return; + } + if (mRecentsView == null) { + mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT, + () -> mRecentsView.setClampScrollOffset(clampScrollOffset)); + return; + } + mRecentsView.setClampScrollOffset(clampScrollOffset); + } + + + /** * Notifies the launcher that the swipe gesture has started. This can be called multiple times. */ @UiThread @@ -941,26 +1009,27 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } /** - * @param endVelocity The velocity in the direction of the nav bar to the middle of the screen. - * @param velocity The x and y components of the velocity when the gesture ends. + * @param endVelocityPxPerMs The velocity in the direction of the nav bar to the middle of the + * screen. + * @param velocityPxPerMs The x and y components of the velocity when the gesture ends. * @param downPos The x and y value of where the gesture started. */ @UiThread - public void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) { + public void onGestureEnded(float endVelocityPxPerMs, PointF velocityPxPerMs, PointF downPos) { float flingThreshold = mContext.getResources() .getDimension(R.dimen.quickstep_fling_threshold_speed); boolean isFling = mGestureStarted && !mIsMotionPaused - && Math.abs(endVelocity) > flingThreshold; + && Math.abs(endVelocityPxPerMs) > flingThreshold; mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED); - boolean isVelocityVertical = Math.abs(velocity.y) > Math.abs(velocity.x); + boolean isVelocityVertical = Math.abs(velocityPxPerMs.y) > Math.abs(velocityPxPerMs.x); if (isVelocityVertical) { - mLogDirectionUpOrLeft = velocity.y < 0; + mLogDirectionUpOrLeft = velocityPxPerMs.y < 0; } else { - mLogDirectionUpOrLeft = velocity.x < 0; + mLogDirectionUpOrLeft = velocityPxPerMs.x < 0; } mDownPos = downPos; - Runnable handleNormalGestureEndCallback = () -> - handleNormalGestureEnd(endVelocity, isFling, velocity, /* isCancel= */ false); + Runnable handleNormalGestureEndCallback = () -> handleNormalGestureEnd( + endVelocityPxPerMs, isFling, velocityPxPerMs, /* isCancel= */ false); if (mRecentsView != null) { mRecentsView.runOnPageScrollsInitialized(handleNormalGestureEndCallback); } else { @@ -1006,12 +1075,16 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, InteractionJankMonitorWrapper.cancel( InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME); } + if (endTarget != RECENTS) { + InteractionJankMonitorWrapper.cancel( + InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS); + } switch (endTarget) { case HOME: mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT); - // Notify swipe-to-home (recents animation) is finished - SystemUiProxy.INSTANCE.get(mContext).notifySwipeToHomeFinished(); + // Notify the SysUI to use fade-in animation when entering PiP + SystemUiProxy.INSTANCE.get(mContext).setPipAnimationTypeToAlpha(); break; case RECENTS: mStateCallback.setState(STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT @@ -1038,7 +1111,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } /** @return Whether this was the task we were waiting to appear, and thus handled it. */ - protected boolean handleTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) { + protected boolean handleTaskAppeared(RemoteAnimationTarget[] appearedTaskTarget) { if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) { return false; } @@ -1051,8 +1124,20 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return false; } + private float dpiFromPx(float pixels) { + return Utilities.dpiFromPx(pixels, mContext.getResources().getDisplayMetrics().densityDpi); + } + private GestureEndTarget calculateEndTarget( - PointF velocity, float endVelocity, boolean isFlingY, boolean isCancel) { + PointF velocityPxPerMs, float endVelocityPxPerMs, boolean isFlingY, boolean isCancel) { + ActiveGestureLog.INSTANCE.addLog( + new ActiveGestureLog.CompoundString("calculateEndTarget: velocities=(x=") + .append(Float.toString(dpiFromPx(velocityPxPerMs.x))) + .append("dp/ms, y=") + .append(Float.toString(dpiFromPx(velocityPxPerMs.y))) + .append("dp/ms), angle=") + .append(Double.toString(Math.toDegrees(Math.atan2( + -velocityPxPerMs.y, velocityPxPerMs.x))))); if (mGestureState.isHandlingAtomicEvent()) { // Button mode, this is only used to go to recents. @@ -1063,9 +1148,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (isCancel) { endTarget = LAST_TASK; } else if (isFlingY) { - endTarget = calculateEndTargetForFlingY(velocity, endVelocity); + endTarget = calculateEndTargetForFlingY(velocityPxPerMs, endVelocityPxPerMs); } else { - endTarget = calculateEndTargetForNonFling(velocity); + endTarget = calculateEndTargetForNonFling(velocityPxPerMs); } if (mDeviceState.isOverviewDisabled() && endTarget == RECENTS) { @@ -1086,20 +1171,11 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return willGoToNewTask || isCenteredOnNewTask ? NEW_TASK : LAST_TASK; } - if (!mDeviceState.isFullyGesturalNavMode()) { - return (!hasReachedOverviewThreshold() && willGoToNewTask) ? NEW_TASK : RECENTS; - } return willGoToNewTask ? NEW_TASK : HOME; } private GestureEndTarget calculateEndTargetForNonFling(PointF velocity) { final boolean isScrollingToNewTask = isScrollingToNewTask(); - final boolean reachedOverviewThreshold = hasReachedOverviewThreshold(); - if (!mDeviceState.isFullyGesturalNavMode()) { - return reachedOverviewThreshold && mGestureStarted - ? RECENTS - : (isScrollingToNewTask ? NEW_TASK : LAST_TASK); - } // Fully gestural mode. final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources() @@ -1112,10 +1188,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return RECENTS; } else if (isScrollingToNewTask) { return NEW_TASK; - } else if (reachedOverviewThreshold) { - return HOME; } - return LAST_TASK; + return velocity.y < 0 && mCanSlowSwipeGoHome ? HOME : LAST_TASK; } private boolean isScrollingToNewTask() { @@ -1131,17 +1205,25 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return runningTaskIndex >= 0 && mRecentsView.getNextPage() != runningTaskIndex; } - private boolean hasReachedOverviewThreshold() { - return mCurrentShift.value > MIN_PROGRESS_FOR_OVERVIEW; + /** + * Sets whether a slow swipe can go to the HOME end target when the user lets go. A slow swipe + * for this purpose must meet two criteria: + * 1) y-velocity is less than quickstep_fling_threshold_speed + * AND + * 2) motion pause has not been detected (possibly because + * {@link MotionPauseDetector#setDisallowPause} has been called with disallowPause == true) + */ + public void setCanSlowSwipeGoHome(boolean canSlowSwipeGoHome) { + mCanSlowSwipeGoHome = canSlowSwipeGoHome; } @UiThread - private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity, - boolean isCancel) { + private void handleNormalGestureEnd( + float endVelocityPxPerMs, boolean isFling, PointF velocityPxPerMs, boolean isCancel) { long duration = MAX_SWIPE_DURATION; float currentShift = mCurrentShift.value; - final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity, - isFling, isCancel); + final GestureEndTarget endTarget = calculateEndTarget( + velocityPxPerMs, endVelocityPxPerMs, isFling, isCancel); // Set the state, but don't notify until the animation completes mGestureState.setEndTarget(endTarget, false /* isAtomic */); mAnimationFactory.setEndTarget(endTarget); @@ -1154,16 +1236,16 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, duration = Math.min(MAX_SWIPE_DURATION, expectedDuration); startShift = currentShift; } else { - startShift = Utilities.boundToRange(currentShift - velocity.y + startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y * getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor); if (mTransitionDragLength > 0) { - float distanceToTravel = (endShift - currentShift) * mTransitionDragLength; + float distanceToTravel = (endShift - currentShift) * mTransitionDragLength; - // we want the page's snap velocity to approximately match the velocity at - // which the user flings, so we scale the duration by a value near to the - // derivative of the scroll interpolator at zero, ie. 2. - long baseDuration = Math.round(Math.abs(distanceToTravel / velocity.y)); - duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration); + // we want the page's snap velocity to approximately match the velocity at + // which the user flings, so we scale the duration by a value near to the + // derivative of the scroll interpolator at zero, ie. 2. + long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y)); + duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration); } } Interpolator interpolator; @@ -1219,16 +1301,19 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, // Let RecentsView handle the scrolling to the task, which we launch in startNewTask() // or resumeLastTask(). + Runnable onPageTransitionEnd = () -> { + mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED); + setClampScrollOffset(false); + }; if (mRecentsView != null) { ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent .SET_ON_PAGE_TRANSITION_END_CALLBACK); - mRecentsView.setOnPageTransitionEndCallback( - () -> mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED)); + mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd); } else { - mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED); + onPageTransitionEnd.run(); } - animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocity); + animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs); } private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask) { @@ -1277,7 +1362,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, protected abstract HomeAnimationFactory createHomeAnimationFactory( ArrayList<IBinder> launchCookies, long duration, boolean isTargetTranslucent, - boolean appCanEnterPip, RemoteAnimationTargetCompat runningTaskTarget); + boolean appCanEnterPip, RemoteAnimationTarget runningTaskTarget); private final TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() { @Override @@ -1304,6 +1389,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, // If we are transitioning to launcher, then listen for the activity to be restarted while // the transition is in progress if (mGestureState.getEndTarget().isLauncher) { + // This is also called when the launcher is resumed, in order to clear the pending + // widgets that have yet to be configured. + DragView.removeAllViews(mActivity); + TaskStackChangeListeners.getInstance().registerTaskStackListener( mActivityRestartListener); @@ -1323,7 +1412,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (mGestureState.getEndTarget() == HOME) { getOrientationHandler().adjustFloatingIconStartVelocity(velocityPxPerMs); - final RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationTargets != null + final RemoteAnimationTarget runningTaskTarget = mRecentsAnimationTargets != null ? mRecentsAnimationTargets.findTask(mGestureState.getRunningTaskId()) : null; final ArrayList<IBinder> cookies = runningTaskTarget != null @@ -1347,9 +1436,16 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mSwipePipToHomeAnimator = createWindowAnimationToPip( homeAnimFactory, runningTaskTarget, start); mSwipePipToHomeAnimators[0] = mSwipePipToHomeAnimator; + if (mSwipePipToHomeReleaseCheck != null) { + mSwipePipToHomeReleaseCheck.setCanRelease(false); + } windowAnim = mSwipePipToHomeAnimators; } else { mSwipePipToHomeAnimator = null; + if (mSwipePipToHomeReleaseCheck != null) { + mSwipePipToHomeReleaseCheck.setCanRelease(true); + mSwipePipToHomeReleaseCheck = null; + } windowAnim = createWindowAnimationToHome(start, homeAnimFactory); windowAnim[0].addAnimatorListener(new AnimationSuccessListener() { @@ -1433,7 +1529,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } } - private int calculateWindowRotation(RemoteAnimationTargetCompat runningTaskTarget, + private int calculateWindowRotation(RemoteAnimationTarget runningTaskTarget, RecentsOrientedState orientationState) { if (runningTaskTarget.rotationChange != 0 && TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) { @@ -1446,7 +1542,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, @Nullable private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory, - RemoteAnimationTargetCompat runningTaskTarget, float startProgress) { + RemoteAnimationTarget runningTaskTarget, float startProgress) { // Directly animate the app to PiP (picture-in-picture) mode final ActivityManager.RunningTaskInfo taskInfo = runningTaskTarget.taskInfo; final RecentsOrientedState orientationState = mRemoteTargetHandles[0].getTaskViewSimulator() @@ -1652,10 +1748,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, private void resumeLastTask() { if (mRecentsAnimationController != null) { mRecentsAnimationController.finish(false /* toRecents */, null); - ActiveGestureLog.INSTANCE.addLog( - /* event= */ "finishRecentsAnimation", - /* extras= */ false, - /* gestureEvent= */ FINISH_RECENTS_ANIMATION); } doLogGesture(LAST_TASK, null); reset(); @@ -1719,8 +1811,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } private void invalidateHandler() { - if (!ENABLE_QUICKSTEP_LIVE_TILE.get() || !mActivityInterface.isInLiveTileMode() - || mGestureState.getEndTarget() != RECENTS) { + if (!mActivityInterface.isInLiveTileMode() || mGestureState.getEndTarget() != RECENTS) { mInputConsumerProxy.destroy(); mTaskAnimationManager.setLiveTileCleanUpHandler(null); } @@ -1765,10 +1856,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, * continued quick switch gesture, which cancels the previous handler but doesn't invalidate it. */ private void resetLauncherListeners() { - // Reset the callback for deferred activity launches - if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { - mActivityInterface.setOnDeferredActivityLaunchCallback(null); - } mActivity.getRootView().setOnApplyWindowInsetsListener(null); mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener); @@ -1790,7 +1877,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED); } else { final int runningTaskId = mGestureState.getRunningTaskId(); - final boolean refreshView = !ENABLE_QUICKSTEP_LIVE_TILE.get() /* refreshView */; boolean finishTransitionPosted = false; if (mRecentsAnimationController != null) { // Update the screenshot of the task @@ -1799,16 +1885,27 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, if (mRecentsAnimationController == null) return; final ThumbnailData taskSnapshot = mRecentsAnimationController.screenshotTask(runningTaskId); + // If split case, we should update all split tasks snapshot + if (mIsSwipeForSplit) { + int[] splitTaskIds = TopTaskTracker.INSTANCE.get( + mContext).getRunningSplitTaskIds(); + for (int i = 0; i < splitTaskIds.length; i++) { + // Skip running one because done above. + if (splitTaskIds[i] == runningTaskId) continue; + + mRecentsAnimationController.screenshotTask(splitTaskIds[i]); + } + } MAIN_EXECUTOR.execute(() -> { mTaskSnapshot = taskSnapshot; - if (!updateThumbnail(runningTaskId, refreshView)) { + if (!updateThumbnail(runningTaskId, false /* refreshView */)) { setScreenshotCapturedState(); } }); }); return; } - finishTransitionPosted = updateThumbnail(runningTaskId, refreshView); + finishTransitionPosted = updateThumbnail(runningTaskId, false /* refreshView */); } if (!finishTransitionPosted) { setScreenshotCapturedState(); @@ -1846,22 +1943,19 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } private void finishCurrentTransitionToRecents() { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { + if (mRecentsView != null + && mActivityInterface.getDesktopVisibilityController() != null + && mActivityInterface.getDesktopVisibilityController().areFreeformTasksVisible()) { + mRecentsView.switchToScreenshot(() -> { + mRecentsView.finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, + () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); + }); + } else { mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); if (mRecentsAnimationController != null) { mRecentsAnimationController.detachNavigationBarFromApp(true); } - } else if (!hasTargets() || mRecentsAnimationController == null) { - // If there are no targets or the animation not started, then there is nothing to finish - mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED); - } else { - mRecentsAnimationController.finish(true /* toRecents */, - () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } - ActiveGestureLog.INSTANCE.addLog( - /* event= */ "finishRecentsAnimation", - /* extras= */ true, - /* gestureEvent= */ FINISH_RECENTS_ANIMATION); } private void finishCurrentTransitionToHome() { @@ -1873,10 +1967,10 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, finishRecentsControllerToHome( () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED)); } - ActiveGestureLog.INSTANCE.addLog( - /* event= */ "finishRecentsAnimation", - /* extras= */ true, - /* gestureEvent= */ FINISH_RECENTS_ANIMATION); + if (mSwipePipToHomeReleaseCheck != null) { + mSwipePipToHomeReleaseCheck.setCanRelease(true); + mSwipePipToHomeReleaseCheck = null; + } doLogGesture(HOME, mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView()); } @@ -1920,31 +2014,20 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } endLauncherTransitionController(); mRecentsView.onSwipeUpAnimationSuccess(); - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - mTaskAnimationManager.setLiveTileCleanUpHandler(() -> { - mRecentsView.cleanupRemoteTargets(); - mInputConsumerProxy.destroy(); - }); - mTaskAnimationManager.enableLiveTileRestartListener(); - } + mTaskAnimationManager.setLiveTileCleanUpHandler(() -> { + mRecentsView.cleanupRemoteTargets(); + mInputConsumerProxy.destroy(); + }); + mTaskAnimationManager.enableLiveTileRestartListener(); SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG); doLogGesture(RECENTS, mRecentsView.getCurrentPageTaskView()); reset(); } - private static boolean isNotInRecents(RemoteAnimationTargetCompat app) { + private static boolean isNotInRecents(RemoteAnimationTarget app) { return app.isNotInRecents - || app.activityType == ACTIVITY_TYPE_HOME; - } - - /** - * To be called at the end of constructor of subclasses. This calls various methods which can - * depend on proper class initialization. - */ - protected void initAfterSubclassConstructor() { - initTransitionEndpoints(mRemoteTargetHandles[0].getTaskViewSimulator() - .getOrientationState().getLauncherDeviceProfile()); + || app.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME; } protected void performHapticFeedback() { @@ -1989,6 +2072,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, mGestureState.updateLastStartedTaskId(taskId); boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds() .contains(taskId); + if (!hasTaskPreviouslyAppeared) { + ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED); + } nextTask.launchTask(success -> { resultCallback.accept(success); if (success) { @@ -2058,19 +2144,59 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, } @Override - public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) { + public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) { if (mRecentsAnimationController != null) { if (handleTaskAppeared(appearedTaskTargets)) { - mRecentsAnimationController.finish(false /* toRecents */, - null /* onFinishComplete */); - ActiveGestureLog.INSTANCE.addLog( - /* event= */ "finishRecentsAnimation", - /* extras= */ false, - /* gestureEvent= */ FINISH_RECENTS_ANIMATION); + Optional<RemoteAnimationTarget> taskTargetOptional = + Arrays.stream(appearedTaskTargets) + .filter(targetCompat -> + targetCompat.taskId == mGestureState.getLastStartedTaskId()) + .findFirst(); + if (!taskTargetOptional.isPresent()) { + finishRecentsAnimationOnTasksAppeared(); + return; + } + RemoteAnimationTarget taskTarget = taskTargetOptional.get(); + TaskView taskView = mRecentsView.getTaskViewByTaskId(taskTarget.taskId); + if (taskView == null || !taskView.getThumbnail().shouldShowSplashView()) { + finishRecentsAnimationOnTasksAppeared(); + return; + } + + ViewGroup splashView = mActivity.getDragLayer(); + + // When revealing the app with launcher splash screen, make the app visible + // and behind the splash view before the splash is animated away. + SurfaceTransactionApplier surfaceApplier = + new SurfaceTransactionApplier(splashView); + SurfaceTransaction transaction = new SurfaceTransaction(); + for (RemoteAnimationTarget target : appearedTaskTargets) { + transaction.forSurface(target.leash).setAlpha(1).setLayer(-1); + } + surfaceApplier.scheduleApply(transaction); + + SplashScreenExitAnimationUtils.startAnimations(splashView, taskTarget.leash, + mSplashMainWindowShiftLength, new TransactionPool(), new Rect(), + SPLASH_ANIMATION_DURATION, SPLASH_FADE_OUT_DURATION, + /* iconStartAlpha= */ 0, /* brandingStartAlpha= */ 0, + SPLASH_APP_REVEAL_DELAY, SPLASH_APP_REVEAL_DURATION, + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + finishRecentsAnimationOnTasksAppeared(); + } + }); } } } + private void finishRecentsAnimationOnTasksAppeared() { + if (mRecentsAnimationController != null) { + mRecentsAnimationController.finish(false /* toRecents */, null /* onFinishComplete */); + } + ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false); + } + /** * @return The index of the TaskView in RecentsView whose taskId matches the task that will * resume if we finish the controller. @@ -2157,6 +2283,35 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>, return scaleProgress; } + /** + * Overrides the gesture displacement to keep the app window at the bottom of the screen while + * the transient taskbar is being swiped in. + * + * There is also a catch up period so that the window can start moving 1:1 with the swipe. + */ + @Override + protected float overrideDisplacementForTransientTaskbar(float displacement) { + if (!mIsTransientTaskbar) { + return displacement; + } + + if (mTaskbarAlreadyOpen || mIsTaskbarAllAppsOpen) { + return displacement; + } + + if (displacement < mTaskbarAppWindowThreshold) { + return 0; + } + + // "Catch up" with the displacement at mTaskbarCatchUpThreshold. + if (displacement < mTaskbarCatchUpThreshold) { + return Utilities.mapToRange(displacement, mTaskbarAppWindowThreshold, + mTaskbarCatchUpThreshold, 0, mTaskbarCatchUpThreshold, ACCEL_DEACCEL); + } + + return displacement; + } + private void setDividerShown(boolean shown, boolean immediate) { if (mDividerAnimator != null) { mDividerAnimator.cancel(); diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 226b173ecd..274b686ea4 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -30,6 +30,7 @@ import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.content.Context; @@ -40,6 +41,7 @@ import android.graphics.Rect; import android.os.Build; import android.view.Gravity; import android.view.MotionEvent; +import android.view.RemoteAnimationTarget; import android.view.View; import androidx.annotation.Nullable; @@ -50,6 +52,7 @@ import com.android.launcher3.R; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statehandlers.DepthController; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarUIController; @@ -61,7 +64,6 @@ import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.recents.model.ThumbnailData; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.HashMap; import java.util.Optional; @@ -118,9 +120,6 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T public abstract void onAssistantVisibilityChanged(float visibility); - /** Called when one handed mode activated or deactivated. */ - public abstract void onOneHandedModeStateChanged(boolean activated); - public abstract AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState, boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback); @@ -141,6 +140,11 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T } @Nullable + public DesktopVisibilityController getDesktopVisibilityController() { + return null; + } + + @Nullable public abstract TaskbarUIController getTaskbarController(); public final boolean isResumed() { @@ -161,7 +165,7 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T public abstract boolean switchToRecentsIfVisible(Runnable onCompleteCallback); public abstract Rect getOverviewWindowBounds( - Rect homeBounds, RemoteAnimationTargetCompat target); + Rect homeBounds, RemoteAnimationTarget target); public abstract boolean allowMinimizeSplitScreen(); @@ -187,7 +191,8 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T * Closes any overlays. */ public void closeOverlay() { - Optional.ofNullable(getTaskbarController()).ifPresent(TaskbarUIController::hideAllApps); + Optional.ofNullable(getTaskbarController()).ifPresent( + TaskbarUIController::hideOverlayWindow); } public void switchRunningTaskViewToScreenshot(HashMap<Integer, ThumbnailData> thumbnailDatas, @@ -474,33 +479,38 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T if (mIsAttachedToWindow == attached && animate) { return; } - mIsAttachedToWindow = attached; - RecentsView recentsView = mActivity.getOverviewPanel(); - if (attached) { - mHasEverAttachedToWindow = true; - } + mActivity.getStateManager() + .cancelStateElementAnimation(INDEX_RECENTS_FADE_ANIM); + mActivity.getStateManager() + .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM); + + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + mIsAttachedToWindow = attached; + if (attached) { + mHasEverAttachedToWindow = true; + } + }}); + + long animationDuration = animate ? RECENTS_ATTACH_DURATION : 0; Animator fadeAnim = mActivity.getStateManager() .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0); + fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2); + fadeAnim.setDuration(animationDuration); + animatorSet.play(fadeAnim); - float fromTranslation = attached ? 1 : 0; + float fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get( + mActivity.getOverviewPanel()); float toTranslation = attached ? 0 : 1; - mActivity.getStateManager() - .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM); - if (!recentsView.isShown() && animate) { - ADJACENT_PAGE_HORIZONTAL_OFFSET.set(recentsView, fromTranslation); - } else { - fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get(recentsView); - } - if (!animate) { - ADJACENT_PAGE_HORIZONTAL_OFFSET.set(recentsView, toTranslation); - } else { - mActivity.getStateManager().createStateElementAnimation( - INDEX_RECENTS_TRANSLATE_X_ANIM, - fromTranslation, toTranslation).start(); - } - fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2); - fadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0).start(); + Animator translationAnimator = mActivity.getStateManager().createStateElementAnimation( + INDEX_RECENTS_TRANSLATE_X_ANIM, fromTranslation, toTranslation); + translationAnimator.setDuration(animationDuration); + animatorSet.play(translationAnimator); + animatorSet.start(); } @Override diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java index 466abbe62f..ae9fb0b385 100644 --- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java @@ -15,7 +15,6 @@ */ package com.android.quickstep; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.util.NavigationMode.NO_BUTTON; import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP; import static com.android.quickstep.fallback.RecentsState.DEFAULT; @@ -26,6 +25,7 @@ import android.animation.AnimatorSet; import android.content.Context; import android.graphics.Rect; import android.view.MotionEvent; +import android.view.RemoteAnimationTarget; import androidx.annotation.Nullable; @@ -39,7 +39,6 @@ import com.android.quickstep.fallback.RecentsState; import com.android.quickstep.util.ActivityInitListener; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.views.RecentsView; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.Consumer; import java.util.function.Predicate; @@ -78,11 +77,6 @@ public final class FallbackActivityInterface extends // set to zero prior to this class becoming active. } - @Override - public void onOneHandedModeStateChanged(boolean activated) { - // Do nothing for FallbackActivityInterface - } - /** 6 */ @Override public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState, @@ -120,8 +114,7 @@ public final class FallbackActivityInterface extends public RecentsView getVisibleRecentsView() { RecentsActivity activity = getCreatedActivity(); if (activity != null) { - if (activity.hasBeenResumed() - || (ENABLE_QUICKSTEP_LIVE_TILE.get() && isInLiveTileMode())) { + if (activity.hasBeenResumed() || isInLiveTileMode()) { return activity.getOverviewPanel(); } } @@ -134,7 +127,7 @@ public final class FallbackActivityInterface extends } @Override - public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) { + public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTarget target) { // TODO: Remove this once b/77875376 is fixed return target.screenSpaceBounds; } diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java index 99f7bdd2e7..d4bebea55f 100644 --- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java @@ -15,6 +15,7 @@ */ package com.android.quickstep; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.content.Intent.EXTRA_COMPONENT_NAME; import static android.content.Intent.EXTRA_USER; @@ -26,7 +27,6 @@ import static com.android.launcher3.GestureNavContract.EXTRA_REMOTE_CALLBACK; import static com.android.launcher3.anim.AnimatorListeners.forEndCallback; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME; import android.animation.ObjectAnimator; import android.annotation.TargetApi; @@ -48,6 +48,7 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; +import android.view.RemoteAnimationTarget; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; @@ -57,6 +58,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.SpringAnimationBuilder; @@ -65,12 +67,11 @@ import com.android.launcher3.util.DisplayController; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.fallback.RecentsState; import com.android.quickstep.util.RectFSpringAnim; +import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; import com.android.quickstep.util.TransformParams; import com.android.quickstep.util.TransformParams.BuilderProxy; import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.system.InputConsumerController; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -125,24 +126,24 @@ public class FallbackSwipeHandler extends } } - private void updateHomeActivityTransformDuringSwipeUp(SurfaceParams.Builder builder, - RemoteAnimationTargetCompat app, TransformParams params) { + private void updateHomeActivityTransformDuringSwipeUp(SurfaceProperties builder, + RemoteAnimationTarget app, TransformParams params) { setHomeScaleAndAlpha(builder, app, mCurrentShift.value, Utilities.boundToRange(1 - mCurrentShift.value, 0, 1)); } - private void setHomeScaleAndAlpha(SurfaceParams.Builder builder, - RemoteAnimationTargetCompat app, float verticalShift, float alpha) { + private void setHomeScaleAndAlpha(SurfaceProperties builder, + RemoteAnimationTarget app, float verticalShift, float alpha) { float scale = Utilities.mapRange(verticalShift, 1, mMaxLauncherScale); mTmpMatrix.setScale(scale, scale, app.localBounds.exactCenterX(), app.localBounds.exactCenterY()); - builder.withMatrix(mTmpMatrix).withAlpha(alpha); + builder.setMatrix(mTmpMatrix).setAlpha(alpha); } @Override protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies, long duration, boolean isTargetTranslucent, boolean appCanEnterPip, - RemoteAnimationTargetCompat runningTaskTarget) { + RemoteAnimationTarget runningTaskTarget) { mAppCanEnterPip = appCanEnterPip; if (appCanEnterPip) { return new FallbackPipToHomeAnimationFactory(); @@ -154,7 +155,7 @@ public class FallbackSwipeHandler extends private void startHomeIntent( @Nullable FallbackHomeAnimationFactory gestureContractAnimationFactory, - @Nullable RemoteAnimationTargetCompat runningTaskTarget) { + @Nullable RemoteAnimationTarget runningTaskTarget) { ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0); Intent intent = new Intent(mGestureState.getHomeIntent()); if (gestureContractAnimationFactory != null && runningTaskTarget != null) { @@ -164,7 +165,7 @@ public class FallbackSwipeHandler extends } @Override - protected boolean handleTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) { + protected boolean handleTaskAppeared(RemoteAnimationTarget[] appearedTaskTarget) { if (mActiveAnimationFactory != null && mActiveAnimationFactory.handleHomeTaskAppeared(appearedTaskTarget)) { mActiveAnimationFactory = null; @@ -279,13 +280,13 @@ public class FallbackSwipeHandler extends return mTargetRect; } - private void updateRecentsActivityTransformDuringHomeAnim(SurfaceParams.Builder builder, - RemoteAnimationTargetCompat app, TransformParams params) { - builder.withAlpha(mRecentsAlpha.value); + private void updateRecentsActivityTransformDuringHomeAnim(SurfaceProperties builder, + RemoteAnimationTarget app, TransformParams params) { + builder.setAlpha(mRecentsAlpha.value); } - private void updateHomeActivityTransformDuringHomeAnim(SurfaceParams.Builder builder, - RemoteAnimationTargetCompat app, TransformParams params) { + private void updateHomeActivityTransformDuringHomeAnim(SurfaceProperties builder, + RemoteAnimationTarget app, TransformParams params) { setHomeScaleAndAlpha(builder, app, mVerticalShiftForScale.value, mHomeAlpha.value); } @@ -304,12 +305,12 @@ public class FallbackSwipeHandler extends } } - public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) { - RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0]; - if (appearedTaskTarget.activityType == ACTIVITY_TYPE_HOME) { + public boolean handleHomeTaskAppeared(RemoteAnimationTarget[] appearedTaskTargets) { + RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0]; + if (appearedTaskTarget.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME) { RemoteAnimationTargets targets = new RemoteAnimationTargets( - new RemoteAnimationTargetCompat[] {appearedTaskTarget}, - new RemoteAnimationTargetCompat[0], new RemoteAnimationTargetCompat[0], + new RemoteAnimationTarget[] {appearedTaskTarget}, + new RemoteAnimationTarget[0], new RemoteAnimationTarget[0], appearedTaskTarget.mode); mHomeAlphaParams.setTargetSet(targets); updateHomeAlpha(); diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index bcd96878e3..31b78b3ec3 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -21,13 +21,13 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERV import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_HOME; -import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_LAST_TASK; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_NEW_TASK; import android.annotation.Nullable; import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; +import android.view.RemoteAnimationTarget; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulActivity; @@ -37,7 +37,6 @@ import com.android.quickstep.TopTaskTracker.CachedTaskInfo; import com.android.quickstep.util.ActiveGestureErrorDetector; import com.android.quickstep.util.ActiveGestureLog; import com.android.systemui.shared.recents.model.ThumbnailData; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.io.PrintWriter; import java.util.ArrayList; @@ -143,7 +142,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL private CachedTaskInfo mRunningTask; private GestureEndTarget mEndTarget; - private RemoteAnimationTargetCompat mLastAppearedTaskTarget; + private RemoteAnimationTarget mLastAppearedTaskTarget; private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>(); private int mLastStartedTaskId = -1; private RecentsAnimationController mRecentsAnimationController; @@ -272,7 +271,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL /** * Updates the last task that appeared during this gesture. */ - public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) { + public void updateLastAppearedTaskTarget(RemoteAnimationTarget lastAppearedTaskTarget) { mLastAppearedTaskTarget = lastAppearedTaskTarget; if (lastAppearedTaskTarget != null) { mPreviouslyAppearedTaskIds.add(lastAppearedTaskTarget.taskId); @@ -341,8 +340,6 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL ActiveGestureLog.INSTANCE.trackEvent(SET_END_TARGET_NEW_TASK); break; case LAST_TASK: - ActiveGestureLog.INSTANCE.trackEvent(SET_END_TARGET_LAST_TASK); - break; case RECENTS: default: // No-Op diff --git a/quickstep/src/com/android/quickstep/KtR.java b/quickstep/src/com/android/quickstep/KtR.java deleted file mode 100644 index 758c6e08ef..0000000000 --- a/quickstep/src/com/android/quickstep/KtR.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2021 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.quickstep; - -import com.android.launcher3.R; - -/** - * Bridge class to allow using resources in Kotlin. - * <br/> - * TODO(b/204069723) Can't use resources directly in Kotlin - */ -public class KtR { - public static final class id { - public static int menu_option_layout = R.id.menu_option_layout; - } - - public static final class dimen { - public static int task_menu_spacing = R.dimen.task_menu_spacing; - public static int task_menu_horizontal_padding = R.dimen.task_menu_horizontal_padding; - public static int taskbar_ime_size = R.dimen.taskbar_ime_size; - } - - public static final class layout { - public static int task_menu_with_arrow = R.layout.task_menu_with_arrow; - public static int task_view_menu_option = R.layout.task_view_menu_option; - } -} diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index 1127e2c8e7..9ff941671b 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -21,25 +21,27 @@ import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.QUICK_SWITCH; import static com.android.launcher3.anim.AnimatorListeners.forEndCallback; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; import android.animation.Animator; import android.animation.AnimatorSet; import android.content.Context; import android.graphics.Rect; import android.view.MotionEvent; +import android.view.RemoteAnimationTarget; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherInitListener; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statehandlers.DepthController; -import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.touch.PagedOrientationHandler; @@ -52,7 +54,6 @@ import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; import com.android.systemui.plugins.shared.LauncherOverlayManager; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.Consumer; import java.util.function.Predicate; @@ -108,15 +109,6 @@ public final class LauncherActivityInterface extends } @Override - public void onOneHandedModeStateChanged(boolean activated) { - Launcher launcher = getCreatedActivity(); - if (launcher == null) { - return; - } - launcher.onOneHandedStateChanged(activated); - } - - @Override public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState, boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) { notifyRecentsOfOrientation(deviceState.getRotationTouchHelper()); @@ -129,8 +121,9 @@ public final class LauncherActivityInterface extends // Animate the blur and wallpaper zoom float fromDepthRatio = BACKGROUND_APP.getDepth(activity); float toDepthRatio = OVERVIEW.getDepth(activity); - pa.addFloat(getDepthController(), - new ClampedDepthProperty(fromDepthRatio, toDepthRatio), + pa.addFloat(getDepthController().stateDepth, + new LauncherAnimUtils.ClampedProperty<>( + MULTI_PROPERTY_VALUE, fromDepthRatio, toDepthRatio), fromDepthRatio, toDepthRatio, LINEAR); } }; @@ -175,6 +168,16 @@ public final class LauncherActivityInterface extends @Nullable @Override + public DesktopVisibilityController getDesktopVisibilityController() { + QuickstepLauncher launcher = getCreatedActivity(); + if (launcher == null) { + return null; + } + return launcher.getDesktopVisibilityController(); + } + + @Nullable + @Override public LauncherTaskbarUIController getTaskbarController() { QuickstepLauncher launcher = getCreatedActivity(); if (launcher == null) { @@ -203,8 +206,7 @@ public final class LauncherActivityInterface extends private Launcher getVisibleLauncher() { Launcher launcher = getCreatedActivity(); return (launcher != null) && launcher.isStarted() - && ((ENABLE_QUICKSTEP_LIVE_TILE.get() && isInLiveTileMode()) - || launcher.hasBeenResumed()) ? launcher : null; + && (isInLiveTileMode() || launcher.hasBeenResumed()) ? launcher : null; } @Override @@ -213,7 +215,7 @@ public final class LauncherActivityInterface extends if (launcher == null) { return false; } - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isInLiveTileMode()) { + if (isInLiveTileMode()) { RecentsView recentsView = getVisibleRecentsView(); if (recentsView == null) { return false; @@ -253,7 +255,7 @@ public final class LauncherActivityInterface extends } @Override - public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) { + public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTarget target) { return homeBounds; } @@ -291,10 +293,6 @@ public final class LauncherActivityInterface extends } else { om.hideOverlay(150); } - LauncherTaskbarUIController taskbarController = getTaskbarController(); - if (taskbarController != null) { - taskbarController.hideEdu(); - } } @Override diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java index 7a281dd2a7..27417516a4 100644 --- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java +++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java @@ -36,6 +36,7 @@ import android.view.SurfaceControl; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.window.BackEvent; +import android.window.BackProgressAnimator; import android.window.IOnBackInvokedCallback; import com.android.launcher3.AbstractFloatingView; @@ -45,8 +46,6 @@ import com.android.launcher3.Utilities; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.quickstep.util.RectFSpringAnim; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; /** * Controls the animation of swiping back and returning to launcher. @@ -84,13 +83,14 @@ public class LauncherBackAnimationController { private final Interpolator mCancelInterpolator; private final PointF mInitialTouchPos = new PointF(); - private RemoteAnimationTargetCompat mBackTarget; + private RemoteAnimationTarget mBackTarget; private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); private boolean mSpringAnimationInProgress = false; private boolean mAnimatorSetInProgress = false; private float mBackProgress = 0; private boolean mBackInProgress = false; private IOnBackInvokedCallback mBackCallback; + private BackProgressAnimator mProgressAnimator = new BackProgressAnimator(); public LauncherBackAnimationController( QuickstepLauncher launcher, @@ -119,30 +119,41 @@ public class LauncherBackAnimationController { mBackCallback = new IOnBackInvokedCallback.Stub() { @Override public void onBackCancelled() { - handler.post(() -> resetPositionAnimated()); + handler.post(() -> { + resetPositionAnimated(); + mProgressAnimator.reset(); + }); } @Override public void onBackInvoked() { - handler.post(() -> startTransition()); + handler.post(() -> { + startTransition(); + mProgressAnimator.reset(); + }); } @Override public void onBackProgressed(BackEvent backEvent) { - mBackProgress = backEvent.getProgress(); - // TODO: Update once the interpolation curve spec is finalized. - mBackProgress = - 1 - (1 - mBackProgress) * (1 - mBackProgress) * (1 - - mBackProgress); - if (!mBackInProgress) { - startBack(backEvent); - } else { - updateBackProgress(mBackProgress, backEvent); - } + handler.post(() -> { + mProgressAnimator.onBackProgressed(backEvent); + }); } @Override - public void onBackStarted() { } + public void onBackStarted(BackEvent backEvent) { + handler.post(() -> { + startBack(backEvent); + mProgressAnimator.onBackStarted(backEvent, event -> { + mBackProgress = event.getProgress(); + // TODO: Update once the interpolation curve spec is finalized. + mBackProgress = + 1 - (1 - mBackProgress) * (1 - mBackProgress) * (1 + - mBackProgress); + updateBackProgress(mBackProgress, event); + }); + }); + } }; SystemUiProxy.INSTANCE.get(mLauncher).setBackToLauncherCallback(mBackCallback); } @@ -170,6 +181,7 @@ public class LauncherBackAnimationController { if (mBackCallback != null) { SystemUiProxy.INSTANCE.get(mLauncher).clearBackToLauncherCallback(mBackCallback); } + mProgressAnimator.reset(); mBackCallback = null; } @@ -183,33 +195,25 @@ public class LauncherBackAnimationController { mTransaction.show(appTarget.leash).apply(); mTransaction.setAnimationTransaction(); - mBackTarget = new RemoteAnimationTargetCompat(appTarget); + mBackTarget = appTarget; mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY()); // TODO(b/218916755): Offset start rectangle in multiwindow mode. mStartRect.set(mBackTarget.windowConfiguration.getMaxBounds()); + mCurrentRect.set(mStartRect); } private void updateBackProgress(float progress, BackEvent event) { - if (mBackTarget == null) { + if (!mBackInProgress || mBackTarget == null) { return; } float screenWidth = mStartRect.width(); float screenHeight = mStartRect.height(); - float dX = Math.abs(event.getTouchX() - mInitialTouchPos.x); - // The 'follow width' is the width of the window if it completely matches - // the gesture displacement. - float followWidth = screenWidth - dX; - // The 'progress width' is the width of the window if it strictly linearly interpolates - // to minimum scale base on progress. - float progressWidth = Utilities.mapRange(progress, 1, MIN_WINDOW_SCALE) * screenWidth; - // The final width is derived from interpolating between the follow with and progress width - // using gesture progress. - float width = Utilities.mapRange(progress, followWidth, progressWidth); + float width = Utilities.mapRange(progress, 1, MIN_WINDOW_SCALE) * screenWidth; float height = screenHeight / screenWidth * width; float deltaYRatio = (event.getTouchY() - mInitialTouchPos.y) / screenHeight; // Base the window movement in the Y axis on the touch movement in the Y axis. - float deltaY = (float) Math.sin(deltaYRatio * Math.PI * 0.5f) * mWindowMaxDeltaY; + float deltaY = (float) Math.sin(deltaYRatio * Math.PI * 0.5f) * mWindowMaxDeltaY * progress; // Move the window along the Y axis. float top = (screenHeight - height) * 0.5f + deltaY; // Move the window along the X axis. @@ -242,20 +246,17 @@ public class LauncherBackAnimationController { /** Transform the target window to match the target rect. */ private void applyTransform(RectF targetRect, float cornerRadius) { - SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder builder = - new SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder(mBackTarget.leash); final float scale = targetRect.width() / mStartRect.width(); mTransformMatrix.reset(); mTransformMatrix.setScale(scale, scale); mTransformMatrix.postTranslate(targetRect.left, targetRect.top); - builder.withMatrix(mTransformMatrix) - .withWindowCrop(mStartRect) - .withCornerRadius(cornerRadius); - SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams = builder.build(); - if (surfaceParams.surface.isValid()) { - surfaceParams.applyTo(mTransaction); + if (mBackTarget.leash.isValid()) { + mTransaction.setMatrix(mBackTarget.leash, mTransformMatrix, new float[9]); + mTransaction.setWindowCrop(mBackTarget.leash, mStartRect); + mTransaction.setCornerRadius(mBackTarget.leash, cornerRadius); } + mTransaction.apply(); } @@ -284,8 +285,8 @@ public class LauncherBackAnimationController { mBackProgress, mWindowScaleStartCornerRadius, mWindowScaleEndCornerRadius); Pair<RectFSpringAnim, AnimatorSet> pair = mQuickstepTransitionManager.createWallpaperOpenAnimations( - new RemoteAnimationTargetCompat[]{mBackTarget}, - new RemoteAnimationTargetCompat[]{}, + new RemoteAnimationTarget[]{mBackTarget}, + new RemoteAnimationTarget[0], false /* fromUnlock */, mCurrentRect, cornerRadius); diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index 36ca993f85..bb781c82b7 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -30,6 +30,7 @@ import android.graphics.RectF; import android.os.IBinder; import android.os.UserHandle; import android.util.Size; +import android.view.RemoteAnimationTarget; import android.view.View; import androidx.annotation.NonNull; @@ -49,7 +50,6 @@ import com.android.quickstep.views.FloatingWidgetView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.InputConsumerController; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.ArrayList; @@ -70,7 +70,7 @@ public class LauncherSwipeHandlerV2 extends @Override protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies, long duration, boolean isTargetTranslucent, boolean appCanEnterPip, - RemoteAnimationTargetCompat runningTaskTarget) { + RemoteAnimationTarget runningTaskTarget) { if (mActivity == null) { mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, isPresent -> mRecentsView.startHome()); @@ -84,7 +84,8 @@ public class LauncherSwipeHandlerV2 extends final View workspaceView = findWorkspaceView(launchCookies, mRecentsView.getRunningTaskView()); - boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow(); + boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow() + && workspaceView.getHeight() > 0; mActivity.getRootView().setForceHideBackArrow(true); if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) { @@ -143,7 +144,7 @@ public class LauncherSwipeHandlerV2 extends private HomeAnimationFactory createWidgetHomeAnimationFactory( LauncherAppWidgetHostView hostView, boolean isTargetTranslucent, - RemoteAnimationTargetCompat runningTaskTarget) { + RemoteAnimationTarget runningTaskTarget) { final float floatingWidgetAlpha = isTargetTranslucent ? 0 : 1; RectF backgroundLocation = new RectF(); Rect crop = new Rect(); diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index 875b72cb34..5a09e021b2 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -116,7 +116,7 @@ public class OverviewCommandHelper { */ @BinderThread public void addCommand(int type) { - if (mPendingCommands.size() > MAX_QUEUE_SIZE) { + if (mPendingCommands.size() >= MAX_QUEUE_SIZE) { return; } CommandInfo cmd = new CommandInfo(type); diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java index 9e3173c1f0..83f2a0a114 100644 --- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java +++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java @@ -34,6 +34,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; +import android.util.Log; import android.util.SparseIntArray; import androidx.annotation.NonNull; @@ -54,6 +55,8 @@ import java.util.function.Consumer; * and provide callers the relevant classes. */ public final class OverviewComponentObserver { + private static final String TAG = "OverviewComponentObserver"; + private final BroadcastReceiver mUserPreferenceChangeReceiver = new SimpleBroadcastReceiver(this::updateOverviewTargets); private final BroadcastReceiver mOtherHomeAppUpdateReceiver = @@ -115,11 +118,6 @@ public final class OverviewComponentObserver { if (mDeviceState.isHomeDisabled() != mIsHomeDisabled) { updateOverviewTargets(); } - - // Notify ALL_APPS touch controller when one handed mode state activated or deactivated - if (mDeviceState.isOneHandedModeEnabled()) { - mActivityInterface.onOneHandedModeStateChanged(mDeviceState.isOneHandedModeActive()); - } } private void updateOverviewTargets(Intent unused) { @@ -151,7 +149,12 @@ public final class OverviewComponentObserver { } } - if (!mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) { + // TODO(b/258022658): Remove temporary logging. + Log.i(TAG, "updateOverviewTargets: mIsHomeDisabled=" + mIsHomeDisabled + + ", isDefaultHomeNull=" + (defaultHome == null) + + ", mIsDefaultHome=" + mIsDefaultHome); + + if (!mIsHomeDisabled && (defaultHome == null || mIsDefaultHome)) { // User default home is same as out home app. Use Overview integrated in Launcher. mActivityInterface = LauncherActivityInterface.INSTANCE; mIsHomeAndOverviewSame = true; diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java index b7cdecd115..54e4a0d3f1 100644 --- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -1,5 +1,6 @@ package com.android.quickstep; +import static com.android.launcher3.testing.shared.TestProtocol.NPE_TRANSIENT_TASKBAR; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import android.app.Activity; @@ -7,19 +8,23 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.os.Bundle; +import android.util.Log; import androidx.annotation.Nullable; import com.android.launcher3.R; +import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.testing.TestInformationHandler; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.PagedOrientationHandler; +import com.android.launcher3.util.DisplayController; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.TISBindHelper; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; +import java.util.function.Function; public class QuickstepTestInformationHandler extends TestInformationHandler { @@ -112,6 +117,33 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size)); return response; } + + case TestProtocol.REQUEST_TASKBAR_ALL_APPS_TOP_PADDING: { + return getTISBinderUIProperty(Bundle::putInt, tisBinder -> + tisBinder.getTaskbarManager() + .getCurrentActivityContext() + .getTaskbarAllAppsTopPadding()); + } + + case TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT: + runOnTISBinder(tisBinder -> { + enableBlockingTimeout(tisBinder, true); + }); + return response; + + case TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT: + runOnTISBinder(tisBinder -> { + enableBlockingTimeout(tisBinder, false); + }); + return response; + + case TestProtocol.REQUEST_ENABLE_TRANSIENT_TASKBAR: + enableTransientTaskbar(true); + return response; + + case TestProtocol.REQUEST_DISABLE_TRANSIENT_TASKBAR: + enableTransientTaskbar(false); + return response; } return super.call(method, arg, extras); @@ -141,6 +173,23 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { enable); } + private void enableBlockingTimeout( + TouchInteractionService.TISBinder tisBinder, boolean enable) { + TaskbarActivityContext context = tisBinder.getTaskbarManager().getCurrentActivityContext(); + if (context == null) { + if (TestProtocol.sDebugTracing) { + Log.d(NPE_TRANSIENT_TASKBAR, "enableBlockingTimeout: enable=" + enable, + new Exception()); + } + } else { + context.enableBlockingTimeoutDuringTests(enable); + } + } + + private void enableTransientTaskbar(boolean enable) { + DisplayController.INSTANCE.get(mContext).enableTransientTaskbarForTests(enable); + } + /** * Runs the given command on the UI thread, after ensuring we are connected to * TouchInteractionService. @@ -159,4 +208,16 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { throw new RuntimeException(e); } } + + private <T> Bundle getTISBinderUIProperty( + BundleSetter<T> bundleSetter, Function<TouchInteractionService.TISBinder, T> provider) { + Bundle response = new Bundle(); + + runOnTISBinder(tisBinder -> bundleSetter.set( + response, + TestProtocol.TEST_INFO_RESPONSE_FIELD, + provider.apply(tisBinder))); + + return response; + } } diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java index 6b616b1b07..b33ceca838 100644 --- a/quickstep/src/com/android/quickstep/RecentTasksList.java +++ b/quickstep/src/com/android/quickstep/RecentTasksList.java @@ -17,10 +17,14 @@ package com.android.quickstep; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; +import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED; +import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM; import android.annotation.TargetApi; import android.app.ActivityManager; import android.app.KeyguardManager; +import android.app.TaskInfo; +import android.content.ComponentName; import android.os.Build; import android.os.Process; import android.os.RemoteException; @@ -30,6 +34,7 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.util.LooperExecutor; import com.android.launcher3.util.SplitConfigurationOptions; +import com.android.quickstep.util.DesktopTask; import com.android.quickstep.util.GroupTask; import com.android.systemui.shared.recents.model.Task; import com.android.wm.shell.recents.IRecentTasksListener; @@ -40,6 +45,8 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Manages the recent task list from the system, caching it as necessary. @@ -124,14 +131,18 @@ public class RecentTasksList { * @return The change id of the current task list */ public synchronized int getTasks(boolean loadKeysOnly, - Consumer<ArrayList<GroupTask>> callback) { + Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) { final int requestLoadId = mChangeId; if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) { // The list is up to date, send the callback on the next frame, // so that requestID can be returned first. if (callback != null) { // Copy synchronously as the changeId might change by next frame - ArrayList<GroupTask> result = copyOf(mResultsUi); + // and filter GroupTasks + ArrayList<GroupTask> result = mResultsUi.stream().filter(filter) + .map(GroupTask::copy) + .collect(Collectors.toCollection(ArrayList<GroupTask>::new)); + mMainThreadExecutor.post(() -> { callback.accept(result); }); @@ -151,7 +162,11 @@ public class RecentTasksList { mLoadingTasksInBackground = false; mResultsUi = loadResult; if (callback != null) { - ArrayList<GroupTask> result = copyOf(mResultsUi); + // filter the tasks if needed before passing them into the callback + ArrayList<GroupTask> result = mResultsUi.stream().filter(filter) + .map(GroupTask::copy) + .collect(Collectors.toCollection(ArrayList<GroupTask>::new)); + callback.accept(result); } }); @@ -253,8 +268,9 @@ public class RecentTasksList { }; TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size()); + for (GroupedRecentTaskInfo rawTask : rawTasks) { - if (rawTask.getType() == GroupedRecentTaskInfo.TYPE_FREEFORM) { + if (DESKTOP_MODE_SUPPORTED && rawTask.getType() == TYPE_FREEFORM) { GroupTask desktopTask = createDesktopTask(rawTask); allTasks.add(desktopTask); continue; @@ -284,14 +300,18 @@ public class RecentTasksList { return allTasks; } - private GroupTask createDesktopTask(GroupedRecentTaskInfo taskInfo) { - // TODO(b/244348395): create a subclass of GroupTask for desktop tile - // We need a single task information as the primary task. Use the first task - Task.TaskKey key = new Task.TaskKey(taskInfo.getTaskInfo1()); - Task task = new Task(key); - task.desktopTile = true; - task.topActivity = key.sourceComponent; - return new GroupTask(task, null, null); + private DesktopTask createDesktopTask(GroupedRecentTaskInfo recentTaskInfo) { + ArrayList<Task> tasks = new ArrayList<>(recentTaskInfo.getTaskInfoList().size()); + for (ActivityManager.RecentTaskInfo taskInfo : recentTaskInfo.getTaskInfoList()) { + Task.TaskKey key = new Task.TaskKey(taskInfo); + Task task = Task.from(key, taskInfo, false); + task.setLastSnapshotData(taskInfo); + task.positionInParent = taskInfo.positionInParent; + task.appBounds = taskInfo.configuration.windowConfiguration.getAppBounds(); + // TODO(b/244348395): tasks should be sorted from oldest to most recently used + tasks.add(task); + } + return new DesktopTask(tasks); } private SplitConfigurationOptions.SplitBounds convertSplitBounds( @@ -306,7 +326,7 @@ public class RecentTasksList { private ArrayList<GroupTask> copyOf(ArrayList<GroupTask> tasks) { ArrayList<GroupTask> newTasks = new ArrayList<>(); for (int i = 0; i < tasks.size(); i++) { - newTasks.add(new GroupTask(tasks.get(i))); + newTasks.add(tasks.get(i).copy()); } return newTasks; } @@ -316,8 +336,14 @@ public class RecentTasksList { writer.println(prefix + " mChangeId=" + mChangeId); writer.println(prefix + " mResultsUi=[id=" + mResultsUi.mRequestId + ", tasks="); for (GroupTask task : mResultsUi) { - writer.println(prefix + " t1=" + task.task1.key.id - + " t2=" + (task.hasMultipleTasks() ? task.task2.key.id : "-1")); + Task task1 = task.task1; + Task task2 = task.task2; + ComponentName cn1 = task1.getTopComponent(); + ComponentName cn2 = task2 != null ? task2.getTopComponent() : null; + writer.println(prefix + " t1: (id=" + task1.key.id + + "; package=" + (cn1 != null ? cn1.getPackageName() + ")" : "no package)") + + " t2: (id=" + (task2 != null ? task2.key.id : "-1") + + "; package=" + (cn2 != null ? cn2.getPackageName() + ")" : "no package)")); } writer.println(prefix + " ]"); int currentUserId = Process.myUserHandle().getIdentifier(); @@ -325,8 +351,14 @@ public class RecentTasksList { mSysUiProxy.getRecentTasks(Integer.MAX_VALUE, currentUserId); writer.println(prefix + " rawTasks=["); for (GroupedRecentTaskInfo task : rawTasks) { - writer.println(prefix + " t1=" + task.getTaskInfo1().taskId - + " t2=" + (task.getTaskInfo2() != null ? task.getTaskInfo2().taskId : "-1")); + TaskInfo taskInfo1 = task.getTaskInfo1(); + TaskInfo taskInfo2 = task.getTaskInfo2(); + ComponentName cn1 = taskInfo1.topActivity; + ComponentName cn2 = taskInfo2 != null ? taskInfo2.topActivity : null; + writer.println(prefix + " t1: (id=" + taskInfo1.taskId + + "; package=" + (cn1 != null ? cn1.getPackageName() + ")" : "no package)") + + " t2: (id=" + (taskInfo2 != null ? taskInfo2.taskId : "-1") + + "; package=" + (cn2 != null ? cn2.getPackageName() + ")" : "no package)")); } writer.println(prefix + " ]"); } diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index c879494c7d..dc405ff8ba 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -15,17 +15,17 @@ */ package com.android.quickstep; +import static android.view.RemoteAnimationTarget.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_OPENING; + import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION; import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_DURATION; import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS; import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL; import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely; import static com.android.quickstep.TaskUtils.taskIsATargetWithMode; import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -37,8 +37,11 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.Display; +import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationTarget; import android.view.SurfaceControl.Transaction; import android.view.View; +import android.window.RemoteTransition; import android.window.SplashScreen; import androidx.annotation.Nullable; @@ -78,8 +81,6 @@ import com.android.quickstep.util.TISBindHelper; import com.android.quickstep.views.OverviewActionsView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; -import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -239,9 +240,9 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> { mActivityLaunchAnimationRunner = new RemoteAnimationFactory() { @Override - public void onCreateAnimation(int transit, RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) { + public void onCreateAnimation(int transit, RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets, AnimationResult result) { mHandler.removeCallbacks(mAnimationStartTimeoutRunnable); AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets, wallpaperTargets, nonAppTargets); @@ -259,13 +260,11 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> { final LauncherAnimationRunner wrapper = new LauncherAnimationRunner( mUiHandler, mActivityLaunchAnimationRunner, true /* startAtFrontOfQueue */); - RemoteAnimationAdapterCompat adapterCompat = new RemoteAnimationAdapterCompat( - wrapper, RECENTS_LAUNCH_DURATION, - RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION - - STATUS_BAR_TRANSITION_PRE_DELAY, getIApplicationThread()); final ActivityOptions options = ActivityOptions.makeRemoteAnimation( - adapterCompat.getWrapped(), - adapterCompat.getRemoteTransition().getTransition()); + new RemoteAnimationAdapter(wrapper, RECENTS_LAUNCH_DURATION, + RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION + - STATUS_BAR_TRANSITION_PRE_DELAY), + new RemoteTransition(wrapper.toRemoteTransition(), getIApplicationThread())); final ActivityOptionsWrapper activityOptions = new ActivityOptionsWrapper(options, onEndCallback); activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); @@ -280,9 +279,9 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> { * Composes the animations for a launch from the recents list if possible. */ private AnimatorSet composeRecentsLaunchAnimator(TaskView taskView, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets) { + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets) { AnimatorSet target = new AnimatorSet(); boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING); PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION); @@ -393,40 +392,33 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> { } public void startHome() { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - RecentsView recentsView = getOverviewPanel(); - recentsView.switchToScreenshot(() -> recentsView.finishRecentsAnimation(true, - this::startHomeInternal)); - } else { - startHomeInternal(); - } + RecentsView recentsView = getOverviewPanel(); + recentsView.switchToScreenshot(() -> recentsView.finishRecentsAnimation(true, + this::startHomeInternal)); } private void startHomeInternal() { LauncherAnimationRunner runner = new LauncherAnimationRunner( getMainThreadHandler(), mAnimationToHomeFactory, true); - RemoteAnimationAdapterCompat adapterCompat = - new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0, - getIApplicationThread()); ActivityOptions options = ActivityOptions.makeRemoteAnimation( - adapterCompat.getWrapped(), - adapterCompat.getRemoteTransition().getTransition()); + new RemoteAnimationAdapter(runner, HOME_APPEAR_DURATION, 0), + new RemoteTransition(runner.toRemoteTransition(), getIApplicationThread())); startHomeIntentSafely(this, options.toBundle()); } private final RemoteAnimationFactory mAnimationToHomeFactory = new RemoteAnimationFactory() { @Override - public void onCreateAnimation(int transit, RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, - RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) { + public void onCreateAnimation(int transit, RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, + RemoteAnimationTarget[] nonAppTargets, AnimationResult result) { AnimatorPlaybackController controller = getStateManager() .createAnimationToNewWorkspace(RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION); controller.dispatchOnStart(); RemoteAnimationTargets targets = new RemoteAnimationTargets( appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING); - for (RemoteAnimationTargetCompat app : targets.apps) { + for (RemoteAnimationTarget app : targets.apps) { new Transaction().setAlpha(app.leash, 1).apply(); } AnimatorSet anim = new AnimatorSet(); diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java index b233521ff2..b82ff03b34 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java @@ -33,9 +33,7 @@ import com.android.quickstep.util.ActiveGestureErrorDetector; import com.android.quickstep.util.ActiveGestureLog; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import java.util.Arrays; import java.util.HashMap; import java.util.Set; @@ -88,17 +86,17 @@ public class RecentsAnimationCallbacks implements @BinderThread @Deprecated public final void onAnimationStart(RecentsAnimationControllerCompat controller, - RemoteAnimationTargetCompat[] appTargets, Rect homeContentInsets, + RemoteAnimationTarget[] appTargets, Rect homeContentInsets, Rect minimizedHomeBounds) { - onAnimationStart(controller, appTargets, new RemoteAnimationTargetCompat[0], + onAnimationStart(controller, appTargets, new RemoteAnimationTarget[0], homeContentInsets, minimizedHomeBounds); } // Called only in R+ platform @BinderThread public final void onAnimationStart(RecentsAnimationControllerCompat animationController, - RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets, + RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, Rect homeContentInsets, Rect minimizedHomeBounds) { mController = new RecentsAnimationController(animationController, mAllowMinimizeSplitScreen, this::onAnimationFinished); @@ -107,12 +105,13 @@ public class RecentsAnimationCallbacks implements Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), mController::finishAnimationToApp); } else { - final RemoteAnimationTarget[] nonAppTargets = mSystemUiProxy.onGoingToRecentsLegacy( - Arrays.stream(appTargets).map(RemoteAnimationTargetCompat::unwrap) - .toArray(RemoteAnimationTarget[]::new)); + RemoteAnimationTarget[] nonAppTargets = + mSystemUiProxy.onGoingToRecentsLegacy(appTargets); + if (nonAppTargets == null) { + nonAppTargets = new RemoteAnimationTarget[0]; + } final RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets, - wallpaperTargets, RemoteAnimationTargetCompat.wrap(nonAppTargets), - homeContentInsets, minimizedHomeBounds); + wallpaperTargets, nonAppTargets, homeContentInsets, minimizedHomeBounds); Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { ActiveGestureLog.INSTANCE.addLog( @@ -131,7 +130,7 @@ public class RecentsAnimationCallbacks implements public final void onAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { ActiveGestureLog.INSTANCE.addLog( - /* event= */ "onRecentsAnimationCancelled", + /* event= */ "RecentsAnimationCallbacks.onAnimationCanceled", /* gestureEvent= */ CANCEL_RECENTS_ANIMATION); for (RecentsAnimationListener listener : getListeners()) { listener.onRecentsAnimationCanceled(thumbnailDatas); @@ -141,9 +140,9 @@ public class RecentsAnimationCallbacks implements @BinderThread @Override - public void onTasksAppeared(RemoteAnimationTargetCompat[] apps) { + public void onTasksAppeared(RemoteAnimationTarget[] apps) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { - ActiveGestureLog.INSTANCE.addLog("onTasksAppeared", + ActiveGestureLog.INSTANCE.addLog("RecentsAnimationCallbacks.onTasksAppeared", ActiveGestureErrorDetector.GestureEvent.TASK_APPEARED); for (RecentsAnimationListener listener : getListeners()) { listener.onTasksAppeared(apps); @@ -165,6 +164,8 @@ public class RecentsAnimationCallbacks implements private final void onAnimationFinished(RecentsAnimationController controller) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { + ActiveGestureLog.INSTANCE.addLog( + /* event= */ "RecentsAnimationCallbacks.onAnimationFinished"); for (RecentsAnimationListener listener : getListeners()) { listener.onRecentsAnimationFinished(controller); } @@ -197,7 +198,7 @@ public class RecentsAnimationCallbacks implements /** * Callback made when a task started from the recents is ready for an app transition. */ - default void onTasksAppeared(@NonNull RemoteAnimationTargetCompat[] appearedTaskTarget) {} + default void onTasksAppeared(@NonNull RemoteAnimationTarget[] appearedTaskTarget) {} /** * @return whether this will call onFinished or not (onFinished should only be called once). diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index 542c0d4b21..4adfae5ee8 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -18,11 +18,13 @@ package com.android.quickstep; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS; +import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION; import android.content.Context; import android.os.RemoteException; import android.util.Log; import android.view.IRecentsAnimationController; +import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.WindowManagerGlobal; import android.window.PictureInPictureSurfaceTransaction; @@ -37,7 +39,6 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.function.Consumer; @@ -114,7 +115,7 @@ public class RecentsAnimationController { * {@link RecentsAnimationCallbacks#onTasksAppeared}}. */ @UiThread - public void removeTaskTarget(@NonNull RemoteAnimationTargetCompat target) { + public void removeTaskTarget(@NonNull RemoteAnimationTarget target) { UI_HELPER_EXECUTOR.execute(() -> mController.removeTask(target.taskId)); } @@ -155,6 +156,10 @@ public class RecentsAnimationController { mPendingFinishCallbacks.add(callback); return; } + ActiveGestureLog.INSTANCE.addLog( + /* event= */ "finishRecentsAnimation", + /* extras= */ toRecents, + /* gestureEvent= */ FINISH_RECENTS_ANIMATION); // Finish not yet requested mFinishRequested = true; @@ -165,6 +170,8 @@ public class RecentsAnimationController { mController.finish(toRecents, sendUserLeaveHint); InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH); InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME); + InteractionJankMonitorWrapper.end( + InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS); MAIN_EXECUTOR.execute(mPendingFinishCallbacks::executeAllAndDestroy); }); } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index e87fdad933..9e25555eec 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -46,10 +46,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_S import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED; import android.app.ActivityTaskManager; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.graphics.Region; import android.inputmethodservice.InputMethodService; import android.net.Uri; @@ -63,12 +60,12 @@ import android.view.MotionEvent; import androidx.annotation.BinderThread; import androidx.annotation.NonNull; -import com.android.launcher3.Utilities; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.NavigationMode; import com.android.launcher3.util.SettingsCache; +import com.android.launcher3.util.SimpleBroadcastReceiver; import com.android.quickstep.TopTaskTracker.CachedTaskInfo; import com.android.quickstep.util.NavBarPosition; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -114,15 +111,12 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener { private boolean mIsUserUnlocked; private final ArrayList<Runnable> mUserUnlockedActions = new ArrayList<>(); - private final BroadcastReceiver mUserUnlockedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (ACTION_USER_UNLOCKED.equals(intent.getAction())) { - mIsUserUnlocked = true; - notifyUserUnlocked(); - } + private final SimpleBroadcastReceiver mUserUnlockedReceiver = new SimpleBroadcastReceiver(i -> { + if (ACTION_USER_UNLOCKED.equals(i.getAction())) { + mIsUserUnlocked = true; + notifyUserUnlocked(); } - }; + }); private int mGestureBlockingTaskId = -1; private @NonNull Region mExclusionRegion = new Region(); @@ -153,10 +147,9 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener { mIsUserUnlocked = context.getSystemService(UserManager.class) .isUserUnlocked(Process.myUserHandle()); if (!mIsUserUnlocked) { - mContext.registerReceiver(mUserUnlockedReceiver, - new IntentFilter(ACTION_USER_UNLOCKED)); + mUserUnlockedReceiver.register(mContext, ACTION_USER_UNLOCKED); } - runOnDestroy(() -> Utilities.unregisterReceiverSafely(mContext, mUserUnlockedReceiver)); + runOnDestroy(() -> mUserUnlockedReceiver.unregisterReceiverSafely(mContext)); // Register for exclusion updates mExclusionListener = new SystemGestureExclusionListenerCompat(mDisplayId) { @@ -347,7 +340,7 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener { action.run(); } mUserUnlockedActions.clear(); - Utilities.unregisterReceiverSafely(mContext, mUserUnlockedReceiver); + mUserUnlockedReceiver.unregisterReceiverSafely(mContext); } /** diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java index b6d9016727..388e1256d8 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java @@ -15,11 +15,10 @@ */ package com.android.quickstep; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_CLOSING; import android.graphics.Rect; - -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import android.view.RemoteAnimationTarget; /** * Extension of {@link RemoteAnimationTargets} with additional information about swipe @@ -30,8 +29,8 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets { public final Rect homeContentInsets; public final Rect minimizedHomeBounds; - public RecentsAnimationTargets(RemoteAnimationTargetCompat[] apps, - RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps, + public RecentsAnimationTargets(RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, Rect homeContentInsets, Rect minimizedHomeBounds) { super(apps, wallpapers, nonApps, MODE_CLOSING); this.homeContentInsets = homeContentInsets; diff --git a/quickstep/src/com/android/quickstep/RecentsFilterState.java b/quickstep/src/com/android/quickstep/RecentsFilterState.java new file mode 100644 index 0000000000..ff6951d33f --- /dev/null +++ b/quickstep/src/com/android/quickstep/RecentsFilterState.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2022 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.quickstep; + +import androidx.annotation.Nullable; + +import com.android.quickstep.util.GroupTask; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; + +/** + * Keeps track of the state of {@code RecentsView}. + * + * <p> More specifically, used for keeping track of the state of filters applied on tasks + * in {@code RecentsView} for multi-instance management. + */ +public class RecentsFilterState { + // the minimum number of tasks per package present to allow filtering + public static final int MIN_FILTERING_TASK_COUNT = 2; + + // default filter that returns true for any input + public static final Predicate<GroupTask> DEFAULT_FILTER = (groupTask -> true); + + // the package name to filter recent tasks by + @Nullable + private String mPackageNameToFilter = null; + + // the callback that gets executed upon filter change + @Nullable + private Runnable mOnFilterUpdatedListener = null; + + // map maintaining the count for each unique base activity package name currently in the recents + @Nullable + private Map<String, Integer> mInstanceCountMap; + + /** + * Returns {@code true} if {@code RecentsView} filters tasks by some package name. + */ + public boolean isFiltered() { + return mPackageNameToFilter != null; + } + + /** + * Returns the package name that tasks are filtered by. + */ + @Nullable + public String getPackageNameToFilter() { + return mPackageNameToFilter; + } + + + /** + * Sets a listener on any changes to the filter. + * + * @param callback listener to be executed upon filter updates + */ + public void setOnFilterUpdatedListener(@Nullable Runnable callback) { + mOnFilterUpdatedListener = callback; + } + + /** + * Updates the filter such that tasks are filtered by a certain package name. + * + * @param packageName package name of the base activity to filter tasks by; + * if null, filter is turned off + */ + public void setFilterBy(@Nullable String packageName) { + if (Objects.equals(packageName, mPackageNameToFilter)) { + return; + } + + mPackageNameToFilter = packageName; + + if (mOnFilterUpdatedListener != null) { + mOnFilterUpdatedListener.run(); + } + } + + /** + * Updates the map of package names to their count in the most recent list of tasks. + * + * @param groupTaskList the list of tasks that map update is be based on + */ + public void updateInstanceCountMap(List<GroupTask> groupTaskList) { + mInstanceCountMap = getInstanceCountMap(groupTaskList); + } + + /** + * Returns the map of package names to their count in the most recent list of tasks. + */ + @Nullable + public Map<String, Integer> getInstanceCountMap() { + return mInstanceCountMap; + } + + /** + * Returns a predicate for filtering out GroupTasks by package name. + * + * @param packageName package name to filter GroupTasks by + * if null, Predicate always returns true. + */ + public static Predicate<GroupTask> getFilter(@Nullable String packageName) { + if (packageName == null) { + return DEFAULT_FILTER; + } + + return (groupTask) -> (groupTask.task2 != null + && groupTask.task2.key.getPackageName().equals(packageName)) + || groupTask.task1.key.getPackageName().equals(packageName); + } + + /** + * Returns a map of package names to their frequencies in a list of GroupTasks. + * + * @param groupTasks the list to go through to create the map + */ + public static Map<String, Integer> getInstanceCountMap(List<GroupTask> groupTasks) { + Map<String, Integer> instanceCountMap = new HashMap<>(); + + for (GroupTask groupTask : groupTasks) { + final String firstTaskPkgName = groupTask.task1.key.getPackageName(); + final String secondTaskPkgName = + groupTask.task2 == null ? null : groupTask.task2.key.getPackageName(); + + // increment the instance count for the first task's base activity package name + incrementOrAddIfNotExists(instanceCountMap, firstTaskPkgName); + + // check if second task is non existent + if (secondTaskPkgName != null) { + // increment the instance count for the second task's base activity package name + incrementOrAddIfNotExists(instanceCountMap, secondTaskPkgName); + } + } + + return instanceCountMap; + } + + /** + * Returns true if tasks of provided package name should show filter UI. + * + * @param taskPackageName package name of the task in question + */ + public boolean shouldShowFilterUI(String taskPackageName) { + // number of occurrences in recents overview with the package name of this task + int instanceCount = getInstanceCountMap().get(taskPackageName); + + // if the number of occurrences isn't enough make sure tasks can't be filtered by + // the package name of this task + return !(isFiltered() || instanceCount < MIN_FILTERING_TASK_COUNT); + } + + private static void incrementOrAddIfNotExists(Map<String, Integer> map, String pkgName) { + if (!map.containsKey(pkgName)) { + map.put(pkgName, 0); + } + map.put(pkgName, map.get(pkgName) + 1); + } +} diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index 305347414c..913f08f41d 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -50,6 +50,7 @@ import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.function.Consumer; +import java.util.function.Predicate; /** * Singleton class to load and manage recents model. @@ -96,14 +97,30 @@ public class RecentsModel implements IconChangeListener, TaskStackChangeListener } /** - * Fetches the list of recent tasks. + * Fetches the list of recent tasks. Tasks are ordered by recency, with the latest active tasks + * at the end of the list. * * @param callback The callback to receive the task plan once its complete or null. This is * always called on the UI thread. * @return the request id associated with this call. */ public int getTasks(Consumer<ArrayList<GroupTask>> callback) { - return mTaskList.getTasks(false /* loadKeysOnly */, callback); + return mTaskList.getTasks(false /* loadKeysOnly */, callback, + RecentsFilterState.DEFAULT_FILTER); + } + + + /** + * Fetches the list of recent tasks, based on a filter + * + * @param callback The callback to receive the task plan once its complete or null. This is + * always called on the UI thread. + * @param filter Returns true if a GroupTask should be included into the list passed into + * callback. + * @return the request id associated with this call. + */ + public int getTasks(Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) { + return mTaskList.getTasks(false /* loadKeysOnly */, callback, filter); } /** @@ -125,8 +142,9 @@ public class RecentsModel implements IconChangeListener, TaskStackChangeListener * Checks if a task has been removed or not. * * @param callback Receives true if task is removed, false otherwise + * @param filter Returns true if GroupTask should be in the list of considerations */ - public void isTaskRemoved(int taskId, Consumer<Boolean> callback) { + public void isTaskRemoved(int taskId, Consumer<Boolean> callback, Predicate<GroupTask> filter) { mTaskList.getTasks(true /* loadKeysOnly */, (taskGroups) -> { for (GroupTask group : taskGroups) { if (group.containsTask(taskId)) { @@ -135,7 +153,7 @@ public class RecentsModel implements IconChangeListener, TaskStackChangeListener } } callback.accept(true); - }); + }, filter); } @Override diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java index 1bd808d13d..80aaad0dd9 100644 --- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java @@ -15,9 +15,11 @@ */ package com.android.quickstep; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import android.view.RemoteAnimationTarget; import java.util.ArrayList; import java.util.concurrent.CopyOnWriteArrayList; @@ -29,41 +31,40 @@ public class RemoteAnimationTargets { private final CopyOnWriteArrayList<ReleaseCheck> mReleaseChecks = new CopyOnWriteArrayList<>(); - public final RemoteAnimationTargetCompat[] unfilteredApps; - public final RemoteAnimationTargetCompat[] apps; - public final RemoteAnimationTargetCompat[] wallpapers; - public final RemoteAnimationTargetCompat[] nonApps; + public final RemoteAnimationTarget[] unfilteredApps; + public final RemoteAnimationTarget[] apps; + public final RemoteAnimationTarget[] wallpapers; + public final RemoteAnimationTarget[] nonApps; public final int targetMode; public final boolean hasRecents; private boolean mReleased = false; - public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps, - RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps, + public RemoteAnimationTargets(RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, int targetMode) { - ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>(); + ArrayList<RemoteAnimationTarget> filteredApps = new ArrayList<>(); boolean hasRecents = false; if (apps != null) { - for (RemoteAnimationTargetCompat target : apps) { + for (RemoteAnimationTarget target : apps) { if (target.mode == targetMode) { filteredApps.add(target); } - hasRecents |= target.activityType == - RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS; + hasRecents |= target.windowConfiguration.getActivityType() == ACTIVITY_TYPE_RECENTS; } } this.unfilteredApps = apps; - this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]); + this.apps = filteredApps.toArray(new RemoteAnimationTarget[filteredApps.size()]); this.wallpapers = wallpapers; this.targetMode = targetMode; this.hasRecents = hasRecents; this.nonApps = nonApps; } - public RemoteAnimationTargetCompat findTask(int taskId) { - for (RemoteAnimationTargetCompat target : apps) { + public RemoteAnimationTarget findTask(int taskId) { + for (RemoteAnimationTarget target : apps) { if (target.taskId == taskId) { return target; } @@ -74,12 +75,12 @@ public class RemoteAnimationTargets { /** * Gets the navigation bar remote animation target if exists. */ - public RemoteAnimationTargetCompat getNavBarRemoteAnimationTarget() { + public RemoteAnimationTarget getNavBarRemoteAnimationTarget() { return getNonAppTargetOfType(TYPE_NAVIGATION_BAR); } - public RemoteAnimationTargetCompat getNonAppTargetOfType(int type) { - for (RemoteAnimationTargetCompat target : nonApps) { + public RemoteAnimationTarget getNonAppTargetOfType(int type) { + for (RemoteAnimationTarget target : nonApps) { if (target.windowType == type) { return target; } @@ -88,19 +89,19 @@ public class RemoteAnimationTargets { } /** Returns the first opening app target. */ - public RemoteAnimationTargetCompat getFirstAppTarget() { + public RemoteAnimationTarget getFirstAppTarget() { return apps.length > 0 ? apps[0] : null; } /** Returns the task id of the first opening app target, or -1 if none is found. */ public int getFirstAppTargetTaskId() { - RemoteAnimationTargetCompat target = getFirstAppTarget(); + RemoteAnimationTarget target = getFirstAppTarget(); return target == null ? -1 : target.taskId; } public boolean isAnimatingHome() { - for (RemoteAnimationTargetCompat target : unfilteredApps) { - if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + for (RemoteAnimationTarget target : unfilteredApps) { + if (target.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME) { return true; } } @@ -123,15 +124,19 @@ public class RemoteAnimationTargets { } mReleaseChecks.clear(); mReleased = true; + release(unfilteredApps); + release(wallpapers); + release(nonApps); + } - for (RemoteAnimationTargetCompat target : unfilteredApps) { - target.release(); - } - for (RemoteAnimationTargetCompat target : wallpapers) { - target.release(); - } - for (RemoteAnimationTargetCompat target : nonApps) { - target.release(); + private static void release(RemoteAnimationTarget[] targets) { + for (RemoteAnimationTarget target : targets) { + if (target.leash != null) { + target.leash.release(); + } + if (target.startLeash != null) { + target.startLeash.release(); + } } } diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java index 7183c49ca2..4c41bef26a 100644 --- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java +++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java @@ -17,6 +17,8 @@ package com.android.quickstep; import android.content.Context; +import android.graphics.Rect; +import android.view.RemoteAnimationTarget; import androidx.annotation.Nullable; @@ -24,7 +26,6 @@ import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TransformParams; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.ArrayList; @@ -75,7 +76,7 @@ public class RemoteTargetGluer { */ public RemoteTargetHandle[] assignTargets(RemoteAnimationTargets targets) { for (int i = 0; i < mRemoteTargetHandles.length; i++) { - RemoteAnimationTargetCompat primaryTaskTarget = targets.apps[i]; + RemoteAnimationTarget primaryTaskTarget = targets.apps[i]; mRemoteTargetHandles[i].mTransformParams.setTargetSet( createRemoteAnimationTargetsForTarget(targets, null)); mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null); @@ -100,8 +101,8 @@ public class RemoteTargetGluer { */ public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets, int[] splitIds) { - RemoteAnimationTargetCompat topLeftTarget; // only one set if single/fullscreen task - RemoteAnimationTargetCompat bottomRightTarget; + RemoteAnimationTarget topLeftTarget; // only one set if single/fullscreen task + RemoteAnimationTarget bottomRightTarget; if (mRemoteTargetHandles.length == 1) { // If we're not in split screen, the splitIds count doesn't really matter since we // should always hit this case. @@ -119,8 +120,8 @@ public class RemoteTargetGluer { // remoteTargetHandle[0] denotes topLeft task, so we pass in the bottomRight to exclude, // vice versa mSplitBounds = new SplitBounds( - topLeftTarget.startScreenSpaceBounds, - bottomRightTarget.startScreenSpaceBounds, splitIds[0], splitIds[1]); + getStartBounds(topLeftTarget), + getStartBounds(bottomRightTarget), splitIds[0], splitIds[1]); mRemoteTargetHandles[0].mTransformParams.setTargetSet( createRemoteAnimationTargetsForTarget(targets, bottomRightTarget)); mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget, @@ -134,6 +135,10 @@ public class RemoteTargetGluer { return mRemoteTargetHandles; } + private Rect getStartBounds(RemoteAnimationTarget target) { + return target.startBounds == null ? target.screenSpaceBounds : target.startBounds; + } + /** * Ensures that we aren't excluding ancillary targets such as home/recents * @@ -144,11 +149,10 @@ public class RemoteTargetGluer { */ private RemoteAnimationTargets createRemoteAnimationTargetsForTarget( RemoteAnimationTargets targets, - RemoteAnimationTargetCompat targetToExclude) { - ArrayList<RemoteAnimationTargetCompat> targetsWithoutExcluded = - new ArrayList<RemoteAnimationTargetCompat>(); + RemoteAnimationTarget targetToExclude) { + ArrayList<RemoteAnimationTarget> targetsWithoutExcluded = new ArrayList<>(); - for (RemoteAnimationTargetCompat targetCompat : targets.unfilteredApps) { + for (RemoteAnimationTarget targetCompat : targets.unfilteredApps) { if (targetCompat == targetToExclude) { continue; } @@ -162,9 +166,8 @@ public class RemoteTargetGluer { targetsWithoutExcluded.add(targetCompat); } - final RemoteAnimationTargetCompat[] filteredApps = - targetsWithoutExcluded.toArray( - new RemoteAnimationTargetCompat[targetsWithoutExcluded.size()]); + final RemoteAnimationTarget[] filteredApps = targetsWithoutExcluded.toArray( + new RemoteAnimationTarget[targetsWithoutExcluded.size()]); return new RemoteAnimationTargets( filteredApps, targets.wallpapers, targets.nonApps, targets.targetMode); } diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java index baeb514e18..291f8354d2 100644 --- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -24,12 +24,14 @@ import android.graphics.Matrix; import android.graphics.Matrix.ScaleToFit; import android.graphics.Rect; import android.graphics.RectF; +import android.view.RemoteAnimationTarget; import androidx.annotation.NonNull; import androidx.annotation.UiThread; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; @@ -37,11 +39,10 @@ import com.android.launcher3.touch.PagedOrientationHandler; import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.RectFSpringAnim; +import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TransformParams; import com.android.quickstep.util.TransformParams.BuilderProxy; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder; import java.util.Arrays; import java.util.function.Consumer; @@ -65,6 +66,7 @@ public abstract class SwipeUpAnimationLogic implements // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely // visible. protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift); + protected float mCurrentDisplacement; // The distance needed to drag to reach the task size in recents. protected int mTransitionDragLength; @@ -115,7 +117,9 @@ public abstract class SwipeUpAnimationLogic implements @UiThread public void updateDisplacement(float displacement) { // We are moving in the negative x/y direction - displacement = -displacement; + displacement = overrideDisplacementForTransientTaskbar(-displacement); + mCurrentDisplacement = displacement; + float shift; if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) { shift = mDragLengthFactor; @@ -128,6 +132,17 @@ public abstract class SwipeUpAnimationLogic implements } /** + * When Transient Taskbar is enabled, subclasses can override the displacement to keep the app + * window at the bottom of the screen while taskbar is being swiped in. + * @param displacement The distance the user has swiped up from the bottom of the screen. This + * value will be positive unless the user swipe downwards. + * @return the overridden displacement. + */ + protected float overrideDisplacementForTransientTaskbar(float displacement) { + return displacement; + } + + /** * Called when the value of {@link #mCurrentShift} changes */ @UiThread @@ -335,11 +350,11 @@ public abstract class SwipeUpAnimationLogic implements } @Override - public void onBuildTargetParams( - Builder builder, RemoteAnimationTargetCompat app, TransformParams params) { - builder.withMatrix(mMatrix) - .withWindowCrop(mCropRect) - .withCornerRadius(params.getCornerRadius()); + public void onBuildTargetParams(SurfaceProperties builder, RemoteAnimationTarget app, + TransformParams params) { + builder.setMatrix(mMatrix) + .setWindowCrop(mCropRect) + .setCornerRadius(params.getCornerRadius()); } @Override diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 3b2df315b1..bb973342d5 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -44,6 +44,8 @@ import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.window.IOnBackInvokedCallback; +import android.window.RemoteTransition; +import android.window.TransitionFilter; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; @@ -53,13 +55,11 @@ import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; -import com.android.systemui.shared.system.RemoteTransitionCompat; import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController; import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController; import com.android.systemui.shared.system.smartspace.SmartspaceState; import com.android.wm.shell.back.IBackAnimation; import com.android.wm.shell.desktopmode.IDesktopMode; -import com.android.wm.shell.floating.IFloatingTasks; import com.android.wm.shell.onehanded.IOneHanded; import com.android.wm.shell.pip.IPip; import com.android.wm.shell.pip.IPipAnimationListener; @@ -74,6 +74,7 @@ import com.android.wm.shell.util.GroupedRecentTaskInfo; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedHashMap; /** * Holds the reference to SystemUI. @@ -90,7 +91,6 @@ public class SystemUiProxy implements ISystemUiProxy { private IPip mPip; private ISysuiUnlockAnimationController mSysuiUnlockAnimationController; private ISplitScreen mSplitScreen; - private IFloatingTasks mFloatingTasks; private IOneHanded mOneHanded; private IShellTransitions mShellTransitions; private IStartingWindow mStartingWindow; @@ -110,7 +110,8 @@ public class SystemUiProxy implements ISystemUiProxy { private IStartingWindowListener mStartingWindowListener; private ILauncherUnlockAnimationController mLauncherUnlockAnimationController; private IRecentTasksListener mRecentTasksListener; - private final ArrayList<RemoteTransitionCompat> mRemoteTransitions = new ArrayList<>(); + private final LinkedHashMap<RemoteTransition, TransitionFilter> mRemoteTransitions = + new LinkedHashMap<>(); private IOnBackInvokedCallback mBackToLauncherCallback; // Used to dedupe calls to SystemUI @@ -168,7 +169,7 @@ public class SystemUiProxy implements ISystemUiProxy { } public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen, - IFloatingTasks floatingTasks, IOneHanded oneHanded, IShellTransitions shellTransitions, + IOneHanded oneHanded, IShellTransitions shellTransitions, IStartingWindow startingWindow, IRecentTasks recentTasks, ISysuiUnlockAnimationController sysuiUnlockAnimationController, IBackAnimation backAnimation, IDesktopMode desktopMode) { @@ -176,7 +177,6 @@ public class SystemUiProxy implements ISystemUiProxy { mSystemUiProxy = proxy; mPip = pip; mSplitScreen = splitScreen; - mFloatingTasks = floatingTasks; mOneHanded = oneHanded; mShellTransitions = shellTransitions; mStartingWindow = startingWindow; @@ -187,7 +187,7 @@ public class SystemUiProxy implements ISystemUiProxy { linkToDeath(); // re-attach the listeners once missing due to setProxy has not been initialized yet. if (mPipAnimationListener != null && mPip != null) { - setPinnedStackAnimationListener(mPipAnimationListener); + setPipAnimationListener(mPipAnimationListener); } if (mSplitScreenListener != null && mSplitScreen != null) { registerSplitScreenListener(mSplitScreenListener); @@ -198,9 +198,7 @@ public class SystemUiProxy implements ISystemUiProxy { if (mSysuiUnlockAnimationController != null && mLauncherUnlockAnimationController != null) { setLauncherUnlockAnimationController(mLauncherUnlockAnimationController); } - for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) { - registerRemoteTransition(mRemoteTransitions.get(i)); - } + new LinkedHashMap<>(mRemoteTransitions).forEach(this::registerRemoteTransition); if (mRecentTasksListener != null && mRecentTasks != null) { registerRecentTasksListener(mRecentTasksListener); } @@ -210,7 +208,7 @@ public class SystemUiProxy implements ISystemUiProxy { } public void clearProxy() { - setProxy(null, null, null, null, null, null, null, null, null, null, null); + setProxy(null, null, null, null, null, null, null, null, null, null); } // TODO(141886704): Find a way to remove this @@ -347,31 +345,6 @@ public class SystemUiProxy implements ISystemUiProxy { } @Override - public void notifySwipeUpGestureStarted() { - if (mSystemUiProxy != null) { - try { - mSystemUiProxy.notifySwipeUpGestureStarted(); - } catch (RemoteException e) { - Log.w(TAG, "Failed call notifySwipeUpGestureStarted", e); - } - } - } - - /** - * Notifies that swipe-to-home action is finished. - */ - @Override - public void notifySwipeToHomeFinished() { - if (mSystemUiProxy != null) { - try { - mSystemUiProxy.notifySwipeToHomeFinished(); - } catch (RemoteException e) { - Log.w(TAG, "Failed call notifySwipeToHomeFinished", e); - } - } - } - - @Override public void notifyPrioritizedRotation(int rotation) { if (mSystemUiProxy != null) { try { @@ -475,12 +448,12 @@ public class SystemUiProxy implements ISystemUiProxy { } /** - * Sets listener to get pinned stack animation callbacks. + * Sets listener to get pip animation callbacks. */ - public void setPinnedStackAnimationListener(IPipAnimationListener listener) { + public void setPipAnimationListener(IPipAnimationListener listener) { if (mPip != null) { try { - mPip.setPinnedStackAnimationListener(listener); + mPip.setPipAnimationListener(listener); } catch (RemoteException e) { Log.w(TAG, "Failed call setPinnedStackAnimationListener", e); } @@ -522,6 +495,19 @@ public class SystemUiProxy implements ISystemUiProxy { } } + /** + * Sets the next pip animation type to be the alpha animation. + */ + public void setPipAnimationTypeToAlpha() { + if (mPip != null) { + try { + mPip.setPipAnimationTypeToAlpha(); + } catch (RemoteException e) { + Log.w(TAG, "Failed call setPipAnimationTypeToAlpha", e); + } + } + } + // // Splitscreen // @@ -549,15 +535,55 @@ public class SystemUiProxy implements ISystemUiProxy { } /** Start multiple tasks in split-screen simultaneously. */ - public void startTasks(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions, - @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio, - RemoteTransitionCompat remoteTransition, InstanceId instanceId) { + public void startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2, + @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, + RemoteTransition remoteTransition, InstanceId instanceId) { + if (mSystemUiProxy != null) { + try { + mSplitScreen.startTasks(taskId1, options1, taskId2, options2, splitPosition, + splitRatio, remoteTransition, instanceId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call startTasks"); + } + } + } + + public void startIntentAndTask(PendingIntent pendingIntent, Bundle options1, int taskId, + Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, + float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) { if (mSystemUiProxy != null) { try { - mSplitScreen.startTasks(mainTaskId, mainOptions, sideTaskId, sideOptions, - sidePosition, splitRatio, remoteTransition.getTransition(), instanceId); + mSplitScreen.startIntentAndTask(pendingIntent, options1, taskId, options2, + splitPosition, splitRatio, remoteTransition, instanceId); } catch (RemoteException e) { - Log.w(TAG, "Failed call startTask"); + Log.w(TAG, "Failed call startIntentAndTask"); + } + } + } + + public void startIntents(PendingIntent pendingIntent1, Bundle options1, + PendingIntent pendingIntent2, Bundle options2, + @SplitConfigurationOptions.StagePosition int splitPosition, + float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) { + if (mSystemUiProxy != null) { + try { + mSplitScreen.startIntents(pendingIntent1, options1, pendingIntent2, options2, + splitPosition, splitRatio, remoteTransition, instanceId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call startIntents"); + } + } + } + + public void startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId, + Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, + float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) { + if (mSystemUiProxy != null) { + try { + mSplitScreen.startShortcutAndTask(shortcutInfo, options1, taskId, options2, + splitPosition, splitRatio, remoteTransition, instanceId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call startShortcutAndTask"); } } } @@ -565,13 +591,13 @@ public class SystemUiProxy implements ISystemUiProxy { /** * Start multiple tasks in split-screen simultaneously. */ - public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId, - Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition, + public void startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2, + Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) { if (mSystemUiProxy != null) { try { - mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId, - sideOptions, sidePosition, splitRatio, adapter, instanceId); + mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2, + splitPosition, splitRatio, adapter, instanceId); } catch (RemoteException e) { Log.w(TAG, "Failed call startTasksWithLegacyTransition"); } @@ -579,30 +605,42 @@ public class SystemUiProxy implements ISystemUiProxy { } public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, - Intent fillInIntent, int taskId, Bundle mainOptions, Bundle sideOptions, - @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio, + Bundle options1, int taskId, Bundle options2, + @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) { if (mSystemUiProxy != null) { try { - mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, fillInIntent, - taskId, mainOptions, sideOptions, sidePosition, splitRatio, adapter, - instanceId); + mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, options1, taskId, + options2, splitPosition, splitRatio, adapter, instanceId); } catch (RemoteException e) { Log.w(TAG, "Failed call startIntentAndTaskWithLegacyTransition"); } } } - public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, int taskId, - Bundle mainOptions, Bundle sideOptions, + public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1, + int taskId, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, + float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) { + if (mSystemUiProxy != null) { + try { + mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1, + taskId, options2, splitPosition, splitRatio, adapter, instanceId); + } catch (RemoteException e) { + Log.w(TAG, "Failed call startShortcutAndTaskWithLegacyTransition"); + } + } + } + + public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1, Bundle options1, + PendingIntent pendingIntent2, Bundle options2, @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) { if (mSystemUiProxy != null) { try { - mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, taskId, - mainOptions, sideOptions, sidePosition, splitRatio, adapter, instanceId); + mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, options1, + pendingIntent2, options2, sidePosition, splitRatio, adapter, instanceId); } catch (RemoteException e) { - Log.w(TAG, "Failed call startShortcutAndTaskWithLegacyTransition"); + Log.w(TAG, "Failed call startIntentsWithLegacyTransition"); } } } @@ -646,6 +684,7 @@ public class SystemUiProxy implements ISystemUiProxy { * * @return RemoteAnimationTargets of windows that need to animate but only exist in shell. */ + @Nullable public RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) { if (mSplitScreen != null) { try { @@ -657,6 +696,7 @@ public class SystemUiProxy implements ISystemUiProxy { return null; } + @Nullable public RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) { if (mSplitScreen != null) { try { @@ -669,20 +709,6 @@ public class SystemUiProxy implements ISystemUiProxy { } // - // Floating tasks - // - - public void showFloatingTask(Intent intent) { - if (mFloatingTasks != null) { - try { - mFloatingTasks.showTask(intent); - } catch (RemoteException e) { - Log.w(TAG, "Launcher: Failed call showFloatingTask", e); - } - } - } - - // // One handed // @@ -710,24 +736,24 @@ public class SystemUiProxy implements ISystemUiProxy { // Remote transitions // - public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) { + public void registerRemoteTransition( + RemoteTransition remoteTransition, TransitionFilter filter) { if (mShellTransitions != null) { try { - mShellTransitions.registerRemote(remoteTransition.getFilter(), - remoteTransition.getTransition()); + mShellTransitions.registerRemote(filter, remoteTransition); } catch (RemoteException e) { Log.w(TAG, "Failed call registerRemoteTransition"); } } - if (!mRemoteTransitions.contains(remoteTransition)) { - mRemoteTransitions.add(remoteTransition); + if (!mRemoteTransitions.containsKey(remoteTransition)) { + mRemoteTransitions.put(remoteTransition, filter); } } - public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) { + public void unregisterRemoteTransition(RemoteTransition remoteTransition) { if (mShellTransitions != null) { try { - mShellTransitions.unregisterRemote(remoteTransition.getTransition()); + mShellTransitions.unregisterRemote(remoteTransition); } catch (RemoteException e) { Log.w(TAG, "Failed call registerRemoteTransition"); } diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index b9a1b0629f..c45b2f05f8 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -15,12 +15,14 @@ */ package com.android.quickstep; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; + import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED; import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME; +import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION; +import static com.android.systemui.shared.system.RemoteTransitionCompat.newRemoteTransition; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -29,6 +31,7 @@ import android.content.Intent; import android.os.SystemProperties; import android.util.Log; import android.view.RemoteAnimationTarget; +import android.window.RemoteTransition; import androidx.annotation.Nullable; import androidx.annotation.UiThread; @@ -36,15 +39,13 @@ import androidx.annotation.UiThread; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.quickstep.TopTaskTracker.CachedTaskInfo; +import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.RemoteTransitionCompat; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; -import java.util.Arrays; import java.util.HashMap; public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener { @@ -58,7 +59,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn private RecentsAnimationTargets mTargets; // Temporary until we can hook into gesture state events private GestureState mLastGestureState; - private RemoteAnimationTargetCompat mLastAppearedTaskTarget; + private RemoteAnimationTarget mLastAppearedTaskTarget; private Runnable mLiveTileCleanUpHandler; private Context mCtx; @@ -72,7 +73,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn return; } BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode() + if (activityInterface.isInLiveTileMode() && activityInterface.getCreatedActivity() != null) { RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel(); if (recentsView != null) { @@ -102,6 +103,9 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn @UiThread public RecentsAnimationCallbacks startRecentsAnimation(GestureState gestureState, Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) { + ActiveGestureLog.INSTANCE.addLog( + /* event= */ "startRecentsAnimation", + /* gestureEvent= */ START_RECENTS_ANIMATION); // Notify if recents animation is still running if (mController != null) { String msg = "New recents animation started before old animation completed"; @@ -152,12 +156,12 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn } @Override - public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) { - RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0]; + public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) { + RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0]; BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); - for (RemoteAnimationTargetCompat compat : appearedTaskTargets) { - if (compat.activityType == ACTIVITY_TYPE_HOME + for (RemoteAnimationTarget compat : appearedTaskTargets) { + if (compat.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME && activityInterface.getCreatedActivity() instanceof RecentsActivity) { // When receive opening home activity while recents is running, enter home // and dismiss recents. @@ -166,25 +170,25 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn } } - RemoteAnimationTarget[] nonAppTargets = SystemUiProxy.INSTANCE.getNoCreate() - .onStartingSplitLegacy(Arrays.stream(appearedTaskTargets) - .map(RemoteAnimationTargetCompat::unwrap) - .toArray(RemoteAnimationTarget[]::new)); - - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode() + RemoteAnimationTarget[] nonAppTargets = SystemUiProxy.INSTANCE.get(mCtx) + .onStartingSplitLegacy(appearedTaskTargets); + if (nonAppTargets == null) { + nonAppTargets = new RemoteAnimationTarget[0]; + } + if (activityInterface.isInLiveTileMode() && activityInterface.getCreatedActivity() != null) { RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel(); if (recentsView != null) { recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, appearedTaskTargets, - new RemoteAnimationTargetCompat[0] /* wallpaper */, - RemoteAnimationTargetCompat.wrap(nonAppTargets) /* nonApps */); + new RemoteAnimationTarget[0] /* wallpaper */, + nonAppTargets /* nonApps */); return; } - } else if (nonAppTargets != null && nonAppTargets.length > 0) { + } else if (nonAppTargets.length > 0) { TaskViewUtils.createSplitAuxiliarySurfacesAnimator( - RemoteAnimationTargetCompat.wrap(nonAppTargets) /* nonApps */, + nonAppTargets /* nonApps */, true /*shown*/, dividerAnimator -> { dividerAnimator.start(); dividerAnimator.end(); @@ -204,7 +208,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn @Override public boolean onSwitchToScreenshot(Runnable onFinished) { - if (!ENABLE_QUICKSTEP_LIVE_TILE.get() || !activityInterface.isInLiveTileMode() + if (!activityInterface.isInLiveTileMode() || activityInterface.getCreatedActivity() == null) { // No need to switch since tile is already a screenshot. onFinished.run(); @@ -225,11 +229,10 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn mCallbacks.addListener(listener); if (ENABLE_SHELL_TRANSITIONS) { - RemoteTransitionCompat transition = new RemoteTransitionCompat(mCallbacks, + RemoteTransition transition = newRemoteTransition(mCallbacks, mController != null ? mController.getController() : null, mCtx.getIApplicationThread()); - final ActivityOptions options = ActivityOptions.makeRemoteTransition( - transition.getTransition()); + final ActivityOptions options = ActivityOptions.makeRemoteTransition(transition); // Allowing to pause Home if Home is top activity and Recents is not Home. So when user // start home when recents animation is playing, the home activity can be resumed again // to let the transition controller collect Home activity. @@ -252,6 +255,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn * Continues the existing running recents animation for a new gesture. */ public RecentsAnimationCallbacks continueRecentsAnimation(GestureState gestureState) { + ActiveGestureLog.INSTANCE.addLog(/* event= */ "continueRecentsAnimation"); mCallbacks.removeListener(mLastGestureState); mLastGestureState = gestureState; mCallbacks.addListener(gestureState); @@ -266,7 +270,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn return; } BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface(); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode() + if (activityInterface.isInLiveTileMode() && activityInterface.getCreatedActivity() != null) { RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel(); if (recentsView != null) { @@ -290,6 +294,8 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn */ public void finishRunningRecentsAnimation(boolean toHome) { if (mController != null) { + ActiveGestureLog.INSTANCE.addLog( + /* event= */ "finishRunningRecentsAnimation", toHome); mCallbacks.notifyAnimationCanceled(); Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome ? mController::finishAnimationToHome @@ -322,6 +328,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn * Cleans up the recents animation entirely. */ private void cleanUpRecentsAnimation() { + ActiveGestureLog.INSTANCE.addLog(/* event= */ "cleanUpRecentsAnimation"); if (mLiveTileCleanUpHandler != null) { mLiveTileCleanUpHandler.run(); mLiveTileCleanUpHandler = null; diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java index dc60875db8..7c05a1092c 100644 --- a/quickstep/src/com/android/quickstep/TaskIconCache.java +++ b/quickstep/src/com/android/quickstep/TaskIconCache.java @@ -249,12 +249,13 @@ public class TaskIconCache implements DisplayInfoChangeListener { private BitmapInfo getBitmapInfo(Drawable drawable, int userId, int primaryColor, boolean isInstantApp) { try (BaseIconFactory bif = getIconFactory()) { - bif.disableColorExtraction(); bif.setWrapperBackgroundColor(primaryColor); // User version code O, so that the icon is always wrapped in an adaptive icon container return bif.createBadgedIconBitmap(drawable, - new IconOptions().setUser(UserHandle.of(userId)).setInstantApp(isInstantApp)); + new IconOptions().setUser(UserHandle.of(userId)) + .setInstantApp(isInstantApp) + .setExtractedColor(0)); } } diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java index e10cab60e0..d40f2ae017 100644 --- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java @@ -18,7 +18,6 @@ package com.android.quickstep; import static android.view.Surface.ROTATION_0; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL; import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED; @@ -174,14 +173,10 @@ public class TaskOverlayFactory implements ResourceBasedOverride { * @param callback callback to run, after switching to screenshot */ public void endLiveTileMode(@NonNull Runnable callback) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - RecentsView recentsView = mThumbnailView.getTaskView().getRecentsView(); - recentsView.switchToScreenshot( - () -> recentsView.finishRecentsAnimation(true /* toRecents */, - false /* shouldPip */, callback)); - } else { - callback.run(); - } + RecentsView recentsView = mThumbnailView.getTaskView().getRecentsView(); + recentsView.switchToScreenshot( + () -> recentsView.finishRecentsAnimation(true /* toRecents */, + false /* shouldPip */, callback)); } /** diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java index eae79dfa19..663525d0c5 100644 --- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java @@ -303,7 +303,8 @@ public interface TaskShortcutFactory { private boolean isAvailable(BaseDraggingActivity activity, int displayId) { return ActivityManagerWrapper.getInstance().supportsFreeformMultiWindow(activity) - && !SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false); + && !SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false) + && !SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false); } }; diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java index d7227780c6..67360c4cc3 100644 --- a/quickstep/src/com/android/quickstep/TaskUtils.java +++ b/quickstep/src/com/android/quickstep/TaskUtils.java @@ -26,6 +26,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.UserHandle; import android.util.Log; +import android.view.RemoteAnimationTarget; import androidx.annotation.Nullable; @@ -34,7 +35,6 @@ import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageManagerHelper; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.List; @@ -87,9 +87,9 @@ public final class TaskUtils { } - public static boolean taskIsATargetWithMode(RemoteAnimationTargetCompat[] targets, + public static boolean taskIsATargetWithMode(RemoteAnimationTarget[] targets, int taskId, int mode) { - for (RemoteAnimationTargetCompat target : targets) { + for (RemoteAnimationTarget target : targets) { if (target.mode == mode && target.taskId == taskId) { return true; } diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index a96524e186..67de4b1679 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -15,12 +15,15 @@ */ package com.android.quickstep; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.view.RemoteAnimationTarget.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; +import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; +import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_DELAY_NAV_FADE_IN; @@ -35,17 +38,13 @@ import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncest import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR; import static com.android.launcher3.anim.Interpolators.clampToProgress; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; -import static com.android.launcher3.statehandlers.DepthController.STATE_DEPTH; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING; +import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.annotation.TargetApi; -import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.graphics.Matrix; @@ -53,6 +52,7 @@ import android.graphics.Matrix.ScaleToFit; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; +import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.View; import android.window.TransitionInfo; @@ -62,6 +62,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; @@ -72,6 +73,8 @@ import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.util.DisplayController; import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle; import com.android.quickstep.util.MultiValueUpdateListener; +import com.android.quickstep.util.SurfaceTransaction; +import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TransformParams; @@ -82,7 +85,6 @@ import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import java.util.ArrayList; import java.util.List; @@ -104,7 +106,7 @@ public final class TaskViewUtils { * opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView. */ public static TaskView findTaskViewToLaunch( - RecentsView recentsView, View v, RemoteAnimationTargetCompat[] targets) { + RecentsView recentsView, View v, RemoteAnimationTarget[] targets) { if (v instanceof TaskView) { TaskView taskView = (TaskView) v; return recentsView.isTaskViewVisible(taskView) ? taskView : null; @@ -134,7 +136,7 @@ public final class TaskViewUtils { } // Resolve the opening task id int openingTaskId = -1; - for (RemoteAnimationTargetCompat target : targets) { + for (RemoteAnimationTarget target : targets) { if (target.mode == MODE_OPENING) { openingTaskId = target.taskId; break; @@ -157,9 +159,9 @@ public final class TaskViewUtils { public static void createRecentsWindowAnimator( @NonNull TaskView v, boolean skipViewChanges, - @NonNull RemoteAnimationTargetCompat[] appTargets, - @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, - @NonNull RemoteAnimationTargetCompat[] nonAppTargets, + @NonNull RemoteAnimationTarget[] appTargets, + @NonNull RemoteAnimationTarget[] wallpaperTargets, + @NonNull RemoteAnimationTarget[] nonAppTargets, @Nullable DepthController depthController, PendingAnimation out) { RecentsView recentsView = v.getRecentsView(); @@ -169,7 +171,7 @@ public final class TaskViewUtils { final RemoteAnimationTargets targets = new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING); - final RemoteAnimationTargetCompat navBarTarget = targets.getNavBarRemoteAnimationTarget(); + final RemoteAnimationTarget navBarTarget = targets.getNavBarRemoteAnimationTarget(); SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v); targets.addReleaseCheck(applier); @@ -252,21 +254,24 @@ public final class TaskViewUtils { @Override public void onUpdate(float percent, boolean initOnly) { - final SurfaceParams.Builder navBuilder = - new SurfaceParams.Builder(navBarTarget.leash); + // TODO Do we need to operate over multiple TVSs for the navbar leash? for (RemoteTargetHandle handle : remoteTargetHandles) { + SurfaceTransaction transaction = new SurfaceTransaction(); + SurfaceProperties navBuilder = + transaction.forSurface(navBarTarget.leash); + if (mNavFadeIn.value > mNavFadeIn.getStartValue()) { TaskViewSimulator taskViewSimulator = handle.getTaskViewSimulator(); taskViewSimulator.getCurrentCropRect().round(cropRect); - navBuilder.withMatrix(taskViewSimulator.getCurrentMatrix()) - .withWindowCrop(cropRect) - .withAlpha(mNavFadeIn.value); + navBuilder.setMatrix(taskViewSimulator.getCurrentMatrix()) + .setWindowCrop(cropRect) + .setAlpha(mNavFadeIn.value); } else { - navBuilder.withAlpha(mNavFadeOut.value); + navBuilder.setAlpha(mNavFadeOut.value); } - handle.getTransformParams().applySurfaceParams(navBuilder.build()); + handle.getTransformParams().applySurfaceParams(transaction); } } }); @@ -304,9 +309,15 @@ public final class TaskViewUtils { // to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is: // Mt K(0)` K(t) Mt` TaskThumbnailView[] thumbnails = v.getThumbnails(); - Matrix[] mt = new Matrix[simulatorCopies.length]; - Matrix[] mti = new Matrix[simulatorCopies.length]; - for (int i = 0; i < thumbnails.length; i++) { + + // In case simulator copies and thumbnail size do no match, ensure we get the lesser. + // This ensures we do not create arrays with empty elements or attempt to references + // indexes out of array bounds. + final int matrixSize = Math.min(simulatorCopies.length, thumbnails.length); + + Matrix[] mt = new Matrix[matrixSize]; + Matrix[] mti = new Matrix[matrixSize]; + for (int i = 0; i < matrixSize; i++) { TaskThumbnailView ttv = thumbnails[i]; RectF localBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight()); float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()}; @@ -321,16 +332,27 @@ public final class TaskViewUtils { Matrix localMti = new Matrix(); localMt.invert(localMti); mti[i] = localMti; + + // Translations for child thumbnails also get scaled as the parent taskView scales + // Add inverse scaling to keep translations the same + float translationY = ttv.getTranslationY(); + float translationX = ttv.getTranslationX(); + float fullScreenScale = + topMostSimulators[i].getTaskViewSimulator().getFullScreenScale(); + out.addFloat(ttv, VIEW_TRANSLATE_Y, translationY, + translationY / fullScreenScale, TOUCH_RESPONSE_INTERPOLATOR); + out.addFloat(ttv, VIEW_TRANSLATE_X, translationX, + translationX / fullScreenScale, TOUCH_RESPONSE_INTERPOLATOR); } - Matrix[] k0i = new Matrix[simulatorCopies.length]; - for (int i = 0; i < simulatorCopies.length; i++) { + Matrix[] k0i = new Matrix[matrixSize]; + for (int i = 0; i < matrixSize; i++) { k0i[i] = new Matrix(); simulatorCopies[i].getTaskViewSimulator().getCurrentMatrix().invert(k0i[i]); } Matrix animationMatrix = new Matrix(); out.addOnFrameCallback(() -> { - for (int i = 0; i < simulatorCopies.length; i++) { + for (int i = 0; i < matrixSize; i++) { animationMatrix.set(mt[i]); animationMatrix.postConcat(k0i[i]); animationMatrix.postConcat(simulatorCopies[i] @@ -367,8 +389,8 @@ public final class TaskViewUtils { }); if (depthController != null) { - out.setFloat(depthController, STATE_DEPTH, BACKGROUND_APP.getDepth(baseActivity), - TOUCH_RESPONSE_INTERPOLATOR); + out.setFloat(depthController.stateDepth, MULTI_PROPERTY_VALUE, + BACKGROUND_APP.getDepth(baseActivity), TOUCH_RESPONSE_INTERPOLATOR); } } @@ -390,9 +412,8 @@ public final class TaskViewUtils { */ public static void composeRecentsSplitLaunchAnimator(GroupedTaskView launchingTaskView, @NonNull StateManager stateManager, @Nullable DepthController depthController, - int initialTaskId, @Nullable PendingIntent initialTaskPendingIntent, int secondTaskId, - @NonNull TransitionInfo transitionInfo, SurfaceControl.Transaction t, - @NonNull Runnable finishCallback) { + int initialTaskId, int secondTaskId, @NonNull TransitionInfo transitionInfo, + SurfaceControl.Transaction t, @NonNull Runnable finishCallback) { if (launchingTaskView != null) { AnimatorSet animatorSet = new AnimatorSet(); animatorSet.addListener(new AnimatorListenerAdapter() { @@ -402,12 +423,12 @@ public final class TaskViewUtils { } }); - final RemoteAnimationTargetCompat[] appTargets = + final RemoteAnimationTarget[] appTargets = RemoteAnimationTargetCompat.wrapApps(transitionInfo, t, null /* leashMap */); - final RemoteAnimationTargetCompat[] wallpaperTargets = + final RemoteAnimationTarget[] wallpaperTargets = RemoteAnimationTargetCompat.wrapNonApps( transitionInfo, true /* wallpapers */, t, null /* leashMap */); - final RemoteAnimationTargetCompat[] nonAppTargets = + final RemoteAnimationTarget[] nonAppTargets = RemoteAnimationTargetCompat.wrapNonApps( transitionInfo, false /* wallpapers */, t, null /* leashMap */); final RecentsView recentsView = launchingTaskView.getRecentsView(); @@ -426,8 +447,10 @@ public final class TaskViewUtils { TransitionInfo.Change splitRoot2 = null; for (int i = 0; i < transitionInfo.getChanges().size(); ++i) { final TransitionInfo.Change change = transitionInfo.getChanges().get(i); - final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1; + if (change.getTaskInfo() == null) continue; + final int taskId = change.getTaskInfo().taskId; final int mode = change.getMode(); + // Find the target tasks' root tasks since those are the split stages that need to // be animated (the tasks themselves are children and thus inherit animation). if (taskId == initialTaskId || taskId == secondTaskId) { @@ -440,7 +463,7 @@ public final class TaskViewUtils { + "root of " + taskId + " is already visible or has broken hierarchy."); } } - if (taskId == initialTaskId && initialTaskId != INVALID_TASK_ID) { + if (taskId == initialTaskId) { splitRoot1 = transitionInfo.getChange(change.getParent()); } if (taskId == secondTaskId) { @@ -474,17 +497,16 @@ public final class TaskViewUtils { * If {@param launchingTaskView} is not null, then this will play the tasks launch animation * from the position of the GroupedTaskView (when user taps on the TaskView to start it). * Technically this case should be taken care of by - * {@link #composeRecentsSplitLaunchAnimatorLegacy()} below, but the way we launch tasks whether + * {@link #composeRecentsSplitLaunchAnimatorLegacy} below, but the way we launch tasks whether * it's a single task or multiple tasks results in different entry-points. * * If it is null, then it will simply fade in the starting apps and fade out launcher (for the * case where launcher handles animating starting split tasks from app icon) */ public static void composeRecentsSplitLaunchAnimatorLegacy( - @Nullable GroupedTaskView launchingTaskView, int initialTaskId, - @Nullable PendingIntent initialTaskPendingIntent, int secondTaskId, - @NonNull RemoteAnimationTargetCompat[] appTargets, - @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, - @NonNull RemoteAnimationTargetCompat[] nonAppTargets, + @Nullable GroupedTaskView launchingTaskView, int initialTaskId, int secondTaskId, + @NonNull RemoteAnimationTarget[] appTargets, + @NonNull RemoteAnimationTarget[] wallpaperTargets, + @NonNull RemoteAnimationTarget[] nonAppTargets, @NonNull StateManager stateManager, @Nullable DepthController depthController, @NonNull Runnable finishCallback) { @@ -507,7 +529,7 @@ public final class TaskViewUtils { final ArrayList<SurfaceControl> openingTargets = new ArrayList<>(); final ArrayList<SurfaceControl> closingTargets = new ArrayList<>(); - for (RemoteAnimationTargetCompat appTarget : appTargets) { + for (RemoteAnimationTarget appTarget : appTargets) { final int taskId = appTarget.taskInfo != null ? appTarget.taskInfo.taskId : -1; final int mode = appTarget.mode; final SurfaceControl leash = appTarget.leash; @@ -562,9 +584,9 @@ public final class TaskViewUtils { } public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, - @NonNull RemoteAnimationTargetCompat[] appTargets, - @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, - @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing, + @NonNull RemoteAnimationTarget[] appTargets, + @NonNull RemoteAnimationTarget[] wallpaperTargets, + @NonNull RemoteAnimationTarget[] nonAppTargets, boolean launcherClosing, @NonNull StateManager stateManager, @NonNull RecentsView recentsView, @Nullable DepthController depthController) { boolean skipLauncherChanges = !launcherClosing; @@ -637,7 +659,7 @@ public final class TaskViewUtils { }; } pa.add(launcherAnim); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1) { + if (recentsView.getRunningTaskIndex() != -1) { pa.addOnFrameCallback(recentsView::redrawLiveTile); } anim.play(pa.buildAnim()); @@ -656,7 +678,7 @@ public final class TaskViewUtils { * @return the animator animating the surfaces */ public static ValueAnimator createSplitAuxiliarySurfacesAnimator( - RemoteAnimationTargetCompat[] nonApps, boolean shown, + RemoteAnimationTarget[] nonApps, boolean shown, Consumer<ValueAnimator> animatorHandler) { if (nonApps == null || nonApps.length == 0) { return null; @@ -666,7 +688,7 @@ public final class TaskViewUtils { List<SurfaceControl> auxiliarySurfaces = new ArrayList<>(nonApps.length); boolean hasSurfaceToAnimate = false; for (int i = 0; i < nonApps.length; ++i) { - final RemoteAnimationTargetCompat targ = nonApps[i]; + final RemoteAnimationTarget targ = nonApps[i]; final SurfaceControl leash = targ.leash; if (targ.windowType == TYPE_DOCK_DIVIDER && leash != null && leash.isValid()) { auxiliarySurfaces.add(leash); diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 1999701f61..5d17cc77f4 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2022 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. @@ -15,30 +15,32 @@ */ package com.android.quickstep; +import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS; import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.quickstep.GestureState.DEFAULT_STATE; +import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_BACK_ANIMATION; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_DESKTOP_MODE; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_FLOATING_TASKS; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN; +import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW; import android.annotation.TargetApi; import android.app.PendingIntent; @@ -47,7 +49,6 @@ import android.app.Service; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; -import android.graphics.Rect; import android.graphics.Region; import android.graphics.drawable.Icon; import android.os.Build; @@ -55,11 +56,11 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Looper; import android.os.SystemClock; -import android.os.SystemProperties; import android.util.Log; import android.view.Choreographer; import android.view.InputEvent; import android.view.MotionEvent; +import android.view.SurfaceControl; import android.view.accessibility.AccessibilityManager; import androidx.annotation.BinderThread; @@ -67,11 +68,15 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; +import com.android.app.viewcapture.ViewCapture; import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.provider.RestoreDbTask; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarManager; @@ -84,7 +89,6 @@ import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.OnboardingPrefs; import com.android.launcher3.util.TraceHelper; -import com.android.launcher3.util.WindowBounds; import com.android.quickstep.inputconsumers.AccessibilityInputConsumer; import com.android.quickstep.inputconsumers.AssistantInputConsumer; import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer; @@ -101,8 +105,6 @@ import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActiveGestureLog.CompoundString; import com.android.quickstep.util.ProtoTracer; import com.android.quickstep.util.ProxyScreenStatusProvider; -import com.android.quickstep.util.SplitScreenBounds; -import com.android.quickstep.util.ViewCapture; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -113,7 +115,6 @@ import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationContro import com.android.systemui.shared.tracing.ProtoTraceable; import com.android.wm.shell.back.IBackAnimation; import com.android.wm.shell.desktopmode.IDesktopMode; -import com.android.wm.shell.floating.IFloatingTasks; import com.android.wm.shell.onehanded.IOneHanded; import com.android.wm.shell.pip.IPip; import com.android.wm.shell.recents.IRecentTasks; @@ -139,21 +140,7 @@ public class TouchInteractionService extends Service private static final String TAG = "TouchInteractionService"; - private static final boolean BUBBLES_HOME_GESTURE_ENABLED = - SystemProperties.getBoolean("persist.wm.debug.bubbles_home_gesture", true); - - private static final String KEY_BACK_NOTIFICATION_COUNT = "backNotificationCount"; - private static final String NOTIFY_ACTION_BACK = "com.android.quickstep.action.BACK_GESTURE"; private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once"; - private static final int MAX_BACK_NOTIFICATION_COUNT = 3; - - /** - * System Action ID to show all apps. - * TODO: Use AccessibilityService's corresponding global action constant in S - */ - private static final int SYSTEM_ACTION_ID_ALL_APPS = 14; - - private int mBackGestureNotificationCounter = -1; private final TISBinder mTISBinder = new TISBinder(); @@ -171,8 +158,6 @@ public class TouchInteractionService extends Service IPip pip = IPip.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_PIP)); ISplitScreen splitscreen = ISplitScreen.Stub.asInterface(bundle.getBinder( KEY_EXTRA_SHELL_SPLIT_SCREEN)); - IFloatingTasks floatingTasks = IFloatingTasks.Stub.asInterface(bundle.getBinder( - KEY_EXTRA_SHELL_FLOATING_TASKS)); IOneHanded onehanded = IOneHanded.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SHELL_ONE_HANDED)); IShellTransitions shellTransitions = IShellTransitions.Stub.asInterface( @@ -183,14 +168,14 @@ public class TouchInteractionService extends Service ISysuiUnlockAnimationController.Stub.asInterface( bundle.getBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER)); IRecentTasks recentTasks = IRecentTasks.Stub.asInterface( - bundle.getBinder(KEY_EXTRA_RECENT_TASKS)); + bundle.getBinder(KEY_EXTRA_SHELL_RECENT_TASKS)); IBackAnimation backAnimation = IBackAnimation.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SHELL_BACK_ANIMATION)); IDesktopMode desktopMode = IDesktopMode.Stub.asInterface( bundle.getBinder(KEY_EXTRA_SHELL_DESKTOP_MODE)); MAIN_EXECUTOR.execute(() -> { SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip, - splitscreen, floatingTasks, onehanded, shellTransitions, startingWindow, + splitscreen, onehanded, shellTransitions, startingWindow, recentTasks, launcherUnlockAnimationController, backAnimation, desktopMode); TouchInteractionService.this.initInputMonitor("TISBinder#onInitialize()"); preloadOverview(true /* fromInit */); @@ -231,16 +216,12 @@ public class TouchInteractionService extends Service @BinderThread @Override - public void onTip(int actionType, int viewType) { - // Please delete this method from the interface - } - - @BinderThread - @Override - public void onAssistantAvailable(boolean available) { + public void onAssistantAvailable(boolean available, boolean longPressHomeEnabled) { MAIN_EXECUTOR.execute(() -> { mDeviceState.setAssistantAvailable(available); TouchInteractionService.this.onAssistantVisibilityChanged(); + executeForTaskbarManager(() -> mTaskbarManager + .onLongPressHomeEnabled(longPressHomeEnabled)); }); } @@ -253,10 +234,9 @@ public class TouchInteractionService extends Service }); } - @BinderThread - public void onBackAction(boolean completed, int downX, int downY, boolean isButton, - boolean gestureSwipeLeft) { - // Remove this method from the interface + @Override + public void onNavigationBarSurface(SurfaceControl surface) { + // TODO: implement } @BinderThread @@ -273,12 +253,6 @@ public class TouchInteractionService extends Service MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region)); } - @Override - public void onSplitScreenSecondaryBoundsChanged(Rect bounds, Rect insets) { - WindowBounds wb = new WindowBounds(bounds, insets); - MAIN_EXECUTOR.execute(() -> SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb)); - } - @BinderThread @Override public void onScreenTurnedOn() { @@ -297,6 +271,16 @@ public class TouchInteractionService extends Service MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurningOff); } + @BinderThread + @Override + public void enterStageSplitFromRunningApp(boolean leftOrTop) { + StatefulActivity activity = + mOverviewComponentObserver.getActivityInterface().getCreatedActivity(); + if (activity != null) { + activity.enterStageSplitFromRunningApp(leftOrTop); + } + } + /** * Preloads the Overview activity. * @@ -482,8 +466,6 @@ public class TouchInteractionService extends Service // Temporarily disable model preload // new ModelPreload().start(this); - mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this) - .getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT)); resetHomeBounceSeenOnQuickstepEnabledFirstTime(); mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange); @@ -502,7 +484,7 @@ public class TouchInteractionService extends Service } // Reset home bounce seen on quick step enabled for first time - SharedPreferences sharedPrefs = Utilities.getPrefs(this); + SharedPreferences sharedPrefs = LauncherPrefs.getPrefs(this); if (!sharedPrefs.getBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)) { sharedPrefs.edit() .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true) @@ -521,11 +503,11 @@ public class TouchInteractionService extends Service Icon.createWithResource(this, R.drawable.ic_apps), getString(R.string.all_apps_label), getString(R.string.all_apps_label), - PendingIntent.getActivity(this, SYSTEM_ACTION_ID_ALL_APPS, intent, + PendingIntent.getActivity(this, GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)); - am.registerSystemAction(allAppsAction, SYSTEM_ACTION_ID_ALL_APPS); + am.registerSystemAction(allAppsAction, GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS); } else { - am.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS); + am.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS); } StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface() @@ -544,9 +526,22 @@ public class TouchInteractionService extends Service mOverviewComponentObserver.onSystemUiStateChanged(); mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags); - boolean wasExpanded = (lastSysUIFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0; - boolean isExpanded = - (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0; + boolean wasFreeformActive = + (lastSysUIFlags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0; + boolean isFreeformActive = + (systemUiStateFlags & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0; + if (wasFreeformActive != isFreeformActive) { + DesktopVisibilityController controller = mOverviewComponentObserver + .getActivityInterface().getDesktopVisibilityController(); + if (controller != null) { + controller.setFreeformTasksVisible(isFreeformActive); + } + } + + int isShadeExpandedFlag = + SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED; + boolean wasExpanded = (lastSysUIFlags & isShadeExpandedFlag) != 0; + boolean isExpanded = (systemUiStateFlags & isShadeExpandedFlag) != 0; if (wasExpanded != isExpanded && isExpanded) { // End live tile when expanding the notification panel for the first time from // overview. @@ -591,7 +586,7 @@ public class TouchInteractionService extends Service ProtoTracer.INSTANCE.get(this).remove(this); getSystemService(AccessibilityManager.class) - .unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS); + .unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS); mTaskbarManager.destroy(); sConnected = false; @@ -816,27 +811,9 @@ public class TouchInteractionService extends Service if (mDeviceState.isBubblesExpanded()) { reasonString = newCompoundString(reasonPrefix) .append(SUBSTRING_PREFIX) - .append("bubbles expanded"); - if (BUBBLES_HOME_GESTURE_ENABLED) { - reasonString.append(SUBSTRING_PREFIX) - .append("bubbles can handle the home gesture") - .append(", trying to use default input consumer"); - // Bubbles can handle home gesture itself. - base = getDefaultInputConsumer(reasonString); - } else { - // If Bubbles is expanded, use the overlay input consumer, which will close - // Bubbles instead of going all the way home when a swipe up is detected. - // Notification panel can be expanded on top of expanded bubbles. Bubbles remain - // expanded in the back. Make sure swipe up is not passed to bubbles in this - // case. - if (!mDeviceState.isNotificationPanelExpanded()) { - reasonString = newCompoundString(reasonPrefix) - .append(SUBSTRING_PREFIX) - .append("using SysUiOverlayInputConsumer"); - base = new SysUiOverlayInputConsumer( - getBaseContext(), mDeviceState, mInputMonitorCompat); - } - } + .append("bubbles expanded, trying to use default input consumer"); + // Bubbles can handle home gesture itself. + base = getDefaultInputConsumer(reasonString); } if (mDeviceState.isSystemUiDialogShowing()) { @@ -914,6 +891,9 @@ public class TouchInteractionService extends Service .append(consumer.getName()) .append(". reason(s):") .append(reasonString)); + if ((consumer.getType() & InputConsumer.TYPE_OTHER_ACTIVITY) != 0) { + ActiveGestureLog.INSTANCE.trackEvent(FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER); + } } private void handleOrientationSetup(InputConsumer baseInputConsumer) { @@ -955,8 +935,7 @@ public class TouchInteractionService extends Service boolean launcherResumedThroughShellTransition = gestureState.getActivityInterface().isResumed() && !previousGestureState.isRecentsAnimationRunning(); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() - && gestureState.getActivityInterface().isInLiveTileMode()) { + if (gestureState.getActivityInterface().isInLiveTileMode()) { return createOverviewInputConsumer( previousGestureState, gestureState, @@ -1044,8 +1023,7 @@ public class TouchInteractionService extends Service previousGestureState.isRunningAnimationToLauncher(); boolean forcingOverviewInputConsumer = ASSISTANT_GIVES_LAUNCHER_FOCUS.get() && forceOverviewInputConsumer; - boolean isInLiveTileMode = ENABLE_QUICKSTEP_LIVE_TILE.get() - && gestureState.getActivityInterface().isInLiveTileMode(); + boolean isInLiveTileMode = gestureState.getActivityInterface().isInLiveTileMode(); reasonString.append(SUBSTRING_PREFIX) .append(hasWindowFocus ? "activity has window focus" @@ -1227,7 +1205,9 @@ public class TouchInteractionService extends Service } mTaskbarManager.dumpLogs("", pw); - ViewCapture.INSTANCE.get(this).dump(pw, fd); + if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { + ViewCapture.getInstance().dump(pw, fd, this); + } } } @@ -1238,12 +1218,22 @@ public class TouchInteractionService extends Service } private void onCommand(PrintWriter pw, LinkedList<String> args) { - switch (args.pollFirst()) { + String cmd = args.pollFirst(); + if (cmd == null) { + pw.println("Command missing"); + printAvailableCommands(pw); + return; + } + switch (cmd) { case "clear-touch-log": ActiveGestureLog.INSTANCE.clear(); break; case "print-gesture-log": ActiveGestureLog.INSTANCE.dump("", pw); + break; + default: + pw.println("Command does not exist: " + cmd); + printAvailableCommands(pw); } } diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java index 19a6c38901..062e50e30b 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java @@ -45,7 +45,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; -import com.android.launcher3.util.MultiValueAlpha; +import com.android.launcher3.util.MultiPropertyFactory; import com.android.quickstep.RecentsActivity; import com.android.quickstep.views.ClearAllButton; @@ -95,7 +95,7 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState clearAllButtonAlpha, LINEAR); float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0; setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(), - MultiValueAlpha.VALUE, overviewButtonAlpha, LINEAR); + MultiPropertyFactory.MULTI_PROPERTY_VALUE, overviewButtonAlpha, LINEAR); float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity); setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0], diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index e32aaee532..bcaae99e2e 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -200,13 +200,12 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta } @Override - public void setModalStateEnabled(boolean isModalState) { - super.setModalStateEnabled(isModalState); + public void setModalStateEnabled(boolean isModalState, boolean animate) { if (isModalState) { - mActivity.getStateManager().goToState(RecentsState.MODAL_TASK); + mActivity.getStateManager().goToState(RecentsState.MODAL_TASK, animate); } else { if (mActivity.isInState(RecentsState.MODAL_TASK)) { - mActivity.getStateManager().goToState(DEFAULT); + mActivity.getStateManager().goToState(DEFAULT, animate); resetModalVisuals(); } } @@ -243,6 +242,9 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta if (finalState != MODAL_TASK) { setOverviewSelectEnabled(false); } + if (finalState != OVERVIEW_SPLIT_SELECT) { + resetFromSplitSelectionState(); + } if (isOverlayEnabled) { runActionOnRemoteHandles(remoteTargetHandle -> diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java index 223eba5b95..8b5f091e11 100644 --- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java +++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java @@ -55,7 +55,8 @@ public class RecentsState implements BaseState<RecentsState> { public static final RecentsState HOME = new RecentsState(3, 0); public static final RecentsState BG_LAUNCHER = new LauncherState(4, 0); public static final RecentsState OVERVIEW_SPLIT_SELECT = new RecentsState(5, - FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_OVERVIEW_UI | FLAG_CLOSE_POPUPS); + FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_OVERVIEW_UI | FLAG_CLOSE_POPUPS + | FLAG_DISABLE_RESTORE); public final int ordinal; private final int mFlags; diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java index eca61bb07d..db4927a0d1 100644 --- a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java +++ b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java @@ -15,8 +15,6 @@ */ package com.android.quickstep.fallback; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; - import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController; import com.android.quickstep.RecentsActivity; @@ -28,8 +26,7 @@ public class RecentsTaskController extends TaskViewTouchController<RecentsActivi @Override protected boolean isRecentsInteractive() { - return mActivity.hasWindowFocus() || (ENABLE_QUICKSTEP_LIVE_TILE.get() - && mActivity.getStateManager().getState().hasLiveTile()); + return mActivity.hasWindowFocus() || mActivity.getStateManager().getState().hasLiveTile(); } @Override diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index 6bc24f2b9b..5374ff0405 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -37,14 +37,15 @@ import android.graphics.Matrix; import android.graphics.Point; import android.graphics.PointF; import android.view.MotionEvent; +import android.view.RemoteAnimationTarget; import android.view.VelocityTracker; import com.android.launcher3.R; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.DisplayController; -import com.android.quickstep.AnimatedFloat; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.MultiStateCallback; @@ -52,14 +53,14 @@ import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.RecentsAnimationTargets; +import com.android.quickstep.RemoteAnimationTargets; import com.android.quickstep.TaskAnimationManager; +import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; import com.android.quickstep.util.TransformParams; import com.android.quickstep.util.TransformParams.BuilderProxy; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder; import java.util.HashMap; @@ -226,6 +227,10 @@ public class DeviceLockedInputConsumer implements InputConsumer, mStateCallback.setState(STATE_HANDLER_INVALIDATED); } }); + RemoteAnimationTargets targets = mTransformParams.getTargetSet(); + if (targets != null) { + targets.addReleaseCheck(new DeviceLockedReleaseCheck(animator)); + } animator.start(); } else { mStateCallback.setState(STATE_HANDLER_INVALIDATED); @@ -290,9 +295,9 @@ public class DeviceLockedInputConsumer implements InputConsumer, @Override public void onBuildTargetParams( - Builder builder, RemoteAnimationTargetCompat app, TransformParams params) { + SurfaceProperties builder, RemoteAnimationTarget app, TransformParams params) { mMatrix.setTranslate(0, mProgress.value * mMaxTranslationY); - builder.withMatrix(mMatrix); + builder.setMatrix(mMatrix); } @Override @@ -304,4 +309,27 @@ public class DeviceLockedInputConsumer implements InputConsumer, public boolean allowInterceptByParent() { return !mThresholdCrossed; } + + private static final class DeviceLockedReleaseCheck extends + RemoteAnimationTargets.ReleaseCheck { + + private DeviceLockedReleaseCheck(Animator animator) { + setCanRelease(true); + + animator.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationStart(Animator animation) { + super.onAnimationStart(animation); + setCanRelease(false); + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + setCanRelease(true); + } + }); + } + } } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 7ccd8af97a..a7ae6b560b 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -30,7 +30,6 @@ import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS; import static com.android.launcher3.util.VelocityUtils.PX_PER_MS; -import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION; import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; import android.annotation.TargetApi; @@ -39,8 +38,6 @@ import android.content.ContextWrapper; import android.content.Intent; import android.graphics.PointF; import android.os.Build; -import android.os.Handler; -import android.os.Looper; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -66,11 +63,9 @@ import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.RotationTouchHelper; import com.android.quickstep.TaskAnimationManager; -import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.CachedEventDispatcher; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; -import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputMonitorCompat; @@ -136,12 +131,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar. private float mStartDisplacement; - private Handler mMainThreadHandler; - private Runnable mCancelRecentsAnimationRunnable = () -> { - ActivityManagerWrapper.getInstance().cancelRecentsAnimation( - true /* restoreHomeStackPosition */); - }; - public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, boolean isDeferredDownTarget, Consumer<OtherActivityInputConsumer> onCompleteCallback, @@ -152,7 +141,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mNavBarPosition = mDeviceState.getNavBarPosition(); mTaskAnimationManager = taskAnimationManager; mGestureState = gestureState; - mMainThreadHandler = new Handler(Looper.getMainLooper()); mHandlerFactory = handlerFactory; mActivityInterface = mGestureState.getActivityInterface(); @@ -292,6 +280,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC float upDist = -displacement; boolean passedSlop = squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop; + if (!mPassedSlopOnThisGesture && passedSlop) { mPassedSlopOnThisGesture = true; } @@ -336,7 +325,10 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } if (mDeviceState.isFullyGesturalNavMode()) { - mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement + boolean minSwipeMet = upDist >= Math.max(mMotionPauseMinDisplacement, + mInteractionHandler.getThresholdToAllowMotionPause()); + mInteractionHandler.setCanSlowSwipeGoHome(minSwipeMet); + mMotionPauseDetector.setDisallowPause(!minSwipeMet || isLikelyToStartNewTask); mMotionPauseDetector.addPosition(ev); mInteractionHandler.setIsLikelyToStartNewTask(isLikelyToStartNewTask); @@ -373,10 +365,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } private void startTouchTrackingForWindowAnimation(long touchTimeMs) { - ActiveGestureLog.INSTANCE.addLog( - /* event= */ "startRecentsAnimation", - /* gestureEvent= */ START_RECENTS_ANIMATION); - mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs); mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished); mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler.getMotionPauseListener()); @@ -409,16 +397,16 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mInteractionHandler.onGestureCancelled(); } else { mVelocityTracker.computeCurrentVelocity(PX_PER_MS); - float velocityX = mVelocityTracker.getXVelocity(mActivePointerId); - float velocityY = mVelocityTracker.getYVelocity(mActivePointerId); - float velocity = mNavBarPosition.isRightEdge() - ? velocityX + float velocityXPxPerMs = mVelocityTracker.getXVelocity(mActivePointerId); + float velocityYPxPerMs = mVelocityTracker.getYVelocity(mActivePointerId); + float velocityPxPerMs = mNavBarPosition.isRightEdge() + ? velocityXPxPerMs : mNavBarPosition.isLeftEdge() - ? -velocityX - : velocityY; + ? -velocityXPxPerMs + : velocityYPxPerMs; mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement); - mInteractionHandler.onGestureEnded(velocity, new PointF(velocityX, velocityY), - mDownPos); + mInteractionHandler.onGestureEnded( + velocityPxPerMs, new PointF(velocityXPxPerMs, velocityYPxPerMs), mDownPos); } } else { // Since we start touch tracking on DOWN, we may reach this state without actually @@ -437,13 +425,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } onConsumerAboutToBeSwitched(); onInteractionGestureFinished(); - - // Cancel the recents animation if SysUI happens to handle UP before we have a chance - // to start the recents animation. In addition, workaround for b/126336729 by delaying - // the cancel of the animation for a period, in case SysUI is slow to handle UP and we - // handle DOWN & UP and move the home stack before SysUI can start the activity - mMainThreadHandler.removeCallbacks(mCancelRecentsAnimationRunnable); - mMainThreadHandler.postDelayed(mCancelRecentsAnimationRunnable, 100); } cleanupAfterGesture(); TraceHelper.INSTANCE.endSection(traceToken); @@ -465,7 +446,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC @Override public void onConsumerAboutToBeSwitched() { Preconditions.assertUIThread(); - mMainThreadHandler.removeCallbacks(mCancelRecentsAnimationRunnable); if (mInteractionHandler != null) { // The consumer is being switched while we are active. Set up the shared state to be // used by the next animation diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java index 6f35928a9f..64165b66e4 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java @@ -15,7 +15,6 @@ */ package com.android.quickstep.inputconsumers; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import android.media.AudioManager; @@ -100,27 +99,23 @@ public class OverviewInputConsumer<S extends BaseState<S>, T extends StatefulAct @Override public void onHoverEvent(MotionEvent ev) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - mActivity.dispatchGenericMotionEvent(ev); - } + mActivity.dispatchGenericMotionEvent(ev); } @Override public void onKeyEvent(KeyEvent ev) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - switch (ev.getKeyCode()) { - case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_MUTE: - MediaSessionManager mgr = mActivity.getSystemService(MediaSessionManager.class); - mgr.dispatchVolumeKeyEventAsSystemService(ev, - AudioManager.USE_DEFAULT_STREAM_TYPE); - break; - default: - break; - } - mActivity.dispatchKeyEvent(ev); + switch (ev.getKeyCode()) { + case KeyEvent.KEYCODE_VOLUME_DOWN: + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_MUTE: + MediaSessionManager mgr = mActivity.getSystemService(MediaSessionManager.class); + mgr.dispatchVolumeKeyEventAsSystemService(ev, + AudioManager.USE_DEFAULT_STREAM_TYPE); + break; + default: + break; } + mActivity.dispatchKeyEvent(ev); } } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java index b9b5e7c2b9..45ffa1c510 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java @@ -28,14 +28,12 @@ import android.content.Intent; import android.graphics.Point; import android.view.MotionEvent; -import androidx.annotation.Nullable; - +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.launcher3.util.DisplayController; -import com.android.quickstep.AnimatedFloat; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.MultiStateCallback; @@ -43,7 +41,6 @@ import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.TaskAnimationManager; -import com.android.quickstep.util.ActiveGestureErrorDetector; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputMonitorCompat; @@ -102,8 +99,7 @@ public class ProgressDelegateInputConsumer implements InputConsumer, mDisplaySize = DisplayController.INSTANCE.get(context).getInfo().currentSize; // Init states - mStateCallback = new MultiStateCallback( - STATE_NAMES, ProgressDelegateInputConsumer::getTrackedEventForState); + mStateCallback = new MultiStateCallback(STATE_NAMES); mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED, this::endRemoteAnimation); mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_FLING_FINISHED, @@ -113,14 +109,6 @@ public class ProgressDelegateInputConsumer implements InputConsumer, mSwipeDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false); } - @Nullable - private static ActiveGestureErrorDetector.GestureEvent getTrackedEventForState(int stateFlag) { - if (stateFlag == STATE_HANDLER_INVALIDATED) { - return ActiveGestureErrorDetector.GestureEvent.STATE_HANDLER_INVALIDATED; - } - return null; - } - @Override public int getType() { return TYPE_PROGRESS_DELEGATE; diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java index 3785de4ecd..3afd0a3431 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java @@ -15,16 +15,27 @@ */ package com.android.quickstep.inputconsumers; +import static android.view.MotionEvent.INVALID_POINTER_ID; + import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_REVISED_THRESHOLDS; +import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TOUCHING; import android.content.Context; +import android.content.res.Resources; +import android.graphics.PointF; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; +import androidx.annotation.Nullable; + import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.taskbar.TaskbarActivityContext; +import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback; +import com.android.launcher3.touch.OverScroll; +import com.android.launcher3.util.DisplayController; import com.android.quickstep.InputConsumer; import com.android.systemui.shared.system.InputMonitorCompat; @@ -37,20 +48,41 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer { private final GestureDetector mLongPressDetector; private final float mSquaredTouchSlop; - - private float mDownX, mDownY; + private float mLongPressDownX, mLongPressDownY; private boolean mCanceledUnstashHint; private final float mUnstashArea; private final float mScreenWidth; + private final int mTaskbarNavThresholdY; + private final boolean mIsTaskbarAllAppsOpen; + private boolean mHasPassedTaskbarNavThreshold; + + private final PointF mDownPos = new PointF(); + private final PointF mLastPos = new PointF(); + private int mActivePointerId = INVALID_POINTER_ID; + + private final boolean mIsTransientTaskbar; + + private final @Nullable TransitionCallback mTransitionCallback; + public TaskbarStashInputConsumer(Context context, InputConsumer delegate, InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) { super(delegate, inputMonitor); mTaskbarActivityContext = taskbarActivityContext; mSquaredTouchSlop = Utilities.squaredTouchSlop(context); mScreenWidth = taskbarActivityContext.getDeviceProfile().widthPx; - mUnstashArea = context.getResources() - .getDimensionPixelSize(R.dimen.taskbar_unstash_input_area); + + Resources res = context.getResources(); + mUnstashArea = res.getDimensionPixelSize(R.dimen.taskbar_unstash_input_area); + int taskbarNavThreshold = res.getDimensionPixelSize(ENABLE_TASKBAR_REVISED_THRESHOLDS.get() + ? R.dimen.taskbar_nav_threshold_v2 + : R.dimen.taskbar_nav_threshold); + int screenHeight = taskbarActivityContext.getDeviceProfile().heightPx; + mTaskbarNavThresholdY = screenHeight - taskbarNavThreshold; + mIsTaskbarAllAppsOpen = + mTaskbarActivityContext != null && mTaskbarActivityContext.isTaskbarAllAppsOpen(); + + mIsTransientTaskbar = DisplayController.isTransientTaskbar(context); mLongPressDetector = new GestureDetector(context, new SimpleOnGestureListener() { @Override @@ -58,6 +90,10 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer { onLongPressDetected(motionEvent); } }); + + mTransitionCallback = mIsTransientTaskbar + ? taskbarActivityContext.getTranslationCallbacks() + : null; } @Override @@ -76,28 +112,81 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer { final float y = ev.getRawY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: + mActivePointerId = ev.getPointerId(0); + mDownPos.set(ev.getX(), ev.getY()); + mLastPos.set(mDownPos); + + mHasPassedTaskbarNavThreshold = false; + mTaskbarActivityContext.setAutohideSuspendFlag( + FLAG_AUTOHIDE_SUSPEND_TOUCHING, true); if (isInArea(x)) { - mDownX = x; - mDownY = y; - mTaskbarActivityContext.startTaskbarUnstashHint( - /* animateForward = */ true); - mCanceledUnstashHint = false; + if (!mIsTransientTaskbar) { + mLongPressDownX = x; + mLongPressDownY = y; + mTaskbarActivityContext.startTaskbarUnstashHint( + /* animateForward = */ true); + mCanceledUnstashHint = false; + } + } + break; + case MotionEvent.ACTION_POINTER_UP: + int ptrIdx = ev.getActionIndex(); + int ptrId = ev.getPointerId(ptrIdx); + if (ptrId == mActivePointerId) { + final int newPointerIdx = ptrIdx == 0 ? 1 : 0; + mDownPos.set( + ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x), + ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y)); + mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx)); + mActivePointerId = ev.getPointerId(newPointerIdx); } break; case MotionEvent.ACTION_MOVE: - if (!mCanceledUnstashHint - && squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop) { + if (!mIsTransientTaskbar + && !mCanceledUnstashHint + && squaredHypot(mLongPressDownX - x, mLongPressDownY - y) + > mSquaredTouchSlop) { mTaskbarActivityContext.startTaskbarUnstashHint( /* animateForward = */ false); mCanceledUnstashHint = true; } + + int pointerIndex = ev.findPointerIndex(mActivePointerId); + if (pointerIndex == INVALID_POINTER_ID) { + break; + } + mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex)); + + if (mIsTransientTaskbar) { + float dY = mLastPos.y - mDownPos.y; + boolean passedTaskbarNavThreshold = dY < 0 + && mLastPos.y < mTaskbarNavThresholdY; + + if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) { + mHasPassedTaskbarNavThreshold = true; + mTaskbarActivityContext.onSwipeToUnstashTaskbar(); + } + + if (dY < 0) { + dY = -OverScroll.dampedScroll(-dY, mTaskbarNavThresholdY); + if (mTransitionCallback != null && !mIsTaskbarAllAppsOpen) { + mTransitionCallback.onActionMove(dY); + } + } + } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - if (!mCanceledUnstashHint) { + if (!mIsTransientTaskbar && !mCanceledUnstashHint) { mTaskbarActivityContext.startTaskbarUnstashHint( /* animateForward = */ false); } + mTaskbarActivityContext.setAutohideSuspendFlag( + FLAG_AUTOHIDE_SUSPEND_TOUCHING, false); + if (mTransitionCallback != null) { + mTransitionCallback.onActionEnd(); + } + mHasPassedTaskbarNavThreshold = false; break; } } @@ -111,7 +200,9 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer { } private void onLongPressDetected(MotionEvent motionEvent) { - if (mTaskbarActivityContext != null && isInArea(motionEvent.getRawX())) { + if (mTaskbarActivityContext != null + && isInArea(motionEvent.getRawX()) + && !mIsTransientTaskbar) { boolean taskBarPressed = mTaskbarActivityContext.onLongPressToUnstashTaskbar(); if (taskBarPressed) { setActive(motionEvent); diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java index 8ad17cb711..e0262d02eb 100644 --- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java @@ -42,6 +42,7 @@ import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.VibrationEffect; import android.os.Vibrator; +import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.View.AccessibilityDelegate; @@ -53,12 +54,13 @@ import android.widget.TextView; import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.Executors; -import com.android.quickstep.AnimatedFloat; import com.android.quickstep.GestureState; import com.android.quickstep.TouchInteractionService.TISBinder; import com.android.quickstep.util.TISBindHelper; @@ -78,6 +80,7 @@ public class AllSetActivity extends Activity { "#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S.:settings:fragment_args_key=gesture_system_navigation_input_summary;S.:settings:show_fragment=com.android.settings.gestures.SystemNavigationGestureSettings;end"; private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "suwColorAccentDark"; private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "suwColorAccentLight"; + private static final String EXTRA_DEVICE_NAME = "suwDeviceName"; private static final float HINT_BOTTOM_FACTOR = 1 - .94f; @@ -109,7 +112,8 @@ public class AllSetActivity extends Activity { int mode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES; - int accentColor = getIntent().getIntExtra( + Intent intent = getIntent(); + int accentColor = intent.getIntExtra( isDarkTheme ? EXTRA_ACCENT_COLOR_DARK_MODE : EXTRA_ACCENT_COLOR_LIGHT_MODE, isDarkTheme ? Color.WHITE : Color.BLACK); @@ -120,11 +124,12 @@ public class AllSetActivity extends Activity { mContentView = findViewById(R.id.content_view); mSwipeUpShift = getResources().getDimension(R.dimen.allset_swipe_up_shift); - boolean isTablet = InvariantDeviceProfile.INSTANCE.get(getApplicationContext()) - .getDeviceProfile(this).isTablet; TextView subtitle = findViewById(R.id.subtitle); - subtitle.setText(isTablet - ? R.string.allset_description_tablet : R.string.allset_description); + String suwDeviceName = intent.getStringExtra(EXTRA_DEVICE_NAME); + subtitle.setText(getString( + R.string.allset_description_generic, + !TextUtils.isEmpty(suwDeviceName) + ? suwDeviceName : getString(R.string.default_device_name))); TextView tv = findViewById(R.id.navigation_settings); tv.setTextColor(accentColor); @@ -135,14 +140,23 @@ public class AllSetActivity extends Activity { } catch (URISyntaxException e) { Log.e(LOG_TAG, "Failed to parse system nav settings intent", e); } - finish(); }); - findViewById(R.id.hint).setAccessibilityDelegate(new SkipButtonAccessibilityDelegate()); + TextView hintTextView = findViewById(R.id.hint); + DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this); + if (!dp.isGestureMode) { + hintTextView.setText(R.string.allset_button_hint); + } + hintTextView.setAccessibilityDelegate(new SkipButtonAccessibilityDelegate()); mTISBindHelper = new TISBindHelper(this, this::onTISConnected); mVibrator = getSystemService(Vibrator.class); mAnimatedBackground = findViewById(R.id.animated_background); + // There's a bug in the currently used external Lottie library (v5.2.0), and it doesn't load + // the correct animation from the raw resources when configuration changes, so we need to + // manually load the resource and pass it to Lottie. + mAnimatedBackground.setAnimation(getResources().openRawResource(R.raw.all_set_page_bg), + null); startBackgroundAnimation(); } @@ -248,9 +262,6 @@ public class AllSetActivity extends Activity { } private AnimatedFloat createSwipeUpProxy(GestureState state) { - if (!state.getHomeIntent().getComponent().getPackageName().equals(getPackageName())) { - return null; - } if (state.getRunningTaskId() != getTaskId()) { return null; } diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java index 437572b380..8eb40593c9 100644 --- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java +++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java @@ -41,9 +41,9 @@ import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; import com.android.launcher3.R; -import com.android.launcher3.testing.shared.ResourceUtils; import com.android.launcher3.anim.Interpolators; -import com.android.quickstep.util.VibratorWrapper; +import com.android.launcher3.testing.shared.ResourceUtils; +import com.android.launcher3.util.VibratorWrapper; /** Forked from platform/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java. */ public class EdgeBackGesturePanel extends View { diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java index bf7023c217..4a701202db 100644 --- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java @@ -28,8 +28,8 @@ import android.view.Window; import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.logging.StatsLogManager; import com.android.quickstep.TouchInteractionService.TISBinder; import com.android.quickstep.interaction.TutorialController.TutorialType; @@ -63,7 +63,7 @@ public class GestureSandboxActivity extends FragmentActivity { requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.gesture_tutorial_activity); - mSharedPrefs = Utilities.getPrefs(this); + mSharedPrefs = LauncherPrefs.getPrefs(this); mStatsLogManager = StatsLogManager.newInstance(getApplicationContext()); Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState; diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java index e7bf7e2d08..57874d9deb 100644 --- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java +++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java @@ -16,6 +16,7 @@ package com.android.quickstep.interaction; import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_COMPLETED; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_BAD_ANGLE; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT; @@ -25,7 +26,6 @@ import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestu import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_GESTURE_COMPLETED; import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE; -import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC; import android.animation.ValueAnimator; import android.content.Context; @@ -48,10 +48,10 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.testing.shared.ResourceUtils; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.NavigationMode; +import com.android.launcher3.util.VibratorWrapper; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; import com.android.quickstep.util.TriggerSwipeUpTouchTracker; -import com.android.quickstep.util.VibratorWrapper; import com.android.systemui.shared.system.QuickStepContract; /** Utility class to handle Home and Assistant gestures. */ diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java index 6b016cee13..05b246b906 100644 --- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java @@ -24,8 +24,8 @@ import android.graphics.PointF; import android.os.Build; import com.android.launcher3.R; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.PendingAnimation; -import com.android.quickstep.AnimatedFloat; import com.android.quickstep.SwipeUpAnimationLogic; import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult; import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult; diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java index fa7bc04b30..670ee9b333 100644 --- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java @@ -33,7 +33,6 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; -import android.view.SurfaceControl; import android.view.View; import android.view.ViewOutlineProvider; @@ -43,19 +42,21 @@ import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; -import com.android.quickstep.AnimatedFloat; import com.android.quickstep.GestureState; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.RecentsAnimationDeviceState; import com.android.quickstep.RemoteTargetGluer; import com.android.quickstep.SwipeUpAnimationLogic; import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim; +import com.android.quickstep.util.RecordingSurfaceTransaction; import com.android.quickstep.util.RectFSpringAnim; +import com.android.quickstep.util.SurfaceTransaction; +import com.android.quickstep.util.SurfaceTransaction.MockProperties; import com.android.quickstep.util.TransformParams; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; @TargetApi(Build.VERSION_CODES.R) abstract class SwipeUpGestureTutorialController extends TutorialController { @@ -415,21 +416,23 @@ abstract class SwipeUpGestureTutorialController extends TutorialController { private class FakeTransformParams extends TransformParams { @Override - public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) { - SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null); - proxy.onBuildTargetParams(builder, null, this); - return new SurfaceParams[] {builder.build()}; + public SurfaceTransaction createSurfaceParams(BuilderProxy proxy) { + RecordingSurfaceTransaction transaction = new RecordingSurfaceTransaction(); + proxy.onBuildTargetParams(transaction.mockProperties, null, this); + return transaction; } @Override - public void applySurfaceParams(SurfaceParams[] params) { - SurfaceParams p = params[0]; - mFakeTaskView.setAnimationMatrix(p.matrix); - mFakePreviousTaskView.setAnimationMatrix(p.matrix); - mFakeTaskViewRect.set(p.windowCrop); - mFakeTaskViewRadius = p.cornerRadius; - mFakeTaskView.invalidateOutline(); - mFakePreviousTaskView.invalidateOutline(); + public void applySurfaceParams(SurfaceTransaction params) { + if (params instanceof RecordingSurfaceTransaction) { + MockProperties p = ((RecordingSurfaceTransaction) params).mockProperties; + mFakeTaskView.setAnimationMatrix(p.matrix); + mFakePreviousTaskView.setAnimationMatrix(p.matrix); + mFakeTaskViewRect.set(p.windowCrop); + mFakeTaskViewRadius = p.cornerRadius; + mFakeTaskView.invalidateOutline(); + mFakePreviousTaskView.invalidateOutline(); + } } } } diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java index 2ccdfa3b36..5efc45e385 100644 --- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java +++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java @@ -16,8 +16,8 @@ package com.android.quickstep.logging; -import static com.android.launcher3.Utilities.getDevicePrefs; -import static com.android.launcher3.Utilities.getPrefs; +import static com.android.launcher3.LauncherPrefs.getDevicePrefs; +import static com.android.launcher3.LauncherPrefs.getPrefs; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_DISABLED; diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 37a28e554b..0a155cbd47 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -62,11 +62,14 @@ import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.Executors; +import com.android.launcher3.util.IntArray; import com.android.launcher3.util.LogConfig; import com.android.launcher3.views.ActivityContext; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.SysUiStatsLog; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import java.util.OptionalInt; import java.util.concurrent.CopyOnWriteArrayList; @@ -85,6 +88,7 @@ public class StatsLogCompatManager extends StatsLogManager { private static final String TAG = "StatsLog"; private static final String LATENCY_TAG = "StatsLatencyLog"; + private static final String IMPRESSION_TAG = "StatsImpressionLog"; private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG); private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0); // LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates @@ -119,7 +123,12 @@ public class StatsLogCompatManager extends StatsLogManager { @Override protected StatsLatencyLogger createLatencyLogger() { - return new StatsCompatLatencyLogger(mContext, mActivityContext); + return new StatsCompatLatencyLogger(); + } + + @Override + protected StatsImpressionLogger createImpressionLogger() { + return new StatsCompatImpressionLogger(); } /** @@ -190,7 +199,8 @@ public class StatsLogCompatManager extends StatsLogManager { getCardinality(info), // cardinality = 16; info.getWidget().getSpanX(), // span_x = 17 [default = 1]; info.getWidget().getSpanY(), // span_y = 18 [default = 1]; - getAttributes(info) /* attributes */ + getAttributes(info) /* attributes = 19 [(log_mode) = MODE_BYTES] */, + info.getIsKidsMode() /* is_kids_mode = 20 */ ); } @@ -216,6 +226,7 @@ public class StatsLogCompatManager extends StatsLogManager { private Optional<String> mEditText = Optional.empty(); private SliceItem mSliceItem; private LauncherAtom.Slice mSlice; + private Optional<Integer> mCardinality = Optional.empty(); StatsCompatLogger(Context context, ActivityContext activityContext) { mContext = context; @@ -303,6 +314,12 @@ public class StatsLogCompatManager extends StatsLogManager { } @Override + public StatsLogger withCardinality(int cardinality) { + this.mCardinality = Optional.of(cardinality); + return this; + } + + @Override public void log(EventEnum event) { if (!Utilities.ATLEAST_R) { return; @@ -325,6 +342,10 @@ public class StatsLogCompatManager extends StatsLogManager { return; } + if (mItemInfo == null) { + return; + } + if (mItemInfo.container < 0 || appState == null) { // Write log on the model thread so that logs do not go out of order // (for eg: drop comes after drag) @@ -420,6 +441,7 @@ public class StatsLogCompatManager extends StatsLogManager { if (Utilities.IS_RUNNING_IN_TEST_HARNESS) { return; } + int cardinality = mCardinality.orElseGet(() -> getCardinality(atomInfo)); SysUiStatsLog.write( SysUiStatsLog.LAUNCHER_EVENT, SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */, @@ -445,7 +467,7 @@ public class StatsLogCompatManager extends StatsLogManager { atomInfo.getFolderIcon().getFromLabelState().getNumber() /* fromState */, atomInfo.getFolderIcon().getToLabelState().getNumber() /* toState */, atomInfo.getFolderIcon().getLabelInfo() /* edittext */, - getCardinality(atomInfo) /* cardinality */, + cardinality /* cardinality */, getFeatures(atomInfo) /* features */, getSearchAttributes(atomInfo) /* searchAttributes */, getAttributes(atomInfo) /* attributes */ @@ -457,18 +479,12 @@ public class StatsLogCompatManager extends StatsLogManager { * Helps to construct and log statsd compatible latency events. */ private static class StatsCompatLatencyLogger implements StatsLatencyLogger { - private final Context mContext; - private final Optional<ActivityContext> mActivityContext; private InstanceId mInstanceId = DEFAULT_INSTANCE_ID; private LatencyType mType = LatencyType.UNKNOWN; private int mPackageId = 0; private long mLatencyInMillis; private int mQueryLength = -1; - - StatsCompatLatencyLogger(Context context, ActivityContext activityContext) { - mContext = context; - mActivityContext = Optional.ofNullable(activityContext); - } + private int mSubEventType = 0; @Override public StatsLatencyLogger withInstanceId(InstanceId instanceId) { @@ -501,6 +517,12 @@ public class StatsLogCompatManager extends StatsLogManager { } @Override + public StatsLatencyLogger withSubEventType(int type) { + this.mSubEventType = type; + return this; + } + + @Override public void log(EventEnum event) { if (IS_VERBOSE) { String name = (event instanceof Enum) ? ((Enum) event).name() : @@ -517,7 +539,98 @@ public class StatsLogCompatManager extends StatsLogManager { mPackageId, // package_id mLatencyInMillis, // latency_in_millis mType.getId(), //type - mQueryLength // query_length + mQueryLength, // query_length + mSubEventType // sub_event_type + ); + } + } + + /** + * Helps to construct and log statsd compatible impression events. + */ + private static class StatsCompatImpressionLogger implements StatsImpressionLogger { + private final IntArray mResultTypeList = new IntArray(); + private final IntArray mResultCountList = new IntArray(); + private final List<Boolean> mAboveKeyboardList = new ArrayList<>(); + private InstanceId mInstanceId = DEFAULT_INSTANCE_ID; + private State mLauncherState = State.UNKNOWN; + private int mQueryLength = -1; + + @Override + public StatsImpressionLogger withInstanceId(InstanceId instanceId) { + this.mInstanceId = instanceId; + return this; + } + + @Override + public StatsImpressionLogger withState(State state) { + this.mLauncherState = state; + return this; + } + + @Override + public StatsImpressionLogger withQueryLength(int queryLength) { + this.mQueryLength = queryLength; + return this; + } + + @Override + public StatsImpressionLogger withResultType(IntArray resultType) { + this.mResultTypeList.clear(); + this.mResultTypeList.addAll(resultType); + return this; + } + + @Override + public StatsImpressionLogger withResultCount(IntArray resultCount) { + this.mResultCountList.clear(); + this.mResultCountList.addAll(resultCount); + return this; + } + + @Override + public StatsImpressionLogger withAboveKeyboard(List<Boolean> aboveKeyboard) { + this.mAboveKeyboardList.clear(); + this.mAboveKeyboardList.addAll(aboveKeyboard); + return this; + } + + @Override + public void log(EventEnum event) { + boolean [] mAboveKeyboard = new boolean[mAboveKeyboardList.size()]; + for (int i = 0; i < mAboveKeyboardList.size(); i++) { + mAboveKeyboard[i] = mAboveKeyboardList.get(i); + } + if (IS_VERBOSE) { + String name = (event instanceof Enum) ? ((Enum) event).name() : + event.getId() + ""; + StringBuilder logStringBuilder = new StringBuilder("\n"); + logStringBuilder.append(String.format("InstanceId:%s ", mInstanceId)); + logStringBuilder.append(String.format("ImpressionEvent:%s ", name)); + logStringBuilder.append(String.format("LauncherState = %s ", mLauncherState)); + logStringBuilder.append(String.format("QueryLength = %s ", mQueryLength)); + for (int i = 0; i < mResultTypeList.size(); i++) { + logStringBuilder.append(String.format( + "\n ResultType = %s with ResultCount = %s with is_above_keyboard = %s", + mResultTypeList.get(i), mResultCountList.get(i), + mAboveKeyboard[i])); + } + Log.d(IMPRESSION_TAG, logStringBuilder.toString()); + } + + + + SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_IMPRESSION_EVENT, + event.getId(), // event_id + mInstanceId.getId(), // instance_id + mLauncherState.getLauncherState(), // state + mQueryLength, // query_length + //result type list + mResultTypeList.toArray(), + // result count list + mResultCountList.toArray(), + // above keyboard list + mAboveKeyboard ); } } diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java index 53e0c2b631..60065fb16c 100644 --- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java +++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java @@ -33,10 +33,11 @@ public class ActiveGestureErrorDetector { * Enums associated to gesture navigation events. */ public enum GestureEvent { - MOTION_DOWN, MOTION_UP, SET_END_TARGET, SET_END_TARGET_HOME, SET_END_TARGET_LAST_TASK, - SET_END_TARGET_NEW_TASK, ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, - FINISH_RECENTS_ANIMATION, CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, - CANCEL_CURRENT_ANIMATION, CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, + MOTION_DOWN, MOTION_UP, SET_END_TARGET, SET_END_TARGET_HOME, SET_END_TARGET_NEW_TASK, + ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION, + CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION, + CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED, + FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, /** * These GestureEvents are specifically associated to state flags that get set in @@ -91,35 +92,40 @@ public class ActiveGestureErrorDetector { case MOTION_UP: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.MOTION_DOWN), - /* errorMessage= */ prefix + "\t\tMotion up detected before/without" + prefix, + /* errorMessage= */ "Motion up detected before/without" + " motion down.", writer); break; case ON_SETTLED_ON_END_TARGET: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.SET_END_TARGET), - /* errorMessage= */ prefix + "\t\tonSettledOnEndTarget called " + prefix, + /* errorMessage= */ "onSettledOnEndTarget called " + "before/without setEndTarget.", writer); break; case FINISH_RECENTS_ANIMATION: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION), - /* errorMessage= */ prefix + "\t\tfinishRecentsAnimation called " + prefix, + /* errorMessage= */ "finishRecentsAnimation called " + "before/without startRecentsAnimation.", writer); break; case CANCEL_RECENTS_ANIMATION: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION), - /* errorMessage= */ prefix + "\t\tcancelRecentsAnimation called " + prefix, + /* errorMessage= */ "cancelRecentsAnimation called " + "before/without startRecentsAnimation.", writer); break; case CLEANUP_SCREENSHOT: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED), - /* errorMessage= */ prefix + "\t\trecents activity screenshot was " + prefix, + /* errorMessage= */ "recents activity screenshot was " + "cleaned up before/without STATE_SCREENSHOT_CAPTURED " + "being set.", writer); @@ -129,48 +135,66 @@ public class ActiveGestureErrorDetector { encounteredEvents.contains(GestureEvent.SET_END_TARGET_HOME) && !encounteredEvents.contains( GestureEvent.ON_SETTLED_ON_END_TARGET), - /* errorMessage= */ prefix + "\t\trecents view scroller animation " + prefix, + /* errorMessage= */ "recents view scroller animation " + "aborted after setting end target HOME, but before" + " settling on end target.", writer); break; case TASK_APPEARED: errorDetected |= printErrorIfTrue( - !encounteredEvents.contains(GestureEvent.SET_END_TARGET_LAST_TASK) - && !encounteredEvents.contains( - GestureEvent.SET_END_TARGET_NEW_TASK), - /* errorMessage= */ prefix + "\t\tonTasksAppeared called " - + "before/without setting end target to last or new task", + !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK), + prefix, + /* errorMessage= */ "onTasksAppeared called " + + "before/without setting end target to new task", + writer); + errorDetected |= printErrorIfTrue( + !encounteredEvents.contains(GestureEvent.EXPECTING_TASK_APPEARED), + prefix, + /* errorMessage= */ "onTasksAppeared was not expected to be called", + writer); + break; + case EXPECTING_TASK_APPEARED: + errorDetected |= printErrorIfTrue( + !encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK), + prefix, + /* errorMessage= */ "expecting onTasksAppeared to be called " + + "before/without setting end target to new task", writer); break; case STATE_GESTURE_COMPLETED: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.MOTION_UP), - /* errorMessage= */ prefix + "\t\tSTATE_GESTURE_COMPLETED set " + prefix, + /* errorMessage= */ "STATE_GESTURE_COMPLETED set " + "before/without motion up.", writer); errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED), - /* errorMessage= */ prefix + "\t\tSTATE_GESTURE_COMPLETED set " + prefix, + /* errorMessage= */ "STATE_GESTURE_COMPLETED set " + "before/without STATE_GESTURE_STARTED.", writer); break; case STATE_GESTURE_CANCELLED: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.MOTION_UP), - /* errorMessage= */ prefix + "\t\tSTATE_GESTURE_CANCELLED set " + prefix, + /* errorMessage= */ "STATE_GESTURE_CANCELLED set " + "before/without motion up.", writer); errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED), - /* errorMessage= */ prefix + "\t\tSTATE_GESTURE_CANCELLED set " + prefix, + /* errorMessage= */ "STATE_GESTURE_CANCELLED set " + "before/without STATE_GESTURE_STARTED.", writer); break; case STATE_SCREENSHOT_CAPTURED: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.STATE_CAPTURE_SCREENSHOT), - /* errorMessage= */ prefix + "\t\tSTATE_SCREENSHOT_CAPTURED set " + prefix, + /* errorMessage= */ "STATE_SCREENSHOT_CAPTURED set " + "before/without STATE_CAPTURE_SCREENSHOT.", writer); break; @@ -178,7 +202,8 @@ public class ActiveGestureErrorDetector { errorDetected |= printErrorIfTrue( !encounteredEvents.contains( GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK), - /* errorMessage= */ prefix + "\t\tSTATE_RECENTS_SCROLLING_FINISHED " + prefix, + /* errorMessage= */ "STATE_RECENTS_SCROLLING_FINISHED " + "set before/without calling " + "setOnPageTransitionEndCallback.", writer); @@ -187,16 +212,19 @@ public class ActiveGestureErrorDetector { errorDetected |= printErrorIfTrue( !encounteredEvents.contains( GestureEvent.START_RECENTS_ANIMATION), - /* errorMessage= */ prefix + "\t\tSTATE_RECENTS_ANIMATION_CANCELED " + prefix, + /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED " + "set before/without startRecentsAnimation.", writer); break; case MOTION_DOWN: case SET_END_TARGET: case SET_END_TARGET_HOME: + case SET_END_TARGET_NEW_TASK: case START_RECENTS_ANIMATION: case SET_ON_PAGE_TRANSITION_END_CALLBACK: case CANCEL_CURRENT_ANIMATION: + case FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER: case STATE_GESTURE_STARTED: case STATE_END_TARGET_ANIMATION_FINISHED: case STATE_CAPTURE_SCREENSHOT: @@ -210,31 +238,36 @@ public class ActiveGestureErrorDetector { // Check that all required events were found. errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.MOTION_DOWN), - /* errorMessage= */ prefix + "\t\tMotion down never detected.", + prefix, + /* errorMessage= */ "Motion down never detected.", writer); errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.MOTION_UP), - /* errorMessage= */ prefix + "\t\tMotion up never detected.", + prefix, + /* errorMessage= */ "Motion up never detected.", writer); errorDetected |= printErrorIfTrue( /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET) && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET), - /* errorMessage= */ prefix + "\t\tsetEndTarget was called, but " + prefix, + /* errorMessage= */ "setEndTarget was called, but " + "onSettledOnEndTarget wasn't.", writer); errorDetected |= printErrorIfTrue( /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET) && !encounteredEvents.contains( GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED), - /* errorMessage= */ prefix + "\t\tsetEndTarget was called, but " + prefix, + /* errorMessage= */ "setEndTarget was called, but " + "STATE_END_TARGET_ANIMATION_FINISHED was never set.", writer); errorDetected |= printErrorIfTrue( /* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET) && !encounteredEvents.contains( GestureEvent.STATE_RECENTS_SCROLLING_FINISHED), - /* errorMessage= */ prefix + "\t\tsetEndTarget was called, but " + prefix, + /* errorMessage= */ "setEndTarget was called, but " + "STATE_RECENTS_SCROLLING_FINISHED was never set.", writer); errorDetected |= printErrorIfTrue( @@ -243,7 +276,8 @@ public class ActiveGestureErrorDetector { && encounteredEvents.contains( GestureEvent.STATE_RECENTS_SCROLLING_FINISHED) && !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET), - /* errorMessage= */ prefix + "\t\tSTATE_END_TARGET_ANIMATION_FINISHED and " + prefix, + /* errorMessage= */ "STATE_END_TARGET_ANIMATION_FINISHED and " + "STATE_RECENTS_SCROLLING_FINISHED were set, but onSettledOnEndTarget " + "wasn't called.", writer); @@ -253,7 +287,8 @@ public class ActiveGestureErrorDetector { GestureEvent.START_RECENTS_ANIMATION) && !encounteredEvents.contains(GestureEvent.FINISH_RECENTS_ANIMATION) && !encounteredEvents.contains(GestureEvent.CANCEL_RECENTS_ANIMATION), - /* errorMessage= */ prefix + "\t\tstartRecentsAnimation was called, but " + prefix, + /* errorMessage= */ "startRecentsAnimation was called, but " + "finishRecentsAnimation and cancelRecentsAnimation weren't.", writer); @@ -261,7 +296,8 @@ public class ActiveGestureErrorDetector { /* condition= */ encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED) && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_COMPLETED) && !encounteredEvents.contains(GestureEvent.STATE_GESTURE_CANCELLED), - /* errorMessage= */ prefix + "\t\tSTATE_GESTURE_STARTED was set, but " + prefix, + /* errorMessage= */ "STATE_GESTURE_STARTED was set, but " + "STATE_GESTURE_COMPLETED and STATE_GESTURE_CANCELLED weren't.", writer); @@ -269,7 +305,8 @@ public class ActiveGestureErrorDetector { /* condition= */ encounteredEvents.contains( GestureEvent.STATE_CAPTURE_SCREENSHOT) && !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED), - /* errorMessage= */ prefix + "\t\tSTATE_CAPTURE_SCREENSHOT was set, but " + prefix, + /* errorMessage= */ "STATE_CAPTURE_SCREENSHOT was set, but " + "STATE_SCREENSHOT_CAPTURED wasn't.", writer); @@ -278,15 +315,18 @@ public class ActiveGestureErrorDetector { GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK) && !encounteredEvents.contains( GestureEvent.STATE_RECENTS_SCROLLING_FINISHED), - /* errorMessage= */ prefix + "\t\tsetOnPageTransitionEndCallback called, but " + prefix, + /* errorMessage= */ "setOnPageTransitionEndCallback called, but " + "STATE_RECENTS_SCROLLING_FINISHED wasn't set.", writer); errorDetected |= printErrorIfTrue( - /* condition= */ !encounteredEvents.contains( - GestureEvent.CANCEL_CURRENT_ANIMATION) + /* condition= */ encounteredEvents.contains( + GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER) + && !encounteredEvents.contains(GestureEvent.CANCEL_CURRENT_ANIMATION) && !encounteredEvents.contains(GestureEvent.STATE_HANDLER_INVALIDATED), - /* errorMessage= */ prefix + "\t\tAbsSwipeUpHandler.cancelCurrentAnimation " + prefix, + /* errorMessage= */ "AbsSwipeUpHandler.cancelCurrentAnimation " + "wasn't called and STATE_HANDLER_INVALIDATED wasn't set.", writer); @@ -294,23 +334,17 @@ public class ActiveGestureErrorDetector { /* condition= */ encounteredEvents.contains( GestureEvent.STATE_RECENTS_ANIMATION_CANCELED) && !encounteredEvents.contains(GestureEvent.CLEANUP_SCREENSHOT), - /* errorMessage= */ prefix + "\t\tSTATE_RECENTS_ANIMATION_CANCELED was set but " + prefix, + /* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED was set but " + "the task screenshot wasn't cleaned up.", writer); errorDetected |= printErrorIfTrue( /* condition= */ encounteredEvents.contains( - GestureEvent.SET_END_TARGET_LAST_TASK) - && !encounteredEvents.contains(GestureEvent.TASK_APPEARED), - /* errorMessage= */ prefix + "\t\tend target set to last task, but " - + "onTaskAppeared wasn't called.", - writer); - errorDetected |= printErrorIfTrue( - /* condition= */ encounteredEvents.contains( - GestureEvent.SET_END_TARGET_NEW_TASK) + GestureEvent.EXPECTING_TASK_APPEARED) && !encounteredEvents.contains(GestureEvent.TASK_APPEARED), - /* errorMessage= */ prefix + "\t\tend target set to new task, but " - + "onTaskAppeared wasn't called.", + prefix, + /* errorMessage= */ "onTaskAppeared was expected to be called but wasn't.", writer); if (!errorDetected) { @@ -320,11 +354,11 @@ public class ActiveGestureErrorDetector { } private static boolean printErrorIfTrue( - boolean condition, String errorMessage, PrintWriter writer) { + boolean condition, String prefix, String errorMessage, PrintWriter writer) { if (!condition) { return false; } - writer.println(errorMessage); + writer.println(prefix + "\t\t- " + errorMessage); return true; } } diff --git a/quickstep/src/com/android/quickstep/util/BaseDepthController.java b/quickstep/src/com/android/quickstep/util/BaseDepthController.java index 29ae9a13ca..877e28ab4e 100644 --- a/quickstep/src/com/android/quickstep/util/BaseDepthController.java +++ b/quickstep/src/com/android/quickstep/util/BaseDepthController.java @@ -25,6 +25,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.MultiPropertyFactory; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.systemui.shared.system.BlurUtils; /** @@ -45,20 +46,15 @@ public class BaseDepthController { } }; - private static final MultiPropertyFactory<BaseDepthController> DEPTH_PROPERTY_FACTORY = - new MultiPropertyFactory<>("depthProperty", DEPTH, Float::max); - - private static final int DEPTH_INDEX_STATE_TRANSITION = 1; - private static final int DEPTH_INDEX_WIDGET = 2; + private static final int DEPTH_INDEX_STATE_TRANSITION = 0; + private static final int DEPTH_INDEX_WIDGET = 1; + private static final int DEPTH_INDEX_COUNT = 2; + protected final Launcher mLauncher; /** Property to set the depth for state transition. */ - public static final FloatProperty<BaseDepthController> STATE_DEPTH = - DEPTH_PROPERTY_FACTORY.get(DEPTH_INDEX_STATE_TRANSITION); + public final MultiProperty stateDepth; /** Property to set the depth for widget picker. */ - public static final FloatProperty<BaseDepthController> WIDGET_DEPTH = - DEPTH_PROPERTY_FACTORY.get(DEPTH_INDEX_WIDGET); - - protected final Launcher mLauncher; + public final MultiProperty widgetDepth; /** * Blur radius when completely zoomed out, in pixels. @@ -71,7 +67,7 @@ public class BaseDepthController { * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in. * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float) */ - protected float mDepth; + private float mDepth; protected SurfaceControl mSurface; @@ -92,6 +88,11 @@ public class BaseDepthController { mLauncher = activity; mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius); mWallpaperManager = activity.getSystemService(WallpaperManager.class); + + MultiPropertyFactory<BaseDepthController> depthProperty = + new MultiPropertyFactory<>(this, DEPTH, DEPTH_INDEX_COUNT, Float::max); + stateDepth = depthProperty.get(DEPTH_INDEX_STATE_TRANSITION); + widgetDepth = depthProperty.get(DEPTH_INDEX_WIDGET); } protected void setCrossWindowBlursEnabled(boolean isEnabled) { @@ -143,7 +144,7 @@ public class BaseDepthController { } } - protected void setDepth(float depth) { + private void setDepth(float depth) { depth = Utilities.boundToRange(depth, 0, 1); // Round out the depth to dedupe frequent, non-perceptable updates int depthI = (int) (depth * 256); diff --git a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java index 143042fb31..2a513ee7ee 100644 --- a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java +++ b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java @@ -16,12 +16,14 @@ package com.android.quickstep.util; import android.annotation.CallSuper; +import android.view.Surface.Rotation; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator; import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener; +import com.android.systemui.unfold.updates.RotationChangeProvider; import java.util.HashMap; import java.util.Map; @@ -32,15 +34,20 @@ import java.util.Map; public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProgressListener { private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimation; + private final RotationChangeProvider mRotationChangeProvider; private final Map<ViewGroup, Boolean> mOriginalClipToPadding = new HashMap<>(); private final Map<ViewGroup, Boolean> mOriginalClipChildren = new HashMap<>(); + private final UnfoldMoveFromCenterRotationListener mRotationListener = + new UnfoldMoveFromCenterRotationListener(); private boolean mAnimationInProgress = false; - public BaseUnfoldMoveFromCenterAnimator(WindowManager windowManager) { + public BaseUnfoldMoveFromCenterAnimator(WindowManager windowManager, + RotationChangeProvider rotationChangeProvider) { mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager, new LauncherViewsMoveFromCenterTranslationApplier()); + mRotationChangeProvider = rotationChangeProvider; } @CallSuper @@ -50,6 +57,7 @@ public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProg mMoveFromCenterAnimation.updateDisplayProperties(); onPrepareViewsForAnimation(); onTransitionProgress(0f); + mRotationChangeProvider.addCallback(mRotationListener); } @CallSuper @@ -62,6 +70,7 @@ public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProg @Override public void onTransitionFinished() { mAnimationInProgress = false; + mRotationChangeProvider.removeCallback(mRotationListener); mMoveFromCenterAnimation.onTransitionFinished(); clearRegisteredViews(); } @@ -109,4 +118,14 @@ public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProg view.setClipChildren(originalClipChildren); } } + + private class UnfoldMoveFromCenterRotationListener implements + RotationChangeProvider.RotationListener { + + @Override + public void onRotationChanged(@Rotation int newRotation) { + mMoveFromCenterAnimation.updateDisplayProperties(newRotation); + updateRegisteredViewsIfNeeded(); + } + } } diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.java b/quickstep/src/com/android/quickstep/util/DesktopTask.java new file mode 100644 index 0000000000..433d23fa97 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/DesktopTask.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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.quickstep.util; + +import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.recents.model.Task; + +import java.util.ArrayList; + +/** + * A {@link Task} container that can contain N number of tasks that are part of the desktop in + * recent tasks list. + */ +public class DesktopTask extends GroupTask { + + public ArrayList<Task> tasks; + + public DesktopTask(ArrayList<Task> tasks) { + super(tasks.get(0), null, null, TaskView.Type.DESKTOP); + this.tasks = tasks; + } + + @Override + public boolean containsTask(int taskId) { + for (Task task : tasks) { + if (task.key.id == taskId) { + return true; + } + } + return false; + } + + @Override + public boolean hasMultipleTasks() { + return true; + } + + @Override + public DesktopTask copy() { + return new DesktopTask(tasks); + } +} diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java index f30d00c722..2be4f0a519 100644 --- a/quickstep/src/com/android/quickstep/util/GroupTask.java +++ b/quickstep/src/com/android/quickstep/util/GroupTask.java @@ -20,6 +20,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; +import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; /** @@ -27,24 +28,25 @@ import com.android.systemui.shared.recents.model.Task; * are represented as an app-pair in the recents task list. */ public class GroupTask { - public @NonNull Task task1; - public @Nullable Task task2; - public @Nullable - SplitBounds mSplitBounds; + @NonNull + public final Task task1; + @Nullable + public final Task task2; + @Nullable + public final SplitBounds mSplitBounds; + @TaskView.Type + public final int taskViewType; - public GroupTask(@NonNull Task t1, @Nullable Task t2, - @Nullable SplitBounds splitBounds) { + public GroupTask(@NonNull Task t1, @Nullable Task t2, @Nullable SplitBounds splitBounds) { + this(t1, t2, splitBounds, t2 != null ? TaskView.Type.GROUPED : TaskView.Type.SINGLE); + } + + protected GroupTask(@NonNull Task t1, @Nullable Task t2, @Nullable SplitBounds splitBounds, + @TaskView.Type int taskViewType) { task1 = t1; task2 = t2; mSplitBounds = splitBounds; - } - - public GroupTask(@NonNull GroupTask group) { - task1 = new Task(group.task1); - task2 = group.task2 != null - ? new Task(group.task2) - : null; - mSplitBounds = group.mSplitBounds; + this.taskViewType = taskViewType; } public boolean containsTask(int taskId) { @@ -54,4 +56,14 @@ public class GroupTask { public boolean hasMultipleTasks() { return task2 != null; } + + /** + * Create a copy of this instance + */ + public GroupTask copy() { + return new GroupTask( + new Task(task1), + task2 != null ? new Task(task2) : null, + mSplitBounds); + } } diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java index 97be4370b9..170c622035 100644 --- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java +++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java @@ -18,13 +18,11 @@ package com.android.quickstep.util; import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY; import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_UNFOLD_ANIMATION; import static com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY; -import static com.android.launcher3.Utilities.comp; import android.annotation.Nullable; import android.util.FloatProperty; import android.util.MathUtils; import android.view.WindowManager; -import android.view.WindowManagerGlobal; import androidx.core.view.OneShotPreDrawListener; @@ -34,6 +32,7 @@ import com.android.launcher3.Workspace; import com.android.launcher3.util.HorizontalInsettableView; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener; +import com.android.systemui.unfold.updates.RotationChangeProvider; import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider; import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider; @@ -62,16 +61,17 @@ public class LauncherUnfoldAnimationController { public LauncherUnfoldAnimationController( Launcher launcher, WindowManager windowManager, - UnfoldTransitionProgressProvider unfoldTransitionProgressProvider) { + UnfoldTransitionProgressProvider unfoldTransitionProgressProvider, + RotationChangeProvider rotationChangeProvider) { mLauncher = launcher; mProgressProvider = new ScopedUnfoldTransitionProgressProvider( unfoldTransitionProgressProvider); mUnfoldMoveFromCenterHotseatAnimator = new UnfoldMoveFromCenterHotseatAnimator(launcher, - windowManager); + windowManager, rotationChangeProvider); mUnfoldMoveFromCenterWorkspaceAnimator = new UnfoldMoveFromCenterWorkspaceAnimator(launcher, - windowManager); + windowManager, rotationChangeProvider); mNaturalOrientationProgressProvider = new NaturalRotationUnfoldProgressProvider(launcher, - WindowManagerGlobal.getWindowManagerService(), mProgressProvider); + rotationChangeProvider, mProgressProvider); mNaturalOrientationProgressProvider.init(); // Animated in all orientations @@ -134,7 +134,7 @@ public class LauncherUnfoldAnimationController { @Override public void onTransitionProgress(float progress) { if (mQsbInsettable != null) { - float insetPercentage = comp(progress) * MAX_WIDTH_INSET_FRACTION; + float insetPercentage = (1 - progress) * MAX_WIDTH_INSET_FRACTION; mQsbInsettable.setHorizontalInsets(insetPercentage); } } diff --git a/quickstep/src/com/android/quickstep/util/PhoneSplitToConfirmTimings.java b/quickstep/src/com/android/quickstep/util/PhoneSplitToConfirmTimings.java index 9e7351a2de..3d9e09ee81 100644 --- a/quickstep/src/com/android/quickstep/util/PhoneSplitToConfirmTimings.java +++ b/quickstep/src/com/android/quickstep/util/PhoneSplitToConfirmTimings.java @@ -16,10 +16,6 @@ package com.android.quickstep.util; -import static com.android.launcher3.anim.Interpolators.EMPHASIZED; - -import android.view.animation.Interpolator; - /** * Timings for the OverviewSplitSelect > confirmed animation on phones. */ @@ -33,8 +29,4 @@ public class PhoneSplitToConfirmTimings public int getStagedRectSlideEnd() { return 333; } public int getDuration() { return PHONE_CONFIRM_DURATION; } - public Interpolator getStagedRectXInterpolator() { return EMPHASIZED; } - public Interpolator getStagedRectYInterpolator() { return EMPHASIZED; } - public Interpolator getStagedRectScaleXInterpolator() { return EMPHASIZED; } - public Interpolator getStagedRectScaleYInterpolator() { return EMPHASIZED; } } diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java index c459f303d1..db8c7f23b9 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java +++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java @@ -45,7 +45,7 @@ import androidx.annotation.NonNull; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.Utilities; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.DisplayController; @@ -139,7 +139,7 @@ public class RecentsOrientedState implements public RecentsOrientedState(Context context, BaseActivityInterface sizeStrategy, IntConsumer rotationChangeListener) { mContext = context; - mSharedPrefs = Utilities.getPrefs(context); + mSharedPrefs = LauncherPrefs.getPrefs(context); mOrientationListener = new OrientationEventListener(context) { @Override public void onOrientationChanged(int degrees) { diff --git a/quickstep/src/com/android/quickstep/util/RecordingSurfaceTransaction.java b/quickstep/src/com/android/quickstep/util/RecordingSurfaceTransaction.java new file mode 100644 index 0000000000..a2f48ddc9b --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/RecordingSurfaceTransaction.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 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.quickstep.util; + +/** + * Extension for {@link SurfaceTransaction} which records the commands for mocking + */ +public class RecordingSurfaceTransaction extends SurfaceTransaction { + + /** + * A mock builder which can be used for recording values + */ + public final MockProperties mockProperties = new MockProperties(); + +} diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java index ee82ae67df..10f2eaa2f0 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java +++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java @@ -16,23 +16,22 @@ package com.android.quickstep.util; import android.animation.AnimatorSet; - -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import android.view.RemoteAnimationTarget; public abstract class RemoteAnimationProvider { - public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets); + public abstract AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets); /** * @return the target with the lowest opaque layer for a certain app animation, or null. */ - public static RemoteAnimationTargetCompat findLowestOpaqueLayerTarget( - RemoteAnimationTargetCompat[] appTargets, int mode) { + public static RemoteAnimationTarget findLowestOpaqueLayerTarget( + RemoteAnimationTarget[] appTargets, int mode) { int lowestLayer = Integer.MAX_VALUE; int lowestLayerIndex = -1; for (int i = appTargets.length - 1; i >= 0; i--) { - RemoteAnimationTargetCompat target = appTargets[i]; + RemoteAnimationTarget target = appTargets[i]; if (target.mode == mode && !target.isTranslucent) { int layer = target.prefixOrderIndex; if (layer < lowestLayer) { diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java index 81c124f7e2..382cf79e1e 100644 --- a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java +++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java @@ -15,14 +15,14 @@ */ package com.android.quickstep.util; -import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; +import static android.view.RemoteAnimationTarget.MODE_CLOSING; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl.Transaction; import com.android.quickstep.RemoteAnimationTargets; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.TransactionCompat; /** * Animation listener which fades out the closing targets @@ -32,24 +32,24 @@ public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener { private final RemoteAnimationTargets mTarget; private boolean mFirstFrame = true; - public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] appTargets, - RemoteAnimationTargetCompat[] wallpaperTargets) { + public RemoteFadeOutAnimationListener(RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets) { mTarget = new RemoteAnimationTargets(appTargets, wallpaperTargets, - new RemoteAnimationTargetCompat[0], MODE_CLOSING); + new RemoteAnimationTarget[0], MODE_CLOSING); } @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { - TransactionCompat t = new TransactionCompat(); + Transaction t = new Transaction(); if (mFirstFrame) { - for (RemoteAnimationTargetCompat target : mTarget.unfilteredApps) { + for (RemoteAnimationTarget target : mTarget.unfilteredApps) { t.show(target.leash); } mFirstFrame = false; } float alpha = 1 - valueAnimator.getAnimatedFraction(); - for (RemoteAnimationTargetCompat app : mTarget.apps) { + for (RemoteAnimationTarget app : mTarget.apps) { t.setAlpha(app.leash, alpha); } t.apply(); diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java b/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java index 2966fbb5db..7dc1b32858 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java @@ -25,7 +25,7 @@ import android.view.animation.Interpolator; */ public interface SplitAnimationTimings { int TABLET_ENTER_DURATION = 866; - int TABLET_CONFIRM_DURATION = 383; + int TABLET_CONFIRM_DURATION = 500; int PHONE_ENTER_DURATION = 517; int PHONE_CONFIRM_DURATION = 333; diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenBounds.java b/quickstep/src/com/android/quickstep/util/SplitScreenBounds.java deleted file mode 100644 index 483a1c652a..0000000000 --- a/quickstep/src/com/android/quickstep/util/SplitScreenBounds.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2020 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.quickstep.util; - -import static android.view.Surface.ROTATION_0; -import static android.view.Surface.ROTATION_180; - -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.view.WindowManager; -import android.view.WindowMetrics; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.UiThread; - -import com.android.launcher3.R; -import com.android.launcher3.util.DisplayController; -import com.android.launcher3.util.WindowBounds; - -import java.util.ArrayList; - -/** - * Utility class to hold the information abound a window bounds for split screen - */ -@TargetApi(Build.VERSION_CODES.R) -public class SplitScreenBounds { - - public static final SplitScreenBounds INSTANCE = new SplitScreenBounds(); - private final ArrayList<OnChangeListener> mListeners = new ArrayList<>(); - - @Nullable - private WindowBounds mBounds; - - private SplitScreenBounds() { } - - @UiThread - public void setSecondaryWindowBounds(@NonNull WindowBounds bounds) { - if (!bounds.equals(mBounds)) { - mBounds = bounds; - for (OnChangeListener listener : mListeners) { - listener.onSecondaryWindowBoundsChanged(); - } - } - } - - public @NonNull WindowBounds getSecondaryWindowBounds(Context context) { - if (mBounds == null) { - mBounds = createDefaultWindowBounds(context); - } - return mBounds; - } - - /** - * Creates window bounds as 50% of device size - */ - private static WindowBounds createDefaultWindowBounds(Context context) { - WindowMetrics wm = context.getSystemService(WindowManager.class).getMaximumWindowMetrics(); - WindowBounds bounds = WindowBounds.fromWindowMetrics(wm); - - int rotation = DisplayController.INSTANCE.get(context).getInfo().rotation; - int halfDividerSize = context.getResources() - .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2; - - if (rotation == ROTATION_0 || rotation == ROTATION_180) { - bounds.bounds.top = bounds.insets.top + bounds.availableSize.y / 2 + halfDividerSize; - bounds.insets.top = 0; - } else { - bounds.bounds.left = bounds.insets.left + bounds.availableSize.x / 2 + halfDividerSize; - bounds.insets.left = 0; - } - return new WindowBounds(bounds.bounds, bounds.insets); - } - - public void addOnChangeListener(OnChangeListener listener) { - mListeners.add(listener); - } - - public void removeOnChangeListener(OnChangeListener listener) { - mListeners.remove(listener); - } - - /** - * Interface to receive window bounds changes - */ - public interface OnChangeListener { - - /** - * Called when window bounds for secondary window changes - */ - void onSecondaryWindowBoundsChanged(); - } -} diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java index efbe783125..681f068e52 100644 --- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java @@ -22,10 +22,10 @@ import static android.app.PendingIntent.FLAG_MUTABLE; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO; -import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; -import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT; +import static com.android.launcher3.util.SplitConfigurationOptions.getOppositeStagePosition; import android.annotation.NonNull; +import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.PendingIntent; @@ -35,12 +35,16 @@ import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.os.Handler; import android.os.IBinder; +import android.os.RemoteException; import android.os.UserHandle; -import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.view.RemoteAnimationAdapter; +import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; +import android.window.IRemoteTransition; +import android.window.IRemoteTransitionFinishedCallback; +import android.window.RemoteTransition; import android.window.TransitionInfo; import androidx.annotation.Nullable; @@ -58,14 +62,11 @@ import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.TaskViewUtils; +import com.android.quickstep.views.FloatingTaskView; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; -import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.RemoteTransitionCompat; -import com.android.systemui.shared.system.RemoteTransitionRunner; import java.util.function.Consumer; @@ -86,8 +87,8 @@ public class SplitSelectStateController { private ItemInfo mItemInfo; private Intent mInitialTaskIntent; private int mInitialTaskId = INVALID_TASK_ID; + private Intent mSecondTaskIntent; private int mSecondTaskId = INVALID_TASK_ID; - private String mSecondTaskPackageName; private boolean mRecentsAnimationRunning; @Nullable private UserHandle mUser; @@ -97,6 +98,8 @@ public class SplitSelectStateController { /** Represents where split is intended to be invoked from. */ private StatsLogManager.EventEnum mSplitEvent; + private FloatingTaskView mFirstFloatingTaskView; + public SplitSelectStateController(Context context, Handler handler, StateManager stateManager, DepthController depthController, StatsLogManager statsLogManager) { mContext = context; @@ -108,19 +111,38 @@ public class SplitSelectStateController { } /** - * To be called after first task selected + * To be called after first task selected in Overview. */ - public void setInitialTaskSelect(int taskId, @StagePosition int stagePosition, + public void setInitialTaskSelect(Task task, @StagePosition int stagePosition, StatsLogManager.EventEnum splitEvent, ItemInfo itemInfo) { - mInitialTaskId = taskId; + mInitialTaskId = task.key.id; setInitialData(stagePosition, splitEvent, itemInfo); } + /** + * To be called after first task selected from home or all apps. + */ public void setInitialTaskSelect(Intent intent, @StagePosition int stagePosition, - @NonNull ItemInfo itemInfo, StatsLogManager.EventEnum splitEvent) { - mInitialTaskIntent = intent; - mUser = itemInfo.user; - mItemInfo = itemInfo; + @NonNull ItemInfo itemInfo, StatsLogManager.EventEnum splitEvent, + @Nullable Task alreadyRunningTask) { + if (alreadyRunningTask != null) { + mInitialTaskId = alreadyRunningTask.key.id; + } else { + mInitialTaskIntent = intent; + mUser = itemInfo.user; + } + + setInitialData(stagePosition, splitEvent, itemInfo); + } + + /** + * To be called after first task selected from using a split shortcut from the fullscreen + * running app. + */ + public void setInitialTaskSelect(ActivityManager.RunningTaskInfo info, + @StagePosition int stagePosition, @NonNull ItemInfo itemInfo, + StatsLogManager.EventEnum splitEvent) { + mInitialTaskId = info.taskId; setInitialData(stagePosition, splitEvent, itemInfo); } @@ -136,26 +158,10 @@ public class SplitSelectStateController { * to be launched. Call after launcher side animations are complete. */ public void launchSplitTasks(Consumer<Boolean> callback) { - final Intent fillInIntent; - if (mInitialTaskIntent != null) { - fillInIntent = new Intent(); - if (TextUtils.equals(mInitialTaskIntent.getComponent().getPackageName(), - mSecondTaskPackageName)) { - fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - } - } else { - fillInIntent = null; - } - - final PendingIntent pendingIntent = mInitialTaskIntent == null ? null : (mUser != null - ? PendingIntent.getActivityAsUser(mContext, 0, mInitialTaskIntent, - FLAG_MUTABLE, null /* options */, mUser) - : PendingIntent.getActivity(mContext, 0, mInitialTaskIntent, FLAG_MUTABLE)); - Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds = LogUtils.getShellShareableInstanceId(); - launchTasks(mInitialTaskId, pendingIntent, fillInIntent, mSecondTaskId, mStagePosition, - callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO, + launchTasks(mInitialTaskId, mInitialTaskIntent, mSecondTaskId, mSecondTaskIntent, + mStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO, instanceIds.first); mStatsLogManager.logger() @@ -164,23 +170,23 @@ public class SplitSelectStateController { .log(mSplitEvent); } - /** * To be called as soon as user selects the second task (even if animations aren't complete) * @param task The second task that will be launched. */ public void setSecondTask(Task task) { mSecondTaskId = task.key.id; - if (mInitialTaskIntent != null) { - mSecondTaskPackageName = task.getTopComponent().getPackageName(); - } + } + + public void setSecondTask(Intent intent) { + mSecondTaskIntent = intent; } /** * To be called when we want to launch split pairs from an existing GroupedTaskView. */ - public void launchTasks(GroupedTaskView groupedTaskView, - Consumer<Boolean> callback, boolean freezeTaskList) { + public void launchTasks(GroupedTaskView groupedTaskView, Consumer<Boolean> callback, + boolean freezeTaskList) { mLaunchingTaskView = groupedTaskView; TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers = groupedTaskView.getTaskIdAttributeContainers(); @@ -196,73 +202,118 @@ public class SplitSelectStateController { */ public void launchTasks(int taskId1, int taskId2, @StagePosition int stagePosition, Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) { - launchTasks(taskId1, null /* taskPendingIntent */, null /* fillInIntent */, taskId2, - stagePosition, callback, freezeTaskList, splitRatio, null); + launchTasks(taskId1, null /* intent1 */, taskId2, null /* intent2 */, stagePosition, + callback, freezeTaskList, splitRatio, null); } /** * To be called when we want to launch split pairs from Overview. Split can be initiated from * either Overview or home, or all apps. Either both taskIds are set, or a pending intent + a * fill in intent with a taskId2 are set. - * @param taskPendingIntent is null when split is initiated from Overview + * @param intent1 is null when split is initiated from Overview * @param stagePosition representing location of task1 - * @param shellInstanceId loggingId to be used by shell, will be non-null for actions that create - * a split instance, null for cases that bring existing instaces to the + * @param shellInstanceId loggingId to be used by shell, will be non-null for actions that + * create a split instance, null for cases that bring existing instaces to the * foreground (quickswitch, launching previous pairs from overview) */ - public void launchTasks(int taskId1, @Nullable PendingIntent taskPendingIntent, - @Nullable Intent fillInIntent, int taskId2, @StagePosition int stagePosition, + public void launchTasks(int taskId1, @Nullable Intent intent1, int taskId2, + @Nullable Intent intent2, @StagePosition int stagePosition, Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio, @Nullable InstanceId shellInstanceId) { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "launchSplitTasks"); - // Assume initial task is for top/left part of screen - final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT - ? new int[]{taskId1, taskId2} - : new int[]{taskId2, taskId1}; + final ActivityOptions options1 = ActivityOptions.makeBasic(); + if (freezeTaskList) { + options1.setFreezeRecentTasksReordering(); + } if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) { - RemoteSplitLaunchTransitionRunner animationRunner = - new RemoteSplitLaunchTransitionRunner(taskId1, taskPendingIntent, taskId2, - callback); - mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1], - null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, - new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR, - ActivityThread.currentActivityThread().getApplicationThread()), - shellInstanceId); - // TODO(b/237635859): handle intent/shortcut + task with shell transition + final RemoteSplitLaunchTransitionRunner animationRunner = + new RemoteSplitLaunchTransitionRunner(taskId1, taskId2, callback); + final RemoteTransition remoteTransition = new RemoteTransition(animationRunner, + ActivityThread.currentActivityThread().getApplicationThread()); + if (intent1 == null && intent2 == null) { + mSystemUiProxy.startTasks(taskId1, options1.toBundle(), taskId2, + null /* options2 */, stagePosition, splitRatio, remoteTransition, + shellInstanceId); + } else if (intent2 == null) { + launchIntentOrShortcut(intent1, options1, taskId2, stagePosition, splitRatio, + remoteTransition, shellInstanceId); + } else if (intent1 == null) { + launchIntentOrShortcut(intent2, options1, taskId1, + getOppositeStagePosition(stagePosition), splitRatio, remoteTransition, + shellInstanceId); + } else { + mSystemUiProxy.startIntents(getPendingIntent(intent1), options1.toBundle(), + getPendingIntent(intent2), null /* options2 */, stagePosition, + splitRatio, remoteTransition, shellInstanceId); + } } else { - RemoteSplitLaunchAnimationRunner animationRunner = - new RemoteSplitLaunchAnimationRunner(taskId1, taskPendingIntent, taskId2, - callback); + final RemoteSplitLaunchAnimationRunner animationRunner = + new RemoteSplitLaunchAnimationRunner(taskId1, taskId2, callback); final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter( - RemoteAnimationAdapterCompat.wrapRemoteAnimationRunner(animationRunner), - 300, 150, + animationRunner, 300, 150, ActivityThread.currentActivityThread().getApplicationThread()); - ActivityOptions mainOpts = ActivityOptions.makeBasic(); - if (freezeTaskList) { - mainOpts.setFreezeRecentTasksReordering(); - } - if (taskPendingIntent == null) { - mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(), - taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, - splitRatio, adapter, shellInstanceId); + if (intent1 == null && intent2 == null) { + mSystemUiProxy.startTasksWithLegacyTransition(taskId1, options1.toBundle(), + taskId2, null /* options2 */, stagePosition, splitRatio, adapter, + shellInstanceId); + } else if (intent2 == null) { + launchIntentOrShortcutLegacy(intent1, options1, taskId2, stagePosition, splitRatio, + adapter, shellInstanceId); + } else if (intent1 == null) { + launchIntentOrShortcutLegacy(intent2, options1, taskId1, + getOppositeStagePosition(stagePosition), splitRatio, adapter, + shellInstanceId); } else { - final ShortcutInfo shortcutInfo = getShortcutInfo(mInitialTaskIntent, - taskPendingIntent.getCreatorUserHandle()); - if (shortcutInfo != null) { - mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(shortcutInfo, taskId2, - mainOpts.toBundle(), null /* sideOptions */, stagePosition, splitRatio, - adapter, shellInstanceId); - } else { - mSystemUiProxy.startIntentAndTaskWithLegacyTransition(taskPendingIntent, - fillInIntent, taskId2, mainOpts.toBundle(), null /* sideOptions */, - stagePosition, splitRatio, adapter, shellInstanceId); - } + mSystemUiProxy.startIntentsWithLegacyTransition(getPendingIntent(intent1), + options1.toBundle(), getPendingIntent(intent2), null /* options2 */, + stagePosition, splitRatio, adapter, shellInstanceId); } } } + private void launchIntentOrShortcut(Intent intent, ActivityOptions options1, int taskId, + @StagePosition int stagePosition, float splitRatio, RemoteTransition remoteTransition, + @Nullable InstanceId shellInstanceId) { + PendingIntent pendingIntent = getPendingIntent(intent); + final ShortcutInfo shortcutInfo = getShortcutInfo(intent, + pendingIntent.getCreatorUserHandle()); + if (shortcutInfo != null) { + mSystemUiProxy.startShortcutAndTask(shortcutInfo, + options1.toBundle(), taskId, null /* options2 */, stagePosition, + splitRatio, remoteTransition, shellInstanceId); + } else { + mSystemUiProxy.startIntentAndTask(pendingIntent, options1.toBundle(), taskId, + null /* options2 */, stagePosition, splitRatio, remoteTransition, + shellInstanceId); + } + } + + private void launchIntentOrShortcutLegacy(Intent intent, ActivityOptions options1, int taskId, + @StagePosition int stagePosition, float splitRatio, RemoteAnimationAdapter adapter, + @Nullable InstanceId shellInstanceId) { + PendingIntent pendingIntent = getPendingIntent(intent); + final ShortcutInfo shortcutInfo = getShortcutInfo(intent, + pendingIntent.getCreatorUserHandle()); + if (shortcutInfo != null) { + mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(shortcutInfo, + options1.toBundle(), taskId, null /* options2 */, stagePosition, + splitRatio, adapter, shellInstanceId); + } else { + mSystemUiProxy.startIntentAndTaskWithLegacyTransition(pendingIntent, + options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio, + adapter, shellInstanceId); + } + } + + private PendingIntent getPendingIntent(Intent intent) { + return intent == null ? null : (mUser != null + ? PendingIntent.getActivityAsUser(mContext, 0, intent, + FLAG_MUTABLE, null /* options */, mUser) + : PendingIntent.getActivity(mContext, 0, intent, FLAG_MUTABLE)); + } + public @StagePosition int getActiveSplitStagePosition() { return mStagePosition; } @@ -272,7 +323,7 @@ public class SplitSelectStateController { } public void setRecentsAnimationRunning(boolean running) { - this.mRecentsAnimationRunning = running; + mRecentsAnimationRunning = running; } @Nullable @@ -300,65 +351,75 @@ public class SplitSelectStateController { /** * Requires Shell Transitions */ - private class RemoteSplitLaunchTransitionRunner implements RemoteTransitionRunner { + private class RemoteSplitLaunchTransitionRunner extends IRemoteTransition.Stub { private final int mInitialTaskId; - private final PendingIntent mInitialTaskPendingIntent; private final int mSecondTaskId; private final Consumer<Boolean> mSuccessCallback; - RemoteSplitLaunchTransitionRunner(int initialTaskId, PendingIntent initialTaskPendingIntent, - int secondTaskId, Consumer<Boolean> callback) { + RemoteSplitLaunchTransitionRunner(int initialTaskId, int secondTaskId, + Consumer<Boolean> callback) { mInitialTaskId = initialTaskId; - mInitialTaskPendingIntent = initialTaskPendingIntent; mSecondTaskId = secondTaskId; mSuccessCallback = callback; } @Override - public void startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction t, @NonNull Runnable finishCallback) { - TaskViewUtils.composeRecentsSplitLaunchAnimator(mLaunchingTaskView, mStateManager, - mDepthController, mInitialTaskId, mInitialTaskPendingIntent, mSecondTaskId, - info, t, () -> { - finishCallback.run(); - if (mSuccessCallback != null) { - mSuccessCallback.accept(true); - } - }); - // After successful launch, call resetState - resetState(); + public void startAnimation(IBinder transition, TransitionInfo info, + SurfaceControl.Transaction t, + IRemoteTransitionFinishedCallback finishedCallback) { + final Runnable finishAdapter = () -> { + try { + finishedCallback.onTransitionFinished(null /* wct */, null /* sct */); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call transition finished callback", e); + } + }; + + MAIN_EXECUTOR.execute(() -> { + TaskViewUtils.composeRecentsSplitLaunchAnimator(mLaunchingTaskView, mStateManager, + mDepthController, mInitialTaskId, mSecondTaskId, info, t, () -> { + finishAdapter.run(); + if (mSuccessCallback != null) { + mSuccessCallback.accept(true); + } + }); + // After successful launch, call resetState + resetState(); + }); } + + @Override + public void mergeAnimation(IBinder transition, TransitionInfo info, + SurfaceControl.Transaction t, IBinder mergeTarget, + IRemoteTransitionFinishedCallback finishedCallback) { } } /** * LEGACY * Remote animation runner for animation to launch an app. */ - private class RemoteSplitLaunchAnimationRunner implements RemoteAnimationRunnerCompat { + private class RemoteSplitLaunchAnimationRunner extends RemoteAnimationRunnerCompat { private final int mInitialTaskId; - private final PendingIntent mInitialTaskPendingIntent; private final int mSecondTaskId; private final Consumer<Boolean> mSuccessCallback; - RemoteSplitLaunchAnimationRunner(int initialTaskId, PendingIntent initialTaskPendingIntent, - int secondTaskId, Consumer<Boolean> successCallback) { + RemoteSplitLaunchAnimationRunner(int initialTaskId, int secondTaskId, + Consumer<Boolean> successCallback) { mInitialTaskId = initialTaskId; - mInitialTaskPendingIntent = initialTaskPendingIntent; mSecondTaskId = secondTaskId; mSuccessCallback = successCallback; } @Override - public void onAnimationStart(int transit, RemoteAnimationTargetCompat[] apps, - RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps, + public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, Runnable finishedCallback) { postAsyncCallback(mHandler, () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy( - mLaunchingTaskView, mInitialTaskId, mInitialTaskPendingIntent, - mSecondTaskId, apps, wallpapers, nonApps, mStateManager, - mDepthController, () -> { + mLaunchingTaskView, mInitialTaskId, mSecondTaskId, apps, wallpapers, + nonApps, mStateManager, mDepthController, () -> { finishedCallback.run(); if (mSuccessCallback != null) { mSuccessCallback.accept(true); @@ -368,7 +429,7 @@ public class SplitSelectStateController { } @Override - public void onAnimationCancelled() { + public void onAnimationCancelled(boolean isKeyguardOccluded) { postAsyncCallback(mHandler, () -> { if (mSuccessCallback != null) { // Launching legacy tasks while recents animation is running will always cause @@ -387,6 +448,7 @@ public class SplitSelectStateController { mInitialTaskId = INVALID_TASK_ID; mInitialTaskIntent = null; mSecondTaskId = INVALID_TASK_ID; + mSecondTaskIntent = null; mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; mRecentsAnimationRunning = false; mLaunchingTaskView = null; @@ -399,7 +461,7 @@ public class SplitSelectStateController { * chosen */ public boolean isSplitSelectActive() { - return isInitialTaskIntentSet() && mSecondTaskId == INVALID_TASK_ID; + return isInitialTaskIntentSet() && !isSecondTaskIntentSet(); } /** @@ -407,7 +469,7 @@ public class SplitSelectStateController { * be launched */ public boolean isBothSplitAppsConfirmed() { - return isInitialTaskIntentSet() && mSecondTaskId != INVALID_TASK_ID; + return isInitialTaskIntentSet() && isSecondTaskIntentSet(); } private boolean isInitialTaskIntentSet() { @@ -417,4 +479,16 @@ public class SplitSelectStateController { public int getInitialTaskId() { return mInitialTaskId; } + + private boolean isSecondTaskIntentSet() { + return (mSecondTaskId != INVALID_TASK_ID || mSecondTaskIntent != null); + } + + public void setFirstFloatingTaskView(FloatingTaskView floatingTaskView) { + mFirstFloatingTaskView = floatingTaskView; + } + + public FloatingTaskView getFirstFloatingTaskView() { + return mFirstFloatingTaskView; + } } diff --git a/quickstep/src/com/android/quickstep/util/SplitToConfirmTimings.java b/quickstep/src/com/android/quickstep/util/SplitToConfirmTimings.java index 3026e98aa9..f5b00cf42b 100644 --- a/quickstep/src/com/android/quickstep/util/SplitToConfirmTimings.java +++ b/quickstep/src/com/android/quickstep/util/SplitToConfirmTimings.java @@ -16,6 +16,8 @@ package com.android.quickstep.util; +import static com.android.launcher3.anim.Interpolators.EMPHASIZED; + import android.view.animation.Interpolator; /** @@ -33,12 +35,12 @@ abstract class SplitToConfirmTimings implements SplitAnimationTimings { // Common timings public int getInstructionsFadeStart() { return 0; } public int getInstructionsFadeEnd() { return 67; } + public Interpolator getStagedRectXInterpolator() { return EMPHASIZED; } + public Interpolator getStagedRectYInterpolator() { return EMPHASIZED; } + public Interpolator getStagedRectScaleXInterpolator() { return EMPHASIZED; } + public Interpolator getStagedRectScaleYInterpolator() { return EMPHASIZED; } abstract public int getDuration(); - abstract public Interpolator getStagedRectXInterpolator(); - abstract public Interpolator getStagedRectYInterpolator(); - abstract public Interpolator getStagedRectScaleXInterpolator(); - abstract public Interpolator getStagedRectScaleYInterpolator(); public float getInstructionsFadeStartOffset() { return (float) getInstructionsFadeStart() / getDuration(); diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java new file mode 100644 index 0000000000..e5c74dc2e3 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2022 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.quickstep.util; + +import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Intent; +import android.graphics.Rect; +import android.graphics.RectF; +import android.view.View; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.icons.BitmapInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.quickstep.views.FloatingTaskView; +import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.system.InteractionJankMonitorWrapper; + +/** Handles when the stage split lands on the home screen. */ +public class SplitToWorkspaceController { + + private final Launcher mLauncher; + private final DeviceProfile mDP; + private final SplitSelectStateController mController; + + private final int mHalfDividerSize; + + public SplitToWorkspaceController(Launcher launcher, SplitSelectStateController controller) { + mLauncher = launcher; + mDP = mLauncher.getDeviceProfile(); + mController = controller; + + mHalfDividerSize = mLauncher.getResources().getDimensionPixelSize( + R.dimen.multi_window_task_divider_size) / 2; + } + + /** + * Handles second app selection from stage split. If the item can't be opened in split or + * it's not in stage split state, we pass it onto Launcher's default item click handler. + */ + public boolean handleSecondAppSelectionForSplit(View view) { + if ((!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get() + && !ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) + || !mController.isSplitSelectActive()) { + return false; + } + Object tag = view.getTag(); + Intent intent; + BitmapInfo bitmapInfo; + if (tag instanceof WorkspaceItemInfo) { + final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag; + intent = workspaceItemInfo.intent; + bitmapInfo = workspaceItemInfo.bitmap; + } else if (tag instanceof com.android.launcher3.model.data.AppInfo) { + final com.android.launcher3.model.data.AppInfo appInfo = + (com.android.launcher3.model.data.AppInfo) tag; + intent = appInfo.intent; + bitmapInfo = appInfo.bitmap; + } else { + return false; + } + + mController.setSecondTask(intent); + + boolean isTablet = mLauncher.getDeviceProfile().isTablet; + SplitAnimationTimings timings = AnimUtils.getDeviceSplitToConfirmTimings(isTablet); + PendingAnimation pendingAnimation = new PendingAnimation(timings.getDuration()); + + Rect firstTaskStartingBounds = new Rect(); + Rect firstTaskEndingBounds = new Rect(); + RectF secondTaskStartingBounds = new RectF(); + Rect secondTaskEndingBounds = new Rect(); + + RecentsView recentsView = mLauncher.getOverviewPanel(); + recentsView.getPagedOrientationHandler().getFinalSplitPlaceholderBounds(mHalfDividerSize, + mDP, mController.getActiveSplitStagePosition(), firstTaskEndingBounds, + secondTaskEndingBounds); + + FloatingTaskView firstFloatingTaskView = mController.getFirstFloatingTaskView(); + firstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds); + firstFloatingTaskView.addConfirmAnimation(pendingAnimation, + new RectF(firstTaskStartingBounds), firstTaskEndingBounds, + false /* fadeWithThumbnail */, true /* isStagedTask */); + + FloatingTaskView secondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mLauncher, + view, null /* thumbnail */, bitmapInfo.newIcon(mLauncher), + secondTaskStartingBounds); + secondFloatingTaskView.setAlpha(1); + secondFloatingTaskView.addConfirmAnimation(pendingAnimation, secondTaskStartingBounds, + secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isStagedTask */); + + pendingAnimation.addListener(new AnimatorListenerAdapter() { + private boolean mIsCancelled = false; + + @Override + public void onAnimationCancel(Animator animation) { + mIsCancelled = true; + cleanUp(); + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!mIsCancelled) { + mController.launchSplitTasks(aBoolean -> cleanUp()); + InteractionJankMonitorWrapper.end( + InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER); + } + } + + private void cleanUp() { + mLauncher.getDragLayer().removeView(firstFloatingTaskView); + mLauncher.getDragLayer().removeView(secondFloatingTaskView); + mController.resetState(); + } + }); + pendingAnimation.buildAnim().start(); + return true; + } +} diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java new file mode 100644 index 0000000000..24d832640f --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2022 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.quickstep.util; + +import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_RIGHT_BOTTOM; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; +import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; +import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.app.ActivityManager; +import android.content.Intent; +import android.graphics.Rect; +import android.graphics.RectF; +import android.os.SystemClock; +import android.os.UserHandle; +import android.view.View; + +import androidx.annotation.BinderThread; + +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.R; +import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.model.data.WorkspaceItemInfo; +import com.android.launcher3.uioverrides.QuickstepLauncher; +import com.android.quickstep.OverviewCommandHelper; +import com.android.quickstep.OverviewComponentObserver; +import com.android.quickstep.RecentsAnimationCallbacks; +import com.android.quickstep.RecentsAnimationController; +import com.android.quickstep.RecentsAnimationDeviceState; +import com.android.quickstep.RecentsAnimationTargets; +import com.android.quickstep.RecentsModel; +import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.views.FloatingTaskView; +import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.system.ActivityManagerWrapper; + +/** Transitions app from fullscreen to stage split when triggered from keyboard shortcuts. */ +public class SplitWithKeyboardShortcutController { + + private final QuickstepLauncher mLauncher; + private final SplitSelectStateController mController; + private final OverviewComponentObserver mOverviewComponentObserver; + + private final int mSplitPlaceholderSize; + private final int mSplitPlaceholderInset; + + public SplitWithKeyboardShortcutController(QuickstepLauncher launcher, + SplitSelectStateController controller) { + mLauncher = launcher; + mController = controller; + RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState( + launcher.getApplicationContext()); + mOverviewComponentObserver = new OverviewComponentObserver(launcher.getApplicationContext(), + deviceState); + + mSplitPlaceholderSize = mLauncher.getResources().getDimensionPixelSize( + R.dimen.split_placeholder_size); + mSplitPlaceholderInset = mLauncher.getResources().getDimensionPixelSize( + R.dimen.split_placeholder_inset); + } + + @BinderThread + public void enterStageSplit(boolean leftOrTop) { + if (!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()) { + return; + } + RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks( + SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext()), + false /* allowMinimizeSplitScreen */); + SplitWithKeyboardShortcutRecentsAnimationListener listener = + new SplitWithKeyboardShortcutRecentsAnimationListener(leftOrTop); + + MAIN_EXECUTOR.execute(() -> { + callbacks.addListener(listener); + UI_HELPER_EXECUTOR.execute( + // Transition from fullscreen app to enter stage split in launcher with + // recents animation. + () -> ActivityManagerWrapper.getInstance().startRecentsActivity( + mOverviewComponentObserver.getOverviewIntent(), + SystemClock.uptimeMillis(), callbacks, null, null)); + }); + } + + public void onDestroy() { + mOverviewComponentObserver.onDestroy(); + } + + private class SplitWithKeyboardShortcutRecentsAnimationListener implements + RecentsAnimationCallbacks.RecentsAnimationListener { + + private final boolean mLeftOrTop; + private final Rect mTempRect = new Rect(); + + private SplitWithKeyboardShortcutRecentsAnimationListener(boolean leftOrTop) { + mLeftOrTop = leftOrTop; + } + + @Override + public void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { + ActivityManager.RunningTaskInfo runningTaskInfo = + ActivityManagerWrapper.getInstance().getRunningTask(); + mController.setInitialTaskSelect(runningTaskInfo, + mLeftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT, + null /* itemInfo */, + mLeftOrTop ? LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP + : LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_RIGHT_BOTTOM); + + RecentsView recentsView = mLauncher.getOverviewPanel(); + recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds( + mSplitPlaceholderSize, mSplitPlaceholderInset, mLauncher.getDeviceProfile(), + mController.getActiveSplitStagePosition(), mTempRect); + + PendingAnimation anim = new PendingAnimation( + SplitAnimationTimings.TABLET_HOME_TO_SPLIT.getDuration()); + RectF startingTaskRect = new RectF(); + final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView( + mLauncher, mLauncher.getDragLayer(), + controller.screenshotTask(runningTaskInfo.taskId).thumbnail, + null /* icon */, startingTaskRect); + RecentsModel.INSTANCE.get(mLauncher.getApplicationContext()) + .getIconCache() + .updateIconInBackground( + Task.from(new Task.TaskKey(runningTaskInfo), runningTaskInfo, + false /* isLocked */), + (task) -> { + if (task.thumbnail != null) { + floatingTaskView.setIcon(task.thumbnail.thumbnail); + } + }); + floatingTaskView.setAlpha(1); + floatingTaskView.addStagingAnimation(anim, startingTaskRect, mTempRect, + false /* fadeWithThumbnail */, true /* isStagedTask */); + mController.setFirstFloatingTaskView(floatingTaskView); + + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + controller.finish(true /* toRecents */, null /* onFinishComplete */, + false /* sendUserLeaveHint */); + } + }); + anim.buildAnim().start(); + } + }; +} diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index eec8582756..ad54a709d7 100644 --- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -46,6 +46,7 @@ import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Workspace; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.SpringAnimationBuilder; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.uioverrides.QuickstepLauncher; @@ -122,8 +123,7 @@ public class StaggeredWorkspaceAnim { if (grid.isVerticalBarLayout()) { for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) { View child = hotseatIcons.getChildAt(i); - CellLayout.LayoutParams lp = - ((CellLayout.LayoutParams) child.getLayoutParams()); + CellLayoutLayoutParams lp = ((CellLayoutLayoutParams) child.getLayoutParams()); addStaggeredAnimationForView(child, lp.cellY + 1, totalRows, duration); } } else { @@ -193,7 +193,7 @@ public class StaggeredWorkspaceAnim { // Set up springs on workspace items. for (int i = itemsContainer.getChildCount() - 1; i >= 0; i--) { View child = itemsContainer.getChildAt(i); - CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams()); + CellLayoutLayoutParams lp = ((CellLayoutLayoutParams) child.getLayoutParams()); addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows, duration); } diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java b/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java new file mode 100644 index 0000000000..7ab285dfa7 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2022 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.quickstep.util; + +import android.graphics.Matrix; +import android.graphics.Rect; +import android.view.SurfaceControl; +import android.view.SurfaceControl.Transaction; + +/** + * Helper class for building a {@link Transaction}. + */ +public class SurfaceTransaction { + + private final Transaction mTransaction = new Transaction(); + private final float[] mTmpValues = new float[9]; + + /** + * Creates a new builder for the provided surface + */ + public SurfaceProperties forSurface(SurfaceControl surface) { + return surface.isValid() ? new SurfaceProperties(surface) : new MockProperties(); + } + + /** + * Returns the final transaction + */ + public Transaction getTransaction() { + return mTransaction; + } + + /** + * Utility class to update surface params in a transaction + */ + public class SurfaceProperties { + + private final SurfaceControl mSurface; + + SurfaceProperties(SurfaceControl surface) { + mSurface = surface; + } + + /** + * @param alpha The alpha value to apply to the surface. + * @return this Builder + */ + public SurfaceProperties setAlpha(float alpha) { + mTransaction.setAlpha(mSurface, alpha); + return this; + } + + /** + * @param matrix The matrix to apply to the surface. + * @return this Builder + */ + public SurfaceProperties setMatrix(Matrix matrix) { + mTransaction.setMatrix(mSurface, matrix, mTmpValues); + return this; + } + + /** + * @param windowCrop The window crop to apply to the surface. + * @return this Builder + */ + public SurfaceProperties setWindowCrop(Rect windowCrop) { + mTransaction.setWindowCrop(mSurface, windowCrop); + return this; + } + + /** + * @param relativeLayer The relative layer. + * @return this Builder + */ + public SurfaceProperties setLayer(int relativeLayer) { + mTransaction.setLayer(mSurface, relativeLayer); + return this; + } + + /** + * @param radius the Radius for rounded corners to apply to the surface. + * @return this Builder + */ + public SurfaceProperties setCornerRadius(float radius) { + mTransaction.setCornerRadius(mSurface, radius); + return this; + } + + /** + * @param radius the Radius for the shadows to apply to the surface. + * @return this Builder + */ + public SurfaceProperties setShadowRadius(float radius) { + mTransaction.setShadowRadius(mSurface, radius); + return this; + } + } + + /** + * Extension of {@link SurfaceProperties} which just stores all the values locally + */ + public class MockProperties extends SurfaceProperties { + + public float alpha = -1; + public Matrix matrix = null; + public Rect windowCrop = null; + public float cornerRadius = 0; + public float shadowRadius = 0; + + protected MockProperties() { + super(null); + } + + @Override + public SurfaceProperties setAlpha(float alpha) { + this.alpha = alpha; + return this; + } + + @Override + public SurfaceProperties setMatrix(Matrix matrix) { + this.matrix = matrix; + return this; + } + + @Override + public SurfaceProperties setWindowCrop(Rect windowCrop) { + this.windowCrop = windowCrop; + return this; + } + + @Override + public SurfaceProperties setLayer(int relativeLayer) { + return this; + } + + @Override + public SurfaceProperties setCornerRadius(float radius) { + this.cornerRadius = radius; + return this; + } + + @Override + public SurfaceProperties setShadowRadius(float radius) { + this.shadowRadius = radius; + return this; + } + } +} diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java index 1200208e30..95473dc39a 100644 --- a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java +++ b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java @@ -25,7 +25,6 @@ import android.view.View; import android.view.ViewRootImpl; import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import java.util.function.Consumer; @@ -70,18 +69,12 @@ public class SurfaceTransactionApplier extends ReleaseCheck { * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into * this method to avoid synchronization issues. */ - public void scheduleApply(final SurfaceParams... params) { + public void scheduleApply(SurfaceTransaction params) { View view = mTargetViewRootImpl.getView(); if (view == null) { return; } - Transaction t = new Transaction(); - for (int i = params.length - 1; i >= 0; i--) { - SurfaceParams surfaceParams = params[i]; - if (surfaceParams.surface.isValid()) { - surfaceParams.applyTo(t); - } - } + Transaction t = params.getTransaction(); mLastSequenceNumber++; final int toApplySeqNo = mLastSequenceNumber; @@ -102,7 +95,7 @@ public class SurfaceTransactionApplier extends ReleaseCheck { } /** - * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is + * Creates an instance of SurfaceTransactionApplier, deferring until the target view is * attached if necessary. */ public static void create( diff --git a/quickstep/src/com/android/quickstep/util/TabletSplitToConfirmTimings.java b/quickstep/src/com/android/quickstep/util/TabletSplitToConfirmTimings.java index 3ea8466148..3756b4af59 100644 --- a/quickstep/src/com/android/quickstep/util/TabletSplitToConfirmTimings.java +++ b/quickstep/src/com/android/quickstep/util/TabletSplitToConfirmTimings.java @@ -16,10 +16,6 @@ package com.android.quickstep.util; -import static com.android.launcher3.anim.Interpolators.LINEAR; - -import android.view.animation.Interpolator; - /** * Timings for the OverviewSplitSelect > confirmed animation on tablets. */ @@ -30,11 +26,7 @@ public class TabletSplitToConfirmTimings public int getPlaceholderIconFadeInStart() { return 167; } public int getPlaceholderIconFadeInEnd() { return 250; } public int getStagedRectSlideStart() { return 0; } - public int getStagedRectSlideEnd() { return 383; } + public int getStagedRectSlideEnd() { return 500; } public int getDuration() { return TABLET_CONFIRM_DURATION; } - public Interpolator getStagedRectXInterpolator() { return LINEAR; } - public Interpolator getStagedRectYInterpolator() { return LINEAR; } - public Interpolator getStagedRectScaleXInterpolator() { return LINEAR; } - public Interpolator getStagedRectScaleYInterpolator() { return LINEAR; } } diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java index 1a026fc31d..04af19f729 100644 --- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java +++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java @@ -17,7 +17,6 @@ package com.android.quickstep.util; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.states.RotationHelper.deltaRotation; import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; @@ -36,22 +35,22 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.util.Log; +import android.view.RemoteAnimationTarget; import androidx.annotation.NonNull; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; import com.android.launcher3.util.TraceHelper; -import com.android.quickstep.AnimatedFloat; import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.TaskAnimationManager; -import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper; +import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; import com.android.quickstep.views.TaskView.FullscreenDrawParams; import com.android.systemui.shared.recents.model.ThumbnailData; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder; +import com.android.systemui.shared.recents.utilities.PreviewPositionHelper; /** * A utility class which emulates the layout behavior of TaskView and RecentsView @@ -172,8 +171,11 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { /** * Sets the targets which the simulator will control */ - public void setPreview(RemoteAnimationTargetCompat runningTarget) { - setPreviewBounds(runningTarget.startScreenSpaceBounds, runningTarget.contentInsets); + public void setPreview(RemoteAnimationTarget runningTarget) { + setPreviewBounds( + runningTarget.startBounds == null + ? runningTarget.screenSpaceBounds : runningTarget.startBounds, + runningTarget.contentInsets); } /** @@ -182,7 +184,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { * * @param splitInfo set to {@code null} when not in staged split mode */ - public void setPreview(RemoteAnimationTargetCompat runningTarget, SplitBounds splitInfo) { + public void setPreview(RemoteAnimationTarget runningTarget, SplitBounds splitInfo) { setPreview(runningTarget); mSplitBounds = splitInfo; if (mSplitBounds == null) { @@ -192,6 +194,7 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds) ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT; + mPositionHelper.setSplitBounds(convertSplitBounds(mSplitBounds), mStagePosition); } /** @@ -318,9 +321,9 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { // mIsRecentsRtl is the inverse of TaskView RTL. boolean isRtlEnabled = !mIsRecentsRtl; mPositionHelper.updateThumbnailMatrix( - mThumbnailPosition, mThumbnailData, - mTaskRect.width(), mTaskRect.height(), - mDp, mOrientationState.getRecentsActivityRotation(), isRtlEnabled); + mThumbnailPosition, mThumbnailData, mTaskRect.width(), mTaskRect.height(), + mDp.widthPx, mDp.heightPx, mDp.taskbarSize, mDp.isTablet, + mOrientationState.getRecentsActivityRotation(), isRtlEnabled); mPositionHelper.getMatrix().invert(mInversePositionMatrix); if (DEBUG) { Log.d(TAG, " taskRect: " + mTaskRect); @@ -387,19 +390,19 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { @Override public void onBuildTargetParams( - Builder builder, RemoteAnimationTargetCompat app, TransformParams params) { - builder.withMatrix(mMatrix) - .withWindowCrop(mTmpCropRect) - .withCornerRadius(getCurrentCornerRadius()); + SurfaceProperties builder, RemoteAnimationTarget app, TransformParams params) { + builder.setMatrix(mMatrix) + .setWindowCrop(mTmpCropRect) + .setCornerRadius(getCurrentCornerRadius()); // If mDrawsBelowRecents is unset, no reordering will be enforced. - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mDrawsBelowRecents != null) { + if (mDrawsBelowRecents != null) { // In legacy transitions, the animation leashes remain in same hierarchy in the // TaskDisplayArea, so we don't want to bump the layer too high otherwise it will // conflict with layers that WM core positions (ie. the input consumers). For shell // transitions, the animation leashes are reparented to an animation container so we // can bump layers as needed. - builder.withLayer(mDrawsBelowRecents + builder.setLayer(mDrawsBelowRecents ? Integer.MIN_VALUE + 1 : ENABLE_SHELL_TRANSITIONS ? Integer.MAX_VALUE : 0); } @@ -419,4 +422,15 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy { return Math.max(Math.abs(mTempPoint[0]), Math.abs(mTempPoint[1])); } + /** + * TODO(b/254378592): Remove this after consolidation of classes + */ + public static com.android.wm.shell.util.SplitBounds convertSplitBounds(SplitBounds bounds) { + return new com.android.wm.shell.util.SplitBounds( + bounds.leftTopBounds, + bounds.rightBottomBounds, + bounds.leftTopTaskId, + bounds.rightBottomTaskId + ); + } } diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java index a7f25d40ef..aa9a45bd8b 100644 --- a/quickstep/src/com/android/quickstep/util/TransformParams.java +++ b/quickstep/src/com/android/quickstep/util/TransformParams.java @@ -15,16 +15,18 @@ */ package com.android.quickstep.util; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; + import android.util.FloatProperty; +import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; import com.android.quickstep.RemoteAnimationTargets; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; -import com.android.systemui.shared.system.TransactionCompat; +import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; public class TransformParams { @@ -113,8 +115,7 @@ public class TransformParams { * Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that * are computed based on these TransformParams. */ - public TransformParams setSyncTransactionApplier( - SurfaceTransactionApplier applier) { + public TransformParams setSyncTransactionApplier(SurfaceTransactionApplier applier) { mSyncTransactionApplier = applier; return this; } @@ -137,28 +138,26 @@ public class TransformParams { return this; } - public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) { + public SurfaceTransaction createSurfaceParams(BuilderProxy proxy) { RemoteAnimationTargets targets = mTargetSet; - final int appLength = targets.unfilteredApps.length; - final int wallpaperLength = targets.wallpapers != null ? targets.wallpapers.length : 0; - SurfaceParams[] surfaceParams = new SurfaceParams[appLength + wallpaperLength]; + SurfaceTransaction transaction = new SurfaceTransaction(); mRecentsSurface = getRecentsSurface(targets); - for (int i = 0; i < appLength; i++) { - RemoteAnimationTargetCompat app = targets.unfilteredApps[i]; - SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash); + for (int i = 0; i < targets.unfilteredApps.length; i++) { + RemoteAnimationTarget app = targets.unfilteredApps[i]; + SurfaceProperties builder = transaction.forSurface(app.leash); if (app.mode == targets.targetMode) { - if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { + int activityType = app.windowConfiguration.getActivityType(); + if (activityType == ACTIVITY_TYPE_HOME) { mHomeBuilderProxy.onBuildTargetParams(builder, app, this); } else { // Fade out Assistant overlay. - if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT - && app.isNotInRecents) { + if (activityType == ACTIVITY_TYPE_ASSISTANT && app.isNotInRecents) { float progress = Utilities.boundToRange(getProgress(), 0, 1); - builder.withAlpha(1 - Interpolators.DEACCEL_2_5.getInterpolation(progress)); + builder.setAlpha(1 - Interpolators.DEACCEL_2_5.getInterpolation(progress)); } else { - builder.withAlpha(getTargetAlpha()); + builder.setAlpha(getTargetAlpha()); } proxy.onBuildTargetParams(builder, app, this); @@ -166,22 +165,22 @@ public class TransformParams { } else { mBaseBuilderProxy.onBuildTargetParams(builder, app, this); } - surfaceParams[i] = builder.build(); } + // always put wallpaper layer to bottom. + final int wallpaperLength = targets.wallpapers != null ? targets.wallpapers.length : 0; for (int i = 0; i < wallpaperLength; i++) { - RemoteAnimationTargetCompat wallpaper = targets.wallpapers[i]; - surfaceParams[appLength + i] = new SurfaceParams.Builder(wallpaper.leash) - .withLayer(Integer.MIN_VALUE).build(); + RemoteAnimationTarget wallpaper = targets.wallpapers[i]; + transaction.forSurface(wallpaper.leash).setLayer(Integer.MIN_VALUE); } - return surfaceParams; + return transaction; } private static SurfaceControl getRecentsSurface(RemoteAnimationTargets targets) { for (int i = 0; i < targets.unfilteredApps.length; i++) { - RemoteAnimationTargetCompat app = targets.unfilteredApps[i]; + RemoteAnimationTarget app = targets.unfilteredApps[i]; if (app.mode == targets.targetMode) { - if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_RECENTS) { + if (app.windowConfiguration.getActivityType() == ACTIVITY_TYPE_RECENTS) { return app.leash; } } else { @@ -213,15 +212,11 @@ public class TransformParams { return mTargetSet; } - public void applySurfaceParams(SurfaceParams... params) { + public void applySurfaceParams(SurfaceTransaction builder) { if (mSyncTransactionApplier != null) { - mSyncTransactionApplier.scheduleApply(params); + mSyncTransactionApplier.scheduleApply(builder); } else { - TransactionCompat t = new TransactionCompat(); - for (SurfaceParams param : params) { - SyncRtSurfaceTransactionApplierCompat.applyParams(t, param); - } - t.apply(); + builder.getTransaction().apply(); } } @@ -229,9 +224,9 @@ public class TransformParams { public interface BuilderProxy { BuilderProxy NO_OP = (builder, app, params) -> { }; - BuilderProxy ALWAYS_VISIBLE = (builder, app, params) ->builder.withAlpha(1); + BuilderProxy ALWAYS_VISIBLE = (builder, app, params) -> builder.setAlpha(1); - void onBuildTargetParams(SurfaceParams.Builder builder, - RemoteAnimationTargetCompat app, TransformParams params); + void onBuildTargetParams(SurfaceProperties builder, + RemoteAnimationTarget app, TransformParams params); } } diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java index dc97dd6f86..01a997a451 100644 --- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java +++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java @@ -21,6 +21,7 @@ import android.view.WindowManager; import com.android.launcher3.Hotseat; import com.android.launcher3.Launcher; +import com.android.systemui.unfold.updates.RotationChangeProvider; /** * Animation that moves hotseat icons from center to the sides (final position) @@ -29,8 +30,9 @@ public class UnfoldMoveFromCenterHotseatAnimator extends BaseUnfoldMoveFromCente private final Launcher mLauncher; - public UnfoldMoveFromCenterHotseatAnimator(Launcher launcher, WindowManager windowManager) { - super(windowManager); + public UnfoldMoveFromCenterHotseatAnimator(Launcher launcher, WindowManager windowManager, + RotationChangeProvider rotationChangeProvider) { + super(windowManager, rotationChangeProvider); mLauncher = launcher; } diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java index 354d1579b0..95a4b8f2e2 100644 --- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java +++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java @@ -22,6 +22,7 @@ import com.android.launcher3.CellLayout; import com.android.launcher3.Launcher; import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Workspace; +import com.android.systemui.unfold.updates.RotationChangeProvider; /** * Animation that moves launcher icons and widgets from center to the sides (final position) @@ -30,8 +31,9 @@ public class UnfoldMoveFromCenterWorkspaceAnimator extends BaseUnfoldMoveFromCen private final Launcher mLauncher; - public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager) { - super(windowManager); + public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager, + RotationChangeProvider rotationChangeProvider) { + super(windowManager, rotationChangeProvider); mLauncher = launcher; } diff --git a/quickstep/src/com/android/quickstep/util/VibrationConstants.java b/quickstep/src/com/android/quickstep/util/VibrationConstants.java new file mode 100644 index 0000000000..0f0306e344 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/VibrationConstants.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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.quickstep.util; + +import android.os.VibrationEffect; + +public class VibrationConstants { + public static final VibrationEffect EFFECT_TEXTURE_TICK = + VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK); +}
\ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/util/ViewCapture.java b/quickstep/src/com/android/quickstep/util/ViewCapture.java deleted file mode 100644 index cfcfce0b6a..0000000000 --- a/quickstep/src/com/android/quickstep/util/ViewCapture.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (C) 2022 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.quickstep.util; - -import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; -import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; -import static com.android.launcher3.util.Executors.createAndStartNewLooper; - -import static java.util.stream.Collectors.toList; - -import android.content.Context; -import android.content.res.Resources; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Process; -import android.os.Trace; -import android.text.TextUtils; -import android.util.Base64; -import android.util.Base64OutputStream; -import android.util.Log; -import android.util.Pair; -import android.util.SparseArray; -import android.view.View; -import android.view.View.OnAttachStateChangeListener; -import android.view.ViewGroup; -import android.view.ViewTreeObserver.OnDrawListener; -import android.view.Window; - -import androidx.annotation.UiThread; -import androidx.annotation.WorkerThread; - -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.util.LooperExecutor; -import com.android.launcher3.util.MainThreadInitializedObject; -import com.android.launcher3.util.SafeCloseable; -import com.android.launcher3.view.ViewCaptureData.ExportedData; -import com.android.launcher3.view.ViewCaptureData.FrameData; -import com.android.launcher3.view.ViewCaptureData.ViewNode; - -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Future; -import java.util.zip.GZIPOutputStream; - -/** - * Utility class for capturing view data every frame - */ -public class ViewCapture { - - private static final String TAG = "ViewCapture"; - - // These flags are copies of two private flags in the View class. - private static final int PFLAG_INVALIDATED = 0x80000000; - private static final int PFLAG_DIRTY_MASK = 0x00200000; - - // Number of frames to keep in memory - private static final int MEMORY_SIZE = 2000; - // Initial size of the reference pool. This is at least be 5 * total number of views in - // Launcher. This allows the first free frames avoid object allocation during view capture. - private static final int INIT_POOL_SIZE = 300; - - public static final MainThreadInitializedObject<ViewCapture> INSTANCE = - new MainThreadInitializedObject<>(ViewCapture::new); - - private final List<WindowListener> mListeners = new ArrayList<>(); - - private final Context mContext; - private final LooperExecutor mExecutor; - - // Pool used for capturing view tree on the UI thread. - private ViewRef mPool = new ViewRef(); - - private ViewCapture(Context context) { - mContext = context; - if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { - Looper looper = createAndStartNewLooper("ViewCapture", - Process.THREAD_PRIORITY_FOREGROUND); - mExecutor = new LooperExecutor(looper); - mExecutor.execute(this::initPool); - } else { - mExecutor = UI_HELPER_EXECUTOR; - } - } - - @UiThread - private void addToPool(ViewRef start, ViewRef end) { - end.next = mPool; - mPool = start; - } - - @WorkerThread - private void initPool() { - ViewRef start = new ViewRef(); - ViewRef current = start; - - for (int i = 0; i < INIT_POOL_SIZE; i++) { - current.next = new ViewRef(); - current = current.next; - } - - ViewRef finalCurrent = current; - MAIN_EXECUTOR.execute(() -> addToPool(start, finalCurrent)); - } - - /** - * Attaches the ViewCapture to the provided window and returns a handle to detach the listener - */ - public SafeCloseable startCapture(Window window) { - String title = window.getAttributes().getTitle().toString(); - String name = TextUtils.isEmpty(title) ? window.toString() : title; - return startCapture(window.getDecorView(), name); - } - - /** - * Attaches the ViewCapture to the provided window and returns a handle to detach the listener - */ - public SafeCloseable startCapture(View view, String name) { - if (!FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { - return () -> { }; - } - - WindowListener listener = new WindowListener(view, name); - mExecutor.execute(() -> MAIN_EXECUTOR.execute(listener::attachToRoot)); - mListeners.add(listener); - return () -> { - mListeners.remove(listener); - listener.destroy(); - }; - } - - /** - * Dumps all the active view captures - */ - public void dump(PrintWriter writer, FileDescriptor out) { - if (!FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { - return; - } - ViewIdProvider idProvider = new ViewIdProvider(mContext.getResources()); - - // Collect all the tasks first so that all the tasks are posted on the executor - List<Pair<String, Future<ExportedData>>> tasks = mListeners.stream() - .map(l -> Pair.create(l.name, mExecutor.submit(() -> l.dumpToProto(idProvider)))) - .collect(toList()); - - tasks.forEach(pair -> { - writer.println(); - writer.println(" ContinuousViewCapture:"); - writer.println(" window " + pair.first + ":"); - writer.println(" pkg:" + mContext.getPackageName()); - writer.print(" data:"); - writer.flush(); - try (OutputStream os = new FileOutputStream(out)) { - ExportedData data = pair.second.get(); - OutputStream encodedOS = new GZIPOutputStream(new Base64OutputStream(os, - Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP)); - data.writeTo(encodedOS); - encodedOS.close(); - os.flush(); - } catch (Exception e) { - Log.e(TAG, "Error capturing proto", e); - } - writer.println(); - writer.println("--end--"); - }); - } - - private class WindowListener implements OnDrawListener { - - private final View mRoot; - public final String name; - - private final Handler mHandler; - private final ViewRef mViewRef = new ViewRef(); - - private int mFrameIndexBg = -1; - private boolean mIsFirstFrame = true; - private final long[] mFrameTimesBg = new long[MEMORY_SIZE]; - private final ViewPropertyRef[] mNodesBg = new ViewPropertyRef[MEMORY_SIZE]; - - private boolean mDestroyed = false; - - WindowListener(View view, String name) { - mRoot = view; - this.name = name; - mHandler = new Handler(mExecutor.getLooper(), this::captureViewPropertiesBg); - } - - @Override - public void onDraw() { - Trace.beginSection("view_capture"); - captureViewTree(mRoot, mViewRef); - Message m = Message.obtain(mHandler); - m.obj = mViewRef.next; - mHandler.sendMessage(m); - mIsFirstFrame = false; - Trace.endSection(); - } - - /** - * Captures the View property on the background thread, and transfer all the ViewRef objects - * back to the pool - */ - @WorkerThread - private boolean captureViewPropertiesBg(Message msg) { - ViewRef viewRefStart = (ViewRef) msg.obj; - long time = msg.getWhen(); - if (viewRefStart == null) { - return false; - } - mFrameIndexBg++; - if (mFrameIndexBg >= MEMORY_SIZE) { - mFrameIndexBg = 0; - } - mFrameTimesBg[mFrameIndexBg] = time; - - ViewPropertyRef recycle = mNodesBg[mFrameIndexBg]; - - ViewPropertyRef resultStart = null; - ViewPropertyRef resultEnd = null; - - ViewRef viewRefEnd = viewRefStart; - while (viewRefEnd != null) { - ViewPropertyRef propertyRef = recycle; - if (propertyRef == null) { - propertyRef = new ViewPropertyRef(); - } else { - recycle = recycle.next; - propertyRef.next = null; - } - - ViewPropertyRef copy = null; - if (viewRefEnd.childCount < 0) { - copy = findInLastFrame(viewRefEnd.view.hashCode()); - viewRefEnd.childCount = (copy != null) ? copy.childCount : 0; - } - viewRefEnd.transferTo(propertyRef); - - if (resultStart == null) { - resultStart = propertyRef; - resultEnd = resultStart; - } else { - resultEnd.next = propertyRef; - resultEnd = resultEnd.next; - } - - if (copy != null) { - int pending = copy.childCount; - while (pending > 0) { - copy = copy.next; - pending = pending - 1 + copy.childCount; - - propertyRef = recycle; - if (propertyRef == null) { - propertyRef = new ViewPropertyRef(); - } else { - recycle = recycle.next; - propertyRef.next = null; - } - - copy.transferTo(propertyRef); - - resultEnd.next = propertyRef; - resultEnd = resultEnd.next; - } - } - - if (viewRefEnd.next == null) { - // The compiler will complain about using a non-final variable from - // an outer class in a lambda if we pass in viewRefEnd directly. - final ViewRef finalViewRefEnd = viewRefEnd; - MAIN_EXECUTOR.execute(() -> addToPool(viewRefStart, finalViewRefEnd)); - break; - } - viewRefEnd = viewRefEnd.next; - } - mNodesBg[mFrameIndexBg] = resultStart; - return true; - } - - private ViewPropertyRef findInLastFrame(int hashCode) { - int lastFrameIndex = (mFrameIndexBg == 0) ? MEMORY_SIZE - 1 : mFrameIndexBg - 1; - ViewPropertyRef viewPropertyRef = mNodesBg[lastFrameIndex]; - while (viewPropertyRef != null && viewPropertyRef.hashCode != hashCode) { - viewPropertyRef = viewPropertyRef.next; - } - return viewPropertyRef; - } - - void attachToRoot() { - if (mRoot.isAttachedToWindow()) { - mRoot.getViewTreeObserver().addOnDrawListener(this); - } else { - mRoot.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - if (!mDestroyed) { - mRoot.getViewTreeObserver().addOnDrawListener(WindowListener.this); - } - mRoot.removeOnAttachStateChangeListener(this); - } - - @Override - public void onViewDetachedFromWindow(View v) { } - }); - } - } - - void destroy() { - mRoot.getViewTreeObserver().removeOnDrawListener(this); - mDestroyed = true; - } - - @WorkerThread - private ExportedData dumpToProto(ViewIdProvider idProvider) { - ExportedData.Builder dataBuilder = ExportedData.newBuilder(); - ArrayList<Class> classList = new ArrayList<>(); - - int size = (mNodesBg[MEMORY_SIZE - 1] == null) ? mFrameIndexBg + 1 : MEMORY_SIZE; - for (int i = size - 1; i >= 0; i--) { - int index = (MEMORY_SIZE + mFrameIndexBg - i) % MEMORY_SIZE; - ViewNode.Builder nodeBuilder = ViewNode.newBuilder(); - mNodesBg[index].toProto(idProvider, classList, nodeBuilder); - dataBuilder.addFrameData(FrameData.newBuilder() - .setNode(nodeBuilder) - .setTimestamp(mFrameTimesBg[index])); - } - return dataBuilder - .addAllClassname(classList.stream().map(Class::getName).collect(toList())) - .build(); - } - - private ViewRef captureViewTree(View view, ViewRef start) { - ViewRef ref; - if (mPool != null) { - ref = mPool; - mPool = mPool.next; - ref.next = null; - } else { - ref = new ViewRef(); - } - ref.view = view; - start.next = ref; - if (view instanceof ViewGroup) { - ViewGroup parent = (ViewGroup) view; - // If a view has not changed since the last frame, we will copy - // its children from the last processed frame's data. - if ((view.mPrivateFlags & (PFLAG_INVALIDATED | PFLAG_DIRTY_MASK)) == 0 - && !mIsFirstFrame) { - // A negative child count is the signal to copy this view from the last frame. - ref.childCount = -parent.getChildCount(); - return ref; - } - ViewRef result = ref; - int childCount = ref.childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - result = captureViewTree(parent.getChildAt(i), result); - } - return result; - } else { - ref.childCount = 0; - return ref; - } - } - } - - private static class ViewPropertyRef { - // We store reference in memory to avoid generating and storing too many strings - public Class clazz; - public int hashCode; - public int childCount = 0; - - public int id; - public int left, top, right, bottom; - public int scrollX, scrollY; - - public float translateX, translateY; - public float scaleX, scaleY; - public float alpha; - public float elevation; - - public int visibility; - public boolean willNotDraw; - public boolean clipChildren; - - public ViewPropertyRef next; - - public void transferTo(ViewPropertyRef out) { - out.clazz = this.clazz; - out.hashCode = this.hashCode; - out.childCount = this.childCount; - out.id = this.id; - out.left = this.left; - out.top = this.top; - out.right = this.right; - out.bottom = this.bottom; - out.scrollX = this.scrollX; - out.scrollY = this.scrollY; - out.scaleX = this.scaleX; - out.scaleY = this.scaleY; - out.translateX = this.translateX; - out.translateY = this.translateY; - out.alpha = this.alpha; - out.visibility = this.visibility; - out.willNotDraw = this.willNotDraw; - out.clipChildren = this.clipChildren; - out.next = this.next; - out.elevation = this.elevation; - } - - /** - * Converts the data to the proto representation and returns the next property ref - * at the end of the iteration. - * @return - */ - public ViewPropertyRef toProto(ViewIdProvider idProvider, ArrayList<Class> classList, - ViewNode.Builder outBuilder) { - int classnameIndex = classList.indexOf(clazz); - if (classnameIndex < 0) { - classnameIndex = classList.size(); - classList.add(clazz); - } - outBuilder - .setClassnameIndex(classnameIndex) - .setHashcode(hashCode) - .setId(idProvider.getName(id)) - .setLeft(left) - .setTop(top) - .setWidth(right - left) - .setHeight(bottom - top) - .setTranslationX(translateX) - .setTranslationY(translateY) - .setScaleX(scaleX) - .setScaleY(scaleY) - .setAlpha(alpha) - .setVisibility(visibility) - .setWillNotDraw(willNotDraw) - .setElevation(elevation) - .setClipChildren(clipChildren); - - ViewPropertyRef result = next; - for (int i = 0; (i < childCount) && (result != null); i++) { - ViewNode.Builder childBuilder = ViewNode.newBuilder(); - result = result.toProto(idProvider, classList, childBuilder); - outBuilder.addChildren(childBuilder); - } - return result; - } - } - - private static class ViewRef { - public View view; - public int childCount = 0; - public ViewRef next; - - public void transferTo(ViewPropertyRef out) { - out.childCount = this.childCount; - - View view = this.view; - this.view = null; - - out.clazz = view.getClass(); - out.hashCode = view.hashCode(); - out.id = view.getId(); - out.left = view.getLeft(); - out.top = view.getTop(); - out.right = view.getRight(); - out.bottom = view.getBottom(); - out.scrollX = view.getScrollX(); - out.scrollY = view.getScrollY(); - - out.translateX = view.getTranslationX(); - out.translateY = view.getTranslationY(); - out.scaleX = view.getScaleX(); - out.scaleY = view.getScaleY(); - out.alpha = view.getAlpha(); - out.elevation = view.getElevation(); - - out.visibility = view.getVisibility(); - out.willNotDraw = view.willNotDraw(); - } - } - - private static final class ViewIdProvider { - - private final SparseArray<String> mNames = new SparseArray<>(); - private final Resources mRes; - - ViewIdProvider(Resources res) { - mRes = res; - } - - String getName(int id) { - String name = mNames.get(id); - if (name == null) { - if (id >= 0) { - try { - name = mRes.getResourceTypeName(id) + '/' + mRes.getResourceEntryName(id); - } catch (Resources.NotFoundException e) { - name = "id/" + "0x" + Integer.toHexString(id).toUpperCase(); - } - } else { - name = "NO_ID"; - } - mNames.put(id, name); - } - return name; - } - } -} diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java index 50be5ea565..d098ffc2fb 100644 --- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java +++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java @@ -99,6 +99,10 @@ public class ClearAllButton extends Button { return false; } + public float getScrollAlpha() { + return mScrollAlpha; + } + public void setContentAlpha(float alpha) { if (mContentAlpha != alpha) { mContentAlpha = alpha; diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java new file mode 100644 index 0000000000..c878278da5 --- /dev/null +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java @@ -0,0 +1,475 @@ +/* + * Copyright (C) 2022 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.quickstep.views; + +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; + +import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; + +import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.RoundRectShape; +import android.os.SystemProperties; +import android.util.AttributeSet; +import android.util.Log; +import android.util.SparseArray; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Utilities; +import com.android.launcher3.touch.PagedOrientationHandler; +import com.android.launcher3.util.RunnableList; +import com.android.quickstep.RecentsModel; +import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.TaskThumbnailCache; +import com.android.quickstep.util.CancellableTask; +import com.android.quickstep.util.RecentsOrientedState; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.model.ThumbnailData; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.function.Consumer; + +/** + * TaskView that contains all tasks that are part of the desktop. + */ +// TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks. +public class DesktopTaskView extends TaskView { + + /** Flag to indicate whether desktop windowing proto 2 is enabled */ + public static final boolean DESKTOP_IS_PROTO2_ENABLED = SystemProperties.getBoolean( + "persist.wm.debug.desktop_mode_2", false); + + /** Flags to indicate whether desktop mode is available on the device */ + public static final boolean DESKTOP_MODE_SUPPORTED = + SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false) + || DESKTOP_IS_PROTO2_ENABLED; + + private static final String TAG = DesktopTaskView.class.getSimpleName(); + + private static final boolean DEBUG = true; + + private List<Task> mTasks; + + private final ArrayList<TaskThumbnailView> mSnapshotViews = new ArrayList<>(); + + /** Maps {@code taskIds} to corresponding {@link TaskThumbnailView}s */ + private final SparseArray<TaskThumbnailView> mSnapshotViewMap = new SparseArray<>(); + + private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>(); + + public DesktopTaskView(Context context) { + this(context, null); + } + + public DesktopTaskView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DesktopTaskView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + float[] outerRadii = new float[8]; + Arrays.fill(outerRadii, getTaskCornerRadius()); + RoundRectShape shape = new RoundRectShape(outerRadii, null, null); + ShapeDrawable background = new ShapeDrawable(shape); + background.setTint(getResources().getColor(android.R.color.system_neutral2_300)); + // TODO(b/244348395): this should be wallpaper + setBackground(background); + + mSnapshotViews.add(mSnapshotView); + } + + @Override + public void bind(Task task, RecentsOrientedState orientedState) { + bind(Collections.singletonList(task), orientedState); + } + + /** + * Updates this desktop task to the gives task list defined in {@code tasks} + */ + public void bind(List<Task> tasks, RecentsOrientedState orientedState) { + if (DEBUG) { + StringBuilder sb = new StringBuilder(); + sb.append("bind tasks=").append(tasks.size()).append("\n"); + for (Task task : tasks) { + sb.append(" key=").append(task.key).append("\n"); + } + Log.d(TAG, sb.toString()); + } + if (tasks.isEmpty()) { + return; + } + cancelPendingLoadTasks(); + + mTasks = tasks; + mSnapshotViewMap.clear(); + + // Ensure there are equal number of snapshot views and tasks. + // More tasks than views, add views. More views than tasks, remove views. + // TODO(b/251586230): use a ViewPool for creating TaskThumbnailViews + if (mSnapshotViews.size() > mTasks.size()) { + int diff = mSnapshotViews.size() - mTasks.size(); + for (int i = 0; i < diff; i++) { + TaskThumbnailView snapshotView = mSnapshotViews.remove(0); + removeView(snapshotView); + } + } else if (mSnapshotViews.size() < mTasks.size()) { + int diff = mTasks.size() - mSnapshotViews.size(); + for (int i = 0; i < diff; i++) { + TaskThumbnailView snapshotView = new TaskThumbnailView(getContext()); + mSnapshotViews.add(snapshotView); + addView(snapshotView, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); + } + } + + for (int i = 0; i < mTasks.size(); i++) { + Task task = mTasks.get(i); + TaskThumbnailView snapshotView = mSnapshotViews.get(i); + snapshotView.bind(task); + mSnapshotViewMap.put(task.key.id, snapshotView); + } + + updateTaskIdContainer(); + updateTaskIdAttributeContainer(); + + setOrientationState(orientedState); + } + + private void updateTaskIdContainer() { + // TODO(b/249371338): TaskView expects the array to have at least 2 elements. + // At least 2 elements in the array + mTaskIdContainer = new int[Math.max(mTasks.size(), 2)]; + for (int i = 0; i < mTasks.size(); i++) { + mTaskIdContainer[i] = mTasks.get(i).key.id; + } + } + + private void updateTaskIdAttributeContainer() { + // TODO(b/249371338): TaskView expects the array to have at least 2 elements. + // At least 2 elements in the array + mTaskIdAttributeContainer = new TaskIdAttributeContainer[Math.max(mTasks.size(), 2)]; + for (int i = 0; i < mTasks.size(); i++) { + Task task = mTasks.get(i); + TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id); + mTaskIdAttributeContainer[i] = createAttributeContainer(task, thumbnailView); + } + } + + private TaskIdAttributeContainer createAttributeContainer(Task task, + TaskThumbnailView thumbnailView) { + return new TaskIdAttributeContainer(task, thumbnailView, null, STAGE_POSITION_UNDEFINED); + } + + @Nullable + @Override + public Task getTask() { + // TODO(b/249371338): returning first task. This won't work well with multiple tasks. + return mTasks.size() > 0 ? mTasks.get(0) : null; + } + + @Override + public TaskThumbnailView getThumbnail() { + // TODO(b/249371338): returning single thumbnail. This won't work well with multiple tasks. + Task task = getTask(); + if (task != null) { + return mSnapshotViewMap.get(task.key.id); + } + return null; + } + + @Override + public boolean containsTaskId(int taskId) { + // Thumbnail map contains taskId -> thumbnail map. Use the keys for contains + return mSnapshotViewMap.contains(taskId); + } + + @Override + public void onTaskListVisibilityChanged(boolean visible, int changes) { + cancelPendingLoadTasks(); + if (visible) { + RecentsModel model = RecentsModel.INSTANCE.get(getContext()); + TaskThumbnailCache thumbnailCache = model.getThumbnailCache(); + + if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) { + for (Task task : mTasks) { + CancellableTask<?> thumbLoadRequest = + thumbnailCache.updateThumbnailInBackground(task, thumbnailData -> { + TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id); + if (thumbnailView != null) { + thumbnailView.setThumbnail(task, thumbnailData); + } + }); + if (thumbLoadRequest != null) { + mPendingThumbnailRequests.add(thumbLoadRequest); + } + } + } + } else { + if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) { + for (Task task : mTasks) { + TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id); + if (thumbnailView != null) { + thumbnailView.setThumbnail(null, null); + } + // Reset the task thumbnail ref + task.thumbnail = null; + } + } + } + } + + @Override + public void setOrientationState(RecentsOrientedState orientationState) { + // TODO(b/249371338): this copies logic from TaskView + PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler(); + boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; + DeviceProfile deviceProfile = mActivity.getDeviceProfile(); + + LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams(); + + int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx; + int taskIconHeight = deviceProfile.overviewTaskIconSizePx; + int taskMargin = deviceProfile.overviewTaskMarginPx; + + orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight, + thumbnailTopMargin, isRtl); + + LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams(); + snapshotParams.topMargin = thumbnailTopMargin; + + for (int i = 0; i < mSnapshotViewMap.size(); i++) { + TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i); + thumbnailView.setLayoutParams(snapshotParams); + } + } + + @Override + protected void cancelPendingLoadTasks() { + for (CancellableTask<?> cancellableTask : mPendingThumbnailRequests) { + cancellableTask.cancel(); + } + mPendingThumbnailRequests.clear(); + } + + @Override + public boolean offerTouchToChildren(MotionEvent event) { + return false; + } + + @Override + protected boolean showTaskMenuWithContainer(IconView iconView) { + return false; + } + + @Override + public RunnableList launchTasks() { + SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps(); + getRecentsView().startHome(); + return null; + } + + @Nullable + @Override + public RunnableList launchTaskAnimated() { + return launchTasks(); + } + + @Override + public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) { + launchTasks(); + callback.accept(true); + } + + @Override + void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) { + // Sets new thumbnails based on the incoming data and refreshes the rest. + // Create a copy of the thumbnail map, so we can track thumbnails that need refreshing. + SparseArray<TaskThumbnailView> thumbnailsToRefresh = mSnapshotViewMap.clone(); + if (thumbnailDatas != null) { + for (Task task : mTasks) { + int key = task.key.id; + TaskThumbnailView thumbnailView = thumbnailsToRefresh.get(key); + ThumbnailData thumbnailData = thumbnailDatas.get(key); + if (thumbnailView != null && thumbnailData != null) { + thumbnailView.setThumbnail(task, thumbnailData); + // Remove this thumbnail from the list that should be refreshed. + thumbnailsToRefresh.remove(key); + } + } + } + + // Refresh the rest that were not updated. + for (int i = 0; i < thumbnailsToRefresh.size(); i++) { + thumbnailsToRefresh.valueAt(i).refresh(); + } + } + + @Override + public TaskThumbnailView[] getThumbnails() { + TaskThumbnailView[] thumbnails = new TaskThumbnailView[mSnapshotViewMap.size()]; + for (int i = 0; i < thumbnails.length; i++) { + thumbnails[i] = mSnapshotViewMap.valueAt(i); + } + return thumbnails; + } + + @Override + public void onRecycle() { + resetPersistentViewTransforms(); + // Clear any references to the thumbnail (it will be re-read either from the cache or the + // system on next bind) + for (Task task : mTasks) { + TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id); + if (thumbnailView != null) { + thumbnailView.setThumbnail(task, null); + } + } + setOverlayEnabled(false); + onTaskListVisibilityChanged(false); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int containerWidth = MeasureSpec.getSize(widthMeasureSpec); + int containerHeight = MeasureSpec.getSize(heightMeasureSpec); + + setMeasuredDimension(containerWidth, containerHeight); + + int thumbnails = mSnapshotViewMap.size(); + if (thumbnails == 0) { + return; + } + + int windowWidth = mActivity.getDeviceProfile().widthPx; + int windowHeight = mActivity.getDeviceProfile().heightPx; + + float scaleWidth = containerWidth / (float) windowWidth; + float scaleHeight = containerHeight / (float) windowHeight; + + if (DEBUG) { + Log.d(TAG, + "onMeasure: container=[" + containerWidth + "," + containerHeight + "] window=[" + + windowWidth + "," + windowHeight + "] scale=[" + scaleWidth + "," + + scaleHeight + "]"); + } + + // Desktop tile is a shrunk down version of launcher and freeform task thumbnails. + for (int i = 0; i < mTasks.size(); i++) { + Task task = mTasks.get(i); + Rect taskSize = task.appBounds; + if (taskSize == null) { + // Default to quarter of the desktop if we did not get app bounds. + taskSize = new Rect(0, 0, windowWidth / 4, windowHeight / 4); + } + + int thumbWidth = (int) (taskSize.width() * scaleWidth); + int thumbHeight = (int) (taskSize.height() * scaleHeight); + + TaskThumbnailView thumbnailView = mSnapshotViewMap.get(task.key.id); + if (thumbnailView != null) { + thumbnailView.measure(MeasureSpec.makeMeasureSpec(thumbWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(thumbHeight, MeasureSpec.EXACTLY)); + + // Position the task to the same position as it would be on the desktop + Point positionInParent = task.positionInParent; + if (positionInParent == null) { + positionInParent = new Point(0, 0); + } + int taskX = (int) (positionInParent.x * scaleWidth); + int taskY = (int) (positionInParent.y * scaleHeight); + thumbnailView.setX(taskX); + thumbnailView.setY(taskY); + + if (DEBUG) { + Log.d(TAG, "onMeasure: task=" + task.key + " thumb=[" + thumbWidth + "," + + thumbHeight + "]" + " pos=[" + taskX + "," + taskY + "]"); + } + } + } + } + + @Override + public void setOverlayEnabled(boolean overlayEnabled) { + // Intentional no-op to prevent setting smart actions overlay on thumbnails + } + + @Override + public void setFullscreenProgress(float progress) { + // TODO(b/249371338): this copies parent implementation and makes it work for N thumbs + progress = Utilities.boundToRange(progress, 0, 1); + mFullscreenProgress = progress; + for (int i = 0; i < mSnapshotViewMap.size(); i++) { + TaskThumbnailView thumbnailView = mSnapshotViewMap.valueAt(i); + thumbnailView.getTaskOverlay().setFullscreenProgress(progress); + updateSnapshotRadius(); + } + } + + @Override + protected void updateSnapshotRadius() { + for (int i = 0; i < mSnapshotViewMap.size(); i++) { + mSnapshotViewMap.valueAt(i).setFullscreenParams(mCurrentFullscreenParams); + } + } + + @Override + protected void setIconsAndBannersTransitionProgress(float progress, boolean invert) { + // no-op + } + + @Override + public void setColorTint(float amount, int tintColor) { + for (int i = 0; i < mSnapshotViewMap.size(); i++) { + mSnapshotViewMap.valueAt(i).setDimAlpha(amount); + } + } + + @Override + protected void applyThumbnailSplashAlpha() { + for (int i = 0; i < mSnapshotViewMap.size(); i++) { + mSnapshotViewMap.valueAt(i).setSplashAlpha(mTaskThumbnailSplashAlpha); + } + } + + @Override + void setThumbnailVisibility(int visibility) { + for (int i = 0; i < mSnapshotViewMap.size(); i++) { + mSnapshotViewMap.valueAt(i).setVisibility(visibility); + } + } + + @Override + protected boolean confirmSecondSplitSelectApp() { + // Desktop tile can't be in split screen + return false; + } +} diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java index dc1ae520a3..75a8ea2b3b 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java @@ -11,6 +11,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.FloatProperty; @@ -27,6 +28,7 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StatefulActivity; +import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.views.BaseDragLayer; @@ -74,6 +76,7 @@ public class FloatingTaskView extends FrameLayout { } }; + private int mSplitHolderSize; private FloatingTaskThumbnailView mThumbnailView; private SplitPlaceholderView mSplitPlaceholderView; private RectF mStartingPosition; @@ -83,6 +86,7 @@ public class FloatingTaskView extends FrameLayout { private PagedOrientationHandler mOrientationHandler; @SplitConfigurationOptions.StagePosition private int mStagePosition; + private final Rect mTmpRect = new Rect(); public FloatingTaskView(Context context) { this(context, null); @@ -97,6 +101,9 @@ public class FloatingTaskView extends FrameLayout { mActivity = BaseActivity.fromContext(context); mIsRtl = Utilities.isRtl(getResources()); mFullscreenParams = new FullscreenDrawParams(context); + + mSplitHolderSize = context.getResources().getDimensionPixelSize( + R.dimen.split_placeholder_icon_size); } @Override @@ -126,8 +133,7 @@ public class FloatingTaskView extends FrameLayout { RecentsView recentsView = launcher.getOverviewPanel(); mOrientationHandler = recentsView.getPagedOrientationHandler(); mStagePosition = recentsView.getSplitSelectController().getActiveSplitStagePosition(); - mSplitPlaceholderView.setIcon(icon, - mContext.getResources().getDimensionPixelSize(R.dimen.split_placeholder_icon_size)); + mSplitPlaceholderView.setIcon(icon, mSplitHolderSize); mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated()); } @@ -154,10 +160,24 @@ public class FloatingTaskView extends FrameLayout { } public void updateInitialPositionForView(View originalView) { - Rect viewBounds = new Rect(0, 0, originalView.getWidth(), originalView.getHeight()); - Utilities.getBoundsForViewInDragLayer(mActivity.getDragLayer(), originalView, viewBounds, - false /* ignoreTransform */, null /* recycle */, - mStartingPosition); + if (originalView.getContext() instanceof TaskbarActivityContext) { + // If original View is a button on the Taskbar, find the on-screen bounds and calculate + // the equivalent bounds in the DragLayer, so we can set the initial position of + // this FloatingTaskView and start the split animation at the correct spot. + originalView.getBoundsOnScreen(mTmpRect); + mStartingPosition.set(mTmpRect); + int[] dragLayerPositionRelativeToScreen = + mActivity.getDragLayer().getLocationOnScreen(); + mStartingPosition.offset( + -dragLayerPositionRelativeToScreen[0], + -dragLayerPositionRelativeToScreen[1]); + } else { + Rect viewBounds = new Rect(0, 0, originalView.getWidth(), originalView.getHeight()); + Utilities.getBoundsForViewInDragLayer(mActivity.getDragLayer(), originalView, + viewBounds, false /* ignoreTransform */, null /* recycle */, + mStartingPosition); + } + final BaseDragLayer.LayoutParams lp = new BaseDragLayer.LayoutParams( Math.round(mStartingPosition.width()), Math.round(mStartingPosition.height())); @@ -193,6 +213,10 @@ public class FloatingTaskView extends FrameLayout { mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated()); } + public void setIcon(Bitmap icon) { + mSplitPlaceholderView.setIcon(new BitmapDrawable(icon), mSplitHolderSize); + } + protected void initPosition(RectF pos, InsettableFrameLayout.LayoutParams lp) { mStartingPosition.set(pos); lp.ignoreInsets = true; diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java index 8a5f42afaf..6431bdf5aa 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java @@ -25,6 +25,7 @@ import android.os.Build; import android.util.AttributeSet; import android.util.Size; import android.view.GhostView; +import android.view.RemoteAnimationTarget; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; @@ -41,7 +42,6 @@ import com.android.launcher3.views.FloatingView; import com.android.launcher3.views.ListenerView; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.RoundedCornerEnforcement; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; /** A view that mimics an App Widget through a launch animation. */ @TargetApi(Build.VERSION_CODES.S) @@ -304,7 +304,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, * context's theme background color. */ public static int getDefaultBackgroundColor( - Context context, RemoteAnimationTargetCompat target) { + Context context, RemoteAnimationTarget target) { return (target != null && target.taskInfo.taskDescription != null) ? target.taskInfo.taskDescription.getBackgroundColor() : Themes.getColorBackground(context); diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java index 3a5f606467..3f7d677970 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java @@ -1,9 +1,7 @@ package com.android.quickstep.views; -import static com.android.launcher3.AbstractFloatingView.getAnyView; import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; -import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT; import android.content.Context; import android.graphics.PointF; @@ -14,11 +12,11 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.RunnableList; +import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; import com.android.launcher3.util.TransformingTouchDelegate; import com.android.quickstep.RecentsModel; @@ -26,8 +24,10 @@ import com.android.quickstep.TaskIconCache; import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.util.CancellableTask; import com.android.quickstep.util.RecentsOrientedState; +import com.android.quickstep.util.TaskViewSimulator; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.utilities.PreviewPositionHelper; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import java.util.HashMap; @@ -86,9 +86,35 @@ public class GroupedTaskView extends TaskView { mTaskIdContainer[1] = secondary.key.id; mTaskIdAttributeContainer[1] = new TaskIdAttributeContainer(secondary, mSnapshotView2, mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT); - mTaskIdAttributeContainer[0].setStagePosition(STAGE_POSITION_TOP_OR_LEFT); + mTaskIdAttributeContainer[0].setStagePosition( + SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT); mSnapshotView2.bind(secondary); mSplitBoundsConfig = splitBoundsConfig; + if (mSplitBoundsConfig == null) { + return; + } + mSnapshotView.getPreviewPositionHelper().setSplitBounds(TaskViewSimulator + .convertSplitBounds(splitBoundsConfig), + PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT); + mSnapshotView2.getPreviewPositionHelper().setSplitBounds(TaskViewSimulator + .convertSplitBounds(splitBoundsConfig), + PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT); + } + + /** + * Sets up an on-click listener and the visibility for show_windows icon on top of each task. + */ + @Override + public void setUpShowAllInstancesListener() { + // sets up the listener for the left/top task + super.setUpShowAllInstancesListener(); + + // right/bottom task's base package name + String taskPackageName = mTaskIdAttributeContainer[1].getTask().key.getPackageName(); + + // icon of the right/bottom task + View showWindowsView = findViewById(R.id.show_windows_right); + updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName)); } @Override @@ -164,21 +190,6 @@ public class GroupedTaskView extends TaskView { } } - @Override - protected boolean showTaskMenuWithContainer(IconView iconView) { - boolean showedTaskMenu = super.showTaskMenuWithContainer(iconView); - if (iconView == mIconView2 && showedTaskMenu && !mActivity.getDeviceProfile().isTablet) { - // Adjust the position of the secondary task's menu view (only on phones) - TaskMenuView taskMenuView = getAnyView(mActivity, AbstractFloatingView.TYPE_TASK_MENU); - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); - getRecentsView().getPagedOrientationHandler() - .setSecondaryTaskMenuPosition(mSplitBoundsConfig, this, - deviceProfile, mTaskIdAttributeContainer[0].getThumbnailView(), - taskMenuView); - } - return showedTaskMenu; - } - @Nullable @Override public RunnableList launchTaskAnimated() { @@ -207,7 +218,8 @@ public class GroupedTaskView extends TaskView { @Override public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) { getRecentsView().getSplitSelectController().launchTasks(mTask.key.id, mSecondaryTask.key.id, - STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList, getSplitRatio()); + SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList, + getSplitRatio()); } @Override @@ -225,6 +237,12 @@ public class GroupedTaskView extends TaskView { } @Override + public boolean containsTaskId(int taskId) { + return (mTask != null && mTask.key.id == taskId) + || (mSecondaryTask != null && mSecondaryTask.key.id == taskId); + } + + @Override public TaskThumbnailView[] getThumbnails() { return new TaskThumbnailView[]{mSnapshotView, mSnapshotView2}; } @@ -313,8 +331,8 @@ public class GroupedTaskView extends TaskView { } @Override - protected void setIconAndDimTransitionProgress(float progress, boolean invert) { - super.setIconAndDimTransitionProgress(progress, invert); + protected void setIconsAndBannersTransitionProgress(float progress, boolean invert) { + super.setIconsAndBannersTransitionProgress(progress, invert); // Value set by super call float scale = mIconView.getAlpha(); mIconView2.setAlpha(scale); diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index bb8506d26f..6c27587058 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -147,6 +147,9 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher & CLEAR_ALL_BUTTON) != 0; setDisallowScrollToClearAll(!hasClearAllButton); } + if (mActivity.getDesktopVisibilityController() != null) { + mActivity.getDesktopVisibilityController().setOverviewStateEnabled(enabled); + } } @Override @@ -162,13 +165,12 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher } @Override - public void setModalStateEnabled(boolean isModalState) { - super.setModalStateEnabled(isModalState); + public void setModalStateEnabled(boolean isModalState, boolean animate) { if (isModalState) { - mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK); + mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK, animate); } else { if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) { - mActivity.getStateManager().goToState(LauncherState.OVERVIEW); + mActivity.getStateManager().goToState(LauncherState.OVERVIEW, animate); resetModalVisuals(); } } diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index 08a17c49f0..eeabdc83d1 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -31,9 +31,10 @@ import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.R; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.DisplayController; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.launcher3.util.MultiValueAlpha; -import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.NavigationMode; import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks; import com.android.quickstep.util.LayoutUtils; @@ -81,11 +82,14 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo private static final int INDEX_FULLSCREEN_ALPHA = 2; private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3; private static final int INDEX_SHARE_TARGET_ALPHA = 4; + private static final int INDEX_SCROLL_ALPHA = 5; + private static final int NUM_ALPHAS = 6; - public @interface SplitButtonDisabledFlags { } - + public @interface SplitButtonHiddenFlags { } public static final int FLAG_IS_NOT_TABLET = 1 << 0; - public static final int FLAG_SINGLE_TASK = 1 << 1; + + public @interface SplitButtonDisabledFlags { } + public static final int FLAG_SINGLE_TASK = 1 << 0; private MultiValueAlpha mMultiValueAlpha; private Button mSplitButton; @@ -96,6 +100,9 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo @ActionsDisabledFlags protected int mDisabledFlags; + @SplitButtonHiddenFlags + private int mSplitButtonHiddenFlags; + @SplitButtonDisabledFlags private int mSplitButtonDisabledFlags; @@ -121,11 +128,10 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo @Override protected void onFinishInflate() { super.onFinishInflate(); - mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), 5); + mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS); mMultiValueAlpha.setUpdateVisibility(true); findViewById(R.id.action_screenshot).setOnClickListener(this); - mSplitButton = findViewById(R.id.action_split); mSplitButton.setOnClickListener(this); } @@ -172,7 +178,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo mHiddenFlags &= ~visibilityFlags; } boolean isHidden = mHiddenFlags != 0; - mMultiValueAlpha.getProperty(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1); + mMultiValueAlpha.get(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1); } /** @@ -191,36 +197,60 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo } boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0; LayoutUtils.setViewEnabled(this, isEnabled); + updateSplitButtonEnabledState(); } /** - * Updates the proper flags to indicate whether the "Split screen" button should be enabled. + * Updates the proper flags to indicate whether the "Split screen" button should be hidden. * - * @param flag The flag to update. - * @param enable Whether to enable the disable flag: True will cause view to be disabled. + * @param flag The flag to update. + * @param enable Whether to enable the hidden flag: True will cause view to be hidden. + */ + public void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag, boolean enable) { + if (enable) { + mSplitButtonHiddenFlags |= flag; + } else { + mSplitButtonHiddenFlags &= ~flag; + } + if (mSplitButton == null) return; + boolean shouldBeVisible = mSplitButtonHiddenFlags == 0; + mSplitButton.setVisibility(shouldBeVisible ? VISIBLE : GONE); + findViewById(R.id.action_split_space).setVisibility(shouldBeVisible ? VISIBLE : GONE); + } + + /** + * Updates the proper flags to indicate whether the "Split screen" button should be disabled. + * + * @param flag The flag to update. + * @param enable Whether to enable the disable flag: True will cause view to be disabled. */ - public void updateSplitButtonFlags(@SplitButtonDisabledFlags int flag, boolean enable) { + public void updateSplitButtonDisabledFlags(@SplitButtonDisabledFlags int flag, boolean enable) { if (enable) { mSplitButtonDisabledFlags |= flag; } else { mSplitButtonDisabledFlags &= ~flag; } + updateSplitButtonEnabledState(); } - public AlphaProperty getContentAlpha() { - return mMultiValueAlpha.getProperty(INDEX_CONTENT_ALPHA); + public MultiProperty getContentAlpha() { + return mMultiValueAlpha.get(INDEX_CONTENT_ALPHA); } - public AlphaProperty getVisibilityAlpha() { - return mMultiValueAlpha.getProperty(INDEX_VISIBILITY_ALPHA); + public MultiProperty getVisibilityAlpha() { + return mMultiValueAlpha.get(INDEX_VISIBILITY_ALPHA); } - public AlphaProperty getFullscreenAlpha() { - return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA); + public MultiProperty getFullscreenAlpha() { + return mMultiValueAlpha.get(INDEX_FULLSCREEN_ALPHA); } - public AlphaProperty getShareTargetAlpha() { - return mMultiValueAlpha.getProperty(INDEX_SHARE_TARGET_ALPHA); + public MultiProperty getShareTargetAlpha() { + return mMultiValueAlpha.get(INDEX_SHARE_TARGET_ALPHA); + } + + public MultiProperty getIndexScrollAlpha() { + return mMultiValueAlpha.get(INDEX_SCROLL_ALPHA); } /** @@ -234,7 +264,9 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo // If in 3-button mode, shift action buttons to accommodate 3-button layout. // (Special exception for landscape tablets, where there is enough room and we don't need to // shift the action buttons.) - if (mDp.areNavButtonsInline && !largeScreenLandscape) { + if (mDp.areNavButtonsInline && !largeScreenLandscape + // If taskbar is in overview, overview action has dedicated space above nav buttons + && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) { // Add extra horizontal spacing int additionalPadding = mDp.hotseatBarEndOffset; if (isLayoutRtl()) { @@ -264,7 +296,8 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo return 0; } - if (!mDp.isGestureMode && mDp.isTaskbarPresent) { + if (!mDp.isGestureMode && mDp.isTaskbarPresent + && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) { return mDp.getOverviewActionsClaimedSpaceBelow(); } @@ -289,16 +322,16 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo } /** - * Shows/hides the "Split" button based on the status of mHiddenFlags. + * Enables/disables the "Split" button based on the status of mSplitButtonDisabledFlags and + * mDisabledFlags. */ - public void updateSplitButtonVisibility() { + private void updateSplitButtonEnabledState() { if (mSplitButton == null) { return; } - boolean shouldBeVisible = mSplitButtonDisabledFlags == 0 - // and neither of these flags are active - && (mHiddenFlags & (HIDDEN_SPLIT_SCREEN | HIDDEN_SPLIT_SELECT_ACTIVE)) == 0; - mSplitButton.setVisibility(shouldBeVisible ? VISIBLE : GONE); - findViewById(R.id.action_split_space).setVisibility(shouldBeVisible ? VISIBLE : GONE); + boolean isParentEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0; + boolean shouldBeEnabled = mSplitButtonDisabledFlags == 0 && isParentEnabled; + mSplitButton.setEnabled(shouldBeEnabled); } + } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 7ad0e48ccb..5e645ea917 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -41,20 +41,22 @@ import static com.android.launcher3.anim.Interpolators.FINAL_FRAME; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_0_75; import static com.android.launcher3.anim.Interpolators.clampToProgress; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCH_FROM_STAGED_APP; +import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_ACTIONS_SPLIT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN; -import static com.android.launcher3.statehandlers.DepthController.STATE_DEPTH; import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; +import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT; import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK; import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId; import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA; +import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED; import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET; import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK; import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION; @@ -73,9 +75,13 @@ import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.annotation.TargetApi; +import android.app.WindowConfiguration; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.LocusId; import android.content.res.Configuration; +import android.graphics.Bitmap; import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.Color; @@ -103,6 +109,7 @@ import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; +import android.view.RemoteAnimationTarget; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; @@ -128,6 +135,7 @@ import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.PagedView; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; @@ -145,19 +153,19 @@ import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.DynamicResource; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; -import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.ResourceBasedOverride.Overrides; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; import com.android.launcher3.util.Themes; import com.android.launcher3.util.TranslateEdgeEffect; +import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.util.ViewPool; -import com.android.quickstep.AnimatedFloat; import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.GestureState; import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationTargets; +import com.android.quickstep.RecentsFilterState; import com.android.quickstep.RecentsModel; import com.android.quickstep.RemoteAnimationTargets; import com.android.quickstep.RemoteTargetGluer; @@ -172,30 +180,30 @@ import com.android.quickstep.ViewUtils; import com.android.quickstep.util.ActiveGestureErrorDetector; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.AnimUtils; +import com.android.quickstep.util.DesktopTask; import com.android.quickstep.util.GroupTask; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.SplitAnimationTimings; -import com.android.quickstep.util.SplitScreenBounds; import com.android.quickstep.util.SplitSelectStateController; +import com.android.quickstep.util.SurfaceTransaction; import com.android.quickstep.util.SurfaceTransactionApplier; import com.android.quickstep.util.TaskViewSimulator; import com.android.quickstep.util.TaskVisualsChangeListener; import com.android.quickstep.util.TransformParams; -import com.android.quickstep.util.VibratorWrapper; +import com.android.quickstep.util.VibrationConstants; import com.android.systemui.plugins.ResourceProvider; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.PackageManagerWrapper; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.wm.shell.pip.IPipAnimationListener; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -208,7 +216,7 @@ import java.util.function.Consumer; public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>, STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable, TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback, - TaskVisualsChangeListener, SplitScreenBounds.OnChangeListener { + TaskVisualsChangeListener { private static final String TAG = "RecentsView"; private static final boolean DEBUG = false; @@ -276,7 +284,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1; public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f; public static final VibrationEffect SCROLL_VIBRATION_FALLBACK = - VibratorWrapper.EFFECT_TEXTURE_TICK; + VibrationConstants.EFFECT_TEXTURE_TICK; /** * Can be used to tint the color of the RecentsView to simulate a scrim that can views @@ -478,10 +486,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T private final InvariantDeviceProfile mIdp; /** - * Getting views should be done via {@link #getTaskViewFromPool(boolean)} + * Getting views should be done via {@link #getTaskViewFromPool(int)} */ private final ViewPool<TaskView> mTaskViewPool; private final ViewPool<GroupedTaskView> mGroupedTaskViewPool; + private final ViewPool<DesktopTaskView> mDesktopTaskViewPool; private final TaskOverlayFactory mTaskOverlayFactory; @@ -492,6 +501,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T private boolean mOverviewFullscreenEnabled; private boolean mOverviewSelectEnabled; + private boolean mShouldClampScrollOffset; + private int mClampedScrollOffsetBound; + private float mAdjacentPageHorizontalOffset = 0; protected float mTaskViewsSecondaryTranslation = 0; protected float mTaskViewsPrimarySplitTranslation = 0; @@ -570,7 +582,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T if (taskRemoved) { dismissTask(taskId); } - }); + }, RecentsFilterState.getFilter(mFilterState.getPackageNameToFilter())); } })); } @@ -659,8 +671,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T private TaskView mSecondSplitHiddenView; @Nullable private SplitBounds mSplitBoundsConfig; - private final Toast mSplitToast = Toast.makeText(getContext(), - R.string.toast_split_select_app, Toast.LENGTH_SHORT); private final Toast mSplitUnsupportedToast = Toast.makeText(getContext(), R.string.toast_split_app_unsupported, Toast.LENGTH_SHORT); @@ -713,6 +723,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T @Nullable private TaskLaunchListener mTaskLaunchListener; + // keeps track of the state of the filter for tasks in recents view + private final RecentsFilterState mFilterState = new RecentsFilterState(); + public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, BaseActivityInterface sizeStrategy) { super(context, attrs, defStyleAttr); @@ -738,6 +751,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T 10 /* initial size */); mGroupedTaskViewPool = new ViewPool<>(context, this, R.layout.task_grouped, 20 /* max size */, 10 /* initial size */); + mDesktopTaskViewPool = new ViewPool<>(context, this, R.layout.task_desktop, + 5 /* max size */, 1 /* initial size */); mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources()); setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); @@ -746,6 +761,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T mSplitPlaceholderInset = getResources().getDimensionPixelSize( R.dimen.split_placeholder_inset); mSquaredTouchSlop = squaredTouchSlop(context); + mClampedScrollOffsetBound = getResources().getDimensionPixelSize( + R.dimen.transient_taskbar_clamped_offset_bound); mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents); mEmptyIcon.setCallback(this); @@ -772,6 +789,55 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5); mTintingColor = getForegroundScrimDimColor(context); + + // if multi-instance feature is enabled + if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) { + // invalidate the current list of tasks if filter changes + mFilterState.setOnFilterUpdatedListener(this::invalidateTaskList); + } + // make sure filter is turned off by default + mFilterState.setFilterBy(null); + } + + /** Get the state of the filter */ + public RecentsFilterState getFilterState() { + return mFilterState; + } + + /** + * Toggles the filter and reloads the recents view if needed. + * + * @param packageName package name to filter by if the filter is being turned on; + * should be null if filter is being turned off + */ + public void setAndApplyFilter(@Nullable String packageName) { + mFilterState.setFilterBy(packageName); + updateClearAllFunction(); + reloadIfNeeded(); + } + + /** + * Updates the "Clear All" button and its function depending on the recents view state. + * + * TODO: add a different button for going back to overview. Present solution is for demo only. + */ + public void updateClearAllFunction() { + if (mFilterState.isFiltered()) { + mClearAllButton.setText(R.string.recents_back); + mClearAllButton.setOnClickListener((view) -> { + this.setAndApplyFilter(null); + }); + } else { + mClearAllButton.setText(R.string.recents_clear_all); + mClearAllButton.setOnClickListener(this::dismissAllTasks); + } + } + + /** + * Invalidates the list of tasks so that an update occurs to the list of tasks if requested. + */ + private void invalidateTaskList() { + mTaskListChangeId = -1; } public OverScroller getScroller() { @@ -817,8 +883,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } super.dispatchDraw(canvas); } - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile - && mRemoteTargetHandles != null) { + if (mEnableDrawingLiveTile && mRemoteTargetHandles != null) { redrawLiveTile(); } } @@ -941,10 +1006,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T .setSyncTransactionApplier(mSyncTransactionApplier)); RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this); mIPipAnimationListener.setActivityAndRecentsView(mActivity, this); - SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener( + SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener( mIPipAnimationListener); mOrientationState.initListeners(); - SplitScreenBounds.INSTANCE.addOnChangeListener(this); mTaskOverlayFactory.initListeners(); } @@ -960,8 +1024,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T .setSyncTransactionApplier(null)); executeSideTaskLaunchCallback(); RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this); - SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null); - SplitScreenBounds.INSTANCE.removeOnChangeListener(this); + SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener(null); mIPipAnimationListener.setActivityAndRecentsView(null, null); mOrientationState.destroyListeners(); mTaskOverlayFactory.removeListeners(); @@ -983,6 +1046,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } if (child instanceof GroupedTaskView) { mGroupedTaskViewPool.recycle((GroupedTaskView) taskView); + } else if (child instanceof DesktopTaskView) { + mDesktopTaskViewPool.recycle((DesktopTaskView) taskView); } else { mTaskViewPool.recycle(taskView); } @@ -1057,8 +1122,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } } - public void launchSideTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps, - RemoteAnimationTargetCompat[] wallpaper, RemoteAnimationTargetCompat[] nonApps) { + public void launchSideTaskInLiveTileMode(int taskId, RemoteAnimationTarget[] apps, + RemoteAnimationTarget[] wallpaper, RemoteAnimationTarget[] nonApps) { AnimatorSet anim = new AnimatorSet(); TaskView taskView = getTaskViewByTaskId(taskId); if (taskView == null || !isTaskViewVisible(taskView)) { @@ -1070,14 +1135,15 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T appAnimator.setInterpolator(ACCEL_DEACCEL); appAnimator.addUpdateListener(valueAnimator -> { float percent = valueAnimator.getAnimatedFraction(); - SurfaceParams.Builder builder = new SurfaceParams.Builder( - apps[apps.length - 1].leash); + SurfaceTransaction transaction = new SurfaceTransaction(); Matrix matrix = new Matrix(); matrix.postScale(percent, percent); matrix.postTranslate(mActivity.getDeviceProfile().widthPx * (1 - percent) / 2, mActivity.getDeviceProfile().heightPx * (1 - percent) / 2); - builder.withAlpha(percent).withMatrix(matrix); - surfaceApplier.scheduleApply(builder.build()); + transaction.forSurface(apps[apps.length - 1].leash) + .setAlpha(percent) + .setMatrix(matrix); + surfaceApplier.scheduleApply(transaction); }); anim.play(appAnimator); anim.addListener(new AnimatorListenerAdapter() { @@ -1201,14 +1267,60 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T for (int i = 0; i < getTaskViewCount(); i++) { TaskView taskView = requireTaskViewAt(i); - int[] taskIds = taskView.getTaskIds(); - if (taskIds[0] == taskId || taskIds[1] == taskId) { + if (taskView.containsTaskId(taskId)) { return taskView; } } return null; } + /** + * Pulls the list of active Tasks from RecentModel, and finds the most recently active Task + * matching a given ComponentName. Then uses that Task (which could be null) with the given + * callback. + * + * Used in various splitscreen operations when we need to check if there is a currently running + * Task of a certain type and use the most recent one. + */ + public void findLastActiveTaskAndDoSplitOperation(ComponentName componentName, + Consumer<Task> callback) { + mModel.getTasks(taskGroups -> { + Task lastActiveTask = null; + // Loop through tasks in reverse, since they are ordered with most-recent tasks last. + for (int i = taskGroups.size() - 1; i >= 0; i--) { + GroupTask groupTask = taskGroups.get(i); + Task task1 = groupTask.task1; + if (isInstanceOfComponent(task1, componentName)) { + lastActiveTask = task1; + break; + } + Task task2 = groupTask.task2; + if (isInstanceOfComponent(task2, componentName)) { + lastActiveTask = task2; + break; + } + } + + callback.accept(lastActiveTask); + }); + } + + /** + * Checks if a given Task is the most recently-active Task of type componentName. Used for + * selecting already-running Tasks for splitscreen. + */ + public boolean isInstanceOfComponent(@Nullable Task task, ComponentName componentName) { + if (task == null) { + return false; + } + // Exclude the task that is already staged + if (mSplitHiddenTaskView != null && mSplitHiddenTaskView.getTask().equals(task)) { + return false; + } + + return task.key.baseIntent.getComponent().equals(componentName); + } + public void setOverviewStateEnabled(boolean enabled) { mOverviewStateEnabled = enabled; updateTaskStackListenerState(); @@ -1239,6 +1351,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T if (!mActivity.getDeviceProfile().isTablet) { mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, true); } + InteractionJankMonitorWrapper.begin(/* view= */ this, + InteractionJankMonitorWrapper.CUJ_RECENTS_SCROLLING); } @Override @@ -1252,6 +1366,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T if (getNextPage() > 0) { setSwipeDownShouldLaunchApp(true); } + InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_RECENTS_SCROLLING); } @Override @@ -1442,6 +1557,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T ActiveGestureErrorDetector.GestureEvent.SCROLLER_ANIMATION_ABORTED); } + @Override + protected boolean isPageScrollsInitialized() { + return super.isPageScrollsInitialized() && mLoadPlanEverApplied; + } + protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) { if (mPendingAnimation != null) { mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups)); @@ -1455,6 +1575,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T // With all tasks removed, touch handling in PagedView is disabled and we need to reset // touch state or otherwise values will be obsolete. resetTouchState(); + if (isPageScrollsInitialized()) { + onPageScrollsInitialized(); + } return; } @@ -1480,36 +1603,68 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T int previousCurrentPage = mCurrentPage; removeAllViews(); - // Add views as children based on whether it's grouped or single task + // If we are entering Overview as a result of initiating a split from somewhere else + // (e.g. split from Home), we need to make sure the staged app is not drawn as a thumbnail. + Task stagedTaskToBeRemovedFromGrid = + mSplitSelectSource != null ? mSplitSelectSource.alreadyRunningTask : null; + + // update the map of instance counts + mFilterState.updateInstanceCountMap(taskGroups); + + // Add views as children based on whether it's grouped or single task. Looping through + // taskGroups backwards populates the thumbnail grid from least recent to most recent. for (int i = taskGroups.size() - 1; i >= 0; i--) { GroupTask groupTask = taskGroups.get(i); - boolean hasMultipleTasks = groupTask.hasMultipleTasks(); - TaskView taskView = getTaskViewFromPool(hasMultipleTasks); + boolean isRemovalNeeded = stagedTaskToBeRemovedFromGrid != null + && groupTask.containsTask(stagedTaskToBeRemovedFromGrid.key.id); + + TaskView taskView; + if (isRemovalNeeded && groupTask.hasMultipleTasks()) { + // If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE + // to be a temporary container for the remaining task. + taskView = getTaskViewFromPool(TaskView.Type.SINGLE); + } else { + taskView = getTaskViewFromPool(groupTask.taskViewType); + } + addView(taskView); - if (hasMultipleTasks) { + if (isRemovalNeeded && groupTask.hasMultipleTasks()) { + if (groupTask.task1.equals(stagedTaskToBeRemovedFromGrid)) { + taskView.bind(groupTask.task2, mOrientationState); + } else { + taskView.bind(groupTask.task1, mOrientationState); + } + } else if (isRemovalNeeded) { + // If the task we need to remove is not part of a pair, bind it to the TaskView + // first (to prevent problems), then remove the whole thing. + taskView.bind(groupTask.task1, mOrientationState); + removeView(taskView); + } else if (taskView instanceof GroupedTaskView) { boolean firstTaskIsLeftTopTask = groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id; Task leftTopTask = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2; Task rightBottomTask = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1; + ((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState, groupTask.mSplitBounds); + } else if (taskView instanceof DesktopTaskView) { + ((DesktopTaskView) taskView).bind(((DesktopTask) groupTask).tasks, + mOrientationState); } else { taskView.bind(groupTask.task1, mOrientationState); } + + // enables instance filtering if the feature flag for it is on + if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) { + taskView.setUpShowAllInstancesListener(); + } } + if (!taskGroups.isEmpty()) { addView(mClearAllButton); } - boolean settlingOnNewTask = mNextPage != INVALID_PAGE; - if (settlingOnNewTask) { - // Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll. - mCurrentPage = previousCurrentPage; - } else { - setCurrentPage(previousCurrentPage); - } - // Keep same previous focused task TaskView newFocusedTaskView = getTaskViewByTaskId(focusedTaskId); // If the list changed, maybe the focused task doesn't exist anymore @@ -1534,21 +1689,36 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } int targetPage = -1; - if (!settlingOnNewTask) { + if (mNextPage != INVALID_PAGE) { + // Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll. + mCurrentPage = previousCurrentPage; + if (currentTaskId != -1) { + currentTaskView = getTaskViewByTaskId(currentTaskId); + if (currentTaskView != null) { + targetPage = indexOfChild(currentTaskView); + } + } + } else { // Set the current page to the running task, but not if settling on new task. if (runningTaskId != -1) { targetPage = indexOfChild(newRunningTaskView); } else if (getTaskViewCount() > 0) { targetPage = indexOfChild(requireTaskViewAt(0)); } - } else if (currentTaskId != -1) { - currentTaskView = getTaskViewByTaskId(currentTaskId); - if (currentTaskView != null) { - targetPage = indexOfChild(currentTaskView); - } } if (targetPage != -1 && mCurrentPage != targetPage) { - setCurrentPage(targetPage); + int finalTargetPage = targetPage; + runOnPageScrollsInitialized(() -> { + // TODO(b/246283207): Remove logging once root cause of flake detected. + if (Utilities.IS_RUNNING_IN_TEST_HARNESS) { + Log.d("b/246283207", "RecentsView#applyLoadPlan() -> " + + "previousCurrentPage: " + previousCurrentPage + + ", targetPage: " + finalTargetPage + + ", getScrollForPage(targetPage): " + + getScrollForPage(finalTargetPage)); + } + setCurrentPage(finalTargetPage); + }); } if (mIgnoreResetTaskId != -1 && @@ -1561,6 +1731,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T resetTaskVisuals(); onTaskStackUpdated(); updateEnabledOverlays(); + if (isPageScrollsInitialized()) { + onPageScrollsInitialized(); + } } private boolean isModal() { @@ -1629,22 +1802,20 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T taskView.setTaskThumbnailSplashAlpha(mTaskThumbnailSplashAlpha); } } - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - // resetTaskVisuals is called at the end of dismiss animation which could update - // primary and secondary translation of the live tile cut out. We will need to do so - // here accordingly. - runActionOnRemoteHandles(remoteTargetHandle -> { - TaskViewSimulator simulator = remoteTargetHandle.getTaskViewSimulator(); - simulator.taskPrimaryTranslation.value = 0; - simulator.taskSecondaryTranslation.value = 0; - simulator.fullScreenProgress.value = 0; - simulator.recentsViewScale.value = 1; - }); - // Similar to setRunningTaskHidden below, reapply the state before runningTaskView is - // null. - if (!mRunningTaskShowScreenshot) { - setRunningTaskViewShowScreenshot(mRunningTaskShowScreenshot); - } + // resetTaskVisuals is called at the end of dismiss animation which could update + // primary and secondary translation of the live tile cut out. We will need to do so + // here accordingly. + runActionOnRemoteHandles(remoteTargetHandle -> { + TaskViewSimulator simulator = remoteTargetHandle.getTaskViewSimulator(); + simulator.taskPrimaryTranslation.value = 0; + simulator.taskSecondaryTranslation.value = 0; + simulator.fullScreenProgress.value = 0; + simulator.recentsViewScale.value = 1; + }); + // Similar to setRunningTaskHidden below, reapply the state before runningTaskView is + // null. + if (!mRunningTaskShowScreenshot) { + setRunningTaskViewShowScreenshot(mRunningTaskShowScreenshot); } if (mRunningTaskTileHidden) { setRunningTaskHidden(mRunningTaskTileHidden); @@ -1724,6 +1895,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T // Changed orientations, update controllers so they intercept accordingly. mActivity.getDragLayer().recreateControllers(); onOrientationChanged(); + resetTaskVisuals(); } boolean isInLandscape = mOrientationState.getTouchRotation() != ROTATION_0 @@ -1745,7 +1917,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T private void onOrientationChanged() { // If overview is in modal state when rotate, reset it to overview state without running // animation. - setModalStateEnabled(false); + setModalStateEnabled(/* isModalState= */ false, /* animate= */ false); if (isSplitSelectionActive()) { onRotateInSplitSelectionState(); } @@ -1878,9 +2050,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T private void animateActionsViewAlpha(float alphaValue, long duration) { mActionsViewAlphaAnimator = ObjectAnimator.ofFloat( - mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, alphaValue); + mActionsView.getVisibilityAlpha(), MULTI_PROPERTY_VALUE, alphaValue); mActionsViewAlphaAnimatorFinalValue = alphaValue; mActionsViewAlphaAnimator.setDuration(duration); + // Set autocancel to prevent race-conditiony setting of alpha from other animations + mActionsViewAlphaAnimator.setAutoCancel(true); mActionsViewAlphaAnimator.start(); } @@ -1893,6 +2067,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } int scroll = mOrientationHandler.getPrimaryScroll(this); mClearAllButton.onRecentsViewScroll(scroll, mOverviewGridEnabled); + + // Clear all button alpha was set by the previous line. + mActionsView.getIndexScrollAlpha().setValue(1 - mClearAllButton.getScrollAlpha()); } @Override @@ -1900,7 +2077,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T if (!mActivity.getDeviceProfile().isTablet) { return super.getDestinationPage(scaledScroll); } - if (!pageScrollsInitialized()) { + if (!isPageScrollsInitialized()) { Log.e(TAG, "Cannot get destination page: RecentsView not properly initialized", new IllegalStateException()); @@ -2036,7 +2213,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T mFocusedTaskViewId = -1; if (mRecentsAnimationController != null) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile) { + if (mEnableDrawingLiveTile) { // We are still drawing the live tile, finish it now to clean up. finishRecentsAnimation(true /* toRecents */, null); } else { @@ -2117,10 +2294,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T * Handle the edge case where Recents could increment task count very high over long * period of device usage. Probably will never happen, but meh. */ - private <T extends TaskView> T getTaskViewFromPool(boolean isGrouped) { - T taskView = isGrouped ? - (T) mGroupedTaskViewPool.getView() : - (T) mTaskViewPool.getView(); + private TaskView getTaskViewFromPool(@TaskView.Type int type) { + TaskView taskView; + switch (type) { + case TaskView.Type.GROUPED: + taskView = mGroupedTaskViewPool.getView(); + break; + case TaskView.Type.DESKTOP: + taskView = mDesktopTaskViewPool.getView(); + break; + case TaskView.Type.SINGLE: + default: + taskView = mTaskViewPool.getView(); + } taskView.setTaskViewId(mTaskViewIdCount); if (mTaskViewIdCount == Integer.MAX_VALUE) { mTaskViewIdCount = 0; @@ -2145,7 +2331,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T */ public void reloadIfNeeded() { if (!mModel.isTaskListValid(mTaskListChangeId)) { - mTaskListChangeId = mModel.getTasks(this::applyLoadPlan); + mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState + .getFilter(mFilterState.getPackageNameToFilter())); } } @@ -2212,8 +2399,14 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T for (int i = 0; i < getTaskViewCount(); i++) { requireTaskViewAt(i).setOrientationState(mOrientationState); } + boolean shouldRotateMenuForFakeRotation = + !mOrientationState.isRecentsActivityRotationAllowed(); + if (!shouldRotateMenuForFakeRotation) { + return; + } TaskMenuView tv = (TaskMenuView) getTopOpenViewWithType(mActivity, TYPE_TASK_MENU); if (tv != null) { + // Rotation is supported on phone (details at b/254198019#comment4) tv.onRotationChanged(); } } @@ -2275,9 +2468,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T setEnableFreeScroll(true); setEnableDrawingLiveTile(mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS); - if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) { - setRunningTaskViewShowScreenshot(true); - } setRunningTaskHidden(false); animateUpTaskIconScale(); animateActionsViewIn(); @@ -2315,12 +2505,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } int runningTaskViewId = -1; boolean needGroupTaskView = runningTasks.length > 1; + boolean needDesktopTask = hasDesktopTask(runningTasks); if (shouldAddStubTaskView(runningTasks)) { boolean wasEmpty = getChildCount() == 0; // Add an empty view for now until the task plan is loaded and applied final TaskView taskView; - if (needGroupTaskView) { - taskView = getTaskViewFromPool(true); + if (needDesktopTask) { + taskView = getTaskViewFromPool(TaskView.Type.DESKTOP); + mTmpRunningTasks = Arrays.copyOf(runningTasks, runningTasks.length); + addView(taskView, 0); + ((DesktopTaskView) taskView).bind(Arrays.asList(mTmpRunningTasks), + mOrientationState); + } else if (needGroupTaskView) { + taskView = getTaskViewFromPool(TaskView.Type.GROUPED); mTmpRunningTasks = new Task[]{runningTasks[0], runningTasks[1]}; addView(taskView, 0); // When we create a placeholder task view mSplitBoundsConfig will be null, but with @@ -2329,7 +2526,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T ((GroupedTaskView)taskView).bind(mTmpRunningTasks[0], mTmpRunningTasks[1], mOrientationState, mSplitBoundsConfig); } else { - taskView = getTaskViewFromPool(false); + taskView = getTaskViewFromPool(TaskView.Type.SINGLE); addView(taskView, 0); // The temporary running task is only used for the duration between the start of the // gesture and the task list is loaded and applied @@ -2364,6 +2561,18 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T reloadIfNeeded(); } + private boolean hasDesktopTask(Task[] runningTasks) { + if (!DESKTOP_MODE_SUPPORTED) { + return false; + } + for (Task task : runningTasks) { + if (task.key.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) { + return true; + } + } + return false; + } + /** * Sets the running task id, cleaning up the old running task if necessary. */ @@ -2402,12 +2611,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } private void setRunningTaskViewShowScreenshot(boolean showScreenshot) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - mRunningTaskShowScreenshot = showScreenshot; - TaskView runningTaskView = getRunningTaskView(); - if (runningTaskView != null) { - runningTaskView.setShowScreenshot(mRunningTaskShowScreenshot); - } + mRunningTaskShowScreenshot = showScreenshot; + TaskView runningTaskView = getRunningTaskView(); + if (runningTaskView != null) { + runningTaskView.setShowScreenshot(mRunningTaskShowScreenshot); } } @@ -2698,13 +2905,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T * @param gridProgress 0 = carousel; 1 = 2 row grid. */ private void setGridProgress(float gridProgress) { - int taskCount = getTaskViewCount(); - if (taskCount == 0) { - return; - } - mGridProgress = gridProgress; + int taskCount = getTaskViewCount(); for (int i = 0; i < taskCount; i++) { requireTaskViewAt(i).setGridProgress(gridProgress); } @@ -2788,8 +2991,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T anim.add(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate, verticalFactor * secondaryTaskDimension * 2).setDuration(duration), LINEAR, sp); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile - && taskView.isRunningTask()) { + if (mEnableDrawingLiveTile && taskView.isRunningTask()) { anim.addOnFrameCallback(() -> { runActionOnRemoteHandles( remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator() @@ -2838,6 +3040,11 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T false /* fadeWithThumbnail */, true /* isStagedTask */); } + // TODO (b/257513449): Launch animation not fully complete. OK to remove flag once it is. + if (ENABLE_LAUNCH_FROM_STAGED_APP.get()) { + mFirstFloatingTaskView.setOnClickListener(this::animateToFullscreen); + } + // SplitInstructionsView: animate in safeRemoveDragLayerView(mSplitInstructionsView); mSplitInstructionsView = SplitInstructionsView.getSplitInstructionsView(mActivity); @@ -2855,6 +3062,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T InteractionJankMonitorWrapper.begin(this, InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected"); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + if (mSplitHiddenTaskView == getRunningTaskView()) { + finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, + null /* onFinishComplete */); + } else { + switchToScreenshot( + () -> finishRecentsAnimation(true /* toRecents */, + false /* shouldPip */, null /* onFinishComplete */)); + } + } + }); anim.addEndListener(success -> { if (success) { InteractionJankMonitorWrapper.end( @@ -2868,6 +3088,34 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T }); } + private void animateToFullscreen(View view) { + FloatingTaskView stagedTaskView = (FloatingTaskView) view; + + boolean isTablet = mActivity.getDeviceProfile().isTablet; + int duration = isTablet + ? SplitAnimationTimings.TABLET_CONFIRM_DURATION + : SplitAnimationTimings.PHONE_CONFIRM_DURATION; + + PendingAnimation pendingAnimation = new PendingAnimation(duration); + + Rect firstTaskStartingBounds = new Rect(); + Rect firstTaskEndingBounds = new Rect(); + + stagedTaskView.getBoundsOnScreen(firstTaskStartingBounds); + mActivity.getDragLayer().getBoundsOnScreen(firstTaskEndingBounds); + + stagedTaskView.addConfirmAnimation( + pendingAnimation, + new RectF(firstTaskStartingBounds), + firstTaskEndingBounds, + false /* fadeWithThumbnail */, + true /* isStagedTask */); + + pendingAnimation.addEndListener(success -> launchStagedTask()); + + pendingAnimation.buildAnim().start(); + } + /** * Creates a {@link PendingAnimation} for dismissing the specified {@link TaskView}. * @param dismissedTaskView the {@link TaskView} to be dismissed @@ -3028,8 +3276,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T dismissTranslationInterpolationEnd - halfAdditionalDismissTranslationOffset, END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile - && taskView.isRunningTask()) { + if (mEnableDrawingLiveTile && taskView.isRunningTask()) { anim.addOnFrameCallback(() -> { runActionOnRemoteHandles( remoteTargetHandle -> @@ -3124,8 +3371,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T ) ); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile - && child instanceof TaskView + if (mEnableDrawingLiveTile && child instanceof TaskView && ((TaskView) child).isRunningTask()) { anim.addOnFrameCallback(() -> { runActionOnRemoteHandles( @@ -3248,8 +3494,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T mPendingAnimation.addEndListener(new Consumer<Boolean>() { @Override public void accept(Boolean success) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile - && dismissedTaskView.isRunningTask() && success) { + if (mEnableDrawingLiveTile && dismissedTaskView.isRunningTask() && success) { finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, () -> onEnd(success)); } else { @@ -3266,8 +3511,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T if (success) { if (shouldRemoveTask) { if (dismissedTaskView.getTask() != null) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get() - && dismissedTaskView.isRunningTask()) { + if (dismissedTaskView.isRunningTask()) { finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, () -> removeTaskInternal(dismissedTaskViewId)); } else { @@ -3368,7 +3612,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T removeViewInLayout(mClearAllButton); if (isHomeTaskDismissed) { updateEmptyMessage(); - } else { + } else if (!(ENABLE_TASKBAR_IN_OVERVIEW.get() && + mSplitSelectStateController.isSplitSelectActive())) { startHome(); } } else { @@ -3468,10 +3713,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView; mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit); mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive()); - mActionsView.updateSplitButtonFlags(FLAG_IS_NOT_TABLET, + mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET, !mActivity.getDeviceProfile().isTablet); - mActionsView.updateSplitButtonFlags(FLAG_SINGLE_TASK, getTaskViewCount() <= 1); - mActionsView.updateSplitButtonVisibility(); + mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, + !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get() && getTaskViewCount() <= 1); } /** @@ -3926,8 +4171,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T ? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty() : mOrientationHandler.getPrimaryViewTranslate(); translationProperty.set(child, totalTranslation); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile - && i == getRunningTaskIndex()) { + if (mEnableDrawingLiveTile && i == getRunningTaskIndex()) { runActionOnRemoteHandles( remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator() .taskPrimaryTranslation.value = totalTranslation); @@ -4148,20 +4392,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T public void initiateSplitSelect(TaskView taskView, @StagePosition int stagePosition, StatsLogManager.EventEnum splitEvent) { mSplitHiddenTaskView = taskView; - mSplitSelectStateController.setInitialTaskSelect(taskView.getTask().key.id, + mSplitSelectStateController.setInitialTaskSelect(taskView.getTask(), stagePosition, splitEvent, taskView.getItemInfo()); mSplitHiddenTaskViewIndex = indexOfChild(taskView); - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, - null /* onFinishComplete */); - } } + /** + * Called when staging a split from Home/AllApps, using the icon long-press menu. + */ public void initiateSplitSelect(QuickstepSystemShortcut.SplitSelectSource splitSelectSource) { mSplitSelectSource = splitSelectSource; mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent, - splitSelectSource.position.stagePosition, splitSelectSource.mItemInfo, - splitSelectSource.splitEvent); + splitSelectSource.position.stagePosition, splitSelectSource.itemInfo, + splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTask); } /** @@ -4182,24 +4425,39 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T * Confirms the selection of the next split task. The extra data is passed through because the * user may be selecting a subtask in a group. * + * @param containerTaskView If our second selected app is currently running in Recents, this is + * the "container" TaskView from Recents. If we are starting a fresh + * instance of the app from an Intent, this will be null. + * @param task The Task corresponding to our second selected app. If we are starting a fresh + * instance of the app from an Intent, this will be null. + * @param drawable The Drawable corresponding to our second selected app's icon. + * @param secondView The View representing the current space on the screen where the second app + * is (either the ThumbnailView or the tapped icon). + * @param intent If we are launching a fresh instance of the app, this is the Intent for it. If + * the second app is already running in Recents, this will be null. * @return true if waiting for confirmation of second app or if split animations are running, * false otherwise */ - public boolean confirmSplitSelect(TaskView containerTaskView, Task task, IconView iconView, - TaskThumbnailView thumbnailView) { + public boolean confirmSplitSelect(TaskView containerTaskView, Task task, Drawable drawable, + View secondView, @Nullable Bitmap thumbnail, Intent intent) { if (canLaunchFullscreenTask()) { return false; } if (mSplitSelectStateController.isBothSplitAppsConfirmed()) { return true; } - mSplitToast.cancel(); - if (!task.isDockable) { - // Task not split screen supported - mSplitUnsupportedToast.show(); - return true; + // Second task is selected either as an already-running Task or an Intent + if (task != null) { + if (!task.isDockable) { + // Task does not support split screen + mSplitUnsupportedToast.show(); + return true; + } + mSplitSelectStateController.setSecondTask(task); + } else { + mSplitSelectStateController.setSecondTask(intent); } - mSplitSelectStateController.setSecondTask(task); + RectF secondTaskStartingBounds = new RectF(); Rect secondTaskEndingBounds = new Rect(); // TODO(194414938) starting bounds seem slightly off, investigate @@ -4207,11 +4465,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T Rect firstTaskEndingBounds = mTempRect; boolean isTablet = mActivity.getDeviceProfile().isTablet; - int duration = isTablet - ? SplitAnimationTimings.TABLET_CONFIRM_DURATION - : SplitAnimationTimings.PHONE_CONFIRM_DURATION; - PendingAnimation pendingAnimation = new PendingAnimation(duration); SplitAnimationTimings timings = AnimUtils.getDeviceSplitToConfirmTimings(isTablet); + PendingAnimation pendingAnimation = new PendingAnimation(timings.getDuration()); int halfDividerSize = getResources() .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2; @@ -4226,9 +4481,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T false /* fadeWithThumbnail */, true /* isStagedTask */); safeRemoveDragLayerView(mSecondFloatingTaskView); - mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity, - thumbnailView, thumbnailView.getThumbnail(), - iconView.getDrawable(), secondTaskStartingBounds); + + mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity, secondView, + thumbnail, drawable, secondTaskStartingBounds); mSecondFloatingTaskView.setAlpha(1); mSecondFloatingTaskView.addConfirmAnimation(pendingAnimation, secondTaskStartingBounds, secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isStagedTask */); @@ -4244,7 +4499,9 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T }); mSecondSplitHiddenView = containerTaskView; - mSecondSplitHiddenView.setThumbnailVisibility(INVISIBLE); + if (mSecondSplitHiddenView != null) { + mSecondSplitHiddenView.setThumbnailVisibility(INVISIBLE); + } InteractionJankMonitorWrapper.begin(this, InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "Second tile selected"); @@ -4295,6 +4552,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T resetTaskVisuals(); mSplitHiddenTaskViewIndex = -1; + if (mSplitHiddenTaskView != null) { + mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE); + mSplitHiddenTaskView = null; + } } private void safeRemoveDragLayerView(@Nullable View viewToRemove) { @@ -4434,9 +4695,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex), mOrientationHandler.getPrimaryViewTranslate(), primaryTranslation)); int runningTaskIndex = getRunningTaskIndex(); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() - && runningTaskIndex != -1 - && runningTaskIndex != taskIndex + if (runningTaskIndex != -1 && runningTaskIndex != taskIndex && getRemoteTargetHandles() != null) { for (RemoteTargetHandle remoteHandle : getRemoteTargetHandles()) { anim.play(ObjectAnimator.ofFloat( @@ -4514,8 +4773,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T DepthController depthController = getDepthController(); if (depthController != null) { - ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController, STATE_DEPTH, - BACKGROUND_APP.getDepth(mActivity)); + ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController.stateDepth, + MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mActivity)); anim.play(depthAnimator); } anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0f, 1f)); @@ -4525,12 +4784,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T mPendingAnimation = new PendingAnimation(duration); mPendingAnimation.add(anim); - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - runActionOnRemoteHandles( - remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator() - .addOverviewToAppAnim(mPendingAnimation, interpolator)); - mPendingAnimation.addOnFrameCallback(this::redrawLiveTile); - } + runActionOnRemoteHandles( + remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator() + .addOverviewToAppAnim(mPendingAnimation, interpolator)); + mPendingAnimation.addOnFrameCallback(this::redrawLiveTile); mPendingAnimation.addEndListener(isSuccess -> { if (isSuccess) { if (tv.getTaskIds()[1] != -1 && mRemoteTargetHandles != null) { @@ -4542,7 +4799,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T dividerAnimator.end(); }); } - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) { + if (tv.isRunningTask()) { finishRecentsAnimation(false /* toRecents */, null); onTaskLaunchAnimationEnd(true /* success */); } else { @@ -4561,6 +4818,16 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T return mPendingAnimation; } + protected void launchStagedTask() { + if (mSplitHiddenTaskView != null) { + // Split staging was started from an existing running task (in Overview) + mSplitHiddenTaskView.launchTask(success -> resetFromSplitSelectionState()); + } else { + // Split staging was started from a new intent (from app menu in Home/AllApps) + mActivity.startActivity(mSplitSelectSource.intent); + } + } + protected void onTaskLaunchAnimationEnd(boolean success) { if (success) { resetTaskVisuals(); @@ -4715,7 +4982,7 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T if (sendUserLeaveHint) { // Notify the SysUI to use fade-in animation when entering PiP from live tile. final SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(getContext()); - systemUiProxy.notifySwipeToHomeFinished(); + systemUiProxy.setPipAnimationTypeToAlpha(); systemUiProxy.setShelfHeight(true, mActivity.getDeviceProfile().hotseatBarSizePx); // Transaction to hide the task to avoid flicker for entering PiP from split-screen. // See also {@link AbsSwipeUpHandler#maybeFinishSwipeToHome}. @@ -4926,9 +5193,35 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T } /** + * Sets whether or not we should clamp the scroll offset. + * This is used to avoid x-axis movement when swiping up transient taskbar. + * Should only be set at the beginning and end of the gesture, otherwise a jump may occur. + * @param clampScrollOffset When true, we clamp the scroll to 0 before the clamp threshold is + * met. + */ + public void setClampScrollOffset(boolean clampScrollOffset) { + mShouldClampScrollOffset = clampScrollOffset; + } + + /** * Returns how many pixels the page is offset on the currently laid out dominant axis. */ public int getScrollOffset(int pageIndex) { + int unclampedOffset = getUnclampedScrollOffset(pageIndex); + if (!mShouldClampScrollOffset) { + return unclampedOffset; + } + if (Math.abs(unclampedOffset) < mClampedScrollOffsetBound) { + return 0; + } + return unclampedOffset + - Math.round(Math.signum(unclampedOffset) * mClampedScrollOffsetBound); + } + + /** + * Returns how many pixels the page is offset on the currently laid out dominant axis. + */ + private int getUnclampedScrollOffset(int pageIndex) { if (pageIndex == -1) { return 0; } @@ -5158,17 +5451,8 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T return null; } - @Override - public void onSecondaryWindowBoundsChanged() { - // Invalidate the task view size - setInsets(mInsets); - } - - /** - * Enables or disables modal state for RecentsView - * @param isModalState - */ - public void setModalStateEnabled(boolean isModalState) { } + /** Enables or disables modal state for RecentsView */ + public abstract void setModalStateEnabled(boolean isModalState, boolean animate); public TaskOverlayFactory getTaskOverlayFactory() { return mTaskOverlayFactory; diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java index 27ec01a640..b0b111d376 100644 --- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java +++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java @@ -29,6 +29,7 @@ import androidx.appcompat.widget.AppCompatTextView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.util.DisplayController; @@ -114,11 +115,13 @@ public class SplitInstructionsView extends FrameLayout { int getThreeButtonNavShift() { DeviceProfile dp = mLauncher.getDeviceProfile(); if ((DisplayController.getNavigationMode(getContext()) == THREE_BUTTONS) - && ((dp.isTwoPanels) || (dp.isTablet && !dp.isLandscape))) { + && ((dp.isTwoPanels) || (dp.isTablet && !dp.isLandscape)) + // If taskbar is in overview, overview action has dedicated space above nav buttons + && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) { int navButtonWidth = getResources().getDimensionPixelSize( R.dimen.taskbar_nav_buttons_size); int extraMargin = getResources().getDimensionPixelSize( - R.dimen.taskbar_contextual_button_margin); + R.dimen.taskbar_split_instructions_margin); // Explanation: The 3-button nav for non-phones sits on one side of the screen, taking // up 3 buttons + a side margin worth of space. Our splitInstructionsView starts in the // center of the screen and we want to center it in the remaining space, therefore we diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index 681574573e..2c9afb4b4c 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -23,7 +23,6 @@ import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Outline; -import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.RectShape; @@ -32,7 +31,6 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewOutlineProvider; -import android.view.ViewTreeObserver.OnScrollChangedListener; import android.widget.LinearLayout; import android.widget.TextView; @@ -56,13 +54,12 @@ import com.android.quickstep.views.TaskView.TaskIdAttributeContainer; /** * Contains options for a recent task when long-pressing its icon. */ -public class TaskMenuView extends AbstractFloatingView implements OnScrollChangedListener { +public class TaskMenuView extends AbstractFloatingView { private static final Rect sTempRect = new Rect(); private static final int REVEAL_OPEN_DURATION = 150; private static final int REVEAL_CLOSE_DURATION = 100; - private final float mTaskInsetMargin; private BaseDraggingActivity mActivity; private TextView mTaskName; @@ -81,7 +78,6 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange mActivity = BaseDraggingActivity.fromContext(context); setClipToOutline(true); - mTaskInsetMargin = getResources().getDimension(R.dimen.task_card_margin); } @Override @@ -129,33 +125,6 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange }; } - private void setPosition(float x, float y, int overscrollShift) { - PagedOrientationHandler pagedOrientationHandler = mTaskView.getPagedOrientationHandler(); - // Inset due to margin - PointF additionalInset = pagedOrientationHandler - .getAdditionalInsetForTaskMenu(mTaskInsetMargin); - DeviceProfile deviceProfile = mActivity.getDeviceProfile(); - int taskTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx; - - float adjustedY = y + taskTopMargin - additionalInset.y; - float adjustedX = x - additionalInset.x; - // Changing pivot to make computations easier - // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set, - // which would render the X and Y position set here incorrect - setPivotX(0); - if (deviceProfile.isTablet) { - // In tablet, set pivotY to original position without mThumbnailTopMargin adjustment. - setPivotY(-taskTopMargin); - } else { - setPivotY(0); - } - setRotation(pagedOrientationHandler.getDegreesRotated()); - setX(pagedOrientationHandler.getTaskMenuX(adjustedX, - mTaskContainer.getThumbnailView(), overscrollShift, deviceProfile)); - setY(pagedOrientationHandler.getTaskMenuY( - adjustedY, mTaskContainer.getThumbnailView(), overscrollShift)); - } - public void onRotationChanged() { if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) { mOpenCloseAnimator.end(); @@ -187,17 +156,9 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange return false; } post(this::animateOpen); - ((RecentsView) mActivity.getOverviewPanel()).addOnScrollChangedListener(this); return true; } - @Override - public void onScrollChanged() { - RecentsView rv = mActivity.getOverviewPanel(); - setPosition(mTaskView.getX() - rv.getScrollX(), mTaskView.getY() - rv.getScrollY(), - rv.getOverScrollShift()); - } - /** @return true if successfully able to populate task view menu, false otherwise */ private boolean populateAndLayoutMenu() { if (mTaskContainer.getTask().icon == null) { @@ -234,18 +195,18 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange RecentsView recentsView = mActivity.getOverviewPanel(); PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler(); measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - orientationHandler.setTaskMenuAroundTaskView(this, mTaskInsetMargin); // Get Position DeviceProfile deviceProfile = mActivity.getDeviceProfile(); - mActivity.getDragLayer().getDescendantRectRelativeToSelf(mTaskView, sTempRect); + mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskContainer.getThumbnailView(), + sTempRect); Rect insets = mActivity.getDragLayer().getInsets(); BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams(); int padding = getResources() .getDimensionPixelSize(R.dimen.task_menu_vertical_padding); params.width = orientationHandler .getTaskMenuWidth(taskContainer.getThumbnailView(), - deviceProfile) - (2 * padding); + deviceProfile, taskContainer.getStagePosition()) - (2 * padding); // Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start params.gravity = Gravity.LEFT; setLayoutParams(params); @@ -260,7 +221,22 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange orientationHandler.setTaskOptionsMenuLayoutOrientation( deviceProfile, mOptionLayout, dividerSpacing, divider); - setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top, 0); + float thumbnailAlignedX = sTempRect.left - insets.left; + float thumbnailAlignedY = sTempRect.top - insets.top; + // Changing pivot to make computations easier + // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set, + // which would render the X and Y position set here incorrect + setPivotX(0); + setPivotY(0); + setRotation(orientationHandler.getDegreesRotated()); + + // Margin that insets the menuView inside the taskView + float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin); + setTranslationX(orientationHandler.getTaskMenuX(thumbnailAlignedX, + mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMargin)); + setTranslationY(orientationHandler.getTaskMenuY( + thumbnailAlignedY, mTaskContainer.getThumbnailView(), + mTaskContainer.getStagePosition(), this, taskInsetMargin)); } private void animateOpen() { @@ -306,7 +282,6 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange private void closeComplete() { mIsOpen = false; mActivity.getDragLayer().removeView(this); - ((RecentsView) mActivity.getOverviewPanel()).removeOnScrollChangedListener(this); } private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() { diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt index b586ac37b0..bdc0585f83 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt +++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt @@ -37,7 +37,6 @@ import com.android.launcher3.popup.ArrowPopup import com.android.launcher3.popup.RoundedArrowDrawable import com.android.launcher3.popup.SystemShortcut import com.android.launcher3.util.Themes -import com.android.quickstep.KtR import com.android.quickstep.TaskOverlayFactory import com.android.quickstep.views.TaskView.TaskIdAttributeContainer @@ -53,9 +52,9 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> { .fromContext<BaseDraggingActivity>(taskContainer.taskView.context) val taskMenuViewWithArrow = activity.layoutInflater .inflate( - KtR.layout.task_menu_with_arrow, - activity.dragLayer, - false + R.layout.task_menu_with_arrow, + activity.dragLayer, + false ) as TaskMenuViewWithArrow<*> return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignSecondRow) @@ -93,7 +92,7 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> { private var optionMeasuredHeight = 0 private val arrowHorizontalPadding: Int get() = if (taskView.isFocusedTask) - resources.getDimensionPixelSize(KtR.dimen.task_menu_horizontal_padding) + resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding) else 0 @@ -119,7 +118,7 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> { override fun onFinishInflate() { super.onFinishInflate() - optionLayout = findViewById(KtR.id.menu_option_layout) + optionLayout = findViewById(R.id.menu_option_layout) } private fun populateAndShowForTask( @@ -170,7 +169,7 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> { // Add the spaces between items val divider = ShapeDrawable(RectShape()) divider.paint.color = resources.getColor(android.R.color.transparent) - val dividerSpacing = resources.getDimension(KtR.dimen.task_menu_spacing).toInt() + val dividerSpacing = resources.getDimension(R.dimen.task_menu_spacing).toInt() optionLayout.showDividers = SHOW_DIVIDER_MIDDLE // Set the orientation, which makes the menu show @@ -187,7 +186,7 @@ class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> { private fun addMenuOption(menuOption: SystemShortcut<*>) { val menuOptionView = mActivityContext.layoutInflater.inflate( - KtR.layout.task_view_menu_option, this, false + R.layout.task_view_menu_option, this, false ) as LinearLayout menuOption.setIconAndLabelFor( menuOptionView.findViewById(R.id.icon), diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index d7a8599eae..f6e172aad0 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -16,11 +16,11 @@ package com.android.quickstep.views; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; +import static com.android.systemui.shared.recents.utilities.PreviewPositionHelper.MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT; +import static com.android.systemui.shared.recents.utilities.Utilities.isRelativePercentDifferenceGreaterThan; import android.content.Context; import android.graphics.Bitmap; @@ -41,7 +41,6 @@ import android.os.Build; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Property; -import android.view.Surface; import android.view.View; import android.widget.ImageView; @@ -60,6 +59,7 @@ import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.quickstep.views.TaskView.FullscreenDrawParams; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.utilities.PreviewPositionHelper; /** * A task in the Recents view. @@ -67,7 +67,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData; public class TaskThumbnailView extends View { private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS = new MainThreadInitializedObject<>(FullscreenDrawParams::new); - private static final float MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT = 0.1f; public static final Property<TaskThumbnailView, Float> DIM_ALPHA = new FloatProperty<TaskThumbnailView>("dimAlpha") { @@ -320,13 +319,11 @@ public class TaskThumbnailView extends View { public void drawOnCanvas(Canvas canvas, float x, float y, float width, float height, float cornerRadius) { - if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { - if (mTask != null && getTaskView().isRunningTask() && !getTaskView().showScreenshot()) { - canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mClearPaint); - canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, - mDimmingPaintAfterClearing); - return; - } + if (mTask != null && getTaskView().isRunningTask() && !getTaskView().showScreenshot()) { + canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mClearPaint); + canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, + mDimmingPaintAfterClearing); + return; } // Always draw the background since the snapshots might be translucent or partially empty @@ -373,7 +370,7 @@ public class TaskThumbnailView extends View { * <p>We want to show the splash if the aspect ratio or rotation of the thumbnail would be * different from the task. */ - boolean shouldShowSplashView() { + public boolean shouldShowSplashView() { return isThumbnailAspectRatioDifferentFromThumbnailData() || isThumbnailRotationDifferentFromTask(); } @@ -417,11 +414,13 @@ public class TaskThumbnailView extends View { return false; } - float thumbnailViewAspect = getWidth() / (float) getHeight(); + RectF insets = mPreviewPositionHelper.getClippedInsets(); + float thumbnailViewAspect = (getWidth() + insets.left + insets.right) + / (getHeight() + insets.top + insets.bottom); float thumbnailDataAspect = mThumbnailData.thumbnail.getWidth() / (float) mThumbnailData.thumbnail.getHeight(); - return Utilities.isRelativePercentDifferenceGreaterThan(thumbnailViewAspect, + return isRelativePercentDifferenceGreaterThan(thumbnailViewAspect, thumbnailDataAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT); } @@ -445,8 +444,8 @@ public class TaskThumbnailView extends View { */ private void refreshOverlay() { if (mOverlayEnabled) { - getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix, - mPreviewPositionHelper.mIsOrientationChanged); + getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.getMatrix(), + mPreviewPositionHelper.isOrientationChanged()); } else { getTaskOverlay().reset(); } @@ -467,7 +466,8 @@ public class TaskThumbnailView extends View { } private void updateThumbnailMatrix() { - mPreviewPositionHelper.mIsOrientationChanged = false; + DeviceProfile dp = mActivity.getDeviceProfile(); + mPreviewPositionHelper.setOrientationChanged(false); if (mBitmapShader != null && mThumbnailData != null) { mPreviewRect.set(0, 0, mThumbnailData.thumbnail.getWidth(), mThumbnailData.thumbnail.getHeight()); @@ -475,10 +475,10 @@ public class TaskThumbnailView extends View { .getRecentsActivityRotation(); boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; mPreviewPositionHelper.updateThumbnailMatrix(mPreviewRect, mThumbnailData, - getMeasuredWidth(), getMeasuredHeight(), mActivity.getDeviceProfile(), - currentRotation, isRtl); + getMeasuredWidth(), getMeasuredHeight(), dp.widthPx, dp.heightPx, + dp.taskbarSize, dp.isTablet, currentRotation, isRtl); - mBitmapShader.setLocalMatrix(mPreviewPositionHelper.mMatrix); + mBitmapShader.setLocalMatrix(mPreviewPositionHelper.getMatrix()); mPaint.setShader(mBitmapShader); } getTaskView().updateCurrentFullscreenParams(mPreviewPositionHelper); @@ -518,199 +518,4 @@ public class TaskThumbnailView extends View { } return mThumbnailData.isRealSnapshot && !mTask.isLocked; } - - /** - * Utility class to position the thumbnail in the TaskView - */ - public static class PreviewPositionHelper { - - private static final RectF EMPTY_RECT_F = new RectF(); - - // Contains the portion of the thumbnail that is unclipped when fullscreen progress = 1. - private final RectF mClippedInsets = new RectF(); - private final Matrix mMatrix = new Matrix(); - private boolean mIsOrientationChanged; - - public Matrix getMatrix() { - return mMatrix; - } - - /** - * Updates the matrix based on the provided parameters - */ - public void updateThumbnailMatrix(Rect thumbnailBounds, ThumbnailData thumbnailData, - int canvasWidth, int canvasHeight, DeviceProfile dp, int currentRotation, - boolean isRtl) { - boolean isRotated = false; - boolean isOrientationDifferent; - - int thumbnailRotation = thumbnailData.rotation; - int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation); - RectF thumbnailClipHint = new RectF(); - float canvasScreenRatio = canvasWidth / (float) dp.widthPx; - float scaledTaskbarSize = dp.taskbarSize * canvasScreenRatio; - thumbnailClipHint.bottom = dp.isTablet ? scaledTaskbarSize : 0; - - float scale = thumbnailData.scale; - final float thumbnailScale; - - // Landscape vs portrait change. - // Note: Disable rotation in grid layout. - boolean windowingModeSupportsRotation = - thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN && !dp.isTablet; - isOrientationDifferent = isOrientationChange(deltaRotate) - && windowingModeSupportsRotation; - if (canvasWidth == 0 || canvasHeight == 0 || scale == 0) { - // If we haven't measured , skip the thumbnail drawing and only draw the background - // color - thumbnailScale = 0f; - } else { - // Rotate the screenshot if not in multi-window mode - isRotated = deltaRotate > 0 && windowingModeSupportsRotation; - - float surfaceWidth = thumbnailBounds.width() / scale; - float surfaceHeight = thumbnailBounds.height() / scale; - float availableWidth = surfaceWidth - - (thumbnailClipHint.left + thumbnailClipHint.right); - float availableHeight = surfaceHeight - - (thumbnailClipHint.top + thumbnailClipHint.bottom); - - float canvasAspect = canvasWidth / (float) canvasHeight; - float availableAspect = isRotated - ? availableHeight / availableWidth - : availableWidth / availableHeight; - boolean isAspectLargelyDifferent = - Utilities.isRelativePercentDifferenceGreaterThan(canvasAspect, - availableAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT); - if (isRotated && isAspectLargelyDifferent) { - // Do not rotate thumbnail if it would not improve fit - isRotated = false; - isOrientationDifferent = false; - } - - if (isAspectLargelyDifferent) { - // Crop letterbox insets if insets isn't already clipped - thumbnailClipHint.left = thumbnailData.letterboxInsets.left; - thumbnailClipHint.right = thumbnailData.letterboxInsets.right; - thumbnailClipHint.top = thumbnailData.letterboxInsets.top; - thumbnailClipHint.bottom = thumbnailData.letterboxInsets.bottom; - availableWidth = surfaceWidth - - (thumbnailClipHint.left + thumbnailClipHint.right); - availableHeight = surfaceHeight - - (thumbnailClipHint.top + thumbnailClipHint.bottom); - } - - final float targetW, targetH; - if (isOrientationDifferent) { - targetW = canvasHeight; - targetH = canvasWidth; - } else { - targetW = canvasWidth; - targetH = canvasHeight; - } - float targetAspect = targetW / targetH; - - // Update the clipHint such that - // > the final clipped position has same aspect ratio as requested by canvas - // > first fit the width and crop the extra height - // > if that will leave empty space, fit the height and crop the width instead - float croppedWidth = availableWidth; - float croppedHeight = croppedWidth / targetAspect; - if (croppedHeight > availableHeight) { - croppedHeight = availableHeight; - if (croppedHeight < targetH) { - croppedHeight = Math.min(targetH, surfaceHeight); - } - croppedWidth = croppedHeight * targetAspect; - - // One last check in case the task aspect radio messed up something - if (croppedWidth > surfaceWidth) { - croppedWidth = surfaceWidth; - croppedHeight = croppedWidth / targetAspect; - } - } - - // Update the clip hints. Align to 0,0, crop the remaining. - if (isRtl) { - thumbnailClipHint.left += availableWidth - croppedWidth; - if (thumbnailClipHint.right < 0) { - thumbnailClipHint.left += thumbnailClipHint.right; - thumbnailClipHint.right = 0; - } - } else { - thumbnailClipHint.right += availableWidth - croppedWidth; - if (thumbnailClipHint.left < 0) { - thumbnailClipHint.right += thumbnailClipHint.left; - thumbnailClipHint.left = 0; - } - } - thumbnailClipHint.bottom += availableHeight - croppedHeight; - if (thumbnailClipHint.top < 0) { - thumbnailClipHint.bottom += thumbnailClipHint.top; - thumbnailClipHint.top = 0; - } else if (thumbnailClipHint.bottom < 0) { - thumbnailClipHint.top += thumbnailClipHint.bottom; - thumbnailClipHint.bottom = 0; - } - - thumbnailScale = targetW / (croppedWidth * scale); - } - - if (!isRotated) { - mMatrix.setTranslate( - -thumbnailClipHint.left * scale, - -thumbnailClipHint.top * scale); - } else { - setThumbnailRotation(deltaRotate, thumbnailBounds); - } - - mClippedInsets.set(0, 0, 0, scaledTaskbarSize); - - mMatrix.postScale(thumbnailScale, thumbnailScale); - mIsOrientationChanged = isOrientationDifferent; - } - - private int getRotationDelta(int oldRotation, int newRotation) { - int delta = newRotation - oldRotation; - if (delta < 0) delta += 4; - return delta; - } - - /** - * @param deltaRotation the number of 90 degree turns from the current orientation - * @return {@code true} if the change in rotation results in a shift from landscape to - * portrait or vice versa, {@code false} otherwise - */ - private boolean isOrientationChange(int deltaRotation) { - return deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270; - } - - private void setThumbnailRotation(int deltaRotate, Rect thumbnailPosition) { - float translateX = 0; - float translateY = 0; - - mMatrix.setRotate(90 * deltaRotate); - switch (deltaRotate) { /* Counter-clockwise */ - case Surface.ROTATION_90: - translateX = thumbnailPosition.height(); - break; - case Surface.ROTATION_270: - translateY = thumbnailPosition.width(); - break; - case Surface.ROTATION_180: - translateX = thumbnailPosition.width(); - translateY = thumbnailPosition.height(); - break; - } - mMatrix.postTranslate(translateX, translateY); - } - - /** - * Insets to used for clipping the thumbnail (in case it is drawing outside its own space) - */ - public RectF getInsetsToDrawInFullscreen(DeviceProfile dp) { - return dp.isTaskbarPresent && !dp.isTaskbarPresentInApps - ? mClippedInsets : EMPTY_RECT_F; - } - } } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index a0f195ce26..aa37fddb8b 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -18,14 +18,12 @@ package com.android.quickstep.views; import static android.view.Display.DEFAULT_DISPLAY; import static android.widget.Toast.LENGTH_SHORT; -import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR; -import static com.android.launcher3.Utilities.comp; +import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; @@ -55,6 +53,7 @@ import android.util.FloatProperty; import android.util.Log; import android.view.Display; import android.view.MotionEvent; +import android.view.RemoteAnimationTarget; import android.view.TouchDelegate; import android.view.View; import android.view.ViewGroup; @@ -80,6 +79,7 @@ import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; @@ -88,7 +88,6 @@ import com.android.launcher3.util.ViewPool.Reusable; import com.android.quickstep.RecentsModel; import com.android.quickstep.RemoteAnimationTargets; import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle; -import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskIconCache; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskThumbnailCache; @@ -99,12 +98,11 @@ import com.android.quickstep.util.RecentsOrientedState; import com.android.quickstep.util.SplitSelectStateController; import com.android.quickstep.util.TaskCornerRadius; import com.android.quickstep.util.TransformParams; -import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.recents.utilities.PreviewPositionHelper; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.lang.annotation.Retention; import java.util.Arrays; @@ -122,6 +120,8 @@ public class TaskView extends FrameLayout implements Reusable { private static final String TAG = TaskView.class.getSimpleName(); private static final boolean DEBUG = false; + private static final RectF EMPTY_RECT_F = new RectF(); + public static final int FLAG_UPDATE_ICON = 1; public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1; @@ -135,6 +135,17 @@ public class TaskView extends FrameLayout implements Reusable { @IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL}) public @interface TaskDataChanges {} + /** + * Type of task view + */ + @Retention(SOURCE) + @IntDef({Type.SINGLE, Type.GROUPED, Type.DESKTOP}) + public @interface Type { + int SINGLE = 1; + int GROUPED = 2; + int DESKTOP = 3; + } + /** The maximum amount that a task view can be scrimmed, dimmed or tinted. */ public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f; @@ -161,7 +172,7 @@ public class TaskView extends FrameLayout implements Reusable { new FloatProperty<TaskView>("focusTransition") { @Override public void setValue(TaskView taskView, float v) { - taskView.setIconAndDimTransitionProgress(v, false /* invert */); + taskView.setIconsAndBannersTransitionProgress(v, false /* invert */); } @Override @@ -331,7 +342,7 @@ public class TaskView extends FrameLayout implements Reusable { protected TaskThumbnailView mSnapshotView; protected IconView mIconView; protected final DigitalWellBeingToast mDigitalWellBeingToast; - private float mFullscreenProgress; + protected float mFullscreenProgress; private float mGridProgress; protected float mTaskThumbnailSplashAlpha; private float mNonGridScale = 1; @@ -373,8 +384,8 @@ public class TaskView extends FrameLayout implements Reusable { /** * Index 0 will contain taskID of left/top task, index 1 will contain taskId of bottom/right */ - protected final int[] mTaskIdContainer = new int[]{-1, -1}; - protected final TaskIdAttributeContainer[] mTaskIdAttributeContainer = + protected int[] mTaskIdContainer = new int[]{-1, -1}; + protected TaskIdAttributeContainer[] mTaskIdAttributeContainer = new TaskIdAttributeContainer[2]; private boolean mShowScreenshot; @@ -489,7 +500,7 @@ public class TaskView extends FrameLayout implements Reusable { return; } mModalness = modalness; - mIconView.setAlpha(comp(modalness)); + mIconView.setAlpha(1 - modalness); mDigitalWellBeingToast.updateBannerOffset(modalness, mCurrentFullscreenParams.mCurrentDrawnInsets.top + mCurrentFullscreenParams.mCurrentDrawnInsets.bottom); @@ -515,6 +526,52 @@ public class TaskView extends FrameLayout implements Reusable { setOrientationState(orientedState); } + /** + * Sets up an on-click listener and the visibility for show_windows icon on top of the task. + */ + public void setUpShowAllInstancesListener() { + String taskPackageName = mTaskIdAttributeContainer[0].mTask.key.getPackageName(); + + // icon of the top/left task + View showWindowsView = findViewById(R.id.show_windows); + updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName)); + } + + /** + * Returns a callback that updates the state of the filter and the recents overview + * + * @param taskPackageName package name of the task to filter by + */ + @Nullable + protected View.OnClickListener getFilterUpdateCallback(String taskPackageName) { + View.OnClickListener cb = (view) -> { + // update and apply a new filter + getRecentsView().setAndApplyFilter(taskPackageName); + }; + + if (!getRecentsView().getFilterState().shouldShowFilterUI(taskPackageName)) { + cb = null; + } + return cb; + } + + /** + * Sets the correct visibility and callback on the provided filterView based on whether + * the callback is null or not + */ + protected void updateFilterCallback(@NonNull View filterView, + @Nullable View.OnClickListener callback) { + // Filtering changes alpha instead of the visibility since visibility + // can be altered separately through RecentsView#resetFromSplitSelectionState() + if (callback == null) { + filterView.setAlpha(0); + } else { + filterView.setAlpha(1); + } + + filterView.setOnClickListener(callback); + } + public TaskIdAttributeContainer[] getTaskIdAttributeContainers() { return mTaskIdAttributeContainer; } @@ -525,6 +582,13 @@ public class TaskView extends FrameLayout implements Reusable { } /** + * Check if given {@code taskId} is tracked in this view + */ + public boolean containsTaskId(int taskId) { + return mTask != null && mTask.key.id == taskId; + } + + /** * @return integer array of two elements to be size consistent with max number of tasks possible * index 0 will contain the taskId, index 1 will be -1 indicating a null taskID value */ @@ -564,13 +628,13 @@ public class TaskView extends FrameLayout implements Reusable { @Override public boolean dispatchTouchEvent(MotionEvent ev) { RecentsView recentsView = getRecentsView(); - if (recentsView == null || mTask == null) { + if (recentsView == null || getTask() == null) { return false; } SplitSelectStateController splitSelectStateController = recentsView.getSplitSelectController(); if (splitSelectStateController.isSplitSelectActive() && - splitSelectStateController.getInitialTaskId() == mTask.key.id) { + splitSelectStateController.getInitialTaskId() == getTask().key.id) { // Prevent taps on the this taskview if it's being animated into split select state return false; } @@ -597,11 +661,15 @@ public class TaskView extends FrameLayout implements Reusable { * @return {@code true} if user is already in split select mode and this tap was to choose the * second app. {@code false} otherwise */ - private boolean confirmSecondSplitSelectApp() { + protected boolean confirmSecondSplitSelectApp() { int index = getLastSelectedChildTaskIndex(); TaskIdAttributeContainer container = mTaskIdAttributeContainer[index]; - return getRecentsView().confirmSplitSelect(this, container.getTask(), - container.getIconView(), container.getThumbnailView()); + if (container != null) { + return getRecentsView().confirmSplitSelect(this, container.getTask(), + container.getIconView().getDrawable(), container.getThumbnailView(), + container.getThumbnailView().getThumbnail(), /* intent */ null); + } + return false; } /** @@ -626,7 +694,7 @@ public class TaskView extends FrameLayout implements Reusable { if (ActivityManagerWrapper.getInstance() .startActivityFromRecents(mTask.key, opts.options)) { RecentsView recentsView = getRecentsView(); - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskViewId() != -1) { + if (recentsView.getRunningTaskViewId() != -1) { recentsView.onTaskLaunchedInLiveTileMode(); // Return a fresh callback in the live tile case, so that it's not accidentally @@ -668,9 +736,7 @@ public class TaskView extends FrameLayout implements Reusable { if (freezeTaskList) { opts.setFreezeRecentTasksReordering(); } - // TODO(b/202826469): Replace setSplashScreenStyle with setDisableStartingWindow. - opts.setSplashScreenStyle(mSnapshotView.shouldShowSplashView() - ? SPLASH_SCREEN_STYLE_SOLID_COLOR : opts.getSplashScreenStyle()); + opts.setDisableStartingWindow(mSnapshotView.shouldShowSplashView()); Task.TaskKey key = mTask.key; UI_HELPER_EXECUTOR.execute(() -> { if (!ActivityManagerWrapper.getInstance().startActivityFromRecents(key, opts)) { @@ -705,18 +771,14 @@ public class TaskView extends FrameLayout implements Reusable { /** * Launch of the current task (both live and inactive tasks) with an animation. */ + @Nullable public RunnableList launchTasks() { RecentsView recentsView = getRecentsView(); RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles; - RunnableList runnableList = new RunnableList(); - if (mTask != null && mTask.desktopTile) { - // clicked on desktop - SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps(); - return runnableList; - } - if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask() && remoteTargetHandles != null) { + if (isRunningTask() && remoteTargetHandles != null) { if (!mIsClickableAsLiveTile) { - return runnableList; + Log.e(TAG, "TaskView is not clickable as a live tile; returning to home."); + return null; } mIsClickableAsLiveTile = false; @@ -726,14 +788,14 @@ public class TaskView extends FrameLayout implements Reusable { } else { TransformParams topLeftParams = remoteTargetHandles[0].getTransformParams(); TransformParams rightBottomParams = remoteTargetHandles[1].getTransformParams(); - RemoteAnimationTargetCompat[] apps = Stream.concat( + RemoteAnimationTarget[] apps = Stream.concat( Arrays.stream(topLeftParams.getTargetSet().apps), Arrays.stream(rightBottomParams.getTargetSet().apps)) - .toArray(RemoteAnimationTargetCompat[]::new); - RemoteAnimationTargetCompat[] wallpapers = Stream.concat( + .toArray(RemoteAnimationTarget[]::new); + RemoteAnimationTarget[] wallpapers = Stream.concat( Arrays.stream(topLeftParams.getTargetSet().wallpapers), Arrays.stream(rightBottomParams.getTargetSet().wallpapers)) - .toArray(RemoteAnimationTargetCompat[]::new); + .toArray(RemoteAnimationTarget[]::new); targets = new RemoteAnimationTargets(apps, wallpapers, topLeftParams.getTargetSet().nonApps, topLeftParams.getTargetSet().targetMode); @@ -741,11 +803,16 @@ public class TaskView extends FrameLayout implements Reusable { if (targets == null) { // If the recents animation is cancelled somehow between the parent if block and // here, try to launch the task as a non live tile task. - launchTaskAnimated(); + RunnableList runnableList = launchTaskAnimated(); + if (runnableList == null) { + Log.e(TAG, "Recents animation cancelled and cannot launch task as non-live tile" + + "; returning to home"); + } mIsClickableAsLiveTile = true; return runnableList; } + RunnableList runnableList = new RunnableList(); AnimatorSet anim = new AnimatorSet(); TaskViewUtils.composeRecentsLaunchAnimator( anim, this, targets.apps, @@ -782,10 +849,10 @@ public class TaskView extends FrameLayout implements Reusable { }); anim.start(); recentsView.onTaskLaunchedInLiveTileMode(); + return runnableList; } else { return launchTaskAnimated(); } - return runnableList; } /** @@ -940,7 +1007,11 @@ public class TaskView extends FrameLayout implements Reusable { return deviceProfile.isTablet && !isFocusedTask(); } - protected void setIconAndDimTransitionProgress(float progress, boolean invert) { + /** + * Called to animate a smooth transition when going directly from an app into Overview (and + * vice versa). Icons fade in, and DWB banners slide in with a "shift up" animation. + */ + protected void setIconsAndBannersTransitionProgress(float progress, boolean invert) { if (invert) { progress = 1 - progress; } @@ -984,7 +1055,7 @@ public class TaskView extends FrameLayout implements Reusable { if (mIconAndDimAnimator != null) { mIconAndDimAnimator.cancel(); } - setIconAndDimTransitionProgress(iconScale, invert); + setIconsAndBannersTransitionProgress(iconScale, invert); } protected void resetPersistentViewTransforms() { @@ -1404,6 +1475,12 @@ public class TaskView extends FrameLayout implements Reusable { mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE); mSnapshotView.getTaskOverlay().setFullscreenProgress(progress); + // Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are + // oversized and banner would look disproportionately large. + if (mActivity.getStateManager().getState() != BACKGROUND_APP) { + setIconsAndBannersTransitionProgress(progress, true); + } + updateSnapshotRadius(); } @@ -1561,9 +1638,12 @@ public class TaskView extends FrameLayout implements Reusable { /** The current scale we apply to the thumbnail to adjust for new left/right insets. */ public float mScale = 1; + private boolean mIsTaskbarTransient; + public FullscreenDrawParams(Context context) { mCornerRadius = TaskCornerRadius.get(context); mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context); + mIsTaskbarTransient = DisplayController.isTransientTaskbar(context); mCurrentDrawnCornerRadius = mCornerRadius; } @@ -1573,7 +1653,7 @@ public class TaskView extends FrameLayout implements Reusable { */ public void setProgress(float fullscreenProgress, float parentScale, float taskViewScale, int previewWidth, DeviceProfile dp, PreviewPositionHelper pph) { - RectF insets = pph.getInsetsToDrawInFullscreen(dp); + RectF insets = getInsetsToDrawInFullscreen(pph, dp, mIsTaskbarTransient); float currentInsetsLeft = insets.left * fullscreenProgress; float currentInsetsTop = insets.top * fullscreenProgress; @@ -1592,6 +1672,18 @@ public class TaskView extends FrameLayout implements Reusable { mScale = previewWidth / (previewWidth + currentInsetsLeft + currentInsetsRight); } } + + /** + * Insets to used for clipping the thumbnail (in case it is drawing outside its own space) + */ + private static RectF getInsetsToDrawInFullscreen(PreviewPositionHelper pph, + DeviceProfile dp, boolean isTaskbarTransient) { + if (dp.isTaskbarPresent && isTaskbarTransient) { + return pph.getClippedInsets(); + } + return dp.isTaskbarPresent && !dp.isTaskbarPresentInApps + ? pph.getClippedInsets() : EMPTY_RECT_F; + } } public class TaskIdAttributeContainer { diff --git a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java index c1b3beb475..83341cb868 100644 --- a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java +++ b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java @@ -36,13 +36,11 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.os.UserHandle; import android.text.TextUtils; -import android.util.Log; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.ComponentWithLabel; import com.android.launcher3.icons.IconCache; import com.android.launcher3.model.BgDataModel.FixedContainerItems; @@ -111,7 +109,6 @@ public final class WidgetsPredicationUpdateTaskTest { doReturn(allWidgets).when(manager).getInstalledProvidersForProfile(eq(myUserHandle())); doAnswer(i -> { String pkg = i.getArgument(0); - Log.e("Hello", "Getting v " + pkg); return TextUtils.isEmpty(pkg) ? allWidgets : allWidgets.stream() .filter(a -> pkg.equals(a.provider.getPackageName())) .collect(Collectors.toList()); @@ -138,21 +135,21 @@ public final class WidgetsPredicationUpdateTaskTest { public void widgetsRecommendationRan_shouldOnlyReturnNotAddedWidgetsInAppPredictionOrder() throws Exception { // WHEN newPredicationTask is executed with app predication of 5 apps. - AppTarget app1 = new AppTarget(new AppTargetId("app1"), "app1", "className", + AppTarget app1 = new AppTarget(new AppTargetId("app1"), "app1", "provider1", mUserHandle); - AppTarget app2 = new AppTarget(new AppTargetId("app2"), "app2", "className", + AppTarget app2 = new AppTarget(new AppTargetId("app2"), "app2", "provider1", mUserHandle); AppTarget app3 = new AppTarget(new AppTargetId("app3"), "app3", "className", mUserHandle); - AppTarget app4 = new AppTarget(new AppTargetId("app4"), "app4", "className", + AppTarget app4 = new AppTarget(new AppTargetId("app4"), "app4", "provider1", mUserHandle); - AppTarget app5 = new AppTarget(new AppTargetId("app5"), "app5", "className", + AppTarget app5 = new AppTarget(new AppTargetId("app5"), "app5", "provider1", mUserHandle); mModelHelper.executeTaskForTest( newWidgetsPredicationTask(List.of(app5, app3, app2, app4, app1))) .forEach(Runnable::run); - // THEN only 3 widgets are returned because + // THEN only 2 widgets are returned because // 1. app5/provider1 & app4/provider1 have already been added to workspace. They are // excluded from the result. // 2. app3 doesn't have a widget. @@ -161,45 +158,39 @@ public final class WidgetsPredicationUpdateTaskTest { .stream() .map(itemInfo -> (PendingAddWidgetInfo) itemInfo) .collect(Collectors.toList()); - assertThat(recommendedWidgets).hasSize(3); + assertThat(recommendedWidgets).hasSize(2); assertWidgetInfo(recommendedWidgets.get(0).info, mApp2Provider1); - assertWidgetInfo(recommendedWidgets.get(1).info, mApp4Provider2); - assertWidgetInfo(recommendedWidgets.get(2).info, mApp1Provider1); + assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1); } @Test - public void widgetsRecommendationRan_localFilterDisabled_shouldReturnWidgetsInPredicationOrder() + public void widgetsRecommendationRan_shouldReturnPackageWidgetsWhenEmpty() throws Exception { - if (FeatureFlags.ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER.get()) { - return; - } - // WHEN newPredicationTask is executed with 5 predicated widgets. - AppTarget widget1 = new AppTarget(new AppTargetId("app1"), "app1", "provider1", - mUserHandle); - AppTarget widget2 = new AppTarget(new AppTargetId("app1"), "app1", "provider2", + // Not installed widget + AppTarget widget1 = new AppTarget(new AppTargetId("app1"), "app1", "provider3", mUserHandle); // Not installed app AppTarget widget3 = new AppTarget(new AppTargetId("app2"), "app3", "provider1", mUserHandle); - // Not installed widget - AppTarget widget4 = new AppTarget(new AppTargetId("app4"), "app4", "provider3", + // Workspace added widgets + AppTarget widget4 = new AppTarget(new AppTargetId("app4"), "app4", "provider1", mUserHandle); AppTarget widget5 = new AppTarget(new AppTargetId("app5"), "app5", "provider1", mUserHandle); mModelHelper.executeTaskForTest( - newWidgetsPredicationTask(List.of(widget5, widget3, widget2, widget4, widget1))) + newWidgetsPredicationTask(List.of(widget5, widget3, widget4, widget1))) .forEach(Runnable::run); - // THEN only 3 widgets are returned because the launcher only filters out non-exist widgets. + // THEN only 2 widgets are returned because the launcher only filters out non-exist widgets. List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items .stream() .map(itemInfo -> (PendingAddWidgetInfo) itemInfo) .collect(Collectors.toList()); - assertThat(recommendedWidgets).hasSize(3); - assertWidgetInfo(recommendedWidgets.get(0).info, mApp5Provider1); - assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider2); - assertWidgetInfo(recommendedWidgets.get(2).info, mApp1Provider1); + assertThat(recommendedWidgets).hasSize(2); + // Another widget from the same package + assertWidgetInfo(recommendedWidgets.get(0).info, mApp4Provider2); + assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1); } private void assertWidgetInfo( diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java index 4eec319f4a..962261940c 100644 --- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java +++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java @@ -18,6 +18,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_S import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -103,12 +104,20 @@ public class TaskbarNavButtonControllerTest { } @Test - public void testLongPressHome() { + public void testLongPressHome_enabled() { + mNavButtonController.setAssistantLongPressEnabled(true /*assistantLongPressEnabled*/); mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView); verify(mockSystemUiProxy, times(1)).startAssistant(any()); } @Test + public void testLongPressHome_disabled() { + mNavButtonController.setAssistantLongPressEnabled(false /*assistantLongPressEnabled*/); + mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView); + verify(mockSystemUiProxy, never()).startAssistant(any()); + } + + @Test public void testPressHome() { mNavButtonController.onButtonClick(BUTTON_HOME, mockView); verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME); diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt new file mode 100644 index 0000000000..58f0949213 --- /dev/null +++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt @@ -0,0 +1,148 @@ +package com.android.launcher3.taskbar.navbutton + +import android.content.res.Resources +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.test.runner.AndroidJUnit4 +import com.android.launcher3.DeviceProfile +import com.android.launcher3.taskbar.TaskbarManager +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import com.android.launcher3.R +import org.junit.Assume.assumeTrue +import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations +import java.lang.IllegalStateException + +@RunWith(AndroidJUnit4::class) +class NavButtonLayoutFactoryTest { + + @Mock + lateinit var mockDeviceProfile: DeviceProfile + @Mock + lateinit var mockParentButtonContainer: FrameLayout + @Mock + lateinit var mockNavLayout: LinearLayout + @Mock + lateinit var mockStartContextualLayout: ViewGroup + @Mock + lateinit var mockEndContextualLayout: ViewGroup + @Mock + lateinit var mockResources: Resources + @Mock + lateinit var mockBackButton: ImageView + @Mock + lateinit var mockRecentsButton: ImageView + @Mock + lateinit var mockHomeButton: ImageView + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + // Init end nav buttons + whenever(mockNavLayout.childCount).thenReturn(3) + whenever(mockNavLayout.findViewById<View>(R.id.back)).thenReturn(mockBackButton) + whenever(mockNavLayout.findViewById<View>(R.id.home)).thenReturn(mockHomeButton) + whenever(mockNavLayout.findViewById<View>(R.id.recent_apps)).thenReturn(mockRecentsButton) + + // Init top level layout + whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons)) + .thenReturn(mockNavLayout) + whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons)) + .thenReturn(mockEndContextualLayout) + whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons)) + .thenReturn(mockStartContextualLayout) + } + + @Test + fun getKidsLayoutter() { + assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) + mockDeviceProfile.isTaskbarPresent = true + val layoutter: NavButtonLayoutFactory.NavButtonLayoutter = + getLayoutter(isKidsMode = true, isInSetup = false, isThreeButtonNav = false, + phoneMode = false) + assert(layoutter is KidsNavLayoutter) + } + + @Test + fun getSetupLayoutter() { + assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) + mockDeviceProfile.isTaskbarPresent = true + val layoutter: NavButtonLayoutFactory.NavButtonLayoutter = + getLayoutter(isKidsMode = false, isInSetup = true, isThreeButtonNav = false, + phoneMode = false) + assert(layoutter is SetupNavLayoutter) + } + + @Test + fun getTaskbarNavLayoutter() { + assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) + mockDeviceProfile.isTaskbarPresent = true + val layoutter: NavButtonLayoutFactory.NavButtonLayoutter = + getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false, + phoneMode = false) + assert(layoutter is TaskbarNavLayoutter) + } + + @Test(expected = IllegalStateException::class) + fun noValidLayoutForLargeScreenTaskbarNotPresent() { + assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) + mockDeviceProfile.isTaskbarPresent = false + getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false, + phoneMode = false) + } + + @Test + fun getTaskbarPortraitLayoutter() { + assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) + mockDeviceProfile.isTaskbarPresent = false + val layoutter: NavButtonLayoutFactory.NavButtonLayoutter = + getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true, + phoneMode = true) + assert(layoutter is PhonePortraitNavLayoutter) + } + + @Test + fun getTaskbarLandscapeLayoutter() { + assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) + mockDeviceProfile.isTaskbarPresent = false + setDeviceProfileLandscape() + val layoutter: NavButtonLayoutFactory.NavButtonLayoutter = + getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true, + phoneMode = true) + assert(layoutter is PhoneLandscapeNavLayoutter) + } + + @Test(expected = IllegalStateException::class) + fun noValidLayoutForPhoneGestureNav() { + assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW) + mockDeviceProfile.isTaskbarPresent = false + getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false, + phoneMode = true) + } + + private fun setDeviceProfileLandscape() { + // Use reflection to modify landscape field + val landscapeField = mockDeviceProfile.javaClass.getDeclaredField("isLandscape") + landscapeField.isAccessible = true + landscapeField.set(mockDeviceProfile, true) + } + + private fun getLayoutter(isKidsMode: Boolean, isInSetup: Boolean, + isThreeButtonNav: Boolean, phoneMode: Boolean): + NavButtonLayoutFactory.NavButtonLayoutter { + return NavButtonLayoutFactory.getUiLayoutter( + deviceProfile = mockDeviceProfile, + navButtonsView = mockParentButtonContainer, + resources = mockResources, + isKidsMode = isKidsMode, isInSetup = isInSetup, + isThreeButtonNav = isThreeButtonNav, phoneMode = phoneMode + ) + } +}
\ No newline at end of file diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java index f190e27237..2c5825fd0b 100644 --- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java +++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java @@ -16,8 +16,6 @@ package com.android.quickstep; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; - import static org.junit.Assert.assertTrue; import android.os.SystemProperties; @@ -41,6 +39,7 @@ public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest { protected TestRule getRulesInsideActivityMonitor() { return RuleChain. outerRule(new NavigationModeSwitchRule(mLauncher)). + around(new TaskbarModeSwitchRule(mLauncher)). around(super.getRulesInsideActivityMonitor()); } @@ -79,8 +78,7 @@ public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest { private boolean isInLiveTileMode(Launcher launcher, LauncherInstrumentation.ContainerType expectedContainerType) { - if (!ENABLE_QUICKSTEP_LIVE_TILE.get() - || expectedContainerType != LauncherInstrumentation.ContainerType.OVERVIEW) { + if (expectedContainerType != LauncherInstrumentation.ContainerType.OVERVIEW) { return false; } diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index f7600ff9bb..47bef7b5b2 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -63,6 +63,7 @@ import com.android.quickstep.views.RecentsView; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.RuleChain; @@ -167,6 +168,7 @@ public class FallbackRecentsTest { // b/143488140 //@NavigationModeSwitch + @Ignore @Test public void goToOverviewFromHome() { mDevice.pressHome(); @@ -178,6 +180,7 @@ public class FallbackRecentsTest { // b/143488140 //@NavigationModeSwitch + @Ignore @Test public void goToOverviewFromApp() { startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); @@ -213,6 +216,7 @@ public class FallbackRecentsTest { // b/143488140 //@NavigationModeSwitch + @Ignore @Test public void testOverview() { startAppFast(getAppPackageName()); diff --git a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt new file mode 100644 index 0000000000..5ec935fee9 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2022 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.quickstep + +import android.graphics.Rect +import android.graphics.RectF +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.launcher3.DeviceProfileBaseTest +import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT +import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT +import com.android.quickstep.views.TaskView.FullscreenDrawParams +import com.android.systemui.shared.recents.model.ThumbnailData +import com.android.systemui.shared.recents.utilities.PreviewPositionHelper +import com.android.wm.shell.util.SplitBounds +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import kotlin.math.roundToInt + +/** + * Test for FullscreenDrawParams class. + */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class FullscreenDrawParamsTest : DeviceProfileBaseTest() { + + private val TASK_SCALE = 0.7f + private var mThumbnailData: ThumbnailData = mock(ThumbnailData::class.java) + + private val mPreviewPositionHelper = PreviewPositionHelper() + private lateinit var params: FullscreenDrawParams + + @Before + fun setup() { + params = FullscreenDrawParams(context) + } + + @Test + fun setFullProgress_currentDrawnInsets_clipTaskbarSizeFromBottomForTablets() { + initializeVarsForTablet() + val dp = newDP() + val previewRect = Rect(0, 0, 100, 100) + val canvasWidth = (dp.widthPx * TASK_SCALE).roundToInt() + val canvasHeight = (dp.heightPx * TASK_SCALE).roundToInt() + val currentRotation = 0 + val isRtl = false + + mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth, + canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation, + isRtl) + params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f, + /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper) + + val expectedClippedInsets = RectF(0f, 0f, 0f, dp.taskbarSize * TASK_SCALE) + assertThat(params.mCurrentDrawnInsets) + .isEqualTo(expectedClippedInsets) + } + + @Test + fun setFullProgress_currentDrawnInsets_clipTaskbarSizeFromBottomForTablets_splitPortrait() { + initializeVarsForTablet() + val dp = newDP() + val previewRect = Rect(0, 0, 100, 100) + val canvasWidth = (dp.widthPx * TASK_SCALE).roundToInt() + val canvasHeight = (dp.heightPx * TASK_SCALE / 2).roundToInt() + val currentRotation = 0 + val isRtl = false + // portrait/vertical split apps + val dividerSize = 10 + val splitBounds = SplitBounds( + Rect(0, 0, dp.widthPx, (dp.heightPx - dividerSize) / 2), + Rect(0, (dp.heightPx + dividerSize) / 2, dp.widthPx, dp.heightPx), + 0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/) + mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_BOTTOM_OR_RIGHT) + + mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth, + canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation, + isRtl) + params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f, + /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper) + + // Probably unhelpful, but also unclear how to test otherwise ¯\_(ツ)_/¯ + val fullscreenTaskHeight = dp.heightPx * + (1 - (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent)) + val canvasScreenRatio = canvasHeight / fullscreenTaskHeight + val expectedBottomHint = dp.taskbarSize * canvasScreenRatio + assertThat(params.mCurrentDrawnInsets.bottom) + .isWithin(1f).of(expectedBottomHint) + } + + @Test + fun setFullProgress_currentDrawnInsets_clipTaskbarSizeFromTopForTablets_splitPortrait() { + initializeVarsForTablet() + val dp = newDP() + val previewRect = Rect(0, 0, 100, 100) + val canvasWidth = (dp.widthPx * TASK_SCALE).roundToInt() + val canvasHeight = (dp.heightPx * TASK_SCALE / 2).roundToInt() + val currentRotation = 0 + val isRtl = false + // portrait/vertical split apps + val dividerSize = 10 + val splitBounds = SplitBounds( + Rect(0, 0, dp.widthPx, (dp.heightPx - dividerSize) / 2), + Rect(0, (dp.heightPx + dividerSize) / 2, dp.widthPx, dp.heightPx), + 0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/) + mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_TOP_OR_LEFT) + + mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth, + canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation, + isRtl) + params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f, + /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper) + + assertThat(params.mCurrentDrawnInsets.bottom) + .isWithin(1f).of((0f)) + } + + @Test + fun setFullProgress_currentDrawnInsets_clipTaskbarSizeFromBottomForTablets_splitLandscape() { + initializeVarsForTablet(isLandscape = true) + val dp = newDP() + val previewRect = Rect(0, 0, 100, 100) + val canvasWidth = (dp.widthPx * TASK_SCALE / 2).roundToInt() + val canvasHeight = (dp.heightPx * TASK_SCALE).roundToInt() + val currentRotation = 0 + val isRtl = false + // portrait/vertical split apps + val dividerSize = 10 + val splitBounds = SplitBounds( + Rect(0, 0, (dp.widthPx - dividerSize) / 2, dp.heightPx), + Rect((dp.widthPx + dividerSize) / 2, 0, dp.widthPx, dp.heightPx), + 0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/) + mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_BOTTOM_OR_RIGHT) + + mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth, + canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation, + isRtl) + params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f, + /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper) + + assertThat(params.mCurrentDrawnInsets.bottom) + .isWithin(1f).of((dp.taskbarSize * TASK_SCALE)) + } + + @Test + fun setFullProgress_currentDrawnInsets_doNotClipTaskbarSizeFromBottomForPhones() { + initializeVarsForPhone() + val dp = newDP() + val previewRect = Rect(0, 0, 100, 100) + val canvasWidth = (dp.widthPx * TASK_SCALE).roundToInt() + val canvasHeight = (dp.heightPx * TASK_SCALE).roundToInt() + val currentRotation = 0 + val isRtl = false + + mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth, + canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation, + isRtl) + params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f, + /* taskViewScale= */ 1.0f, /* previewWidth= */ 0, dp, mPreviewPositionHelper) + + val expectedClippedInsets = RectF(0f, 0f, 0f, 0f) + assertThat(params.mCurrentDrawnInsets) + .isEqualTo(expectedClippedInsets) + } +}
\ No newline at end of file diff --git a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt index 3967f75fa6..4837c6c868 100644 --- a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt +++ b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt @@ -39,12 +39,12 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(558) + assertThat(dp.hotseatBarEndOffset).isEqualTo(510) assertThat(dp.numShownHotseatIcons).isEqualTo(6) - assertThat(dp.hotseatBorderSpace).isEqualTo(69) + assertThat(dp.hotseatBorderSpace).isEqualTo(70) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(176) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(558) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(150) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(580) assertThat(dp.isQsbInline).isFalse() assertThat(dp.hotseatQsbWidth).isEqualTo(1445) @@ -61,15 +61,15 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(558) + assertThat(dp.hotseatBarEndOffset).isEqualTo(510) assertThat(dp.numShownHotseatIcons).isEqualTo(4) - assertThat(dp.hotseatBorderSpace).isEqualTo(76) + assertThat(dp.hotseatBorderSpace).isEqualTo(40) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(122) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(558) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(150) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(550) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.hotseatQsbWidth).isEqualTo(1058) + assertThat(dp.hotseatQsbWidth).isEqualTo(1080) } /** @@ -82,15 +82,15 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(744) + assertThat(dp.hotseatBarEndOffset).isEqualTo(705) assertThat(dp.numShownHotseatIcons).isEqualTo(6) - assertThat(dp.hotseatBorderSpace).isEqualTo(83) + assertThat(dp.hotseatBorderSpace).isEqualTo(54) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(106) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(744) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(231) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(759) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.hotseatQsbWidth).isEqualTo(1467) + assertThat(dp.hotseatQsbWidth).isEqualTo(1468) } /** @@ -107,15 +107,15 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(705) + assertThat(dp.hotseatBarEndOffset).isEqualTo(660) assertThat(dp.numShownHotseatIcons).isEqualTo(6) - assertThat(dp.hotseatBorderSpace).isEqualTo(108) + assertThat(dp.hotseatBorderSpace).isEqualTo(100) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(631) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(300) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(1040) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.hotseatQsbWidth).isEqualTo(1227) + assertThat(dp.hotseatQsbWidth).isEqualTo(1233) } /** @@ -128,15 +128,15 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(705) + assertThat(dp.hotseatBarEndOffset).isEqualTo(660) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(36) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(884) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(864) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(696) assertThat(dp.isQsbInline).isTrue() - assertThat(dp.hotseatQsbWidth).isEqualTo(559) + assertThat(dp.hotseatQsbWidth).isEqualTo(528) } /** @@ -150,12 +150,12 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(705) + assertThat(dp.hotseatBarEndOffset).isEqualTo(660) assertThat(dp.numShownHotseatIcons).isEqualTo(5) - assertThat(dp.hotseatBorderSpace).isEqualTo(56) + assertThat(dp.hotseatBorderSpace).isEqualTo(36) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(801) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(816) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(700) assertThat(dp.isQsbInline).isTrue() assertThat(dp.hotseatQsbWidth).isEqualTo(480) diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java index e5e2cf3337..eded1c961f 100644 --- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java +++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java @@ -51,7 +51,7 @@ import java.util.concurrent.TimeUnit; /** * Test rule that allows executing a test with Quickstep on and then Quickstep off. - * The test should be annotated with @QuickstepOnOff. + * The test should be annotated with @NavigationModeSwitch. */ public class NavigationModeSwitchRule implements TestRule { diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java index 401b967d0d..df5303f4f4 100644 --- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java +++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java @@ -24,6 +24,7 @@ import com.android.launcher3.util.RaceConditionReproducer; import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -56,6 +57,7 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest { eventProcessor.finishIteration(); } + @Ignore @Test @NavigationModeSwitch public void testStressPressHome() { @@ -68,6 +70,7 @@ public class StartLauncherViaGestureTests extends AbstractQuickStepTest { } } + @Ignore @Test @NavigationModeSwitch public void testStressSwipeToOverview() { diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java index 42e9be32e3..9f34775761 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java @@ -44,6 +44,7 @@ import com.android.quickstep.views.RecentsView; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -224,6 +225,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet(); } + @Ignore @Test @NavigationModeSwitch @PortraitLandscape @@ -236,6 +238,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { isInState(() -> LauncherState.OVERVIEW)); } + @Ignore @Test @NavigationModeSwitch @PortraitLandscape @@ -259,6 +262,19 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { return launchedAppState; } + private void quickSwitchToPreviousAppAndAssert(boolean toRight) { + final LaunchedAppState launchedAppState = getAndAssertLaunchedApp(); + if (toRight) { + launchedAppState.quickSwitchToPreviousApp(); + } else { + launchedAppState.quickSwitchToPreviousAppSwipeLeft(); + } + + // While enable shell transition, Launcher can be resumed due to transient launch. + waitForLauncherCondition("Launcher shouldn't stay in resume forever", + this::isInLaunchedApp, 3000 /* timeout */); + } + @Test @PortraitLandscape public void testAllAppsFromHome() throws Exception { @@ -285,13 +301,11 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { startTestActivity(3); startTestActivity(4); - LaunchedAppState launchedAppState = getAndAssertLaunchedApp(); - launchedAppState.quickSwitchToPreviousApp(); + quickSwitchToPreviousAppAndAssert(true /* toRight */); assertTrue("The first app we should have quick switched to is not running", isTestActivityRunning(3)); - launchedAppState = getAndAssertLaunchedApp(); - launchedAppState.quickSwitchToPreviousApp(); + quickSwitchToPreviousAppAndAssert(true /* toRight */); if (mLauncher.getNavigationModel() == NavigationModel.THREE_BUTTON) { // 3-button mode toggles between 2 apps, rather than going back further. assertTrue("Second quick switch should have returned to the first app.", @@ -300,15 +314,39 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { assertTrue("The second app we should have quick switched to is not running", isTestActivityRunning(2)); } - launchedAppState = getAndAssertLaunchedApp(); - launchedAppState.quickSwitchToPreviousAppSwipeLeft(); + + quickSwitchToPreviousAppAndAssert(false /* toRight */); assertTrue("The 2nd app we should have quick switched to is not running", isTestActivityRunning(3)); - launchedAppState = getAndAssertLaunchedApp(); + final LaunchedAppState launchedAppState = getAndAssertLaunchedApp(); launchedAppState.switchToOverview(); } + @Test + @ScreenRecord // b/242163205 + public void testQuickSwitchToPreviousAppForTablet() throws Exception { + assumeTrue(mLauncher.isTablet()); + startTestActivity(2); + startImeTestActivity(); + + // Set ignoreTaskbarVisibility to true to verify the task bar visibility explicitly. + mLauncher.setIgnoreTaskbarVisibility(true); + + // Expect task bar invisible when the launched app was the IME activity. + LaunchedAppState launchedAppState = getAndAssertLaunchedApp(); + launchedAppState.assertTaskbarHidden(); + + // Quick-switch to the test app with swiping to right. + quickSwitchToPreviousAppAndAssert(true /* toRight */); + + assertTrue("The first app we should have quick switched to is not running", + isTestActivityRunning(2)); + // Expect task bar visible when the launched app was the test activity. + launchedAppState = getAndAssertLaunchedApp(); + launchedAppState.assertTaskbarVisible(); + } + private boolean isTestActivityRunning(int activityNumber) { return mDevice.wait(Until.hasObject(By.pkg(getAppPackageName()) .text("TestActivity" + activityNumber)), @@ -341,6 +379,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL); } + @Ignore @Test @PortraitLandscape public void testOverviewForTablet() throws Exception { diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java index 9337cb55bc..0b8bc10fec 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java @@ -17,6 +17,8 @@ package com.android.quickstep; import static androidx.test.InstrumentationRegistry.getInstrumentation; +import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT; + import static junit.framework.TestCase.assertEquals; import android.content.Intent; @@ -27,6 +29,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.tapl.Taskbar; import com.android.launcher3.ui.TaplTestsLauncher3; import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; +import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch; import org.junit.After; import org.junit.Assume; @@ -53,21 +56,25 @@ public class TaplTestsTaskbar extends AbstractQuickStepTest { TaplTestsLauncher3.initialize(this); startAppFast(CALCULATOR_APP_PACKAGE); + mLauncher.enableBlockTimeout(true); mLauncher.showTaskbarIfHidden(); } @After public void tearDown() { mLauncher.useDefaultWorkspaceLayoutOnReload(); + mLauncher.enableBlockTimeout(false); } @Test + @TaskbarModeSwitch(mode = PERSISTENT) public void testHideShowTaskbar() { getTaskbar().hide(); mLauncher.getLaunchedAppState().showTaskbar(); } @Test + @TaskbarModeSwitch(mode = PERSISTENT) public void testHideTaskbarPersistsOnRecreate() { getTaskbar().hide(); mLauncher.recreateTaskbar(); @@ -75,16 +82,19 @@ public class TaplTestsTaskbar extends AbstractQuickStepTest { } @Test + @TaskbarModeSwitch public void testLaunchApp() throws Exception { getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE); } @Test + @TaskbarModeSwitch public void testOpenMenu() throws Exception { getTaskbar().getAppIcon(TEST_APP_NAME).openMenu(); } @Test + @TaskbarModeSwitch public void testLaunchShortcut() throws Exception { getTaskbar().getAppIcon(TEST_APP_NAME) .openDeepShortcutMenu() @@ -95,6 +105,7 @@ public class TaplTestsTaskbar extends AbstractQuickStepTest { @Test @ScreenRecord // b/231615831 @PortraitLandscape + @TaskbarModeSwitch public void testLaunchAppInSplitscreen() throws Exception { getTaskbar().getAppIcon(TEST_APP_NAME).dragToSplitscreen( TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE); @@ -103,6 +114,7 @@ public class TaplTestsTaskbar extends AbstractQuickStepTest { @Test @ScreenRecord // b/231615831 @PortraitLandscape + @TaskbarModeSwitch public void testLaunchShortcutInSplitscreen() throws Exception { getTaskbar().getAppIcon(TEST_APP_NAME) .openDeepShortcutMenu() @@ -111,16 +123,19 @@ public class TaplTestsTaskbar extends AbstractQuickStepTest { } @Test + @TaskbarModeSwitch public void testLaunchApp_FromTaskbarAllApps() throws Exception { getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE); } @Test + @TaskbarModeSwitch public void testOpenMenu_FromTaskbarAllApps() throws Exception { getTaskbar().openAllApps().getAppIcon(TEST_APP_NAME).openMenu(); } @Test + @TaskbarModeSwitch public void testLaunchShortcut_FromTaskbarAllApps() throws Exception { getTaskbar().openAllApps() .getAppIcon(TEST_APP_NAME) @@ -132,6 +147,7 @@ public class TaplTestsTaskbar extends AbstractQuickStepTest { @Test @ScreenRecord // b/231615831 @PortraitLandscape + @TaskbarModeSwitch public void testLaunchAppInSplitscreen_FromTaskbarAllApps() throws Exception { getTaskbar().openAllApps() .getAppIcon(TEST_APP_NAME) @@ -141,6 +157,7 @@ public class TaplTestsTaskbar extends AbstractQuickStepTest { @Test @ScreenRecord // b/231615831 @PortraitLandscape + @TaskbarModeSwitch public void testLaunchShortcutInSplitscreen_FromTaskbarAllApps() throws Exception { getTaskbar().openAllApps() .getAppIcon(TEST_APP_NAME) diff --git a/quickstep/tests/src/com/android/quickstep/TaskThumbnailViewTest.kt b/quickstep/tests/src/com/android/quickstep/TaskThumbnailViewTest.kt deleted file mode 100644 index cf3c8c9b8d..0000000000 --- a/quickstep/tests/src/com/android/quickstep/TaskThumbnailViewTest.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2022 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.quickstep - -import android.graphics.Rect -import android.graphics.RectF -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.launcher3.DeviceProfileBaseTest -import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper -import com.android.systemui.shared.recents.model.ThumbnailData -import com.google.common.truth.Truth.assertThat -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito.mock - -/** - * Test for TaskThumbnailView class. - */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class TaskThumbnailViewTest : DeviceProfileBaseTest() { - - private var mThumbnailData: ThumbnailData = mock(ThumbnailData::class.java) - - private val mPreviewPositionHelper = PreviewPositionHelper() - - @Test - fun getInsetsToDrawInFullscreen_clipTaskbarSizeFromBottomForTablets() { - initializeVarsForTablet() - val dp = newDP() - val previewRect = Rect(0, 0, 100, 100) - val canvasWidth = dp.widthPx / 2 - val canvasHeight = dp.heightPx / 2 - val currentRotation = 0 - val isRtl = false - - mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth, - canvasHeight, dp, currentRotation, isRtl) - - val expectedClippedInsets = RectF(0f, 0f, 0f, dp.taskbarSize / 2f) - assertThat(mPreviewPositionHelper.getInsetsToDrawInFullscreen(dp)) - .isEqualTo(expectedClippedInsets) - } - - @Test - fun getInsetsToDrawInFullscreen_doNotClipTaskbarSizeFromBottomForPhones() { - initializeVarsForPhone() - val dp = newDP() - val previewRect = Rect(0, 0, 100, 100) - val canvasWidth = dp.widthPx / 2 - val canvasHeight = dp.heightPx / 2 - val currentRotation = 0 - val isRtl = false - - mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth, - canvasHeight, dp, currentRotation, isRtl) - - val expectedClippedInsets = RectF(0f, 0f, 0f, 0f) - assertThat(mPreviewPositionHelper.getInsetsToDrawInFullscreen(dp)) - .isEqualTo(expectedClippedInsets) - } -}
\ No newline at end of file diff --git a/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java new file mode 100644 index 0000000000..9e41f74186 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/TaskbarModeSwitchRule.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2022 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.quickstep; + +import static androidx.test.InstrumentationRegistry.getInstrumentation; + +import static com.android.quickstep.TaskbarModeSwitchRule.Mode.ALL; +import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT; +import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT; + +import android.content.Context; +import android.util.Log; + +import com.android.launcher3.tapl.LauncherInstrumentation; +import com.android.launcher3.tapl.TestHelpers; +import com.android.launcher3.ui.AbstractLauncherUiTest; +import com.android.launcher3.util.DisplayController; +import com.android.launcher3.util.rule.FailureWatcher; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Test rule that allows executing a test multiple times with different conditions + * ie. with transient taskbar enabled and disabled. + * The test should be annotated with @TaskbarModeSwitch. + */ +public class TaskbarModeSwitchRule implements TestRule { + + static final String TAG = "TaskbarModeSwitchRule"; + + public static final int WAIT_TIME_MS = 10000; + + public enum Mode { + TRANSIENT, PERSISTENT, ALL + } + + // Annotation for tests that need to be run with quickstep enabled and disabled. + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface TaskbarModeSwitch { + Mode mode() default ALL; + } + + private final LauncherInstrumentation mLauncher; + + public TaskbarModeSwitchRule(LauncherInstrumentation launcher) { + mLauncher = launcher; + } + + @Override + public Statement apply(Statement base, Description description) { + if (TestHelpers.isInLauncherProcess() + && description.getAnnotation(TaskbarModeSwitch.class) != null) { + Mode mode = description.getAnnotation(TaskbarModeSwitch.class).mode(); + return new Statement() { + @Override + public void evaluate() throws Throwable { + mLauncher.enableDebugTracing(); + final boolean wasTransientTaskbarMode = + isTaskbarTransientMode(getInstrumentation().getTargetContext()); + try { + if (mode == TRANSIENT || mode == ALL) { + evaluateWithTransientTaskbar(); + } + if (mode == PERSISTENT || mode == ALL) { + evaluateWithPersistentTaskbar(); + } + } catch (Throwable e) { + Log.e(TAG, "Error", e); + throw e; + } finally { + Log.d(TAG, "In Finally block"); + setTaskbarMode(mLauncher, wasTransientTaskbarMode, description); + } + } + + private void evaluateWithPersistentTaskbar() throws Throwable { + setTaskbarMode(mLauncher, false, description); + base.evaluate(); + } + + private void evaluateWithTransientTaskbar() throws Throwable { + setTaskbarMode(mLauncher, true, description); + base.evaluate(); + } + }; + } else { + return base; + } + } + + private static boolean isTaskbarTransientMode(Context context) { + return DisplayController.isTransientTaskbar(context); + } + + public static void setTaskbarMode(LauncherInstrumentation launcher, + boolean expectTransientTaskbar, Description description) throws Exception { + launcher.enableTransientTaskbar(expectTransientTaskbar); + launcher.recreateTaskbar(); + + Context context = getInstrumentation().getTargetContext(); + assertTrue(launcher, "Couldn't set taskbar=" + expectTransientTaskbar, + isTaskbarTransientMode(context) == expectTransientTaskbar, description); + + AbstractLauncherUiTest.checkDetectedLeaks(launcher); + } + + private static void assertTrue(LauncherInstrumentation launcher, String message, + boolean condition, Description description) { + launcher.checkForAnomaly(true, true); + if (!condition) { + final AssertionError assertionError = new AssertionError(message); + if (description != null) { + FailureWatcher.onError(launcher, description, assertionError); + } + throw assertionError; + } + } +} diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java index 190b002d09..83602be72e 100644 --- a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java +++ b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java @@ -23,8 +23,8 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.util.ArrayMap; +import android.view.RemoteAnimationTarget; import android.view.Surface; -import android.view.SurfaceControl; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -42,8 +42,7 @@ import com.android.launcher3.util.window.CachedDisplayInfo; import com.android.launcher3.util.window.WindowManagerProxy; import com.android.quickstep.FallbackActivityInterface; import com.android.quickstep.SystemUiProxy; -import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; +import com.android.quickstep.util.SurfaceTransaction.MockProperties; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; @@ -207,17 +206,21 @@ public class TaskViewSimulatorTest { } @Override - public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) { - SurfaceParams.Builder builder = new SurfaceParams.Builder((SurfaceControl) null); - proxy.onBuildTargetParams(builder, mock(RemoteAnimationTargetCompat.class), this); - return new SurfaceParams[] {builder.build()}; + public SurfaceTransaction createSurfaceParams(BuilderProxy proxy) { + RecordingSurfaceTransaction transaction = new RecordingSurfaceTransaction(); + proxy.onBuildTargetParams( + transaction.mockProperties, mock(RemoteAnimationTarget.class), this); + return transaction; } @Override - public void applySurfaceParams(SurfaceParams[] params) { + public void applySurfaceParams(SurfaceTransaction params) { + Assert.assertTrue(params instanceof RecordingSurfaceTransaction); + MockProperties p = ((RecordingSurfaceTransaction) params).mockProperties; + // Verify that the task position remains the same RectF newAppBounds = new RectF(mAppBounds); - params[0].matrix.mapRect(newAppBounds); + p.matrix.mapRect(newAppBounds); Assert.assertThat(newAppBounds, new AlmostSame(mAppBounds)); System.err.println("Bounds mapped: " + mAppBounds + " => " + newAppBounds); diff --git a/res/color-night-v31/all_apps_tab_text.xml b/res/color-night-v31/all_apps_tab_text.xml index 83237b49e5..54b95aee8d 100644 --- a/res/color-night-v31/all_apps_tab_text.xml +++ b/res/color-night-v31/all_apps_tab_text.xml @@ -14,6 +14,6 @@ limitations under the License. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@android:color/system_neutral1_50" android:state_selected="true"/> - <item android:color="@android:color/system_neutral2_700"/> + <item android:color="@android:color/system_neutral2_700" android:state_selected="true"/> + <item android:color="@android:color/system_accent2_100"/> </selector>
\ No newline at end of file diff --git a/res/color-night-v31/all_apps_tabs_background.xml b/res/color-night-v31/all_apps_tabs_background.xml new file mode 100644 index 0000000000..9213274d5c --- /dev/null +++ b/res/color-night-v31/all_apps_tabs_background.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral1_800"/> +</selector>
\ No newline at end of file diff --git a/res/color-night-v31/transient_taskbar_background.xml b/res/color-night-v31/transient_taskbar_background.xml new file mode 100644 index 0000000000..40f6494933 --- /dev/null +++ b/res/color-night-v31/transient_taskbar_background.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral1_500" android:lStar="15" /> +</selector> + diff --git a/res/color-night-v31/widgets_picker_scrim.xml b/res/color-night-v31/widgets_picker_scrim.xml deleted file mode 100644 index be7010b80b..0000000000 --- a/res/color-night-v31/widgets_picker_scrim.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2021, 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. -*/ ---> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@android:color/system_neutral1_900" android:alpha="0.8" /> -</selector> diff --git a/res/color-v31/transient_taskbar_background.xml b/res/color-v31/transient_taskbar_background.xml new file mode 100644 index 0000000000..bce947da79 --- /dev/null +++ b/res/color-v31/transient_taskbar_background.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_neutral1_500" android:lStar="95" /> +</selector> + diff --git a/res/color-v31/widgets_picker_scrim.xml b/res/color-v31/widgets_picker_scrim.xml deleted file mode 100644 index 648824ac1e..0000000000 --- a/res/color-v31/widgets_picker_scrim.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2021, 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. -*/ ---> -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="@android:color/system_neutral1_200" android:alpha="0.8" /> -</selector> diff --git a/res/color/widgets_picker_scrim.xml b/res/color/widgets_picker_scrim.xml index 1cf97f61f7..5d5130086a 100644 --- a/res/color/widgets_picker_scrim.xml +++ b/res/color/widgets_picker_scrim.xml @@ -18,5 +18,5 @@ */ --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:color="#000000" android:alpha="0.32" /> + <item android:color="#000000" android:alpha="0.65" /> </selector> diff --git a/res/drawable/bg_all_apps_searchbox.xml b/res/drawable/bg_all_apps_searchbox.xml index c3249279af..3c321e4c49 100644 --- a/res/drawable/bg_all_apps_searchbox.xml +++ b/res/drawable/bg_all_apps_searchbox.xml @@ -15,5 +15,6 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="?attr/popupColorPrimary" /> - <corners android:radius="2dp" /> + <corners android:radius="@dimen/rounded_button_radius" /> + <stroke android:color="?attr/allappsHeaderProtectionColor" android:width=".5dp" /> </shape>
\ No newline at end of file diff --git a/res/drawable/ic_all_apps_button.xml b/res/drawable/ic_all_apps_button.xml index 5770d3cf19..4f0b6a8fbf 100644 --- a/res/drawable/ic_all_apps_button.xml +++ b/res/drawable/ic_all_apps_button.xml @@ -15,30 +15,41 @@ --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="80dp" - android:height="80dp" - android:viewportWidth="80" - android:viewportHeight="80" - android:theme="@style/AllAppsTheme"> - <path - android:pathData="M40,0.5L40,0.5c21.8,0 39.5,17.7 39.5,39.5l0,0c0,21.8 -17.7,39.5 -39.5,39.5l0,0C18.2,79.5 0.5,61.8 0.5,40l0,0C0.5,18.2 18.2,0.5 40,0.5z" - android:fillColor="?attr/allAppsButtonBgColor"/> - <path - android:pathData="M26.8,32.1m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0" - android:fillColor="?attr/allAppsButtonColor1"/> - <path - android:pathData="M26.8,47.9m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0" - android:fillColor="?attr/allAppsButtonColor2"/> - <path - android:pathData="M40,32.1m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0" - android:fillColor="?attr/allAppsButtonColor3"/> - <path - android:pathData="M40,47.9m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0" - android:fillColor="?attr/allAppsButtonColor2"/> - <path - android:pathData="M53.2,32.1m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0" - android:fillColor="?attr/allAppsButtonColor4"/> - <path - android:pathData="M53.2,47.9m-5.3,0a5.3,5.3 0,1 1,10.6 0a5.3,5.3 0,1 1,-10.6 0" - android:fillColor="?attr/allAppsButtonColor2"/> + android:width="29dp" + android:height="28dp" + android:viewportWidth="29" + android:viewportHeight="28"> + <group + android:pivotY="14.5" + android:pivotX="22" + android:scaleX=".50" + android:scaleY=".50"> + <path + android:pathData="M4 7C3.0375 7 2.215 6.65 1.5325 5.9675C0.85 5.285 0.5 4.4625 0.5 3.5C0.5 2.5375 0.85 1.715 1.5325 1.0325C2.215 0.35 3.0375 0 4 0C4.9625 0 5.785 0.35 6.4675 1.0325C7.15 1.715 7.5 2.5375 7.5 3.5C7.5 4.4625 7.15 5.285 6.4675 5.9675C5.785 6.65 4.9625 7 4 7Z" + android:fillColor="@color/all_apps_button_color"/> + <path + android:pathData="M14.5 7C13.5375 7 12.715 6.65 12.0325 5.9675C11.35 5.285 11 4.4625 11 3.5C11 2.5375 11.35 1.715 12.0325 1.0325C12.715 0.35 13.5375 0 14.5 0C15.4625 0 16.285 0.35 16.9675 1.0325C17.65 1.715 18 2.5375 18 3.5C18 4.4625 17.65 5.285 16.9675 5.9675C16.285 6.65 15.4625 7 14.5 7Z" + android:fillColor="@color/all_apps_button_color"/> + <path + android:pathData="M25 7C24.0375 7 23.215 6.65 22.5325 5.9675C21.85 5.285 21.5 4.4625 21.5 3.5C21.5 2.5375 21.85 1.715 22.5325 1.0325C23.215 0.35 24.0375 0 25 0C25.9625 0 26.785 0.35 27.4675 1.0325C28.15 1.715 28.5 2.5375 28.5 3.5C28.5 4.4625 28.15 5.285 27.4675 5.9675C26.785 6.65 25.9625 7 25 7Z" + android:fillColor="@color/all_apps_button_color"/> + <path + android:pathData="M4 17.5C3.0375 17.5 2.215 17.15 1.5325 16.4675C0.85 15.785 0.5 14.9625 0.5 14C0.5 13.0375 0.85 12.215 1.5325 11.5325C2.215 10.85 3.0375 10.5 4 10.5C4.9625 10.5 5.785 10.85 6.4675 11.5325C7.15 12.215 7.5 13.0375 7.5 14C7.5 14.9625 7.15 15.785 6.4675 16.4675C5.785 17.15 4.9625 17.5 4 17.5Z" + android:fillColor="@color/all_apps_button_color"/> + <path + android:pathData="M14.5 17.5C13.5375 17.5 12.715 17.15 12.0325 16.4675C11.35 15.785 11 14.9625 11 14C11 13.0375 11.35 12.215 12.0325 11.5325C12.715 10.85 13.5375 10.5 14.5 10.5C15.4625 10.5 16.285 10.85 16.9675 11.5325C17.65 12.215 18 13.0375 18 14C18 14.9625 17.65 15.785 16.9675 16.4675C16.285 17.15 15.4625 17.5 14.5 17.5Z" + android:fillColor="@color/all_apps_button_color"/> + <path + android:pathData="M25 17.5C24.0375 17.5 23.215 17.15 22.5325 16.4675C21.85 15.785 21.5 14.9625 21.5 14C21.5 13.0375 21.85 12.215 22.5325 11.5325C23.215 10.85 24.0375 10.5 25 10.5C25.9625 10.5 26.785 10.85 27.4675 11.5325C28.15 12.215 28.5 13.0375 28.5 14C28.5 14.9625 28.15 15.785 27.4675 16.4675C26.785 17.15 25.9625 17.5 25 17.5Z" + android:fillColor="@color/all_apps_button_color"/> + <path + android:pathData="M4 28C3.0375 28 2.215 27.65 1.5325 26.9675C0.85 26.285 0.5 25.4625 0.5 24.5C0.5 23.5375 0.85 22.715 1.5325 22.0325C2.215 21.35 3.0375 21 4 21C4.9625 21 5.785 21.35 6.4675 22.0325C7.15 22.715 7.5 23.5375 7.5 24.5C7.5 25.4625 7.15 26.285 6.4675 26.9675C5.785 27.65 4.9625 28 4 28Z" + android:fillColor="@color/all_apps_button_color"/> + <path + android:pathData="M14.5 28C13.5375 28 12.715 27.65 12.0325 26.9675C11.35 26.285 11 25.4625 11 24.5C11 23.5375 11.35 22.715 12.0325 22.0325C12.715 21.35 13.5375 21 14.5 21C15.4625 21 16.285 21.35 16.9675 22.0325C17.65 22.715 18 23.5375 18 24.5C18 25.4625 17.65 26.285 16.9675 26.9675C16.285 27.65 15.4625 28 14.5 28Z" + android:fillColor="@color/all_apps_button_color"/> + <path + android:pathData="M25 28C24.0375 28 23.215 27.65 22.5325 26.9675C21.85 26.285 21.5 25.4625 21.5 24.5C21.5 23.5375 21.85 22.715 22.5325 22.0325C23.215 21.35 24.0375 21 25 21C25.9625 21 26.785 21.35 27.4675 22.0325C28.15 22.715 28.5 23.5375 28.5 24.5C28.5 25.4625 28.15 26.285 27.4675 26.9675C26.785 27.65 25.9625 28 25 28Z" + android:fillColor="@color/all_apps_button_color"/> + </group> </vector> diff --git a/res/drawable/ic_select_windows.xml b/res/drawable/ic_select_windows.xml new file mode 100644 index 0000000000..cba0fde614 --- /dev/null +++ b/res/drawable/ic_select_windows.xml @@ -0,0 +1,26 @@ +<!-- + ~ Copyright (C) 2022 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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M7,44Q5.8,44 4.9,43.1Q4,42.2 4,41V21.65Q4,20.45 4.9,19.55Q5.8,18.65 7,18.65H12.75V7Q12.75,5.8 13.65,4.9Q14.55,4 15.75,4H41Q42.2,4 43.1,4.9Q44,5.8 44,7V26.35Q44,27.55 43.1,28.45Q42.2,29.35 41,29.35H35.3V41Q35.3,42.2 34.4,43.1Q33.5,44 32.3,44ZM7,41H32.3Q32.3,41 32.3,41Q32.3,41 32.3,41V24.65H7V41Q7,41 7,41Q7,41 7,41ZM35.3,26.35H41Q41,26.35 41,26.35Q41,26.35 41,26.35V10H15.75V18.65H31.6Q33.2,18.65 34.25,19.7Q35.3,20.75 35.3,22.35Z"/> +</vector>
\ No newline at end of file diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml index d0d82d48bd..655c75d1b5 100644 --- a/res/layout/all_apps.xml +++ b/res/layout/all_apps.xml @@ -17,42 +17,9 @@ will bake the left/right padding into that view's background itself. --> <com.android.launcher3.allapps.LauncherAllAppsContainerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/apps_view" - android:theme="?attr/allAppsTheme" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="true" android:clipToPadding="false" android:focusable="false" - android:saveEnabled="false"> - - <include - layout="@layout/all_apps_bottom_sheet_background" - android:visibility="gone" /> - - <include - layout="@layout/search_results_rv_layout" - android:visibility="gone" /> - - <include - layout="@layout/all_apps_rv_layout" - android:visibility="gone" /> - - <com.android.launcher3.allapps.FloatingHeaderView - android:id="@+id/all_apps_header" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:clipToPadding="false" - android:paddingTop="@dimen/all_apps_header_top_padding" - android:paddingBottom="@dimen/all_apps_header_bottom_padding" - android:orientation="vertical" > - - <include layout="@layout/floating_header_content" /> - - <include layout="@layout/all_apps_personal_work_tabs" /> - - </com.android.launcher3.allapps.FloatingHeaderView> - - <include layout="@layout/search_container_all_apps" /> - - <include layout="@layout/all_apps_fast_scroller" /> -</com.android.launcher3.allapps.LauncherAllAppsContainerView>
\ No newline at end of file + android:saveEnabled="false" />
\ No newline at end of file diff --git a/res/layout/all_apps_bottom_sheet_background.xml b/res/layout/all_apps_bottom_sheet_background.xml index 3e47690197..b0157c9c3e 100644 --- a/res/layout/all_apps_bottom_sheet_background.xml +++ b/res/layout/all_apps_bottom_sheet_background.xml @@ -16,8 +16,7 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/bottom_sheet_background" android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@drawable/bg_rounded_corner_bottom_sheet"> + android:layout_height="match_parent"> <View android:id="@+id/bottom_sheet_handle_area" diff --git a/res/layout/all_apps_content.xml b/res/layout/all_apps_content.xml new file mode 100644 index 0000000000..925f4d963b --- /dev/null +++ b/res/layout/all_apps_content.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 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 file is used by multiple all_apps.xml. Layout consists of all contents + showed in all apps screen +--> +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + + <include + layout="@layout/all_apps_bottom_sheet_background" + android:visibility="gone" /> + + <include + layout="@layout/search_results_rv_layout" + android:visibility="gone" /> + + <include + layout="@layout/all_apps_rv_layout" + android:visibility="gone" /> + + <com.android.launcher3.allapps.FloatingHeaderView + android:id="@+id/all_apps_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipToPadding="false" + android:layout_below="@id/search_container_all_apps" + android:paddingTop="@dimen/all_apps_header_top_padding" + android:paddingBottom="@dimen/all_apps_header_bottom_padding" + android:orientation="vertical" > + + <include layout="@layout/floating_header_content" /> + + <include layout="@layout/all_apps_personal_work_tabs" /> + + </com.android.launcher3.allapps.FloatingHeaderView> + + <include layout="@layout/all_apps_fast_scroller" /> +</merge>
\ No newline at end of file diff --git a/res/layout/all_apps_personal_work_tabs.xml b/res/layout/all_apps_personal_work_tabs.xml index 4459c870d2..e04b207a3e 100644 --- a/res/layout/all_apps_personal_work_tabs.xml +++ b/res/layout/all_apps_personal_work_tabs.xml @@ -16,6 +16,7 @@ <com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:launcher="http://schemas.android.com/apk/res-auto" android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="@dimen/all_apps_header_pill_height" @@ -24,7 +25,8 @@ android:paddingBottom="@dimen/all_apps_tabs_vertical_padding" android:layout_marginTop="@dimen/all_apps_tabs_margin_top" android:orientation="horizontal" - style="@style/TextHeadline"> + style="@style/TextHeadline" + launcher:alignOnIcon="true"> <Button android:id="@+id/tab_personal" diff --git a/res/layout/page_indicator_dots.xml b/res/layout/page_indicator_dots.xml new file mode 100644 index 0000000000..d5fe51e734 --- /dev/null +++ b/res/layout/page_indicator_dots.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 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. +--> + +<com.android.launcher3.pageindicators.PageIndicatorDots xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/page_indicator" + android:layout_width="match_parent" + android:layout_height="@dimen/workspace_page_indicator_height" + android:layout_gravity="bottom | center_horizontal" + android:theme="@style/HomeScreenElementTheme" />
\ No newline at end of file diff --git a/res/layout/search_container_all_apps.xml b/res/layout/search_container_all_apps.xml index b46298cfdb..db218c3d4b 100644 --- a/res/layout/search_container_all_apps.xml +++ b/res/layout/search_container_all_apps.xml @@ -21,7 +21,6 @@ android:layout_centerHorizontal="true" android:layout_gravity="top|center_horizontal" android:background="@drawable/bg_all_apps_searchbox" - android:elevation="1dp" android:focusableInTouchMode="true" android:gravity="center" android:hint="@string/all_apps_search_bar_hint" diff --git a/res/layout/secondary_launcher.xml b/res/layout/secondary_launcher.xml index 4be2e456ac..f48f3c0aa4 100644 --- a/res/layout/secondary_launcher.xml +++ b/res/layout/secondary_launcher.xml @@ -42,8 +42,7 @@ android:contentDescription="@string/all_apps_button_label" android:onClick="onAppsButtonClicked" /> - <view - class="com.android.launcher3.allapps.SecondaryLauncherAllAppsContainerView" + <com.android.launcher3.allapps.SecondaryLauncherAllAppsContainerView android:id="@+id/apps_view" android:layout_width="match_parent" android:layout_height="match_parent" @@ -53,57 +52,5 @@ android:saveEnabled="false" android:layout_gravity="bottom|end" android:background="@drawable/round_rect_primary" - android:visibility="invisible" > - - <include - layout="@layout/all_apps_bottom_sheet_background" - android:visibility="gone" /> - - <include - layout="@layout/search_results_rv_layout" - android:visibility="gone" /> - - <include - layout="@layout/all_apps_rv_layout" - android:visibility="gone" /> - - <com.android.launcher3.allapps.FloatingHeaderView - android:id="@+id/all_apps_header" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_below="@id/search_container_all_apps" - android:clipToPadding="false" - android:paddingTop="@dimen/all_apps_header_top_padding" - android:orientation="vertical" > - - <include layout="@layout/floating_header_content" /> - <include layout="@layout/all_apps_personal_work_tabs" /> - </com.android.launcher3.allapps.FloatingHeaderView> - - <com.android.launcher3.allapps.search.AppsSearchContainerLayout - android:id="@id/search_container_all_apps" - android:layout_width="match_parent" - android:layout_height="@dimen/all_apps_search_bar_field_height" - android:layout_centerHorizontal="true" - android:layout_gravity="top|center_horizontal" - android:layout_marginTop="24dp" - android:background="@drawable/bg_all_apps_searchbox" - android:elevation="1dp" - android:focusableInTouchMode="true" - android:gravity="center" - android:hint="@string/all_apps_search_bar_hint" - android:imeOptions="actionSearch|flagNoExtractUi" - android:importantForAutofill="no" - android:inputType="text|textNoSuggestions|textCapWords" - android:maxLines="1" - android:padding="8dp" - android:saveEnabled="false" - android:scrollHorizontally="true" - android:singleLine="true" - android:textColor="?android:attr/textColorSecondary" - android:textColorHint="@drawable/all_apps_search_hint" - android:textSize="16sp" /> - - <include layout="@layout/all_apps_fast_scroller" /> - </view> + android:visibility="invisible" /> </com.android.launcher3.secondarydisplay.SecondaryDragLayer>
\ No newline at end of file diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml index 4dee6e7ec3..5518dc88a3 100644 --- a/res/layout/user_folder_icon_normalized.xml +++ b/res/layout/user_folder_icon_normalized.xml @@ -30,12 +30,11 @@ <LinearLayout android:id="@+id/folder_footer" android:layout_width="match_parent" - android:layout_height="@dimen/folder_label_height" + android:layout_height="@dimen/folder_footer_height_default" android:clipChildren="false" android:orientation="horizontal" - android:paddingLeft="12dp" - android:paddingRight="12dp" - android:alpha="0"> + android:paddingLeft="@dimen/folder_footer_horiz_padding" + android:paddingRight="@dimen/folder_footer_horiz_padding"> <com.android.launcher3.folder.FolderNameEditText android:id="@+id/folder_name" diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml index 098c9b05a0..3635c73a68 100644 --- a/res/layout/widgets_full_sheet_paged_view.xml +++ b/res/layout/widgets_full_sheet_paged_view.xml @@ -89,8 +89,7 @@ android:gravity="center_horizontal" android:orientation="horizontal" android:paddingVertical="8dp" - android:paddingLeft="@dimen/widget_tabs_horizontal_padding" - android:paddingRight="@dimen/widget_tabs_horizontal_padding" + android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin" android:background="?android:attr/colorBackground" style="@style/TextHeadline" launcher:layout_sticky="true"> diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml index 9da3e87b17..b2a3a0d3d7 100644 --- a/res/layout/widgets_full_sheet_recyclerview.xml +++ b/res/layout/widgets_full_sheet_recyclerview.xml @@ -30,6 +30,7 @@ android:layout_height="wrap_content" android:layout_below="@id/collapse_handle" android:paddingBottom="16dp" + android:paddingHorizontal="@dimen/widget_list_horizontal_margin" android:orientation="vertical"> <TextView @@ -40,7 +41,6 @@ android:textSize="24sp" android:layout_marginTop="24dp" android:textColor="?android:attr/textColorSecondary" - android:paddingHorizontal="@dimen/widget_list_horizontal_margin" android:text="@string/widget_button_text"/> <FrameLayout @@ -49,7 +49,6 @@ android:layout_height="wrap_content" android:elevation="0.1dp" android:background="?android:attr/colorBackground" - android:paddingHorizontal="@dimen/widget_list_horizontal_margin" android:paddingBottom="8dp" android:clipToPadding="false" launcher:layout_sticky="true" > @@ -63,7 +62,6 @@ android:layout_marginTop="8dp" android:background="@drawable/widgets_recommendation_background" android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding" - android:paddingHorizontal="@dimen/widget_list_horizontal_margin" android:visibility="gone" /> </com.android.launcher3.views.StickyHeaderLayout> diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml index 81b28ba004..c116c12bad 100644 --- a/res/layout/work_mode_fab.xml +++ b/res/layout/work_mode_fab.xml @@ -12,24 +12,35 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.launcher3.allapps.WorkModeSwitch xmlns:android="http://schemas.android.com/apk/res/android" - style="@style/TextHeadline" +<com.android.launcher3.allapps.WorkModeSwitch + xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/work_mode_toggle" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" android:layout_height="@dimen/work_fab_height" android:layout_width="wrap_content" - android:gravity="center" - android:includeFontPadding="false" - android:textDirection="locale" - android:drawableTint="@color/all_apps_tab_text" - android:textColor="@color/all_apps_tab_text" - android:textSize="14sp" + android:minHeight="@dimen/work_fab_height" + android:gravity="center_vertical" android:background="@drawable/work_apps_toggle_background" android:forceHasOverlappingRendering="false" - android:drawablePadding="8dp" - android:drawableStart="@drawable/ic_corp_off" - android:layout_marginBottom="@dimen/work_fab_margin_bottom" - android:paddingLeft="@dimen/work_mode_fab_padding" - android:paddingRight="@dimen/work_mode_fab_padding" - android:text="@string/work_apps_pause_btn_text" />
\ No newline at end of file + android:contentDescription="@string/work_apps_pause_btn_text" + android:animateLayoutChanges="true"> + <ImageView + android:id="@+id/work_icon" + android:layout_width="@dimen/work_fab_icon_size" + android:layout_height="@dimen/work_fab_icon_size" + android:importantForAccessibility="no" + android:src="@drawable/ic_corp_off" + android:scaleType="center"/> + <TextView + android:id="@+id/pause_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="@color/all_apps_tab_text" + android:textSize="14sp" + android:includeFontPadding="false" + android:textDirection="locale" + android:text="@string/work_apps_pause_btn_text" + android:layout_marginStart="@dimen/work_fab_text_start_margin" + style="@style/TextHeadline"/> +</com.android.launcher3.allapps.WorkModeSwitch> diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index c2349004e0..42c51de9e2 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -38,7 +38,7 @@ <string name="widget_accessible_dims_format" msgid="3640149169885301790">"العرض %1$d الطول %2$d"</string> <string name="widget_preview_context_description" msgid="9045841361655787574">"أداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string> <string name="add_item_request_drag_hint" msgid="8730547755622776606">"انقر مع الاستمرار على التطبيق المصغّر لنقله إلى الشاشة الرئيسية."</string> - <string name="add_to_home_screen" msgid="9168649446635919791">"إضافة التطبيق المصغّر إلى الشاشة الرئيسية"</string> + <string name="add_to_home_screen" msgid="9168649446635919791">"إضافة إلى الشاشة الرئيسية"</string> <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"تمت إضافة الأداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g> إلى الشاشة الرئيسية."</string> <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{تطبيق مصغّر واحد}zero{# تطبيق مصغّر}two{تطبيقان مصغّران}few{# تطبيقات مصغّرة}many{# تطبيقًا مصغّرًا}other{# تطبيق مصغّر}}"</string> <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{اختصار واحد}zero{# اختصار}two{اختصاران}few{# اختصارات}many{# اختصارًا}other{# اختصار}}"</string> diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml index eee5ae27d0..67998d53a4 100644 --- a/res/values-as/strings.xml +++ b/res/values-as/strings.xml @@ -21,9 +21,9 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_name" msgid="649227358658669779">"Launcher3"</string> <string name="work_folder_name" msgid="3753320833950115786">"কৰ্মস্থান"</string> - <string name="activity_not_found" msgid="8071924732094499514">"এপটো ইনষ্টল কৰা নহ\'ল।"</string> - <string name="activity_not_available" msgid="7456344436509528827">"এপটো নাই"</string> - <string name="safemode_shortcut_error" msgid="9160126848219158407">"ডাউনল’ড কৰা এপটোক সুৰক্ষিত ম\'ডত অক্ষম কৰা হ’ল"</string> + <string name="activity_not_found" msgid="8071924732094499514">"এপ্টো ইনষ্টল কৰা নহ\'ল।"</string> + <string name="activity_not_available" msgid="7456344436509528827">"এপ্টো নাই"</string> + <string name="safemode_shortcut_error" msgid="9160126848219158407">"ডাউনল’ড কৰা এপ্টোক সুৰক্ষিত ম\'ডত অক্ষম কৰা হ’ল"</string> <string name="safemode_widget_error" msgid="4863470563535682004">"ৱিজেটবোৰক সুৰক্ষিত ম\'ডত অক্ষম কৰা হ’ল"</string> <string name="shortcut_not_available" msgid="2536503539825726397">"শ্বৰ্টকাট নাই"</string> <string name="home_screen" msgid="5629429142036709174">"গৃহ স্ক্ৰীন"</string> @@ -109,7 +109,7 @@ <string name="notification_dots_title" msgid="9062440428204120317">"জাননী বিন্দু"</string> <string name="notification_dots_desc_on" msgid="1679848116452218908">"অন আছে"</string> <string name="notification_dots_desc_off" msgid="1760796511504341095">"অফ আছে"</string> - <string name="title_missing_notification_access" msgid="7503287056163941064">"জাননী চাবলৈ অনুমতিৰ প্ৰয়োজন"</string> + <string name="title_missing_notification_access" msgid="7503287056163941064">"জাননীৰ এক্সেছৰ প্ৰয়োজন"</string> <string name="msg_missing_notification_access" msgid="281113995110910548">"জাননী সম্পৰ্কীয় বিন্দুবোৰ দেখুৱাবলৈ <xliff:g id="NAME">%1$s</xliff:g>ৰ বাবে এপৰ জাননীসমূহ অন কৰক"</string> <string name="title_change_settings" msgid="1376365968844349552">"ছেটিং সলনি কৰক"</string> <string name="notification_dots_service_title" msgid="4284221181793592871">"জাননী বিন্দু দেখুৱাওক"</string> @@ -119,8 +119,8 @@ <string name="package_state_unknown" msgid="7592128424511031410">"অজ্ঞাত"</string> <string name="abandoned_clean_this" msgid="7610119707847920412">"আঁতৰাওক"</string> <string name="abandoned_search" msgid="891119232568284442">"সন্ধান কৰক"</string> - <string name="abandoned_promises_title" msgid="7096178467971716750">"এই এপটো ইনষ্টল কৰা হোৱা নাই"</string> - <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনৰ এপটো ইনষ্টল কৰা হোৱা নাই। আপুনি এইটো আঁতৰাব পাৰে অথবা এপটো বিচাৰি মেনুৱেলভাৱে ইনষ্টল কৰিব পাৰে।"</string> + <string name="abandoned_promises_title" msgid="7096178467971716750">"এই এপ্টো ইনষ্টল কৰা হোৱা নাই"</string> + <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনৰ এপ্টো ইনষ্টল কৰা হোৱা নাই। আপুনি এইটো আঁতৰাব পাৰে অথবা এপ্টো বিচাৰি মেনুৱেলভাৱে ইনষ্টল কৰিব পাৰে।"</string> <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হৈছে"</string> <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনল’ড কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হ’ল"</string> <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল হোৱালৈ অপেক্ষা কৰি থকা হৈছে"</string> diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml index 69a16bae5f..6886b7085d 100644 --- a/res/values-be/strings.xml +++ b/res/values-be/strings.xml @@ -72,7 +72,7 @@ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Спіс працоўных праграм"</string> <string name="remove_drop_target_label" msgid="7812859488053230776">"Выдаліць"</string> <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Дэінсталяваць"</string> - <string name="app_info_drop_target_label" msgid="692894985365717661">"Пра праграму"</string> + <string name="app_info_drop_target_label" msgid="692894985365717661">"Звесткі аб праграме"</string> <string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</string> <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не прапаноўваць праграму"</string> <string name="pin_prediction" msgid="4196423321649756498">"Замацаваць прапанаваную праграму"</string> diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml index 4f15eb5777..aa29d8dc2f 100644 --- a/res/values-en-rCA/strings.xml +++ b/res/values-en-rCA/strings.xml @@ -32,12 +32,12 @@ <string name="split_screen_position_left" msgid="7537793098851830883">"Split left"</string> <string name="split_screen_position_right" msgid="1569377524925193369">"Split right"</string> <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string> - <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string> + <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch & hold to move a widget."</string> <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string> <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string> <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string> <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string> - <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string> + <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch & hold the widget to move it around the home screen"</string> <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string> <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string> <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string> @@ -54,18 +54,18 @@ <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string> <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string> <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string> - <string name="widget_education_close_button" msgid="8676165703104836580">"OK"</string> + <string name="widget_education_close_button" msgid="8676165703104836580">"Got it"</string> <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Change widget settings"</string> <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Search apps"</string> <string name="all_apps_loading_message" msgid="5813968043155271636">"Loading apps…"</string> - <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string> + <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string> <string name="label_application" msgid="8531721983832654978">"App"</string> <string name="all_apps_label" msgid="5015784846527570951">"All apps"</string> <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string> <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Touch & hold to move a shortcut."</string> <string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Double-tap & hold to move a shortcut or use custom actions."</string> <string name="out_of_space" msgid="6455557115204099579">"No room on this home screen"</string> - <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string> + <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favorites tray"</string> <string name="all_apps_button_label" msgid="8130441508702294465">"Apps list"</string> <string name="all_apps_search_results" msgid="5889367432531296759">"Search results"</string> <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personal apps list"</string> @@ -75,13 +75,13 @@ <string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string> <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string> <string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string> - <string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string> + <string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string> <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string> <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string> - <string name="permlab_read_settings" msgid="5136500343007704955">"read Home settings and shortcuts"</string> - <string name="permdesc_read_settings" msgid="4208061150510996676">"Allows the app to read the settings and shortcuts in Home."</string> - <string name="permlab_write_settings" msgid="4820028712156303762">"write Home settings and shortcuts"</string> - <string name="permdesc_write_settings" msgid="726859348127868466">"Allows the app to change the settings and shortcuts in Home."</string> + <string name="permlab_read_settings" msgid="5136500343007704955">"read home settings and shortcuts"</string> + <string name="permdesc_read_settings" msgid="4208061150510996676">"Allows the app to read the settings and shortcuts in home."</string> + <string name="permlab_write_settings" msgid="4820028712156303762">"write home settings and shortcuts"</string> + <string name="permdesc_write_settings" msgid="726859348127868466">"Allows the app to change the settings and shortcuts in home."</string> <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> is not allowed to make phone calls"</string> <string name="gadget_error_text" msgid="740356548025791839">"Can\'t load widget"</string> <string name="gadget_setup_text" msgid="8348374825537681407">"Widget settings"</string> @@ -101,7 +101,7 @@ <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> items"</string> <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> or more items"</string> <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string> - <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper and style"</string> + <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper & style"</string> <string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string> <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string> <string name="allow_rotation_title" msgid="7222049633713050106">"Allow home screen rotation"</string> @@ -113,7 +113,7 @@ <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string> <string name="notification_dots_service_title" msgid="4284221181793592871">"Show notification dots"</string> - <string name="developer_options_title" msgid="700788437593726194">"Developer options"</string> + <string name="developer_options_title" msgid="700788437593726194">"Developer Options"</string> <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Add app icons to home screen"</string> <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string> <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string> @@ -125,7 +125,7 @@ <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string> <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string> <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string> - <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut or remove the icon."</string> + <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut, or remove the icon."</string> <string name="dialog_update" msgid="2178028071796141234">"Update"</string> <string name="dialog_remove" msgid="6510806469849709407">"Remove"</string> <string name="widgets_list" msgid="796804551140113767">"Widgets list"</string> @@ -138,7 +138,7 @@ <string name="action_move" msgid="4339390619886385032">"Move item"</string> <string name="move_to_empty_cell_description" msgid="5254852678218206889">"Move to row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g> in <xliff:g id="STRING">%3$s</xliff:g>"</string> <string name="move_to_position" msgid="6750008980455459790">"Move to position <xliff:g id="NUMBER">%1$s</xliff:g>"</string> - <string name="move_to_hotseat_position" msgid="6295412897075147808">"Move to favourites position <xliff:g id="NUMBER">%1$s</xliff:g>"</string> + <string name="move_to_hotseat_position" msgid="6295412897075147808">"Move to favorites position <xliff:g id="NUMBER">%1$s</xliff:g>"</string> <string name="item_moved" msgid="4606538322571412879">"Item moved"</string> <string name="add_to_folder" msgid="9040534766770853243">"Add to folder: <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="add_to_folder_with_app" msgid="4534929978967147231">"Add to folder with <xliff:g id="NAME">%1$s</xliff:g>"</string> @@ -146,13 +146,13 @@ <string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="folder_created" msgid="6409794597405184510">"Folder created"</string> <string name="action_move_to_workspace" msgid="39528912300293768">"Move to home screen"</string> - <string name="action_resize" msgid="1802976324781771067">"Re-size"</string> + <string name="action_resize" msgid="1802976324781771067">"Resize"</string> <string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string> <string name="action_increase_height" msgid="459390020612501122">"Increase height"</string> <string name="action_decrease_width" msgid="1374549771083094654">"Decrease width"</string> <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string> - <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string> - <string name="action_deep_shortcut" msgid="2864038805849372848">"Short cuts"</string> + <string name="widget_resized" msgid="9130327887929620">"Widget resized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string> + <string name="action_deep_shortcut" msgid="2864038805849372848">"Shortcuts"</string> <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shortcuts and notifications"</string> <string name="action_dismiss_notification" msgid="5909461085055959187">"Dismiss"</string> <string name="accessibility_close" msgid="2277148124685870734">"Close"</string> @@ -161,12 +161,12 @@ <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string> <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string> <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Work apps are badged and visible to your IT admin"</string> - <string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string> + <string name="work_profile_edu_accept" msgid="6069788082535149071">"Got it"</string> <string name="work_apps_paused_title" msgid="3040901117349444598">"Work apps are paused"</string> - <string name="work_apps_paused_body" msgid="261634750995824906">"Your work apps can’t send you notifications, use your battery or access your location"</string> - <string name="work_apps_paused_content_description" msgid="5149623040804051095">"Work apps are off. Your work apps can’t send you notifications, use your battery or access your location"</string> + <string name="work_apps_paused_body" msgid="261634750995824906">"Your work apps can’t send you notifications, use your battery, or access your location"</string> + <string name="work_apps_paused_content_description" msgid="5149623040804051095">"Work apps are off. Your work apps can’t send you notifications, use your battery, or access your location"</string> <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Work apps are badged and visible to your IT admin"</string> - <string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string> + <string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Got it"</string> <string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pause work apps"</string> <string name="work_apps_enable_btn_text" msgid="1156432622148413741">"Turn on work apps"</string> <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string> diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml index 9e2d9a47d1..8b944fe509 100644 --- a/res/values-eu/strings.xml +++ b/res/values-eu/strings.xml @@ -124,7 +124,7 @@ <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> instalatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string> <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> deskargatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string> <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> instalatzeko zain"</string> - <string name="dialog_update_title" msgid="114234265740994042">"Aplikazioa eguneratu behar da"</string> + <string name="dialog_update_title" msgid="114234265740994042">"Aplikazioa eguneratu egin behar da"</string> <string name="dialog_update_message" msgid="4176784553982226114">"Ikonoaren aplikazioa ez dago eguneratuta. Lasterbidea berriro gaitzeko, eskuz egunera dezakezu aplikazioa. Bestela, kendu ikonoa."</string> <string name="dialog_update" msgid="2178028071796141234">"Eguneratu"</string> <string name="dialog_remove" msgid="6510806469849709407">"Kendu"</string> diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 6b4d129c1c..d79c022c7c 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -40,8 +40,8 @@ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"לוחצים לחיצה ארוכה על הווידג\'ט כדי להזיז אותו במסך הבית"</string> <string name="add_to_home_screen" msgid="9168649446635919791">"הוספה למסך הבית"</string> <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g> נוסף למסך הבית"</string> - <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ווידג\'ט אחד}two{# ווידג\'טים}many{# ווידג\'טים}other{# ווידג\'טים}}"</string> - <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{קיצור דרך אחד}two{# קיצורי דרך}many{# קיצורי דרך}other{# קיצורי דרך}}"</string> + <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ווידג\'ט אחד}one{# ווידג\'טים}two{# ווידג\'טים}other{# ווידג\'טים}}"</string> + <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{קיצור דרך אחד}one{# קיצורי דרך}two{# קיצורי דרך}other{# קיצורי דרך}}"</string> <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string> <string name="widget_button_text" msgid="2880537293434387943">"ווידג\'טים"</string> <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"חיפוש"</string> @@ -89,7 +89,7 @@ <string name="uninstall_system_app_text" msgid="4172046090762920660">"זוהי אפליקציית מערכת ולא ניתן להסיר את התקנתה."</string> <string name="folder_hint_text" msgid="5174843001373488816">"עריכת השם"</string> <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> מושבתת"</string> - <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{לאפליקציה {app_name} יש התראה אחת}two{לאפליקציה {app_name} יש # התראות}many{לאפליקציה {app_name} יש # התראות}other{לאפליקציה {app_name} יש # התראות}}"</string> + <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{לאפליקציה {app_name} יש התראה אחת}one{לאפליקציה {app_name} יש # התראות}two{לאפליקציה {app_name} יש # התראות}other{לאפליקציה {app_name} יש # התראות}}"</string> <string name="default_scroll_format" msgid="7475544710230993317">"דף %1$d מתוך %2$d"</string> <string name="workspace_scroll_format" msgid="8458889198184077399">"מסך הבית %1$d מתוך %2$d"</string> <string name="workspace_new_page" msgid="257366611030256142">"מסך הבית חדש"</string> diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index 3cec97d170..69157bc330 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -54,7 +54,7 @@ <string name="widget_education_header" msgid="4874760613775913787">"အသုံးဝင်သော အချက်အလက်များကို အလွယ်တကူ ရယူလိုက်ပါ"</string> <string name="widget_education_content" msgid="1731667670753497052">"အက်ပ်မဖွင့်ဘဲ အချက်အလက်များရယူရန် ပင်မစာမျက်နှာတွင် ဝိဂျက်များ ထည့်နိုင်သည်"</string> <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ဝိဂျက် ဆက်တင်များကို ပြောင်းရန် တို့ပါ"</string> - <string name="widget_education_close_button" msgid="8676165703104836580">"ရပြီ"</string> + <string name="widget_education_close_button" msgid="8676165703104836580">"နားလည်ပြီ"</string> <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ဝိဂျက် ဆက်တင်များကို ပြောင်းပါ"</string> <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ရှာဖွေမှု အက်ပ်များ"</string> <string name="all_apps_loading_message" msgid="5813968043155271636">"အက်ပ်များကို ဖွင့်နေသည်…"</string> @@ -166,7 +166,7 @@ <string name="work_apps_paused_body" msgid="261634750995824906">"သင်၏ အလုပ်သုံးအက်ပ်များက အကြောင်းကြားချက်များ ပို့ခြင်း၊ သင့်ဘက်ထရီ သုံးခြင်း (သို့) သင့်တည်နေရာ သုံးခြင်းတို့ မပြုလုပ်နိုင်ပါ"</string> <string name="work_apps_paused_content_description" msgid="5149623040804051095">"အလုပ်သုံးအက်ပ်များ ပိတ်ထားသည်။ သင်၏ အလုပ်သုံးအက်ပ်များက အကြောင်းကြားချက်များ ပို့ခြင်း၊ သင့်ဘက်ထရီ သုံးခြင်း (သို့) သင့်တည်နေရာ သုံးခြင်းတို့ မပြုလုပ်နိုင်ပါ"</string> <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"အလုပ်သုံးအက်ပ်များကို တံဆိပ်တပ်ထားပြီး သင်၏ IT စီမံခန့်ခွဲသူက မြင်နိုင်ပါသည်"</string> - <string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"ရပြီ"</string> + <string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"နားလည်ပြီ"</string> <string name="work_apps_pause_btn_text" msgid="4669288269140620646">"အလုပ်သုံးအက်ပ်များကို ခဏရပ်ရန်"</string> <string name="work_apps_enable_btn_text" msgid="1156432622148413741">"အလုပ်သုံးအက်ပ်များ ဖွင့်ရန်"</string> <string name="developer_options_filter_hint" msgid="5896817443635989056">"စစ်ထုတ်ရန်"</string> diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml index eefe8c5f81..54d6d8876f 100644 --- a/res/values-night-v31/colors.xml +++ b/res/values-night-v31/colors.xml @@ -25,8 +25,5 @@ <color name="home_settings_track_on_color">@android:color/system_accent2_700</color> <color name="home_settings_track_off_color">@android:color/system_neutral1_700</color> - <color name="all_apps_button_bg_color">@android:color/system_neutral1_800</color> - <color name="all_apps_button_color_1">@android:color/system_accent1_300</color> - <color name="all_apps_button_color_3">@android:color/system_accent1_100</color> - <color name="all_apps_button_color_4">@android:color/system_accent2_100</color> + <color name="all_apps_button_color">?android:attr/textColorSecondary</color> </resources>
\ No newline at end of file diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml index ce272ceade..17fe419a8c 100644 --- a/res/values-night/colors.xml +++ b/res/values-night/colors.xml @@ -17,9 +17,5 @@ --> <resources> - <color name="all_apps_button_bg_color">#2E3132</color> - <color name="all_apps_button_color_1">#33B9DB</color> - <color name="all_apps_button_color_2">#EFFBFF</color> - <color name="all_apps_button_color_3">#B1EBFF</color> - <color name="all_apps_button_color_4">#DEE0FF</color> + <color name="all_apps_button_color">#BFC8CC</color> </resources>
\ No newline at end of file diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml index 7b2ed8bc65..09b2d6f83f 100644 --- a/res/values-sw720dp/dimens.xml +++ b/res/values-sw720dp/dimens.xml @@ -43,4 +43,7 @@ <!-- Bottom sheet--> <dimen name="bottom_sheet_extra_top_padding">300dp</dimen> + + <!-- Folder spaces --> + <dimen name="folder_footer_horiz_padding">24dp</dimen> </resources> diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index e70466f24b..7fddcf4da0 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -58,7 +58,7 @@ <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"విడ్జెట్ సెట్టింగ్లను మార్చండి"</string> <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"యాప్ల కోసం సెర్చ్ చేయండి"</string> <string name="all_apps_loading_message" msgid="5813968043155271636">"అప్లికేషన్లను లోడ్ చేస్తోంది…"</string> - <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అప్లికేషన్లేవీ కనుగొనబడలేదు"</string> + <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి మ్యాచ్ అయ్యే అప్లికేషన్లేవీ కనుగొనబడలేదు"</string> <string name="label_application" msgid="8531721983832654978">"యాప్"</string> <string name="all_apps_label" msgid="5015784846527570951">"అన్ని యాప్లు"</string> <string name="notifications_header" msgid="1404149926117359025">"నోటిఫికేషన్లు"</string> @@ -141,17 +141,17 @@ <string name="move_to_hotseat_position" msgid="6295412897075147808">"ఇష్టమైనవిలో <xliff:g id="NUMBER">%1$s</xliff:g>వ స్థానానికి తరలించు"</string> <string name="item_moved" msgid="4606538322571412879">"అంశం తరలించబడింది"</string> <string name="add_to_folder" msgid="9040534766770853243">"ఈ ఫోల్డర్కి జోడించండి: <xliff:g id="NAME">%1$s</xliff:g>"</string> - <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> గల ఫోల్డర్కు జోడించు"</string> + <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> గల ఫోల్డర్కు జోడించండి"</string> <string name="added_to_folder" msgid="4793259502305558003">"అంశం ఫోల్డర్కు జోడించబడింది"</string> <string name="create_folder_with" msgid="4050141361160214248">"ఈ పేరుతో ఫోల్డర్ను క్రియేట్ చేయండి: <xliff:g id="NAME">%1$s</xliff:g>"</string> <string name="folder_created" msgid="6409794597405184510">"ఫోల్డర్ క్రియేట్ చేయబడింది"</string> <string name="action_move_to_workspace" msgid="39528912300293768">"మొదటి స్క్రీన్కు తరలించండి"</string> - <string name="action_resize" msgid="1802976324781771067">"పరిమాణం మార్చు"</string> + <string name="action_resize" msgid="1802976324781771067">"సైజ్ మార్చు"</string> <string name="action_increase_width" msgid="8773715375078513326">"వెడల్పును పెంచు"</string> <string name="action_increase_height" msgid="459390020612501122">"ఎత్తును పెంచు"</string> <string name="action_decrease_width" msgid="1374549771083094654">"వెడల్పును తగ్గించు"</string> <string name="action_decrease_height" msgid="282377193880900022">"ఎత్తును తగ్గించు"</string> - <string name="widget_resized" msgid="9130327887929620">"విడ్జెట్ పరిమాణం వెడల్పు <xliff:g id="NUMBER_0">%1$s</xliff:g>కి, ఎత్తు <xliff:g id="NUMBER_1">%2$s</xliff:g>కి మార్చబడింది"</string> + <string name="widget_resized" msgid="9130327887929620">"విడ్జెట్ సైజ్ వెడల్పు <xliff:g id="NUMBER_0">%1$s</xliff:g>కి, ఎత్తు <xliff:g id="NUMBER_1">%2$s</xliff:g>కి మార్చబడింది"</string> <string name="action_deep_shortcut" msgid="2864038805849372848">"షార్ట్కట్స్"</string> <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"షార్ట్కట్లు మరియు నోటిఫికేషన్లు"</string> <string name="action_dismiss_notification" msgid="5909461085055959187">"తీసివేయండి"</string> diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml index 7a75ddb5c4..cf4f000340 100644 --- a/res/values-v31/colors.xml +++ b/res/values-v31/colors.xml @@ -61,4 +61,6 @@ <color name="preload_icon_background_color_light">@android:color/system_accent2_200</color> <color name="preload_icon_accent_color_dark">@android:color/system_accent1_300</color> <color name="preload_icon_background_color_dark">@android:color/system_neutral2_700</color> + + <color name="all_apps_button_color">?android:attr/textColorSecondary</color> </resources> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 862341400f..08561d5d51 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -56,12 +56,6 @@ <attr name="preloadIconAccentColor" format="color" /> <attr name="preloadIconBackgroundColor" format="color" /> - <attr name="allAppsButtonBgColor" format="color" /> - <attr name="allAppsButtonColor1" format="color" /> - <attr name="allAppsButtonColor2" format="color" /> - <attr name="allAppsButtonColor3" format="color" /> - <attr name="allAppsButtonColor4" format="color" /> - <!-- BubbleTextView specific attributes. --> <declare-styleable name="BubbleTextView"> <attr name="layoutHorizontal" format="boolean" /> @@ -147,9 +141,12 @@ <attr name="numColumns" format="integer" /> <!-- numSearchContainerColumns defaults to numColumns, if not specified --> <attr name="numSearchContainerColumns" format="integer" /> + <!-- numFolderRows & numFolderColumns defaults to numRows & numColumns, if not specified --> <attr name="numFolderRows" format="integer" /> <attr name="numFolderColumns" format="integer" /> + <attr name="folderStyle" format="reference" /> + <!-- numAllAppsColumns defaults to numColumns, if not specified --> <attr name="numAllAppsColumns" format="integer" /> <!-- Number of columns to use when extending the all-apps size, @@ -179,7 +176,6 @@ <attr name="dbFile" format="string" /> <attr name="defaultLayoutId" format="reference" /> - <attr name="defaultSplitDisplayLayoutId" format="reference" /> <attr name="demoModeLayoutId" format="reference" /> <attr name="isScalable" format="boolean" /> <attr name="devicePaddingId" format="reference" /> @@ -217,6 +213,10 @@ <attr name="c" format="float|dimension" /> </declare-styleable> + <declare-styleable name="PersonalWorkSlidingTabStrip"> + <attr name="alignOnIcon" format="boolean" /> + </declare-styleable> + <declare-styleable name="ProfileDisplayOption"> <attr name="name" /> <attr name="minWidthDps" format="float" /> @@ -339,19 +339,6 @@ if not specified --> <attr name="allAppsBorderSpaceTwoPanelLandscapeVertical" format="float" /> - <!-- defaults to minCellHeight if not specified - when GridDisplayOption#isScalable is true. --> - <attr name="folderCellHeight" format="float" /> - <!-- defaults to minCellWidth, if not specified --> - <attr name="folderCellWidth" format="float" /> - - <!-- defaults to borderSpace, if not specified --> - <!-- space to be used horizontally and vertically --> - <attr name="folderBorderSpace" format="float" /> - - <!-- defaults to folderBorderSpace vertical, if not specified --> - <attr name="folderTopPadding" format="float" /> - <!-- defaults to res.hotseat_bar_bottom_space_default, if not specified --> <attr name="hotseatBarBottomSpace" format="float" /> <!-- defaults to hotseatBarBottomSpace, if not specified --> @@ -400,6 +387,22 @@ </declare-styleable> + <declare-styleable name="FolderDisplayStyle"> + <!-- defaults to minCellHeight if not specified + when GridDisplayOption#isScalable is true. --> + <attr name="folderCellHeight" format="dimension" /> + <!-- defaults to minCellWidth, if not specified --> + <attr name="folderCellWidth" format="dimension" /> + <!-- space to be used horizontally and vertically between icons, + and to the left and right of folder --> + <attr name="folderBorderSpace" format="dimension" /> + <!-- height of the footer of the folder --> + <attr name="folderFooterHeight" format="dimension" /> + <!-- padding on top of the folder --> + <attr name="folderTopPadding" format="dimension" /> + </declare-styleable> + + <declare-styleable name="CellLayout"> <attr name="containerType" format="integer"> <enum name="workspace" value="0" /> diff --git a/res/values/colors.xml b/res/values/colors.xml index 309a1c564a..9d6927b99a 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -80,11 +80,7 @@ <color name="workspace_accent_color_light">#ff8df5e3</color> <color name="workspace_accent_color_dark">#ff3d665f</color> - <color name="all_apps_button_bg_color">#F7F9FA</color> - <color name="all_apps_button_color_1">#00677E</color> - <color name="all_apps_button_color_2">#00677E</color> - <color name="all_apps_button_color_3">#5F757E</color> - <color name="all_apps_button_color_4">#005A6E</color> + <color name="all_apps_button_color">#40484B</color> <color name="preload_icon_accent_color_light">#00668B</color> <color name="preload_icon_background_color_light">#B5CAD7</color> diff --git a/res/values/config.xml b/res/values/config.xml index 11b6e8ca45..016420bf79 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -49,9 +49,6 @@ <!-- View tag key used to determine if we should fade in the child views.. --> <string name="popup_container_iterate_children" translatable="false">popup_container_iterate_children</string> - <!-- config used to determine if header protection is supported in AllApps --> - <bool name="config_header_protection_supported">false</bool> - <!-- Workspace --> <!-- The duration (in ms) of the fade animation on the object outlines, used when we are dragging objects around on the home screen. --> @@ -86,6 +83,7 @@ <string name="model_delegate_class" translatable="false"></string> <string name="window_manager_proxy_class" translatable="false"></string> <string name="secondary_display_predictions_class" translatable="false"></string> + <string name="widget_holder_factory_class" translatable="false"></string> <!-- View ID to use for QSB widget --> <item type="id" name="qsb_widget" /> @@ -205,6 +203,4 @@ <!-- The max scale for the wallpaper when it's zoomed in --> <item name="config_wallpaperMaxScale" format="float" type="dimen">0</item> - <string name="floating_task_package" translatable="false"></string> - <string name="floating_task_action" translatable="false"></string> </resources> diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 47584e2baf..4d2e1b7c6d 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -114,6 +114,8 @@ <dimen name="all_apps_tabs_indicator_height">2dp</dimen> <dimen name="all_apps_header_top_margin">33dp</dimen> <dimen name="all_apps_header_top_padding">36dp</dimen> + <!-- Additional top padding to add when Floating Searchbar is enabled. --> + <dimen name="all_apps_additional_top_padding_floating_search">16dp</dimen> <dimen name="all_apps_header_bottom_padding">14dp</dimen> <dimen name="all_apps_header_top_adjustment">6dp</dimen> <dimen name="all_apps_header_bottom_adjustment">4dp</dimen> @@ -147,6 +149,8 @@ <!-- Floating action button inside work tab to toggle work profile --> <dimen name="work_fab_height">56dp</dimen> <dimen name="work_fab_radius">16dp</dimen> + <dimen name="work_fab_icon_size">24dp</dimen> + <dimen name="work_fab_text_start_margin">8dp</dimen> <dimen name="work_card_padding_horizontal">10dp</dimen> <dimen name="work_card_button_height">52dp</dimen> <dimen name="work_fab_margin">16dp</dimen> @@ -255,7 +259,7 @@ <dimen name="folder_cell_y_padding">6dp</dimen> <!-- label text size = workspace text size multiplied by this scale --> <dimen name="folder_label_text_scale">1.14</dimen> - <dimen name="folder_label_height">56dp</dimen> + <dimen name="folder_footer_height_default">56dp</dimen> <dimen name="folder_content_padding_left_right">8dp</dimen> <dimen name="folder_content_padding_top">16dp</dimen> @@ -333,7 +337,7 @@ <!-- Snackbar --> <dimen name="snackbar_height">48dp</dimen> - <dimen name="snackbar_content_height">32dp</dimen> + <dimen name="snackbar_content_height">48dp</dimen> <dimen name="snackbar_padding">8dp</dimen> <dimen name="snackbar_min_margin_left_right">6dp</dimen> <dimen name="snackbar_max_margin_left_right">72dp</dimen> @@ -359,19 +363,34 @@ <dimen name="qsb_widget_height">0dp</dimen> <dimen name="qsb_shadow_height">0dp</dimen> <dimen name="min_hotseat_icon_space">18dp</dimen> + <dimen name="max_hotseat_icon_space">50dp</dimen> <dimen name="min_hotseat_qsb_width">0dp</dimen> - <dimen name="taskbar_icon_size">44dp</dimen> - <!-- Note that this applies to both sides of all icons, so visible space is double this. --> - <dimen name="taskbar_icon_spacing">8dp</dimen> + <dimen name="taskbar_icon_size">0dp</dimen> + <dimen name="transient_taskbar_icon_size">0dp</dimen> + <!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) --> + <dimen name="transient_taskbar_size">0dp</dimen> + <dimen name="transient_taskbar_margin">0dp</dimen> + <dimen name="transient_taskbar_shadow_blur">0dp</dimen> + <dimen name="transient_taskbar_key_shadow_distance">0dp</dimen> + <dimen name="transient_taskbar_stashed_size">0dp</dimen> + <dimen name="transient_taskbar_clamped_offset_bound">0dp</dimen> + <dimen name="taskbar_icon_spacing">0dp</dimen> <dimen name="taskbar_nav_buttons_size">0dp</dimen> <dimen name="taskbar_contextual_button_margin">0dp</dimen> <dimen name="taskbar_hotseat_nav_spacing">0dp</dimen> <dimen name="taskbar_button_margin_default">0dp</dimen> <dimen name="taskbar_button_space_inbetween">0dp</dimen> - <dimen name="taskbar_button_margin_5_5">0dp</dimen> + <dimen name="taskbar_button_space_inbetween_phone">0dp</dimen> + <dimen name="taskbar_button_margin_split">0dp</dimen> <dimen name="taskbar_button_margin_6_5">0dp</dimen> - <dimen name="taskbar_button_margin_4_5">0dp</dimen> - <dimen name="taskbar_button_margin_4_4">0dp</dimen> + <!-- Taskbar swipe up thresholds threshold --> + <dimen name="taskbar_nav_threshold">0dp</dimen> + <dimen name="taskbar_app_window_threshold">0dp</dimen> + <dimen name="taskbar_home_overview_threshold">0dp</dimen> + <dimen name="taskbar_catch_up_threshold">0dp</dimen> + <dimen name="taskbar_nav_threshold_v2">0dp</dimen> + <dimen name="taskbar_app_window_threshold_v2">0dp</dimen> + <dimen name="taskbar_home_overview_threshold_v2">0dp</dimen> <!-- Size of the maximum radius for the enforced rounded rectangles. --> <dimen name="enforced_rounded_corner_max_radius">16dp</dimen> @@ -426,4 +445,8 @@ <!-- State transition --> <item name="workspace_content_scale" format="float" type="dimen">0.97</item> + + <!-- Folder spaces --> + <dimen name="folder_top_padding_default">24dp</dimen> + <dimen name="folder_footer_horiz_padding">20dp</dimen> </resources> diff --git a/res/values/styles.xml b/res/values/styles.xml index 90553a160e..7582a30435 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -20,6 +20,7 @@ <resources> <!-- Launcher theme --> <style name="BaseLauncherTheme" parent="@android:style/Theme.DeviceDefault.Light"> + <item name="disabledIconAlpha">.54</item> <item name="android:colorBackgroundCacheHint">@null</item> <item name="android:colorEdgeEffect">#FF757575</item> <item name="android:windowActionBar">false</item> @@ -33,7 +34,6 @@ <item name="allAppsScrimColor">?android:attr/colorBackgroundFloating</item> <item name="allappsHeaderProtectionColor">@color/popup_color_tertiary_light</item> <item name="allAppsNavBarScrimColor">#66FFFFFF</item> - <item name="allAppsTheme">@style/AllAppsTheme</item> <item name="popupColorPrimary">@color/popup_color_primary_light</item> <item name="popupColorSecondary">@color/popup_color_secondary_light</item> <item name="popupColorTertiary">@color/popup_color_tertiary_light</item> @@ -61,7 +61,6 @@ <item name="iconOnlyShortcutColor">?android:attr/textColorSecondary</item> <item name="workProfileOverlayTextColor">#FF212121</item> <item name="eduHalfSheetBGColor">?android:attr/colorAccent</item> - <item name="disabledIconAlpha">.54</item> <item name="workspaceAccentColor">@color/workspace_accent_color_light</item> <item name="dropTargetHoverTextColor">@color/workspace_text_color_dark</item> <item name="overviewScrimColor">@color/overview_scrim</item> @@ -73,14 +72,9 @@ <item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:statusBarColor">#00000000</item> <item name="android:navigationBarColor">#00000000</item> - - </style> - <style name="LauncherTheme.DarkMainColor" parent="@style/LauncherTheme"> - <item name="disabledIconAlpha">.54</item> - - </style> + <style name="LauncherTheme.DarkMainColor" parent="@style/LauncherTheme" /> <style name="LauncherTheme.DarkText" parent="@style/LauncherTheme"> <item name="workspaceTextColor">@color/workspace_text_color_dark</item> @@ -102,7 +96,6 @@ <item name="android:colorPrimary">#FF212121</item> <item name="allAppsScrimColor">?android:attr/colorBackgroundFloating</item> <item name="allAppsNavBarScrimColor">#80000000</item> - <item name="allAppsTheme">@style/AllAppsTheme.Dark</item> <item name="popupColorPrimary">@color/popup_color_primary_dark</item> <item name="popupColorSecondary">@color/popup_color_secondary_dark</item> <item name="popupColorTertiary">@color/popup_color_tertiary_dark</item> @@ -129,9 +122,7 @@ <item name="preloadIconBackgroundColor">@color/preload_icon_background_color_dark</item> </style> - <style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark"> - <item name="disabledIconAlpha">.54</item> - </style> + <style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark"/> <style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark"> <item name="android:colorControlHighlight">#19212121</item> @@ -207,22 +198,6 @@ <item name="android:importantForAccessibility">no</item> </style> - <style name="AllAppsButtonTheme"> - <item name="allAppsButtonBgColor">@color/all_apps_button_bg_color</item> - <item name="allAppsButtonColor1">@color/all_apps_button_color_1</item> - <item name="allAppsButtonColor2">@color/all_apps_button_color_2</item> - <item name="allAppsButtonColor3">@color/all_apps_button_color_3</item> - <item name="allAppsButtonColor4">@color/all_apps_button_color_4</item> - </style> - - <style name="AllAppsTheme"> - <item name="disabledIconAlpha">.54</item> - </style> - - <style name="AllAppsTheme.Dark"> - <item name="disabledIconAlpha">.54</item> - </style> - <style name="BaseIconRoot" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/> <style name="BaseIconUnBounded" parent="BaseIconRoot"> @@ -317,4 +292,13 @@ <item name="android:windowLightStatusBar">true</item> <item name="android:windowTranslucentStatus">true</item> </style> + + <style name="FolderDefaultStyle"> + <item name="folderTopPadding">24dp</item> + <item name="folderCellHeight">94dp</item> + <item name="folderCellWidth">80dp</item> + <item name="folderBorderSpace">16dp</item> + <item name="folderFooterHeight">56dp</item> + </style> + </resources> diff --git a/res/xml/default_test2_workspace.xml b/res/xml/default_test2_workspace.xml new file mode 100644 index 0000000000..c560104b9e --- /dev/null +++ b/res/xml/default_test2_workspace.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Split display specific version of Launcher3/res/xml/default_workspace_4x4.xml --> +<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" > + + <!-- Hotseat (We use the screen as the position of the item in the hotseat) --> + <!-- Dialer Messaging Chrome Camera --> + <favorite + launcher:container="-101" + launcher:screen="0" + launcher:x="0" + launcher:y="0" + launcher:className="com.google.android.dialer.extensions.GoogleDialtactsActivity" + launcher:packageName="com.google.android.dialer" /> + + <favorite + launcher:container="-101" + launcher:screen="1" + launcher:x="1" + launcher:y="0" + launcher:className="com.google.android.apps.messaging.ui.ConversationListActivity" + launcher:packageName="com.google.android.apps.messaging" /> + + <favorite + launcher:container="-101" + launcher:screen="2" + launcher:x="2" + launcher:y="0" + launcher:className="com.google.android.apps.chrome.Main" + launcher:packageName="com.android.chrome" /> + + <favorite + launcher:container="-101" + launcher:screen="3" + launcher:x="3" + launcher:y="0" + launcher:className="com.android.camera.CameraLauncher" + launcher:packageName="com.google.android.GoogleCamera" /> + + <!-- Bottom row --> + <!-- Maps [space] [space] Play --> + <favorite + launcher:className="com.google.android.maps.MapsActivity" + launcher:packageName="com.google.android.apps.maps" + launcher:screen="0" + launcher:x="0" + launcher:y="-1" /> + + <favorite + launcher:className="com.android.vending.AssetBrowserActivity" + launcher:packageName="com.android.vending" + launcher:screen="0" + launcher:x="3" + launcher:y="-1" /> + + <!-- TODO: Place weather widget when it's available --> + +</favorites> diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index 407f2176b9..c9a44a1be0 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -57,8 +57,9 @@ launcher:numFolderRows="3" launcher:numFolderColumns="4" launcher:numHotseatIcons="4" + launcher:numExtendedHotseatIcons="6" launcher:dbFile="launcher_4_by_4.db" - launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_4_4" + launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_split" launcher:defaultLayoutId="@xml/default_workspace_4x4" launcher:deviceCategory="phone|multi_display" > @@ -121,8 +122,9 @@ launcher:numFolderRows="4" launcher:numFolderColumns="4" launcher:numHotseatIcons="5" + launcher:numExtendedHotseatIcons="6" launcher:dbFile="launcher.db" - launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_5_5" + launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_split" launcher:defaultLayoutId="@xml/default_workspace_5x5" launcher:deviceCategory="phone|multi_display" > diff --git a/res/xml/paddings_handhelds.xml b/res/xml/paddings_handhelds.xml new file mode 100644 index 0000000000..b9549a6133 --- /dev/null +++ b/res/xml/paddings_handhelds.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> + +<!-- Putting in the test/xml folder gives an error that maxEmptySpace doesn't exist --> +<device-paddings xmlns:launcher="http://schemas.android.com/apk/res-auto" > + + <device-padding + launcher:maxEmptySpace="9999dp"> + <workspaceTopPadding + launcher:a="0.48" + launcher:b="0"/> + <workspaceBottomPadding + launcher:a="0.52" + launcher:b="0"/> + <hotseatBottomPadding + launcher:a="0" + launcher:b="0"/> + </device-padding> +</device-paddings>
\ No newline at end of file diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index 5ee6fce1f7..28d4a9f7a8 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -94,6 +94,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch public static final int TYPE_TASKBAR_EDUCATION_DIALOG = 1 << 16; public static final int TYPE_TASKBAR_ALL_APPS = 1 << 17; public static final int TYPE_ADD_TO_HOME_CONFIRMATION = 1 << 18; + public static final int TYPE_TASKBAR_OVERLAY_PROXY = 1 << 19; public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET @@ -101,13 +102,15 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP | TYPE_WIDGETS_EDUCATION_DIALOG | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS - | TYPE_OPTIONS_POPUP_DIALOG | TYPE_ADD_TO_HOME_CONFIRMATION; + | TYPE_OPTIONS_POPUP_DIALOG | TYPE_ADD_TO_HOME_CONFIRMATION + | TYPE_TASKBAR_OVERLAY_PROXY; // Type of popups which should be kept open during launcher rebind public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_WIDGETS_EDUCATION_DIALOG - | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG; + | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG + | TYPE_TASKBAR_OVERLAY_PROXY; public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER & ~TYPE_ALL_APPS_EDU; diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index fbb0a57618..76a91c0029 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -32,6 +32,7 @@ import androidx.annotation.Nullable; import androidx.annotation.Px; import com.android.launcher3.accessibility.DragViewStateAnnouncer; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.keyboard.ViewGroupFocusHelper; import com.android.launcher3.logging.InstanceId; @@ -248,11 +249,11 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O /* widgetHandler= */ null, (ItemInfo) mWidgetView.getTag())); mLauncher - .getAppWidgetHost() - .startConfigActivity( - mLauncher, - mWidgetView.getAppWidgetId(), - Launcher.REQUEST_RECONFIGURE_APPWIDGET); + .getAppWidgetHolder() + .startConfigActivity( + mLauncher, + mWidgetView.getAppWidgetId(), + Launcher.REQUEST_RECONFIGURE_APPWIDGET); }); if (!hasSeenReconfigurableWidgetEducationTip()) { post(() -> { @@ -265,7 +266,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O } } - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) mWidgetView.getLayoutParams(); ItemInfo widgetInfo = (ItemInfo) mWidgetView.getTag(); lp.cellX = lp.tmpCellX = widgetInfo.cellX; lp.cellY = lp.tmpCellY = widgetInfo.cellY; @@ -405,7 +406,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O */ private void resizeWidgetIfNeeded(boolean onDismiss) { ViewGroup.LayoutParams wlp = mWidgetView.getLayoutParams(); - if (!(wlp instanceof CellLayout.LayoutParams)) { + if (!(wlp instanceof CellLayoutLayoutParams)) { return; } DeviceProfile dp = mLauncher.getDeviceProfile(); @@ -420,7 +421,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O mDirectionVector[0] = 0; mDirectionVector[1] = 0; - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) wlp; + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) wlp; int spanX = lp.cellHSpan; int spanY = lp.cellVSpan; diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java index 75e89b2944..eb6d096602 100644 --- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java +++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java @@ -2,7 +2,6 @@ package com.android.launcher3; import static android.os.Process.myUserHandle; -import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; @@ -12,6 +11,7 @@ import android.content.Intent; import android.database.Cursor; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherSettings.Favorites; @@ -21,7 +21,7 @@ import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.util.ContentWriter; -import com.android.launcher3.widget.LauncherAppWidgetHost; +import com.android.launcher3.widget.LauncherWidgetHolder; public class AppWidgetsRestoredReceiver extends BroadcastReceiver { @@ -32,7 +32,7 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) { int hostId = intent.getIntExtra(AppWidgetManager.EXTRA_HOST_ID, 0); Log.d(TAG, "Widget ID map received for host:" + hostId); - if (hostId != LauncherAppWidgetHost.APPWIDGET_HOST_ID) { + if (hostId != LauncherWidgetHolder.APPWIDGET_HOST_ID) { return; } @@ -50,11 +50,11 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { * Updates the app widgets whose id has changed during the restore process. */ @WorkerThread - public static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds) { - AppWidgetHost appWidgetHost = new LauncherAppWidgetHost(context); + public static void restoreAppWidgetIds(Context context, int[] oldWidgetIds, int[] newWidgetIds, + @NonNull LauncherWidgetHolder holder) { if (WidgetsModel.GO_DISABLE_WIDGETS) { Log.e(TAG, "Skipping widget ID remap as widgets not supported"); - appWidgetHost.deleteHost(); + holder.deleteHost(); return; } if (!RestoreDbTask.isPending(context)) { @@ -63,7 +63,7 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { Log.e(TAG, "Skipping widget ID remap as DB already in use"); for (int widgetId : newWidgetIds) { Log.d(TAG, "Deleting widgetId: " + widgetId); - appWidgetHost.deleteAppWidgetId(widgetId); + holder.deleteAppWidgetId(widgetId); } return; } @@ -100,7 +100,7 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { try { if (!cursor.moveToFirst()) { // The widget no long exists. - appWidgetHost.deleteAppWidgetId(newWidgetIds[i]); + holder.deleteAppWidgetId(newWidgetIds[i]); } } finally { cursor.close(); diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index 64666b0041..55ede6cecb 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -16,7 +16,6 @@ package com.android.launcher3; -import android.appwidget.AppWidgetHost; import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; @@ -32,7 +31,6 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.Log; -import android.util.Pair; import android.util.Patterns; import android.util.Xml; @@ -46,8 +44,9 @@ import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.qsb.QsbContainerView; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.PackageManagerHelper; +import com.android.launcher3.util.Partner; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.LauncherWidgetHolder; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -74,21 +73,18 @@ public class AutoInstallsLayout { private static final String FORMATTED_LAYOUT_RES = "default_layout_%dx%d"; private static final String LAYOUT_RES = "default_layout"; - static AutoInstallsLayout get(Context context, AppWidgetHost appWidgetHost, + static AutoInstallsLayout get(Context context, LauncherWidgetHolder appWidgetHolder, LayoutParserCallback callback) { - Pair<String, Resources> customizationApkInfo = PackageManagerHelper.findSystemApk( - ACTION_LAUNCHER_CUSTOMIZATION, context.getPackageManager()); - if (customizationApkInfo == null) { + Partner partner = Partner.get(context.getPackageManager(), ACTION_LAUNCHER_CUSTOMIZATION); + if (partner == null) { return null; } - String pkg = customizationApkInfo.first; - Resources targetRes = customizationApkInfo.second; InvariantDeviceProfile grid = LauncherAppState.getIDP(context); // Try with grid size and hotseat count String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT, grid.numColumns, grid.numRows, grid.numDatabaseHotseatIcons); - int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg); + int layoutId = partner.getXmlResId(layoutName); // Try with only grid size if (layoutId == 0) { @@ -96,21 +92,21 @@ public class AutoInstallsLayout { + " not found. Trying layout without hosteat"); layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES, grid.numColumns, grid.numRows); - layoutId = targetRes.getIdentifier(layoutName, "xml", pkg); + layoutId = partner.getXmlResId(layoutName); } // Try the default layout if (layoutId == 0) { Log.d(TAG, "Formatted layout: " + layoutName + " not found. Trying the default layout"); - layoutId = targetRes.getIdentifier(LAYOUT_RES, "xml", pkg); + layoutId = partner.getXmlResId(LAYOUT_RES); } if (layoutId == 0) { - Log.e(TAG, "Layout definition not found in package: " + pkg); + Log.e(TAG, "Layout definition not found in package: " + partner.getPackageName()); return null; } - return new AutoInstallsLayout(context, appWidgetHost, callback, targetRes, layoutId, - TAG_WORKSPACE); + return new AutoInstallsLayout(context, appWidgetHolder, callback, partner.getResources(), + layoutId, TAG_WORKSPACE); } // Object Tags @@ -156,7 +152,7 @@ public class AutoInstallsLayout { @Thunk final Context mContext; @Thunk - final AppWidgetHost mAppWidgetHost; + final LauncherWidgetHolder mAppWidgetHolder; protected final LayoutParserCallback mCallback; protected final PackageManager mPackageManager; @@ -174,17 +170,17 @@ public class AutoInstallsLayout { protected SQLiteDatabase mDb; - public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost, + public AutoInstallsLayout(Context context, LauncherWidgetHolder appWidgetHolder, LayoutParserCallback callback, Resources res, int layoutId, String rootTag) { - this(context, appWidgetHost, callback, res, () -> res.getXml(layoutId), rootTag); + this(context, appWidgetHolder, callback, res, () -> res.getXml(layoutId), rootTag); } - public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost, + public AutoInstallsLayout(Context context, LauncherWidgetHolder appWidgetHolder, LayoutParserCallback callback, Resources res, Supplier<XmlPullParser> initialLayoutSupplier, String rootTag) { mContext = context; - mAppWidgetHost = appWidgetHost; + mAppWidgetHolder = appWidgetHolder; mCallback = callback; mPackageManager = context.getPackageManager(); diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java index 83ff0849a6..61707dff49 100644 --- a/src/com/android/launcher3/BaseActivity.java +++ b/src/com/android/launcher3/BaseActivity.java @@ -30,14 +30,13 @@ import android.window.OnBackInvokedDispatcher; import androidx.annotation.IntDef; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.ViewCache; -import com.android.launcher3.views.AppLauncher; +import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.ScrimView; import java.io.PrintWriter; @@ -48,8 +47,7 @@ import java.util.List; /** * Launcher BaseActivity */ -public abstract class BaseActivity extends Activity implements AppLauncher, - DeviceProfileListenable { +public abstract class BaseActivity extends Activity implements ActivityContext { private static final String TAG = "BaseActivity"; @@ -196,8 +194,7 @@ public abstract class BaseActivity extends Activity implements AppLauncher, @Override protected void onResume() { - addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE); - removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE); + setResumed(); super.onResume(); } @@ -228,7 +225,7 @@ public abstract class BaseActivity extends Activity implements AppLauncher, @Override protected void onPause() { - removeActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_DEFERRED_RESUMED); + setPaused(); super.onPause(); // Reset the overridden sysui flags used for the task-swipe launch animation, we do this @@ -260,6 +257,21 @@ public abstract class BaseActivity extends Activity implements AppLauncher, return (mActivityFlags & ACTIVITY_STATE_RESUMED) != 0; } + /** + * Sets the activity to appear as paused. + */ + public void setPaused() { + removeActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_DEFERRED_RESUMED); + } + + /** + * Sets the activity to appear as resumed. + */ + public void setResumed() { + addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE); + removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE); + } + public boolean isUserActive() { return (mActivityFlags & ACTIVITY_STATE_USER_ACTIVE) != 0; } diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 6de3884b93..ca1fe40ed9 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -34,9 +34,6 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.allapps.ActivityAllAppsContainerView; -import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider; -import com.android.launcher3.allapps.search.SearchAdapterProvider; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.util.ActivityOptionsWrapper; @@ -212,16 +209,6 @@ public abstract class BaseDraggingActivity extends BaseActivity return new WindowBounds(new Rect(0, 0, mwSize.x, mwSize.y), new Rect()); } - /** - * Creates and returns {@link SearchAdapterProvider} for build variant specific search result - * views - */ - @Override - public SearchAdapterProvider<?> createSearchAdapterProvider( - ActivityAllAppsContainerView<?> allApps) { - return new DefaultSearchAdapterProvider(this); - } - @Override public boolean isAppBlockedForSafeMode() { return mIsSafeModeEnabled; diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 5fb892554a..9f54f09bb6 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -607,15 +607,16 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, * Get the icon bounds on the view depending on the layout type. */ public void getIconBounds(int iconSize, Rect outBounds) { - Utilities.setRectToViewCenter(this, iconSize, outBounds); + outBounds.set(0, 0, iconSize, iconSize); if (mLayoutHorizontal) { + int top = (getHeight() - iconSize) / 2; if (mIsRtl) { - outBounds.offsetTo(getWidth() - iconSize - getPaddingRight(), outBounds.top); + outBounds.offsetTo(getWidth() - iconSize - getPaddingRight(), top); } else { - outBounds.offsetTo(getPaddingLeft(), outBounds.top); + outBounds.offsetTo(getPaddingLeft(), top); } } else { - outBounds.offsetTo(outBounds.left, getPaddingTop()); + outBounds.offset((getWidth() - iconSize) / 2, getPaddingTop()); } } @@ -942,6 +943,11 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, return mIconSize; } + public boolean isDisplaySearchResult() { + return mDisplay == DISPLAY_SEARCH_RESULT || + mDisplay == DISPLAY_SEARCH_RESULT_SMALL; + } + private void updateTranslation() { super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x + mTranslationForMoveFromCenterAnimation.x diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java index 5abe3d3af6..ee3e278b8d 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -423,14 +423,15 @@ public abstract class ButtonDropTarget extends TextView float textSize = Utilities.pxToSp(getTextSize()); int availableWidth = getMeasuredWidth(); - while (textSize > minSize) { - if (isTextTruncated(availableWidth)) { - textSize -= step; + while (isTextTruncated(availableWidth)) { + textSize -= step; + if (textSize < minSize) { + textSize = minSize; setTextSize(textSize); - } else { - return textSize; + break; } + setTextSize(textSize); } - return minSize; + return textSize; } } diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 9f3e1fa924..ecfd2307c5 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -19,6 +19,7 @@ package com.android.launcher3; import static android.animation.ValueAnimator.areAnimatorsEnabled; import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5; +import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING; import static com.android.launcher3.dragndrop.DraggableView.DRAGGABLE_ICON; import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR; @@ -54,13 +55,13 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import androidx.annotation.IntDef; -import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import androidx.core.view.ViewCompat; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.folder.PreviewBackground; @@ -130,7 +131,7 @@ public class CellLayout extends ViewGroup { // These arrays are used to implement the drag visualization on x-large screens. // They are used as circular arrays, indexed by mDragOutlineCurrent. - @Thunk final CellLayout.LayoutParams[] mDragOutlines = new CellLayout.LayoutParams[4]; + @Thunk final CellLayoutLayoutParams[] mDragOutlines = new CellLayoutLayoutParams[4]; @Thunk final float[] mDragOutlineAlphas = new float[mDragOutlines.length]; private final InterruptibleInOutAnimator[] mDragOutlineAnims = new InterruptibleInOutAnimator[mDragOutlines.length]; @@ -139,7 +140,7 @@ public class CellLayout extends ViewGroup { private int mDragOutlineCurrent = 0; private final Paint mDragOutlinePaint = new Paint(); - @Thunk final ArrayMap<LayoutParams, Animator> mReorderAnimators = new ArrayMap<>(); + @Thunk final ArrayMap<CellLayoutLayoutParams, Animator> mReorderAnimators = new ArrayMap<>(); @Thunk final ArrayMap<Reorderable, ReorderPreviewAnimation> mShakeAnimators = new ArrayMap<>(); private boolean mItemPlacementDirty = false; @@ -191,7 +192,7 @@ public class CellLayout extends ViewGroup { private final Rect mOccupiedRect = new Rect(); private final int[] mDirectionVector = new int[2]; - final int[] mPreviousReorderDirection = new int[2]; + ItemConfiguration mPreviousSolution = null; private static final int INVALID_DIRECTION = -100; private final Rect mTempRect = new Rect(); @@ -245,9 +246,6 @@ public class CellLayout extends ViewGroup { mOccupied = new GridOccupancy(mCountX, mCountY); mTmpOccupied = new GridOccupancy(mCountX, mCountY); - mPreviousReorderDirection[0] = INVALID_DIRECTION; - mPreviousReorderDirection[1] = INVALID_DIRECTION; - mFolderLeaveBehind.mDelegateCellX = -1; mFolderLeaveBehind.mDelegateCellY = -1; @@ -269,7 +267,7 @@ public class CellLayout extends ViewGroup { mDragCell[0] = mDragCell[1] = -1; mDragCellSpan[0] = mDragCellSpan[1] = -1; for (int i = 0; i < mDragOutlines.length; i++) { - mDragOutlines[i] = new CellLayout.LayoutParams(0, 0, 0, 0); + mDragOutlines[i] = new CellLayoutLayoutParams(0, 0, 0, 0, -1); } mDragOutlinePaint.setColor(Themes.getAttrColor(context, R.attr.workspaceTextColor)); @@ -375,7 +373,8 @@ public class CellLayout extends ViewGroup { private void resetCellSizeInternal(DeviceProfile deviceProfile) { switch (mContainerType) { case FOLDER: - mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx); + mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx, + deviceProfile.folderCellLayoutBorderSpacePx); break; case HOTSEAT: mBorderSpace = new Point(deviceProfile.hotseatBorderSpace, @@ -404,7 +403,6 @@ public class CellLayout extends ViewGroup { mCountY = y; mOccupied = new GridOccupancy(mCountX, mCountY); mTmpOccupied = new GridOccupancy(mCountX, mCountY); - mTempRectStack.clear(); mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mCountX, mCountY, mBorderSpace); requestLayout(); @@ -551,7 +549,9 @@ public class CellLayout extends ViewGroup { public void setSpringLoadedProgress(float progress) { if (Float.compare(progress, mSpringLoadedProgress) != 0) { mSpringLoadedProgress = progress; - updateBgAlpha(); + if (!SHOW_HOME_GARDENING.get()) { + updateBgAlpha(); + } setGridAlpha(progress); } } @@ -576,7 +576,9 @@ public class CellLayout extends ViewGroup { public void setScrollProgress(float progress) { if (Float.compare(Math.abs(progress), mScrollProgress) != 0) { mScrollProgress = Math.abs(progress); - updateBgAlpha(); + if (!SHOW_HOME_GARDENING.get()) { + updateBgAlpha(); + } } } @@ -615,7 +617,7 @@ public class CellLayout extends ViewGroup { } } - if (mVisualizeDropLocation) { + if (mVisualizeDropLocation && !SHOW_HOME_GARDENING.get()) { for (int i = 0; i < mDragOutlines.length; i++) { final float alpha = mDragOutlineAlphas[i]; if (alpha <= 0) continue; @@ -737,9 +739,19 @@ public class CellLayout extends ViewGroup { return mContainerType == WORKSPACE; } - public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params, - boolean markCells) { - final LayoutParams lp = params; + /** + * Adds the given view to the CellLayout + * + * @param child view to add. + * @param index index of the CellLayout children where to add the view. + * @param childId id of the view. + * @param params represent the logic of the view on the CellLayout. + * @param markCells if the occupied cells should be marked or not + * @return if adding the view was successful + */ + public boolean addViewToCellLayout(View child, int index, int childId, + CellLayoutLayoutParams params, boolean markCells) { + final CellLayoutLayoutParams lp = params; // Hotseat icons - remove text if (child instanceof BubbleTextView) { @@ -926,7 +938,7 @@ public class CellLayout extends ViewGroup { cellToRect(targetCell[0], targetCell[1], spanX, spanY, cellBoundsWithSpacing); cellBoundsWithSpacing.inset(-mBorderSpace.x / 2, -mBorderSpace.y / 2); - if (canCreateFolder(getChildAt(targetCell[0], targetCell[1]))) { + if (canCreateFolder(getChildAt(targetCell[0], targetCell[1])) && spanX == 1 && spanY == 1) { // Take only the circle in the smaller dimension, to ensure we don't start reordering // too soon before accepting a folder drop. int minRadius = centerPoint[0] - cellBoundsWithSpacing.left; @@ -936,8 +948,9 @@ public class CellLayout extends ViewGroup { return minRadius; } // Take up the entire cell, including space between this cell and the adjacent ones. - return (float) Math.hypot(cellBoundsWithSpacing.width() / 2f, - cellBoundsWithSpacing.height() / 2f); + // Multiply by span to scale radius + return (float) Math.hypot(spanX * cellBoundsWithSpacing.width() / 2f, + spanY * cellBoundsWithSpacing.height() / 2f); } public int getCellWidth() { @@ -1046,7 +1059,7 @@ public class CellLayout extends ViewGroup { ShortcutAndWidgetContainer clc = getShortcutsAndWidgets(); if (clc.indexOfChild(child) != -1 && (child instanceof Reorderable)) { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + final CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); final ItemInfo info = (ItemInfo) child.getTag(); final Reorderable item = (Reorderable) child; @@ -1153,7 +1166,7 @@ public class CellLayout extends ViewGroup { mDragOutlineAnims[oldIndex].animateOut(); mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length; - LayoutParams cell = mDragOutlines[mDragOutlineCurrent]; + CellLayoutLayoutParams cell = mDragOutlines[mDragOutlineCurrent]; cell.cellX = cellX; cell.cellY = cellY; cell.cellHSpan = spanX; @@ -1234,21 +1247,6 @@ public class CellLayout extends ViewGroup { result, resultSpan); } - private final Stack<Rect> mTempRectStack = new Stack<>(); - private void lazyInitTempRectStack() { - if (mTempRectStack.isEmpty()) { - for (int i = 0; i < mCountX * mCountY; i++) { - mTempRectStack.push(new Rect()); - } - } - } - - private void recycleTempRects(Stack<Rect> used) { - while (!used.isEmpty()) { - mTempRectStack.push(used.pop()); - } - } - /** * Find a vacant area that will fit the given bounds nearest the requested * cell location. Uses Euclidean distance to score multiple vacant areas. @@ -1268,8 +1266,6 @@ public class CellLayout extends ViewGroup { */ private int[] findNearestArea(int relativeXPos, int relativeYPos, int minSpanX, int minSpanY, int spanX, int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) { - lazyInitTempRectStack(); - // For items with a spanX / spanY > 1, the passed in point (relativeXPos, relativeYPos) // corresponds to the center of the item, but we are searching based on the top-left cell, // so we translate the point over to correspond to the top-left. @@ -1339,9 +1335,6 @@ public class CellLayout extends ViewGroup { hitMaxY |= ySize >= spanY; incX = !incX; } - incX = true; - hitMaxX = xSize >= spanX; - hitMaxY = ySize >= spanY; } final int[] cellXY = mTmpPoint; cellToCenterPoint(x, y, cellXY); @@ -1349,8 +1342,7 @@ public class CellLayout extends ViewGroup { // We verify that the current rect is not a sub-rect of any of our previous // candidates. In this case, the current rect is disqualified in favour of the // containing rect. - Rect currentRect = mTempRectStack.pop(); - currentRect.set(x, y, x + xSize, y + ySize); + Rect currentRect = new Rect(x, y, x + xSize, y + ySize); boolean contained = false; for (Rect r : validRegions) { if (r.contains(currentRect)) { @@ -1380,10 +1372,399 @@ public class CellLayout extends ViewGroup { bestXY[0] = -1; bestXY[1] = -1; } - recycleTempRects(validRegions); return bestXY; } + private void copySolutionToTempState(ItemConfiguration solution, View dragView) { + mTmpOccupied.clear(); + + int childCount = mShortcutsAndWidgets.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = mShortcutsAndWidgets.getChildAt(i); + if (child == dragView) continue; + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); + CellAndSpan c = solution.map.get(child); + if (c != null) { + lp.tmpCellX = c.cellX; + lp.tmpCellY = c.cellY; + lp.cellHSpan = c.spanX; + lp.cellVSpan = c.spanY; + mTmpOccupied.markCells(c, true); + } + } + mTmpOccupied.markCells(solution, true); + } + + private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean + commitDragView) { + + GridOccupancy occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied; + occupied.clear(); + + int childCount = mShortcutsAndWidgets.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = mShortcutsAndWidgets.getChildAt(i); + if (child == dragView) continue; + CellAndSpan c = solution.map.get(child); + if (c != null) { + animateChildToPosition(child, c.cellX, c.cellY, REORDER_ANIMATION_DURATION, 0, + DESTRUCTIVE_REORDER, false); + occupied.markCells(c, true); + } + } + if (commitDragView) { + occupied.markCells(solution, true); + } + } + + + // This method starts or changes the reorder preview animations + private void beginOrAdjustReorderPreviewAnimations(ItemConfiguration solution, + View dragView, int mode) { + int childCount = mShortcutsAndWidgets.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = mShortcutsAndWidgets.getChildAt(i); + if (child == dragView) continue; + CellAndSpan c = solution.map.get(child); + boolean skip = mode == ReorderPreviewAnimation.MODE_HINT && solution.intersectingViews + != null && !solution.intersectingViews.contains(child); + + + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); + if (c != null && !skip && (child instanceof Reorderable)) { + ReorderPreviewAnimation rha = new ReorderPreviewAnimation((Reorderable) child, + mode, lp.cellX, lp.cellY, c.cellX, c.cellY, c.spanX, c.spanY); + rha.animate(); + } + } + } + + private static final Property<ReorderPreviewAnimation, Float> ANIMATION_PROGRESS = + new Property<ReorderPreviewAnimation, Float>(float.class, "animationProgress") { + @Override + public Float get(ReorderPreviewAnimation anim) { + return anim.animationProgress; + } + + @Override + public void set(ReorderPreviewAnimation anim, Float progress) { + anim.setAnimationProgress(progress); + } + }; + + // Class which represents the reorder preview animations. These animations show that an item is + // in a temporary state, and hint at where the item will return to. + class ReorderPreviewAnimation { + final Reorderable child; + float finalDeltaX; + float finalDeltaY; + float initDeltaX; + float initDeltaY; + final float finalScale; + float initScale; + final int mode; + boolean repeating = false; + private static final int PREVIEW_DURATION = 300; + private static final int HINT_DURATION = Workspace.REORDER_TIMEOUT; + + private static final float CHILD_DIVIDEND = 4.0f; + + public static final int MODE_HINT = 0; + public static final int MODE_PREVIEW = 1; + + float animationProgress = 0; + ValueAnimator a; + + public ReorderPreviewAnimation(Reorderable child, int mode, int cellX0, int cellY0, + int cellX1, int cellY1, int spanX, int spanY) { + regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint); + final int x0 = mTmpPoint[0]; + final int y0 = mTmpPoint[1]; + regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint); + final int x1 = mTmpPoint[0]; + final int y1 = mTmpPoint[1]; + final int dX = x1 - x0; + final int dY = y1 - y0; + + this.child = child; + this.mode = mode; + finalDeltaX = 0; + finalDeltaY = 0; + + child.getReorderBounceOffset(mTmpPointF); + initDeltaX = mTmpPointF.x; + initDeltaY = mTmpPointF.y; + initScale = child.getReorderBounceScale(); + finalScale = mChildScale - (CHILD_DIVIDEND / child.getView().getWidth()) * initScale; + + int dir = mode == MODE_HINT ? -1 : 1; + if (dX == dY && dX == 0) { + } else { + if (dY == 0) { + finalDeltaX = -dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude; + } else if (dX == 0) { + finalDeltaY = -dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude; + } else { + double angle = Math.atan( (float) (dY) / dX); + finalDeltaX = (int) (-dir * Math.signum(dX) + * Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude)); + finalDeltaY = (int) (-dir * Math.signum(dY) + * Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude)); + } + } + } + + void setInitialAnimationValuesToBaseline() { + initScale = mChildScale; + initDeltaX = 0; + initDeltaY = 0; + } + + void animate() { + boolean noMovement = (finalDeltaX == 0) && (finalDeltaY == 0); + + if (mShakeAnimators.containsKey(child)) { + ReorderPreviewAnimation oldAnimation = mShakeAnimators.get(child); + mShakeAnimators.remove(child); + + if (noMovement) { + // A previous animation for this item exists, and no new animation will exist. + // Finish the old animation smoothly. + oldAnimation.finishAnimation(); + return; + } else { + // A previous animation for this item exists, and a new one will exist. Stop + // the old animation in its tracks, and proceed with the new one. + oldAnimation.cancel(); + } + } + if (noMovement) { + return; + } + + ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0, 1); + a = va; + + // Animations are disabled in power save mode, causing the repeated animation to jump + // spastically between beginning and end states. Since this looks bad, we don't repeat + // the animation in power save mode. + if (areAnimatorsEnabled()) { + va.setRepeatMode(ValueAnimator.REVERSE); + va.setRepeatCount(ValueAnimator.INFINITE); + } + + va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION); + va.setStartDelay((int) (Math.random() * 60)); + va.addListener(new AnimatorListenerAdapter() { + public void onAnimationRepeat(Animator animation) { + // We make sure to end only after a full period + setInitialAnimationValuesToBaseline(); + repeating = true; + } + }); + mShakeAnimators.put(child, this); + va.start(); + } + + private void setAnimationProgress(float progress) { + animationProgress = progress; + float r1 = (mode == MODE_HINT && repeating) ? 1.0f : animationProgress; + float x = r1 * finalDeltaX + (1 - r1) * initDeltaX; + float y = r1 * finalDeltaY + (1 - r1) * initDeltaY; + child.setReorderBounceOffset(x, y); + float s = animationProgress * finalScale + (1 - animationProgress) * initScale; + child.setReorderBounceScale(s); + } + + private void cancel() { + if (a != null) { + a.cancel(); + } + } + + /** + * Smoothly returns the item to its baseline position / scale + */ + @Thunk void finishAnimation() { + if (a != null) { + a.cancel(); + } + + setInitialAnimationValuesToBaseline(); + ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, + animationProgress, 0); + a = va; + a.setInterpolator(DEACCEL_1_5); + a.setDuration(REORDER_ANIMATION_DURATION); + a.start(); + } + } + + private void completeAndClearReorderPreviewAnimations() { + for (ReorderPreviewAnimation a: mShakeAnimators.values()) { + a.finishAnimation(); + } + mShakeAnimators.clear(); + } + + private void commitTempPlacement(View dragView) { + mTmpOccupied.copyTo(mOccupied); + + int screenId = getWorkspace().getIdForScreen(this); + int container = Favorites.CONTAINER_DESKTOP; + + if (mContainerType == HOTSEAT) { + screenId = -1; + container = Favorites.CONTAINER_HOTSEAT; + } + + int childCount = mShortcutsAndWidgets.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = mShortcutsAndWidgets.getChildAt(i); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); + ItemInfo info = (ItemInfo) child.getTag(); + // We do a null check here because the item info can be null in the case of the + // AllApps button in the hotseat. + if (info != null && child != dragView) { + final boolean requiresDbUpdate = (info.cellX != lp.tmpCellX + || info.cellY != lp.tmpCellY || info.spanX != lp.cellHSpan + || info.spanY != lp.cellVSpan); + + info.cellX = lp.cellX = lp.tmpCellX; + info.cellY = lp.cellY = lp.tmpCellY; + info.spanX = lp.cellHSpan; + info.spanY = lp.cellVSpan; + + if (requiresDbUpdate) { + Launcher.cast(mActivity).getModelWriter().modifyItemInDatabase(info, container, + screenId, info.cellX, info.cellY, info.spanX, info.spanY); + } + } + } + } + + private void setUseTempCoords(boolean useTempCoords) { + int childCount = mShortcutsAndWidgets.getChildCount(); + for (int i = 0; i < childCount; i++) { + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) mShortcutsAndWidgets.getChildAt( + i).getLayoutParams(); + lp.useTmpCoords = useTempCoords; + } + } + + /** + * Returns a "reorder" where we simply drop the item in the closest empty space, without moving + * any other item in the way. + * + * @param pixelX X coordinate in pixels in the screen + * @param pixelY Y coordinate in pixels in the screen + * @param spanX horizontal cell span + * @param spanY vertical cell span + * @return the configuration that represents the found reorder + */ + private ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY, int minSpanX, + int minSpanY, int spanX, int spanY) { + ItemConfiguration solution = new ItemConfiguration(); + int[] result = new int[2]; + int[] resultSpan = new int[2]; + findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result, + resultSpan); + if (result[0] >= 0 && result[1] >= 0) { + copyCurrentStateToSolution(solution, false); + solution.cellX = result[0]; + solution.cellY = result[1]; + solution.spanX = resultSpan[0]; + solution.spanY = resultSpan[1]; + solution.isSolution = true; + } else { + solution.isSolution = false; + } + return solution; + } + + // For a given cell and span, fetch the set of views intersecting the region. + private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, + View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { + if (boundingRect != null) { + boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); + } + intersectingViews.clear(); + Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); + Rect r1 = new Rect(); + final int count = mShortcutsAndWidgets.getChildCount(); + for (int i = 0; i < count; i++) { + View child = mShortcutsAndWidgets.getChildAt(i); + if (child == dragView) continue; + CellLayoutLayoutParams + lp = (CellLayoutLayoutParams) child.getLayoutParams(); + r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); + if (Rect.intersects(r0, r1)) { + mIntersectingViews.add(child); + if (boundingRect != null) { + boundingRect.union(r1); + } + } + } + } + + boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, + View dragView, int[] result) { + result = findNearestAreaIgnoreOccupied(pixelX, pixelY, spanX, spanY, result); + getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, + mIntersectingViews); + return !mIntersectingViews.isEmpty(); + } + + void revertTempState() { + completeAndClearReorderPreviewAnimations(); + if (isItemPlacementDirty() && !DESTRUCTIVE_REORDER) { + final int count = mShortcutsAndWidgets.getChildCount(); + for (int i = 0; i < count; i++) { + View child = mShortcutsAndWidgets.getChildAt(i); + CellLayoutLayoutParams + lp = (CellLayoutLayoutParams) child.getLayoutParams(); + if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { + lp.tmpCellX = lp.cellX; + lp.tmpCellY = lp.cellY; + animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, + 0, false, false); + } + } + setItemPlacementDirty(false); + } + } + + boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, + View dragView, int[] direction, boolean commit) { + int[] pixelXY = new int[2]; + regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); + + // First we determine if things have moved enough to cause a different layout + ItemConfiguration swapSolution = findReorderSolution(pixelXY[0], pixelXY[1], spanX, spanY, + spanX, spanY, direction, dragView, true, new ItemConfiguration()); + + setUseTempCoords(true); + if (swapSolution != null && swapSolution.isSolution) { + // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother + // committing anything or animating anything as we just want to determine if a solution + // exists + copySolutionToTempState(swapSolution, dragView); + setItemPlacementDirty(true); + animateItemsToSolution(swapSolution, dragView, commit); + + if (commit) { + commitTempPlacement(null); + completeAndClearReorderPreviewAnimations(); + setItemPlacementDirty(false); + } else { + beginOrAdjustReorderPreviewAnimations(swapSolution, dragView, + ReorderPreviewAnimation.MODE_PREVIEW); + } + mShortcutsAndWidgets.requestLayout(); + } + return swapSolution.isSolution; + } + /** * Find a vacant area that will fit the given bounds nearest the requested * cell location, and will also weigh in a suggested direction vector of the @@ -1470,6 +1851,101 @@ public class CellLayout extends ViewGroup { return success; } + private boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, + int[] direction, View dragView, ItemConfiguration currentState) { + + ViewCluster cluster = new ViewCluster(views, currentState); + Rect clusterRect = cluster.getBoundingRect(); + int whichEdge; + int pushDistance; + boolean fail = false; + + // Determine the edge of the cluster that will be leading the push and how far + // the cluster must be shifted. + if (direction[0] < 0) { + whichEdge = ViewCluster.LEFT; + pushDistance = clusterRect.right - rectOccupiedByPotentialDrop.left; + } else if (direction[0] > 0) { + whichEdge = ViewCluster.RIGHT; + pushDistance = rectOccupiedByPotentialDrop.right - clusterRect.left; + } else if (direction[1] < 0) { + whichEdge = ViewCluster.TOP; + pushDistance = clusterRect.bottom - rectOccupiedByPotentialDrop.top; + } else { + whichEdge = ViewCluster.BOTTOM; + pushDistance = rectOccupiedByPotentialDrop.bottom - clusterRect.top; + } + + // Break early for invalid push distance. + if (pushDistance <= 0) { + return false; + } + + // Mark the occupied state as false for the group of views we want to move. + for (View v: views) { + CellAndSpan c = currentState.map.get(v); + mTmpOccupied.markCells(c, false); + } + + // We save the current configuration -- if we fail to find a solution we will revert + // to the initial state. The process of finding a solution modifies the configuration + // in place, hence the need for revert in the failure case. + currentState.save(); + + // The pushing algorithm is simplified by considering the views in the order in which + // they would be pushed by the cluster. For example, if the cluster is leading with its + // left edge, we consider sort the views by their right edge, from right to left. + cluster.sortConfigurationForEdgePush(whichEdge); + + while (pushDistance > 0 && !fail) { + for (View v: currentState.sortedViews) { + // For each view that isn't in the cluster, we see if the leading edge of the + // cluster is contacting the edge of that view. If so, we add that view to the + // cluster. + if (!cluster.views.contains(v) && v != dragView) { + if (cluster.isViewTouchingEdge(v, whichEdge)) { + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) v.getLayoutParams(); + if (!lp.canReorder) { + // The push solution includes the all apps button, this is not viable. + fail = true; + break; + } + cluster.addView(v); + CellAndSpan c = currentState.map.get(v); + + // Adding view to cluster, mark it as not occupied. + mTmpOccupied.markCells(c, false); + } + } + } + pushDistance--; + + // The cluster has been completed, now we move the whole thing over in the appropriate + // direction. + cluster.shift(whichEdge, 1); + } + + boolean foundSolution = false; + clusterRect = cluster.getBoundingRect(); + + // Due to the nature of the algorithm, the only check required to verify a valid solution + // is to ensure that completed shifted cluster lies completely within the cell layout. + if (!fail && clusterRect.left >= 0 && clusterRect.right <= mCountX && clusterRect.top >= 0 && + clusterRect.bottom <= mCountY) { + foundSolution = true; + } else { + currentState.restore(); + } + + // In either case, we set the occupied array as marked for the location of the views + for (View v: cluster.views) { + CellAndSpan c = currentState.map.get(v); + mTmpOccupied.markCells(c, true); + } + + return foundSolution; + } + /** * This helper class defines a cluster of views. It helps with defining complex edges * of the cluster and determining how those edges interact with other views. The edges @@ -1655,152 +2131,6 @@ public class CellLayout extends ViewGroup { } } - private boolean pushViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, - int[] direction, View dragView, ItemConfiguration currentState) { - - ViewCluster cluster = new ViewCluster(views, currentState); - Rect clusterRect = cluster.getBoundingRect(); - int whichEdge; - int pushDistance; - boolean fail = false; - - // Determine the edge of the cluster that will be leading the push and how far - // the cluster must be shifted. - if (direction[0] < 0) { - whichEdge = ViewCluster.LEFT; - pushDistance = clusterRect.right - rectOccupiedByPotentialDrop.left; - } else if (direction[0] > 0) { - whichEdge = ViewCluster.RIGHT; - pushDistance = rectOccupiedByPotentialDrop.right - clusterRect.left; - } else if (direction[1] < 0) { - whichEdge = ViewCluster.TOP; - pushDistance = clusterRect.bottom - rectOccupiedByPotentialDrop.top; - } else { - whichEdge = ViewCluster.BOTTOM; - pushDistance = rectOccupiedByPotentialDrop.bottom - clusterRect.top; - } - - // Break early for invalid push distance. - if (pushDistance <= 0) { - return false; - } - - // Mark the occupied state as false for the group of views we want to move. - for (View v: views) { - CellAndSpan c = currentState.map.get(v); - mTmpOccupied.markCells(c, false); - } - - // We save the current configuration -- if we fail to find a solution we will revert - // to the initial state. The process of finding a solution modifies the configuration - // in place, hence the need for revert in the failure case. - currentState.save(); - - // The pushing algorithm is simplified by considering the views in the order in which - // they would be pushed by the cluster. For example, if the cluster is leading with its - // left edge, we consider sort the views by their right edge, from right to left. - cluster.sortConfigurationForEdgePush(whichEdge); - - while (pushDistance > 0 && !fail) { - for (View v: currentState.sortedViews) { - // For each view that isn't in the cluster, we see if the leading edge of the - // cluster is contacting the edge of that view. If so, we add that view to the - // cluster. - if (!cluster.views.contains(v) && v != dragView) { - if (cluster.isViewTouchingEdge(v, whichEdge)) { - LayoutParams lp = (LayoutParams) v.getLayoutParams(); - if (!lp.canReorder) { - // The push solution includes the all apps button, this is not viable. - fail = true; - break; - } - cluster.addView(v); - CellAndSpan c = currentState.map.get(v); - - // Adding view to cluster, mark it as not occupied. - mTmpOccupied.markCells(c, false); - } - } - } - pushDistance--; - - // The cluster has been completed, now we move the whole thing over in the appropriate - // direction. - cluster.shift(whichEdge, 1); - } - - boolean foundSolution = false; - clusterRect = cluster.getBoundingRect(); - - // Due to the nature of the algorithm, the only check required to verify a valid solution - // is to ensure that completed shifted cluster lies completely within the cell layout. - if (!fail && clusterRect.left >= 0 && clusterRect.right <= mCountX && clusterRect.top >= 0 && - clusterRect.bottom <= mCountY) { - foundSolution = true; - } else { - currentState.restore(); - } - - // In either case, we set the occupied array as marked for the location of the views - for (View v: cluster.views) { - CellAndSpan c = currentState.map.get(v); - mTmpOccupied.markCells(c, true); - } - - return foundSolution; - } - - private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, - int[] direction, View dragView, ItemConfiguration currentState) { - if (views.size() == 0) return true; - - boolean success = false; - Rect boundingRect = new Rect(); - // We construct a rect which represents the entire group of views passed in - currentState.getBoundingRectForViews(views, boundingRect); - - // Mark the occupied state as false for the group of views we want to move. - for (View v: views) { - CellAndSpan c = currentState.map.get(v); - mTmpOccupied.markCells(c, false); - } - - GridOccupancy blockOccupied = new GridOccupancy(boundingRect.width(), boundingRect.height()); - int top = boundingRect.top; - int left = boundingRect.left; - // We mark more precisely which parts of the bounding rect are truly occupied, allowing - // for interlocking. - for (View v: views) { - CellAndSpan c = currentState.map.get(v); - blockOccupied.markCells(c.cellX - left, c.cellY - top, c.spanX, c.spanY, true); - } - - mTmpOccupied.markCells(rectOccupiedByPotentialDrop, true); - - findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), - boundingRect.height(), direction, - mTmpOccupied.cells, blockOccupied.cells, mTempLocation); - - // If we successfuly found a location by pushing the block of views, we commit it - if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { - int deltaX = mTempLocation[0] - boundingRect.left; - int deltaY = mTempLocation[1] - boundingRect.top; - for (View v: views) { - CellAndSpan c = currentState.map.get(v); - c.cellX += deltaX; - c.cellY += deltaY; - } - success = true; - } - - // In either case, we set the occupied array as marked for the location of the views - for (View v: views) { - CellAndSpan c = currentState.map.get(v); - mTmpOccupied.markCells(c, true); - } - return success; - } - // This method tries to find a reordering solution which satisfies the push mechanic by trying // to push items in each of the cardinal directions, in an order based on the direction vector // passed. @@ -1898,6 +2228,123 @@ public class CellLayout extends ViewGroup { return false; } + /* + * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between + * the provided point and the provided cell + */ + private void computeDirectionVector(float deltaX, float deltaY, int[] result) { + double angle = Math.atan(deltaY / deltaX); + + result[0] = 0; + result[1] = 0; + if (Math.abs(Math.cos(angle)) > 0.5f) { + result[0] = (int) Math.signum(deltaX); + } + if (Math.abs(Math.sin(angle)) > 0.5f) { + result[1] = (int) Math.signum(deltaY); + } + } + + /* This seems like it should be obvious and straight-forward, but when the direction vector + needs to match with the notion of the dragView pushing other views, we have to employ + a slightly more subtle notion of the direction vector. The question is what two points is + the vector between? The center of the dragView and its desired destination? Not quite, as + this doesn't necessarily coincide with the interaction of the dragView and items occupying + those cells. Instead we use some heuristics to often lock the vector to up, down, left + or right, which helps make pushing feel right. + */ + private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, + int spanY, View dragView, int[] resultDirection) { + + //TODO(adamcohen) b/151776141 use the items visual center for the direction vector + int[] targetDestination = new int[2]; + + findNearestAreaIgnoreOccupied(dragViewCenterX, dragViewCenterY, spanX, spanY, + targetDestination); + Rect dragRect = new Rect(); + cellToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); + dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); + + Rect dropRegionRect = new Rect(); + getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, + dragView, dropRegionRect, mIntersectingViews); + + int dropRegionSpanX = dropRegionRect.width(); + int dropRegionSpanY = dropRegionRect.height(); + + cellToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), + dropRegionRect.height(), dropRegionRect); + + int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; + int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; + + if (dropRegionSpanX == mCountX || spanX == mCountX) { + deltaX = 0; + } + if (dropRegionSpanY == mCountY || spanY == mCountY) { + deltaY = 0; + } + + if (deltaX == 0 && deltaY == 0) { + // No idea what to do, give a random direction. + resultDirection[0] = 1; + resultDirection[1] = 0; + } else { + computeDirectionVector(deltaX, deltaY, resultDirection); + } + } + + private boolean addViewsToTempLocation(ArrayList<View> views, Rect rectOccupiedByPotentialDrop, + int[] direction, View dragView, ItemConfiguration currentState) { + if (views.size() == 0) return true; + + boolean success = false; + Rect boundingRect = new Rect(); + // We construct a rect which represents the entire group of views passed in + currentState.getBoundingRectForViews(views, boundingRect); + + // Mark the occupied state as false for the group of views we want to move. + for (View v: views) { + CellAndSpan c = currentState.map.get(v); + mTmpOccupied.markCells(c, false); + } + + GridOccupancy blockOccupied = new GridOccupancy(boundingRect.width(), boundingRect.height()); + int top = boundingRect.top; + int left = boundingRect.left; + // We mark more precisely which parts of the bounding rect are truly occupied, allowing + // for interlocking. + for (View v: views) { + CellAndSpan c = currentState.map.get(v); + blockOccupied.markCells(c.cellX - left, c.cellY - top, c.spanX, c.spanY, true); + } + + mTmpOccupied.markCells(rectOccupiedByPotentialDrop, true); + + findNearestArea(boundingRect.left, boundingRect.top, boundingRect.width(), + boundingRect.height(), direction, + mTmpOccupied.cells, blockOccupied.cells, mTempLocation); + + // If we successfully found a location by pushing the block of views, we commit it + if (mTempLocation[0] >= 0 && mTempLocation[1] >= 0) { + int deltaX = mTempLocation[0] - boundingRect.left; + int deltaY = mTempLocation[1] - boundingRect.top; + for (View v: views) { + CellAndSpan c = currentState.map.get(v); + c.cellX += deltaX; + c.cellY += deltaY; + } + success = true; + } + + // In either case, we set the occupied array as marked for the location of the views + for (View v: views) { + CellAndSpan c = currentState.map.get(v); + mTmpOccupied.markCells(c, true); + } + return success; + } + private boolean rearrangementExists(int cellX, int cellY, int spanX, int spanY, int[] direction, View ignoreView, ItemConfiguration solution) { // Return early if get invalid cell positions @@ -1919,7 +2366,7 @@ public class CellLayout extends ViewGroup { for (View child: solution.map.keySet()) { if (child == ignoreView) continue; CellAndSpan c = solution.map.get(child); - LayoutParams lp = (LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); r1.set(c.cellX, c.cellY, c.cellX + c.spanX, c.cellY + c.spanY); if (Rect.intersects(r0, r1)) { if (!lp.canReorder) { @@ -1954,23 +2401,6 @@ public class CellLayout extends ViewGroup { return true; } - /* - * Returns a pair (x, y), where x,y are in {-1, 0, 1} corresponding to vector between - * the provided point and the provided cell - */ - private void computeDirectionVector(float deltaX, float deltaY, int[] result) { - double angle = Math.atan(deltaY / deltaX); - - result[0] = 0; - result[1] = 0; - if (Math.abs(Math.cos(angle)) > 0.5f) { - result[0] = (int) Math.signum(deltaX); - } - if (Math.abs(Math.sin(angle)) > 0.5f) { - result[1] = (int) Math.signum(deltaY); - } - } - private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX, ItemConfiguration solution) { @@ -1983,7 +2413,7 @@ public class CellLayout extends ViewGroup { // We find the nearest cell into which we would place the dragged item, assuming there's // nothing in its way. int result[] = new int[2]; - result = findNearestArea(pixelX, pixelY, spanX, spanY, result); + result = findNearestAreaIgnoreOccupied(pixelX, pixelY, spanX, spanY, result); boolean success; // First we try the exact nearest position of the item being dragged, @@ -2016,7 +2446,7 @@ public class CellLayout extends ViewGroup { int childCount = mShortcutsAndWidgets.getChildCount(); for (int i = 0; i < childCount; i++) { View child = mShortcutsAndWidgets.getChildAt(i); - LayoutParams lp = (LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); CellAndSpan c; if (temp) { c = new CellAndSpan(lp.tmpCellX, lp.tmpCellY, lp.cellHSpan, lp.cellVSpan); @@ -2027,532 +2457,163 @@ public class CellLayout extends ViewGroup { } } - private void copySolutionToTempState(ItemConfiguration solution, View dragView) { - mTmpOccupied.clear(); - - int childCount = mShortcutsAndWidgets.getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = mShortcutsAndWidgets.getChildAt(i); - if (child == dragView) continue; - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - CellAndSpan c = solution.map.get(child); - if (c != null) { - lp.tmpCellX = c.cellX; - lp.tmpCellY = c.cellY; - lp.cellHSpan = c.spanX; - lp.cellVSpan = c.spanY; - mTmpOccupied.markCells(c, true); - } - } - mTmpOccupied.markCells(solution, true); - } - - private void animateItemsToSolution(ItemConfiguration solution, View dragView, boolean - commitDragView) { - - GridOccupancy occupied = DESTRUCTIVE_REORDER ? mOccupied : mTmpOccupied; - occupied.clear(); - - int childCount = mShortcutsAndWidgets.getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = mShortcutsAndWidgets.getChildAt(i); - if (child == dragView) continue; - CellAndSpan c = solution.map.get(child); - if (c != null) { - animateChildToPosition(child, c.cellX, c.cellY, REORDER_ANIMATION_DURATION, 0, - DESTRUCTIVE_REORDER, false); - occupied.markCells(c, true); - } - } - if (commitDragView) { - occupied.markCells(solution, true); - } - } - - - // This method starts or changes the reorder preview animations - private void beginOrAdjustReorderPreviewAnimations(ItemConfiguration solution, - View dragView, int mode) { - int childCount = mShortcutsAndWidgets.getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = mShortcutsAndWidgets.getChildAt(i); - if (child == dragView) continue; - CellAndSpan c = solution.map.get(child); - boolean skip = mode == ReorderPreviewAnimation.MODE_HINT && solution.intersectingViews - != null && !solution.intersectingViews.contains(child); - - - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (c != null && !skip && (child instanceof Reorderable)) { - ReorderPreviewAnimation rha = new ReorderPreviewAnimation((Reorderable) child, - mode, lp.cellX, lp.cellY, c.cellX, c.cellY, c.spanX, c.spanY); - rha.animate(); - } + /** + * Returns a "reorder" if there is empty space without rearranging anything. + * + * @param pixelX X coordinate in pixels in the screen + * @param pixelY Y coordinate in pixels in the screen + * @param spanX horizontal cell span + * @param spanY vertical cell span + * @param dragView view being dragged in reorder + * @return the configuration that represents the found reorder + */ + public ItemConfiguration dropInPlaceSolution(int pixelX, int pixelY, int spanX, + int spanY, View dragView) { + int[] result = new int[2]; + if (isNearestDropLocationOccupied(pixelX, pixelY, spanX, spanY, dragView, result)) { + result[0] = result[1] = -1; } + ItemConfiguration solution = new ItemConfiguration(); + copyCurrentStateToSolution(solution, false); + solution.isSolution = result[0] != -1; + if (!solution.isSolution) { + return solution; + } + solution.cellX = result[0]; + solution.cellY = result[1]; + solution.spanX = spanX; + solution.spanY = spanY; + return solution; } - private static final Property<ReorderPreviewAnimation, Float> ANIMATION_PROGRESS = - new Property<ReorderPreviewAnimation, Float>(float.class, "animationProgress") { - @Override - public Float get(ReorderPreviewAnimation anim) { - return anim.animationProgress; - } - - @Override - public void set(ReorderPreviewAnimation anim, Float progress) { - anim.setAnimationProgress(progress); - } - }; - - // Class which represents the reorder preview animations. These animations show that an item is - // in a temporary state, and hint at where the item will return to. - class ReorderPreviewAnimation { - final Reorderable child; - float finalDeltaX; - float finalDeltaY; - float initDeltaX; - float initDeltaY; - final float finalScale; - float initScale; - final int mode; - boolean repeating = false; - private static final int PREVIEW_DURATION = 300; - private static final int HINT_DURATION = Workspace.REORDER_TIMEOUT; - - private static final float CHILD_DIVIDEND = 4.0f; - - public static final int MODE_HINT = 0; - public static final int MODE_PREVIEW = 1; - - float animationProgress = 0; - ValueAnimator a; - - public ReorderPreviewAnimation(Reorderable child, int mode, int cellX0, int cellY0, - int cellX1, int cellY1, int spanX, int spanY) { - regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint); - final int x0 = mTmpPoint[0]; - final int y0 = mTmpPoint[1]; - regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint); - final int x1 = mTmpPoint[0]; - final int y1 = mTmpPoint[1]; - final int dX = x1 - x0; - final int dY = y1 - y0; - - this.child = child; - this.mode = mode; - finalDeltaX = 0; - finalDeltaY = 0; - - child.getReorderBounceOffset(mTmpPointF); - initDeltaX = mTmpPointF.x; - initDeltaY = mTmpPointF.y; - initScale = child.getReorderBounceScale(); - finalScale = mChildScale - (CHILD_DIVIDEND / child.getView().getWidth()) * initScale; - - int dir = mode == MODE_HINT ? -1 : 1; - if (dX == dY && dX == 0) { - } else { - if (dY == 0) { - finalDeltaX = -dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude; - } else if (dX == 0) { - finalDeltaY = -dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude; - } else { - double angle = Math.atan( (float) (dY) / dX); - finalDeltaX = (int) (-dir * Math.signum(dX) - * Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude)); - finalDeltaY = (int) (-dir * Math.signum(dY) - * Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude)); - } - } - } - - void setInitialAnimationValuesToBaseline() { - initScale = mChildScale; - initDeltaX = 0; - initDeltaY = 0; - } - - void animate() { - boolean noMovement = (finalDeltaX == 0) && (finalDeltaY == 0); - - if (mShakeAnimators.containsKey(child)) { - ReorderPreviewAnimation oldAnimation = mShakeAnimators.get(child); - mShakeAnimators.remove(child); - - if (noMovement) { - // A previous animation for this item exists, and no new animation will exist. - // Finish the old animation smoothly. - oldAnimation.finishAnimation(); - return; - } else { - // A previous animation for this item exists, and a new one will exist. Stop - // the old animation in its tracks, and proceed with the new one. - oldAnimation.cancel(); - } - } - if (noMovement) { - return; - } - - ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0, 1); - a = va; - - // Animations are disabled in power save mode, causing the repeated animation to jump - // spastically between beginning and end states. Since this looks bad, we don't repeat - // the animation in power save mode. - if (areAnimatorsEnabled()) { - va.setRepeatMode(ValueAnimator.REVERSE); - va.setRepeatCount(ValueAnimator.INFINITE); - } - - va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION); - va.setStartDelay((int) (Math.random() * 60)); - va.addListener(new AnimatorListenerAdapter() { - public void onAnimationRepeat(Animator animation) { - // We make sure to end only after a full period - setInitialAnimationValuesToBaseline(); - repeating = true; - } - }); - mShakeAnimators.put(child, this); - va.start(); - } - - private void setAnimationProgress(float progress) { - animationProgress = progress; - float r1 = (mode == MODE_HINT && repeating) ? 1.0f : animationProgress; - float x = r1 * finalDeltaX + (1 - r1) * initDeltaX; - float y = r1 * finalDeltaY + (1 - r1) * initDeltaY; - child.setReorderBounceOffset(x, y); - float s = animationProgress * finalScale + (1 - animationProgress) * initScale; - child.setReorderBounceScale(s); - } + /** + * When the user drags an Item in the workspace sometimes we need to move the items already in + * the workspace to make space for the new item, this function return a solution for that + * reorder. + * + * @param pixelX X coordinate in the screen of the dragView in pixels + * @param pixelY Y coordinate in the screen of the dragView in pixels + * @param minSpanX minimum horizontal span the item can be shrunk to + * @param minSpanY minimum vertical span the item can be shrunk to + * @param spanX occupied horizontal span + * @param spanY occupied vertical span + * @param dragView the view of the item being draged + * @return returns a solution for the given parameters, the solution contains all the icons and + * the locations they should be in the given solution. + */ + public ItemConfiguration calculateReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, + int spanX, int spanY, View dragView) { + getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); - private void cancel() { - if (a != null) { - a.cancel(); - } - } + ItemConfiguration dropInPlaceSolution = dropInPlaceSolution(pixelX, pixelY, spanX, spanY, + dragView); - /** - * Smoothly returns the item to its baseline position / scale - */ - @Thunk void finishAnimation() { - if (a != null) { - a.cancel(); - } + // Find a solution involving pushing / displacing any items in the way + ItemConfiguration swapSolution = findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, + spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); - setInitialAnimationValuesToBaseline(); - ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, - animationProgress, 0); - a = va; - a.setInterpolator(DEACCEL_1_5); - a.setDuration(REORDER_ANIMATION_DURATION); - a.start(); - } - } + // We attempt the approach which doesn't shuffle views at all + ItemConfiguration closestSpaceSolution = closestEmptySpaceReorder(pixelX, pixelY, minSpanX, + minSpanY, spanX, spanY); - private void completeAndClearReorderPreviewAnimations() { - for (ReorderPreviewAnimation a: mShakeAnimators.values()) { - a.finishAnimation(); + // If the reorder solution requires resizing (shrinking) the item being dropped, we instead + // favor a solution in which the item is not resized, but + if (swapSolution.isSolution && swapSolution.area() >= closestSpaceSolution.area()) { + return swapSolution; + } else if (closestSpaceSolution.isSolution) { + return closestSpaceSolution; + } else if (dropInPlaceSolution.isSolution) { + return dropInPlaceSolution; } - mShakeAnimators.clear(); + return null; } - private void commitTempPlacement(View dragView) { - mTmpOccupied.copyTo(mOccupied); - - int screenId = getWorkspace().getIdForScreen(this); - int container = Favorites.CONTAINER_DESKTOP; - - if (mContainerType == HOTSEAT) { - screenId = -1; - container = Favorites.CONTAINER_HOTSEAT; - } - - int childCount = mShortcutsAndWidgets.getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = mShortcutsAndWidgets.getChildAt(i); - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - ItemInfo info = (ItemInfo) child.getTag(); - // We do a null check here because the item info can be null in the case of the - // AllApps button in the hotseat. - if (info != null && child != dragView) { - final boolean requiresDbUpdate = (info.cellX != lp.tmpCellX - || info.cellY != lp.tmpCellY || info.spanX != lp.cellHSpan - || info.spanY != lp.cellVSpan); - - info.cellX = lp.cellX = lp.tmpCellX; - info.cellY = lp.cellY = lp.tmpCellY; - info.spanX = lp.cellHSpan; - info.spanY = lp.cellVSpan; - - if (requiresDbUpdate) { - Launcher.cast(mActivity).getModelWriter().modifyItemInDatabase(info, container, - screenId, info.cellX, info.cellY, info.spanX, info.spanY); - } - } + int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, + View dragView, int[] result, int[] resultSpan, int mode) { + if (resultSpan == null) { + resultSpan = new int[]{-1, -1}; } - } - - private void setUseTempCoords(boolean useTempCoords) { - int childCount = mShortcutsAndWidgets.getChildCount(); - for (int i = 0; i < childCount; i++) { - LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams(); - lp.useTmpCoords = useTempCoords; + if (result == null) { + result = new int[]{-1, -1}; } - } - private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY, - int spanX, int spanY, View dragView, ItemConfiguration solution) { - int[] result = new int[2]; - int[] resultSpan = new int[2]; - findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result, - resultSpan); - if (result[0] >= 0 && result[1] >= 0) { - copyCurrentStateToSolution(solution, false); - solution.cellX = result[0]; - solution.cellY = result[1]; - solution.spanX = resultSpan[0]; - solution.spanY = resultSpan[1]; - solution.isSolution = true; + ItemConfiguration finalSolution = null; + // We want the solution to match the animation of the preview and to match the drop so we + // only recalculate in mode MODE_SHOW_REORDER_HINT because that the first one to run in the + // reorder cycle. + if (mode == MODE_SHOW_REORDER_HINT || mPreviousSolution == null) { + finalSolution = calculateReorder(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, + dragView); + mPreviousSolution = finalSolution; } else { - solution.isSolution = false; - } - return solution; - } - - /* This seems like it should be obvious and straight-forward, but when the direction vector - needs to match with the notion of the dragView pushing other views, we have to employ - a slightly more subtle notion of the direction vector. The question is what two points is - the vector between? The center of the dragView and its desired destination? Not quite, as - this doesn't necessarily coincide with the interaction of the dragView and items occupying - those cells. Instead we use some heuristics to often lock the vector to up, down, left - or right, which helps make pushing feel right. - */ - private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX, - int spanY, View dragView, int[] resultDirection) { - - //TODO(adamcohen) b/151776141 use the items visual center for the direction vector - int[] targetDestination = new int[2]; - - findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination); - Rect dragRect = new Rect(); - cellToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect); - dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY()); - - Rect dropRegionRect = new Rect(); - getViewsIntersectingRegion(targetDestination[0], targetDestination[1], spanX, spanY, - dragView, dropRegionRect, mIntersectingViews); - - int dropRegionSpanX = dropRegionRect.width(); - int dropRegionSpanY = dropRegionRect.height(); - - cellToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(), - dropRegionRect.height(), dropRegionRect); - - int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX; - int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY; - - if (dropRegionSpanX == mCountX || spanX == mCountX) { - deltaX = 0; - } - if (dropRegionSpanY == mCountY || spanY == mCountY) { - deltaY = 0; + finalSolution = mPreviousSolution; + // We reset this vector after drop + if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { + mPreviousSolution = null; + } } - if (deltaX == 0 && deltaY == 0) { - // No idea what to do, give a random direction. - resultDirection[0] = 1; - resultDirection[1] = 0; + if (finalSolution == null || !finalSolution.isSolution) { + result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; } else { - computeDirectionVector(deltaX, deltaY, resultDirection); + result[0] = finalSolution.cellX; + result[1] = finalSolution.cellY; + resultSpan[0] = finalSolution.spanX; + resultSpan[1] = finalSolution.spanY; + performReorder(finalSolution, dragView, mode); } + return result; } - // For a given cell and span, fetch the set of views intersecting the region. - private void getViewsIntersectingRegion(int cellX, int cellY, int spanX, int spanY, - View dragView, Rect boundingRect, ArrayList<View> intersectingViews) { - if (boundingRect != null) { - boundingRect.set(cellX, cellY, cellX + spanX, cellY + spanY); + /** + * Animates and submits in the DB the given ItemConfiguration depending of the mode. + * + * @param solution represents widgets on the screen which the Workspace will animate to and + * would be submitted to the database. + * @param dragView view which is being dragged over the workspace that trigger the reorder + * @param mode depending on the mode different animations would be played and depending on the + * mode the solution would be submitted or not the database. + * The possible modes are {@link MODE_SHOW_REORDER_HINT}, {@link MODE_DRAG_OVER}, + * {@link MODE_ON_DROP}, {@link MODE_ON_DROP_EXTERNAL}, {@link MODE_ACCEPT_DROP} + * defined in {@link CellLayout}. + */ + void performReorder(ItemConfiguration solution, View dragView, int mode) { + if (mode == MODE_SHOW_REORDER_HINT) { + beginOrAdjustReorderPreviewAnimations(solution, dragView, + ReorderPreviewAnimation.MODE_HINT); + return; } - intersectingViews.clear(); - Rect r0 = new Rect(cellX, cellY, cellX + spanX, cellY + spanY); - Rect r1 = new Rect(); - final int count = mShortcutsAndWidgets.getChildCount(); - for (int i = 0; i < count; i++) { - View child = mShortcutsAndWidgets.getChildAt(i); - if (child == dragView) continue; - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - r1.set(lp.cellX, lp.cellY, lp.cellX + lp.cellHSpan, lp.cellY + lp.cellVSpan); - if (Rect.intersects(r0, r1)) { - mIntersectingViews.add(child); - if (boundingRect != null) { - boundingRect.union(r1); - } + // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother + // committing anything or animating anything as we just want to determine if a solution + // exists + if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { + if (!DESTRUCTIVE_REORDER) { + setUseTempCoords(true); } - } - } - - boolean isNearestDropLocationOccupied(int pixelX, int pixelY, int spanX, int spanY, - View dragView, int[] result) { - result = findNearestArea(pixelX, pixelY, spanX, spanY, result); - getViewsIntersectingRegion(result[0], result[1], spanX, spanY, dragView, null, - mIntersectingViews); - return !mIntersectingViews.isEmpty(); - } - void revertTempState() { - completeAndClearReorderPreviewAnimations(); - if (isItemPlacementDirty() && !DESTRUCTIVE_REORDER) { - final int count = mShortcutsAndWidgets.getChildCount(); - for (int i = 0; i < count; i++) { - View child = mShortcutsAndWidgets.getChildAt(i); - LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY) { - lp.tmpCellX = lp.cellX; - lp.tmpCellY = lp.cellY; - animateChildToPosition(child, lp.cellX, lp.cellY, REORDER_ANIMATION_DURATION, - 0, false, false); - } + if (!DESTRUCTIVE_REORDER) { + copySolutionToTempState(solution, dragView); } - setItemPlacementDirty(false); - } - } - - boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, - View dragView, int[] direction, boolean commit) { - int[] pixelXY = new int[2]; - regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); - - // First we determine if things have moved enough to cause a different layout - ItemConfiguration swapSolution = findReorderSolution(pixelXY[0], pixelXY[1], spanX, spanY, - spanX, spanY, direction, dragView, true, new ItemConfiguration()); - - setUseTempCoords(true); - if (swapSolution != null && swapSolution.isSolution) { - // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother - // committing anything or animating anything as we just want to determine if a solution - // exists - copySolutionToTempState(swapSolution, dragView); setItemPlacementDirty(true); - animateItemsToSolution(swapSolution, dragView, commit); + animateItemsToSolution(solution, dragView, mode == MODE_ON_DROP); - if (commit) { - commitTempPlacement(null); + if (!DESTRUCTIVE_REORDER + && (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { + // Since the temp solution didn't update dragView, don't commit it either + commitTempPlacement(dragView); completeAndClearReorderPreviewAnimations(); setItemPlacementDirty(false); } else { - beginOrAdjustReorderPreviewAnimations(swapSolution, dragView, + beginOrAdjustReorderPreviewAnimations(solution, dragView, ReorderPreviewAnimation.MODE_PREVIEW); } - mShortcutsAndWidgets.requestLayout(); - } - return swapSolution.isSolution; - } - - int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, - View dragView, int[] result, int resultSpan[], int mode) { - // First we determine if things have moved enough to cause a different layout - result = findNearestArea(pixelX, pixelY, spanX, spanY, result); - - if (resultSpan == null) { - resultSpan = new int[2]; - } - - // When we are checking drop validity or actually dropping, we don't recompute the - // direction vector, since we want the solution to match the preview, and it's possible - // that the exact position of the item has changed to result in a new reordering outcome. - if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP) - && mPreviousReorderDirection[0] != INVALID_DIRECTION) { - mDirectionVector[0] = mPreviousReorderDirection[0]; - mDirectionVector[1] = mPreviousReorderDirection[1]; - // We reset this vector after drop - if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { - mPreviousReorderDirection[0] = INVALID_DIRECTION; - mPreviousReorderDirection[1] = INVALID_DIRECTION; - } - } else { - getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); - mPreviousReorderDirection[0] = mDirectionVector[0]; - mPreviousReorderDirection[1] = mDirectionVector[1]; - } - - // Find a solution involving pushing / displacing any items in the way - ItemConfiguration swapSolution = findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, - spanX, spanY, mDirectionVector, dragView, true, new ItemConfiguration()); - - // We attempt the approach which doesn't shuffle views at all - ItemConfiguration noShuffleSolution = findConfigurationNoShuffle(pixelX, pixelY, minSpanX, - minSpanY, spanX, spanY, dragView, new ItemConfiguration()); - - ItemConfiguration finalSolution = null; - - // If the reorder solution requires resizing (shrinking) the item being dropped, we instead - // favor a solution in which the item is not resized, but - if (swapSolution.isSolution && swapSolution.area() >= noShuffleSolution.area()) { - finalSolution = swapSolution; - } else if (noShuffleSolution.isSolution) { - finalSolution = noShuffleSolution; } - if (mode == MODE_SHOW_REORDER_HINT) { - if (finalSolution != null) { - beginOrAdjustReorderPreviewAnimations(finalSolution, dragView, - ReorderPreviewAnimation.MODE_HINT); - result[0] = finalSolution.cellX; - result[1] = finalSolution.cellY; - resultSpan[0] = finalSolution.spanX; - resultSpan[1] = finalSolution.spanY; - } else { - result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; - } - return result; - } - - boolean foundSolution = true; - if (!DESTRUCTIVE_REORDER) { - setUseTempCoords(true); - } - - if (finalSolution != null) { - result[0] = finalSolution.cellX; - result[1] = finalSolution.cellY; - resultSpan[0] = finalSolution.spanX; - resultSpan[1] = finalSolution.spanY; - - // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother - // committing anything or animating anything as we just want to determine if a solution - // exists - if (mode == MODE_DRAG_OVER || mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) { - if (!DESTRUCTIVE_REORDER) { - copySolutionToTempState(finalSolution, dragView); - } - setItemPlacementDirty(true); - animateItemsToSolution(finalSolution, dragView, mode == MODE_ON_DROP); - - if (!DESTRUCTIVE_REORDER && - (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL)) { - // Since the temp solution didn't update dragView, don't commit it either - commitTempPlacement(dragView); - completeAndClearReorderPreviewAnimations(); - setItemPlacementDirty(false); - } else { - beginOrAdjustReorderPreviewAnimations(finalSolution, dragView, - ReorderPreviewAnimation.MODE_PREVIEW); - } - } - } else { - foundSolution = false; - result[0] = result[1] = resultSpan[0] = resultSpan[1] = -1; - } - - if ((mode == MODE_ON_DROP || !foundSolution) && !DESTRUCTIVE_REORDER) { + if (mode == MODE_ON_DROP && !DESTRUCTIVE_REORDER) { setUseTempCoords(false); } mShortcutsAndWidgets.requestLayout(); - return result; } void setItemPlacementDirty(boolean dirty) { @@ -2619,7 +2680,8 @@ public class CellLayout extends ViewGroup { * @return The X, Y cell of a vacant area that can contain this object, * nearest the requested location. */ - public int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) { + public int[] findNearestAreaIgnoreOccupied(int pixelX, int pixelY, int spanX, int spanY, + int[] result) { return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, true, result, null); } @@ -2654,6 +2716,7 @@ public class CellLayout extends ViewGroup { */ void onDragEnter() { mDragging = true; + mPreviousSolution = null; } /** @@ -2668,6 +2731,7 @@ public class CellLayout extends ViewGroup { } // Invalidate the drag data + mPreviousSolution = null; mDragCell[0] = mDragCell[1] = -1; mDragCellSpan[0] = mDragCellSpan[1] = -1; mDragOutlineAnims[mDragOutlineCurrent].animateOut(); @@ -2685,7 +2749,8 @@ public class CellLayout extends ViewGroup { */ void onDropChild(View child) { if (child != null) { - LayoutParams lp = (LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams + lp = (CellLayoutLayoutParams) child.getLayoutParams(); lp.dropped = true; child.requestLayout(); markCellsAsOccupiedForView(child); @@ -2727,7 +2792,8 @@ public class CellLayout extends ViewGroup { return; } if (view == null || view.getParent() != mShortcutsAndWidgets) return; - LayoutParams lp = (LayoutParams) view.getLayoutParams(); + CellLayoutLayoutParams + lp = (CellLayoutLayoutParams) view.getLayoutParams(); mOccupied.markCells(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, true); } @@ -2739,7 +2805,8 @@ public class CellLayout extends ViewGroup { return; } if (view == null || view.getParent() != mShortcutsAndWidgets) return; - LayoutParams lp = (LayoutParams) view.getLayoutParams(); + CellLayoutLayoutParams + lp = (CellLayoutLayoutParams) view.getLayoutParams(); mOccupied.markCells(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, false); } @@ -2763,165 +2830,17 @@ public class CellLayout extends ViewGroup { @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { - return new CellLayout.LayoutParams(getContext(), attrs); + return new CellLayoutLayoutParams(getContext(), attrs); } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { - return p instanceof CellLayout.LayoutParams; + return p instanceof CellLayoutLayoutParams; } @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { - return new CellLayout.LayoutParams(p); - } - - public static class LayoutParams extends ViewGroup.MarginLayoutParams { - /** - * Horizontal location of the item in the grid. - */ - @ViewDebug.ExportedProperty - public int cellX; - - /** - * Vertical location of the item in the grid. - */ - @ViewDebug.ExportedProperty - public int cellY; - - /** - * Temporary horizontal location of the item in the grid during reorder - */ - public int tmpCellX; - - /** - * Temporary vertical location of the item in the grid during reorder - */ - public int tmpCellY; - - /** - * Indicates that the temporary coordinates should be used to layout the items - */ - public boolean useTmpCoords; - - /** - * Number of cells spanned horizontally by the item. - */ - @ViewDebug.ExportedProperty - public int cellHSpan; - - /** - * Number of cells spanned vertically by the item. - */ - @ViewDebug.ExportedProperty - public int cellVSpan; - - /** - * Indicates whether the item will set its x, y, width and height parameters freely, - * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. - */ - public boolean isLockedToGrid = true; - - /** - * Indicates whether this item can be reordered. Always true except in the case of the - * the AllApps button and QSB place holder. - */ - public boolean canReorder = true; - - // X coordinate of the view in the layout. - @ViewDebug.ExportedProperty - public int x; - // Y coordinate of the view in the layout. - @ViewDebug.ExportedProperty - public int y; - - boolean dropped; - - public LayoutParams(Context c, AttributeSet attrs) { - super(c, attrs); - cellHSpan = 1; - cellVSpan = 1; - } - - public LayoutParams(ViewGroup.LayoutParams source) { - super(source); - cellHSpan = 1; - cellVSpan = 1; - } - - public LayoutParams(LayoutParams source) { - super(source); - this.cellX = source.cellX; - this.cellY = source.cellY; - this.cellHSpan = source.cellHSpan; - this.cellVSpan = source.cellVSpan; - } - - public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { - super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - this.cellX = cellX; - this.cellY = cellY; - this.cellHSpan = cellHSpan; - this.cellVSpan = cellVSpan; - } - - public void setup(int cellWidth, int cellHeight, boolean invertHorizontally, int colCount, - int rowCount, Point borderSpace, @Nullable Rect inset) { - setup(cellWidth, cellHeight, invertHorizontally, colCount, rowCount, 1.0f, 1.0f, - borderSpace, inset); - } - - /** - * Use this method, as opposed to {@link #setup(int, int, boolean, int, int, Point, Rect)}, - * if the view needs to be scaled. - * - * ie. In multi-window mode, we setup widgets so that they are measured and laid out - * using their full/invariant device profile sizes. - */ - public void setup(int cellWidth, int cellHeight, boolean invertHorizontally, int colCount, - int rowCount, float cellScaleX, float cellScaleY, Point borderSpace, - @Nullable Rect inset) { - if (isLockedToGrid) { - final int myCellHSpan = cellHSpan; - final int myCellVSpan = cellVSpan; - int myCellX = useTmpCoords ? tmpCellX : cellX; - int myCellY = useTmpCoords ? tmpCellY : cellY; - - if (invertHorizontally) { - myCellX = colCount - myCellX - cellHSpan; - } - - int hBorderSpacing = (myCellHSpan - 1) * borderSpace.x; - int vBorderSpacing = (myCellVSpan - 1) * borderSpace.y; - - float myCellWidth = ((myCellHSpan * cellWidth) + hBorderSpacing) / cellScaleX; - float myCellHeight = ((myCellVSpan * cellHeight) + vBorderSpacing) / cellScaleY; - - width = Math.round(myCellWidth) - leftMargin - rightMargin; - height = Math.round(myCellHeight) - topMargin - bottomMargin; - x = leftMargin + (myCellX * cellWidth) + (myCellX * borderSpace.x); - y = topMargin + (myCellY * cellHeight) + (myCellY * borderSpace.y); - - if (inset != null) { - x -= inset.left; - y -= inset.top; - width += inset.left + inset.right; - height += inset.top + inset.bottom; - } - } - } - - /** - * Sets the position to the provided point - */ - public void setCellXY(Point point) { - cellX = point.x; - cellY = point.y; - } - - public String toString() { - return "(" + this.cellX + ", " + this.cellY + ")"; - } + return new CellLayoutLayoutParams(p); } // This class stores info for two purposes: diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java index c707df04c0..3e4e96bec0 100644 --- a/src/com/android/launcher3/CheckLongPressHelper.java +++ b/src/com/android/launcher3/CheckLongPressHelper.java @@ -16,12 +16,16 @@ package com.android.launcher3; +import android.os.Handler; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; +import com.android.launcher3.util.TouchUtil; + /** - * Utility class to handle tripper long press on a view with custom timeout and stylus event + * Utility class to handle tripper long press or right click on a view with custom timeout and + * stylus event */ public class CheckLongPressHelper { @@ -34,6 +38,7 @@ public class CheckLongPressHelper { private float mLongPressTimeoutFactor = DEFAULT_LONG_PRESS_TIMEOUT_FACTOR; private boolean mHasPerformedLongPress; + private boolean mIsInMouseRightClick; private Runnable mPendingCheckForLongPress; @@ -59,6 +64,26 @@ public class CheckLongPressHelper { // start fresh on touch down. cancelLongPress(); + // Mouse right click should immediately trigger a long press + if (TouchUtil.isMouseRightClickDownOrMove(ev)) { + mIsInMouseRightClick = true; + triggerLongPress(); + final Handler handler = mView.getHandler(); + if (handler != null) { + // Send an ACTION_UP to end this click gesture to avoid user dragging with + // mouse's right button. Note that we need to call + // {@link Handler#postAtFrontOfQueue()} instead of {@link View#post()} to + // make sure ACTION_UP is sent before any ACTION_MOVE if user is dragging. + final MotionEvent actionUpEvent = MotionEvent.obtain(ev); + actionUpEvent.setAction(MotionEvent.ACTION_UP); + handler.postAtFrontOfQueue(() -> { + mView.getRootView().dispatchTouchEvent(actionUpEvent); + actionUpEvent.recycle(); + }); + } + break; + } + postCheckForLongPress(); if (isStylusButtonPressed(ev)) { triggerLongPress(); @@ -70,7 +95,8 @@ public class CheckLongPressHelper { cancelLongPress(); break; case MotionEvent.ACTION_MOVE: - if (!Utilities.pointInView(mView, ev.getX(), ev.getY(), mSlop)) { + if (mIsInMouseRightClick + || !Utilities.pointInView(mView, ev.getX(), ev.getY(), mSlop)) { cancelLongPress(); } else if (mPendingCheckForLongPress != null && isStylusButtonPressed(ev)) { // Only trigger long press if it has not been cancelled before @@ -98,9 +124,10 @@ public class CheckLongPressHelper { } /** - * Cancels any pending long press + * Cancels any pending long press and right click */ public void cancelLongPress() { + mIsInMouseRightClick = false; mHasPerformedLongPress = false; clearCallbacks(); } diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java index 4daca8b109..c69ae4dac8 100644 --- a/src/com/android/launcher3/DefaultLayoutParser.java +++ b/src/com/android/launcher3/DefaultLayoutParser.java @@ -1,6 +1,5 @@ package com.android.launcher3; -import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.Context; @@ -20,7 +19,9 @@ import android.util.Log; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.util.Partner; import com.android.launcher3.util.Thunk; +import com.android.launcher3.widget.LauncherWidgetHolder; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -51,13 +52,16 @@ public class DefaultLayoutParser extends AutoInstallsLayout { private static final String ATTR_SHORTCUT_ID = "shortcutId"; private static final String ATTR_PACKAGE_NAME = "packageName"; + public static final String RES_PARTNER_FOLDER = "partner_folder"; + public static final String RES_PARTNER_DEFAULT_LAYOUT = "partner_default_layout"; + // TODO: Remove support for this broadcast, instead use widget options to send bind time options private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE = "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE"; - public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost, + public DefaultLayoutParser(Context context, LauncherWidgetHolder appWidgetHolder, LayoutParserCallback callback, Resources sourceRes, int layoutId) { - super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES); + super(context, appWidgetHolder, callback, sourceRes, layoutId, TAG_FAVORITES); } @Override @@ -278,10 +282,9 @@ public class DefaultLayoutParser extends AutoInstallsLayout { // Folder contents come from an external XML resource final Partner partner = Partner.get(mPackageManager); if (partner != null) { - final Resources partnerRes = partner.getResources(); - final int resId = partnerRes.getIdentifier(Partner.RES_FOLDER, - "xml", partner.getPackageName()); + final int resId = partner.getXmlResId(RES_PARTNER_FOLDER); if (resId != 0) { + final Resources partnerRes = partner.getResources(); final XmlPullParser partnerParser = partnerRes.getXml(resId); beginDocument(partnerParser, TAG_FOLDER); @@ -336,11 +339,11 @@ public class DefaultLayoutParser extends AutoInstallsLayout { final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext); int insertedId = -1; try { - int appWidgetId = mAppWidgetHost.allocateAppWidgetId(); + int appWidgetId = mAppWidgetHolder.allocateAppWidgetId(); if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, cn)) { Log.e(TAG, "Unable to bind app widget id " + cn); - mAppWidgetHost.deleteAppWidgetId(appWidgetId); + mAppWidgetHolder.deleteAppWidgetId(appWidgetId); return -1; } @@ -349,7 +352,7 @@ public class DefaultLayoutParser extends AutoInstallsLayout { mValues.put(Favorites._ID, mCallback.generateNewItemId()); insertedId = mCallback.insertAndCheck(mDb, mValues); if (insertedId < 0) { - mAppWidgetHost.deleteAppWidgetId(appWidgetId); + mAppWidgetHolder.deleteAppWidgetId(appWidgetId); return insertedId; } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 4cad919c3b..25520e1bea 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -23,14 +23,17 @@ import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_PORTR import static com.android.launcher3.Utilities.dpiFromPx; import static com.android.launcher3.Utilities.pxFromSp; import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.config.FeatureFlags.ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH; import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR; import static com.android.launcher3.icons.GraphicsUtils.getShapePath; +import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE; import static com.android.launcher3.testing.shared.ResourceUtils.pxFromDp; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; @@ -43,6 +46,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.CellLayout.ContainerType; import com.android.launcher3.DevicePaddings.DevicePadding; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.icons.IconNormalizer; import com.android.launcher3.model.data.ItemInfo; @@ -52,7 +56,6 @@ import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.WindowBounds; import java.io.PrintWriter; -import java.util.List; import java.util.Locale; @SuppressLint("NewApi") @@ -60,6 +63,7 @@ public class DeviceProfile { private static final int DEFAULT_DOT_SIZE = 100; private static final float ALL_APPS_TABLET_MAX_ROWS = 5.5f; + private static final float MIN_FOLDER_TEXT_SIZE_SP = 16f; public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f); public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE; @@ -75,6 +79,7 @@ public class DeviceProfile { public final boolean isTablet; public final boolean isPhone; public final boolean transposeLayoutWithOrientation; + public final boolean isMultiDisplay; public final boolean isTwoPanels; public final boolean isQsbInline; @@ -122,6 +127,7 @@ public class DeviceProfile { public final int workspaceSpringLoadedMinNextPageVisiblePx; private final int extraSpace; + private int maxEmptySpace; public int workspaceTopPadding; public int workspaceBottomPadding; @@ -146,11 +152,12 @@ public class DeviceProfile { // Folder public float folderLabelTextScale; public int folderLabelTextSizePx; + public int folderFooterHeightPx; public int folderIconSizePx; public int folderIconOffsetYPx; // Folder content - public Point folderCellLayoutBorderSpacePx; + public int folderCellLayoutBorderSpacePx; public int folderContentPaddingLeftRight; public int folderContentPaddingTop; @@ -181,6 +188,10 @@ public class DeviceProfile { public final int hotseatQsbVisualHeight; private final int hotseatQsbShadowHeight; public int hotseatBorderSpace; + private int minHotseatIconSpacePx; + private int minHotseatQsbWidthPx; + private final int maxHotseatIconSpacePx; + private int inlineNavButtonsEndSpacing; // Bottom sheets public int bottomSheetTopPadding; @@ -217,6 +228,9 @@ public class DeviceProfile { public int overviewRowSpacing; public int overviewGridSideMargin; + // Split staging + public int splitPlaceholderInset; + // Widgets private final ViewScaleProvider mViewScaleProvider; @@ -247,6 +261,7 @@ public class DeviceProfile { public boolean isTaskbarPresentInApps; public int taskbarSize; public int stashedTaskbarSize; + public int transientTaskbarMargin; // DragController public int flingToDeleteThresholdVelocity; @@ -254,13 +269,14 @@ public class DeviceProfile { /** TODO: Once we fully migrate to staged split, remove "isMultiWindowMode" */ DeviceProfile(Context context, InvariantDeviceProfile inv, Info info, WindowBounds windowBounds, SparseArray<DotRenderer> dotRendererCache, boolean isMultiWindowMode, - boolean transposeLayoutWithOrientation, boolean useTwoPanels, boolean isGestureMode, + boolean transposeLayoutWithOrientation, boolean isMultiDisplay, boolean isGestureMode, @NonNull final ViewScaleProvider viewScaleProvider) { this.inv = inv; this.isLandscape = windowBounds.isLandscape(); this.isMultiWindowMode = isMultiWindowMode; this.transposeLayoutWithOrientation = transposeLayoutWithOrientation; + this.isMultiDisplay = isMultiDisplay; this.isGestureMode = isGestureMode; windowX = windowBounds.bounds.left; windowY = windowBounds.bounds.top; @@ -272,7 +288,7 @@ public class DeviceProfile { mInfo = info; isTablet = info.isTablet(windowBounds); isPhone = !isTablet; - isTwoPanels = isTablet && useTwoPanels; + isTwoPanels = isTablet && isMultiDisplay; isTaskbarPresent = isTablet && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS; // Some more constants. @@ -308,8 +324,16 @@ public class DeviceProfile { } if (isTaskbarPresent) { - taskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_size); - stashedTaskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size); + if (DisplayController.isTransientTaskbar(context)) { + taskbarSize = res.getDimensionPixelSize(R.dimen.transient_taskbar_size); + stashedTaskbarSize = + res.getDimensionPixelSize(R.dimen.transient_taskbar_stashed_size); + transientTaskbarMargin = + res.getDimensionPixelSize(R.dimen.transient_taskbar_margin); + } else { + taskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_size); + stashedTaskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size); + } } edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin); @@ -329,30 +353,53 @@ public class DeviceProfile { bottomSheetCloseDuration = res.getInteger(R.integer.config_bottomSheetCloseDuration); if (isTablet) { bottomSheetWorkspaceScale = workspaceContentScale; - // The goal is to set wallpaper to zoom at workspaceContentScale when in AllApps. - // When depth is 0, wallpaper zoom is set to maxWallpaperScale. - // When depth is 1, wallpaper zoom is set to 1. - // For depth to achieve zoom set to maxWallpaperScale * workspaceContentScale: - float maxWallpaperScale = res.getFloat(R.dimen.config_wallpaperMaxScale); - bottomSheetDepth = Utilities.mapToRange(maxWallpaperScale * workspaceContentScale, - maxWallpaperScale, 1f, 0f, 1f, LINEAR); + if (isMultiDisplay && !ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH.get()) { + // TODO(b/259893832): Revert to use maxWallpaperScale to calculate bottomSheetDepth + // when screen recorder bug is fixed. + bottomSheetDepth = 1f; + } else { + // The goal is to set wallpaper to zoom at workspaceContentScale when in AllApps. + // When depth is 0, wallpaper zoom is set to maxWallpaperScale. + // When depth is 1, wallpaper zoom is set to 1. + // For depth to achieve zoom set to maxWallpaperScale * workspaceContentScale: + float maxWallpaperScale = res.getFloat(R.dimen.config_wallpaperMaxScale); + bottomSheetDepth = Utilities.mapToRange(maxWallpaperScale * workspaceContentScale, + maxWallpaperScale, 1f, 0f, 1f, LINEAR); + } } else { bottomSheetWorkspaceScale = 1f; bottomSheetDepth = 0f; } folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale); - folderContentPaddingLeftRight = - res.getDimensionPixelSize(R.dimen.folder_content_padding_left_right); - folderContentPaddingTop = res.getDimensionPixelSize(R.dimen.folder_content_padding_top); + + if (inv.folderStyle != INVALID_RESOURCE_HANDLE) { + TypedArray folderStyle = context.obtainStyledAttributes(inv.folderStyle, + R.styleable.FolderDisplayStyle); + // These are re-set in #updateFolderCellSize if the grid is not scalable + folderCellHeightPx = folderStyle.getDimensionPixelSize( + R.styleable.FolderDisplayStyle_folderCellHeight, 0); + folderCellWidthPx = folderStyle.getDimensionPixelSize( + R.styleable.FolderDisplayStyle_folderCellWidth, 0); + + folderContentPaddingTop = folderStyle.getDimensionPixelSize( + R.styleable.FolderDisplayStyle_folderTopPadding, 0); + folderCellLayoutBorderSpacePx = folderStyle.getDimensionPixelSize( + R.styleable.FolderDisplayStyle_folderBorderSpace, 0); + folderFooterHeightPx = folderStyle.getDimensionPixelSize( + R.styleable.FolderDisplayStyle_folderFooterHeight, 0); + folderStyle.recycle(); + } else { + folderCellLayoutBorderSpacePx = 0; + folderFooterHeightPx = 0; + folderContentPaddingTop = res.getDimensionPixelSize(R.dimen.folder_top_padding_default); + } cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv); + cellLayoutBorderSpaceOriginalPx = new Point(cellLayoutBorderSpacePx); allAppsBorderSpacePx = new Point( pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].x, mMetrics), pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].y, mMetrics)); - cellLayoutBorderSpaceOriginalPx = new Point(cellLayoutBorderSpacePx); - folderCellLayoutBorderSpacePx = new Point(pxFromDp(inv.folderBorderSpaces.x, mMetrics), - pxFromDp(inv.folderBorderSpaces.y, mMetrics)); workspacePageIndicatorHeight = res.getDimensionPixelSize( R.dimen.workspace_page_indicator_height); @@ -389,7 +436,7 @@ public class DeviceProfile { || inv.inlineQsb[INDEX_TWO_PANEL_LANDSCAPE] : inv.inlineQsb[INDEX_DEFAULT] || inv.inlineQsb[INDEX_LANDSCAPE]) && hotseatQsbHeight > 0; - isQsbInline = inv.inlineQsb[mTypeIndex] && canQsbInline; + isQsbInline = isScalableGrid && inv.inlineQsb[mTypeIndex] && canQsbInline; areNavButtonsInline = isTaskbarPresent && !isGestureMode; numShownHotseatIcons = @@ -429,17 +476,17 @@ public class DeviceProfile { hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0; updateHotseatSizes(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics)); if (areNavButtonsInline && !isPhone) { + inlineNavButtonsEndSpacing = res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing); /* * 3 nav buttons + * Spacing between nav buttons + - * Little space at the end for contextual buttons + - * Little space between icons and nav buttons + * Space at the end for contextual buttons */ hotseatBarEndOffset = 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) + 2 * res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween) - + res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing) - + res.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing); + + inlineNavButtonsEndSpacing; } else { + inlineNavButtonsEndSpacing = 0; hotseatBarEndOffset = 0; } @@ -458,14 +505,18 @@ public class DeviceProfile { overviewRowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing); overviewGridSideMargin = res.getDimensionPixelSize(R.dimen.overview_grid_side_margin); + splitPlaceholderInset = res.getDimensionPixelSize(R.dimen.split_placeholder_inset); + // Calculate all of the remaining variables. extraSpace = updateAvailableDimensions(res); // Now that we have all of the variables calculated, we can tune certain sizes. - if (isScalableGrid && inv.devicePaddings != null) { + if (isScalableGrid && inv.devicePaddingId != INVALID_RESOURCE_HANDLE) { // Paddings were created assuming no scaling, so we first unscale the extra space. int unscaledExtraSpace = (int) (extraSpace / cellScaleToFit); - DevicePadding padding = inv.devicePaddings.getDevicePadding(unscaledExtraSpace); + DevicePaddings devicePaddings = new DevicePaddings(context, inv.devicePaddingId); + DevicePadding padding = devicePaddings.getDevicePadding(unscaledExtraSpace); + maxEmptySpace = padding.getMaxEmptySpacePx(); int paddingWorkspaceTop = padding.getWorkspaceTopPadding(unscaledExtraSpace); int paddingWorkspaceBottom = padding.getWorkspaceBottomPadding(unscaledExtraSpace); @@ -482,8 +533,12 @@ public class DeviceProfile { cellLayoutPadding); updateWorkspacePadding(); + minHotseatIconSpacePx = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space); + minHotseatQsbWidthPx = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width); + maxHotseatIconSpacePx = areNavButtonsInline + ? res.getDimensionPixelSize(R.dimen.max_hotseat_icon_space) : Integer.MAX_VALUE; // Hotseat and QSB width depends on updated cellSize and workspace padding - recalculateHotseatWidthAndBorderSpace(res); + recalculateHotseatWidthAndBorderSpace(); // AllApps height calculation depends on updated cellSize if (isTablet) { @@ -572,68 +627,57 @@ public class DeviceProfile { } } - private void recalculateHotseatWidthAndBorderSpace(Resources res) { - hotseatBorderSpace = calculateHotseatBorderSpace(); + /** + * Calculates the width of the hotseat, changing spaces between the icons and removing icons if + * necessary. + */ + public void recalculateHotseatWidthAndBorderSpace() { + if (!isScalableGrid) return; + + int columns = inv.hotseatColumnSpan[mTypeIndex]; + float hotseatWidthPx = getIconToIconWidthForColumns(columns); + hotseatBorderSpace = calculateHotseatBorderSpace(hotseatWidthPx, /* numExtraBorder= */ 0); hotseatQsbWidth = calculateQsbWidth(hotseatBorderSpace); - // Spaces should be correct when there nav buttons are not inline + // Spaces should be correct when the nav buttons are not inline if (!areNavButtonsInline) { return; } - // Get the maximum width that the hotseat can be - int columns = getPanelCount() * inv.numColumns; - int maxHotseatWidth = getIconToIconWidthForColumns(columns); - int sideSpace = (availableWidthPx - maxHotseatWidth) / 2; - int inlineButtonsOverlap = Math.max(0, hotseatBarEndOffset - sideSpace); - // decrease how much the nav buttons go "inside" the hotseat - maxHotseatWidth -= inlineButtonsOverlap; - - // Get how much space is required to show the hotseat with QSB - int requiredWidth = getHotseatRequiredWidth(); - - // If spaces are fine, use them - if (requiredWidth <= maxHotseatWidth) { - return; - } - - // Calculate the difference of widths and remove a little from each space between icons - // and QSB if it's inline - int spaceDiff = requiredWidth - maxHotseatWidth; - int numOfSpaces = numShownHotseatIcons - (isQsbInline ? 0 : 1); - hotseatBorderSpace -= (spaceDiff / numOfSpaces); - - int minHotseatIconSpaceDp = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space); - int minHotseatQsbWidthDp = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width); + // The side space with inline buttons should be what is defined in InvariantDeviceProfile + int sideSpace = inlineNavButtonsEndSpacing; + int maxHotseatWidth = availableWidthPx - sideSpace - hotseatBarEndOffset; + int maxHotseatIconsWidth = maxHotseatWidth - (isQsbInline ? hotseatQsbWidth : 0); + hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidth, + (isQsbInline ? 1 : 0) + /* border between nav buttons and first icon */ 1); - if (hotseatBorderSpace >= minHotseatIconSpaceDp) { + if (hotseatBorderSpace >= minHotseatIconSpacePx) { return; } // Border space can't be less than the minimum - hotseatBorderSpace = minHotseatIconSpaceDp; - requiredWidth = getHotseatRequiredWidth(); + hotseatBorderSpace = minHotseatIconSpacePx; + int requiredWidth = getHotseatRequiredWidth(); // If there is an inline qsb, change its size if (isQsbInline) { hotseatQsbWidth -= requiredWidth - maxHotseatWidth; - if (hotseatQsbWidth >= minHotseatQsbWidthDp) { + if (hotseatQsbWidth >= minHotseatQsbWidthPx) { return; } // QSB can't be less than the minimum - hotseatQsbWidth = minHotseatQsbWidthDp; + hotseatQsbWidth = minHotseatQsbWidthPx; } + maxHotseatIconsWidth = maxHotseatWidth - (isQsbInline ? hotseatQsbWidth : 0); + // If it still doesn't fit, start removing icons do { numShownHotseatIcons--; - requiredWidth = getHotseatRequiredWidth(); - } while (requiredWidth > maxHotseatWidth && numShownHotseatIcons > 1); + hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidth, + (isQsbInline ? 1 : 0) + /* border between nav buttons and first icon */ 1); + } while (hotseatBorderSpace < minHotseatIconSpacePx && numShownHotseatIcons > 1); - // Add back some space between the icons - spaceDiff = maxHotseatWidth - requiredWidth; - numOfSpaces = numShownHotseatIcons - (isQsbInline ? 0 : 1); - hotseatBorderSpace += (spaceDiff / numOfSpaces); } private Point getCellLayoutBorderSpace(InvariantDeviceProfile idp) { @@ -683,7 +727,7 @@ public class DeviceProfile { return new Builder(context, inv, mInfo) .setWindowBounds(bounds) - .setUseTwoPanels(isTwoPanels) + .setIsMultiDisplay(isMultiDisplay) .setMultiWindowMode(isMultiWindowMode) .setDotRendererCache(dotRendererCache) .setGestureMode(isGestureMode); @@ -768,6 +812,11 @@ public class DeviceProfile { * Returns the amount of extra (or unused) vertical space. */ private int updateAvailableDimensions(Resources res) { + float invIconSizeDp = inv.iconSize[mTypeIndex]; + float invIconTextSizeSp = inv.iconTextSize[mTypeIndex]; + iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics)); + iconTextSizePx = pxFromSp(invIconTextSizeSp, mMetrics); + updateIconSize(1f, res); updateWorkspacePadding(); @@ -824,20 +873,52 @@ public class DeviceProfile { // Workspace final boolean isVerticalLayout = isVerticalBarLayout(); - float invIconSizeDp = inv.iconSize[mTypeIndex]; - float invIconTextSizeSp = inv.iconTextSize[mTypeIndex]; - - iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, iconScale)); - iconTextSizePx = (int) (pxFromSp(invIconTextSizeSp, mMetrics) * iconScale); iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * iconScale); - cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv, scale); if (isScalableGrid) { cellWidthPx = pxFromDp(inv.minCellSize[mTypeIndex].x, mMetrics, scale); cellHeightPx = pxFromDp(inv.minCellSize[mTypeIndex].y, mMetrics, scale); - int cellContentHeight = iconSizePx + iconDrawablePaddingPx - + Utilities.calculateTextHeight(iconTextSizePx); + + if (cellWidthPx < iconSizePx) { + // If cellWidth no longer fit iconSize, reduce borderSpace to make cellWidth bigger. + int numColumns = getPanelCount() * inv.numColumns; + int numBorders = numColumns - 1; + int extraWidthRequired = (iconSizePx - cellWidthPx) * numColumns; + if (cellLayoutBorderSpacePx.x * numBorders >= extraWidthRequired) { + cellWidthPx = iconSizePx; + cellLayoutBorderSpacePx.x -= extraWidthRequired / numBorders; + } else { + // If it still doesn't fit, set borderSpace to 0 and distribute the space for + // cellWidth, and reduce iconSize. + cellWidthPx = (cellWidthPx * numColumns + + cellLayoutBorderSpacePx.x * numBorders) / numColumns; + iconSizePx = Math.min(iconSizePx, cellWidthPx); + cellLayoutBorderSpacePx.x = 0; + } + } + + int cellTextAndPaddingHeight = + iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx); + int cellContentHeight = iconSizePx + cellTextAndPaddingHeight; + if (cellHeightPx < cellContentHeight) { + // If cellHeight no longer fit iconSize, reduce borderSpace to make cellHeight + // bigger. + int numBorders = inv.numRows - 1; + int extraHeightRequired = (cellContentHeight - cellHeightPx) * inv.numRows; + if (cellLayoutBorderSpacePx.y * numBorders >= extraHeightRequired) { + cellHeightPx = cellContentHeight; + cellLayoutBorderSpacePx.y -= extraHeightRequired / numBorders; + } else { + // If it still doesn't fit, set borderSpace to 0 and distribute the space for + // cellHeight, and reduce iconSize. + cellHeightPx = (cellHeightPx * inv.numRows + + cellLayoutBorderSpacePx.y * numBorders) / inv.numRows; + iconSizePx = Math.min(iconSizePx, cellHeightPx - cellTextAndPaddingHeight); + cellLayoutBorderSpacePx.y = 0; + } + cellContentHeight = iconSizePx + cellTextAndPaddingHeight; + } cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2; desiredWorkspaceHorizontalMarginPx = (int) (desiredWorkspaceHorizontalMarginOriginalPx * scale); @@ -868,15 +949,14 @@ public class DeviceProfile { } /** - * Hotseat width spans a certain number of columns on scalable grids. - * This method calculates the space between the icons to achieve that width. + * This method calculates the space between the icons to achieve a certain width. */ - private int calculateHotseatBorderSpace() { - if (!isScalableGrid) return 0; - int columns = inv.hotseatColumnSpan[mTypeIndex]; - float hotseatWidthPx = getIconToIconWidthForColumns(columns); + private int calculateHotseatBorderSpace(float hotseatWidthPx, int numExtraBorder) { float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons; - return (int) (hotseatWidthPx - hotseatIconsTotalPx) / (numShownHotseatIcons - 1); + int hotseatBorderSpace = + (int) (hotseatWidthPx - hotseatIconsTotalPx) + / (numShownHotseatIcons - 1 + numExtraBorder); + return Math.min(hotseatBorderSpace, maxHotseatIconSpacePx); } @@ -889,17 +969,41 @@ public class DeviceProfile { pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].y, mMetrics, scale)); // AllApps cells don't have real space between cells, // so we add the border space to the cell height - allAppsCellHeightPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].y, mMetrics, scale) + allAppsCellHeightPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].y, mMetrics) + allAppsBorderSpacePx.y; // but width is just the cell, // the border is added in #updateAllAppsContainerWidth if (isScalableGrid) { - allAppsIconSizePx = - pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics, scale); - allAppsIconTextSizePx = - pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics, scale); + allAppsIconSizePx = pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics); + allAppsIconTextSizePx = pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics); allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx; allAppsCellWidthPx = pxFromDp(inv.allAppsCellSize[mTypeIndex].x, mMetrics, scale); + + if (allAppsCellWidthPx < allAppsIconSizePx) { + // If allAppsCellWidth no longer fit allAppsIconSize, reduce allAppsBorderSpace to + // make allAppsCellWidth bigger. + int numBorders = inv.numAllAppsColumns - 1; + int extraWidthRequired = + (allAppsIconSizePx - allAppsCellWidthPx) * inv.numAllAppsColumns; + if (allAppsBorderSpacePx.x * numBorders >= extraWidthRequired) { + allAppsCellWidthPx = allAppsIconSizePx; + allAppsBorderSpacePx.x -= extraWidthRequired / numBorders; + } else { + // If it still doesn't fit, set allAppsBorderSpace to 0 and distribute the space + // for allAppsCellWidth, and reduce allAppsIconSize. + allAppsCellWidthPx = (allAppsCellWidthPx * inv.numAllAppsColumns + + allAppsBorderSpacePx.x * numBorders) / inv.numAllAppsColumns; + allAppsIconSizePx = Math.min(allAppsIconSizePx, allAppsCellWidthPx); + allAppsBorderSpacePx.x = 0; + } + } + + int cellContentHeight = allAppsIconSizePx + + Utilities.calculateTextHeight(allAppsIconTextSizePx) + allAppsBorderSpacePx.y; + if (allAppsCellHeightPx < cellContentHeight) { + // Increase allAppsCellHeight to fit its content. + allAppsCellHeightPx = cellContentHeight; + } } else { float invIconSizeDp = inv.allAppsIconSize[mTypeIndex]; float invIconTextSizeSp = inv.allAppsIconTextSize[mTypeIndex]; @@ -919,22 +1023,20 @@ public class DeviceProfile { private void updateAvailableFolderCellDimensions(Resources res) { updateFolderCellSize(1f, res); - final int folderBottomPanelSize = res.getDimensionPixelSize(R.dimen.folder_label_height); - // Don't let the folder get too close to the edges of the screen. int folderMargin = edgeMarginPx * 2; Point totalWorkspacePadding = getTotalWorkspacePadding(); // Check if the icons fit within the available height. float contentUsedHeight = folderCellHeightPx * inv.numFolderRows - + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx.y); - int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y - folderBottomPanelSize + + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx); + int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y - folderFooterHeightPx - folderMargin - folderContentPaddingTop; float scaleY = contentMaxHeight / contentUsedHeight; // Check if the icons fit within the available width. float contentUsedWidth = folderCellWidthPx * inv.numFolderColumns - + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx.x); + + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx); int contentMaxWidth = availableWidthPx - totalWorkspacePadding.x - folderMargin - folderContentPaddingLeftRight * 2; float scaleX = contentMaxWidth / contentUsedWidth; @@ -946,25 +1048,21 @@ public class DeviceProfile { } private void updateFolderCellSize(float scale, Resources res) { - float invIconSizeDp = isVerticalBarLayout() - ? inv.iconSize[INDEX_LANDSCAPE] - : inv.iconSize[INDEX_DEFAULT]; + float invIconSizeDp = inv.iconSize[mTypeIndex]; folderChildIconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, scale)); - folderChildTextSizePx = - pxFromSp(inv.iconTextSize[INDEX_DEFAULT], mMetrics, scale); - folderLabelTextSizePx = (int) (folderChildTextSizePx * folderLabelTextScale); + folderChildTextSizePx = pxFromSp(inv.iconTextSize[mTypeIndex], mMetrics, scale); + folderLabelTextSizePx = Math.max(pxFromSp(MIN_FOLDER_TEXT_SIZE_SP, mMetrics), + (int) (folderChildTextSizePx * folderLabelTextScale)); int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx); if (isScalableGrid) { - folderCellWidthPx = pxFromDp(inv.folderCellSize.x, mMetrics, scale); - folderCellHeightPx = pxFromDp(inv.folderCellSize.y, mMetrics, scale); - - folderCellLayoutBorderSpacePx = new Point( - pxFromDp(inv.folderBorderSpaces.x, mMetrics, scale), - pxFromDp(inv.folderBorderSpaces.y, mMetrics, scale)); - folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx.x; - folderContentPaddingTop = pxFromDp(inv.folderTopPadding, mMetrics, scale); + if (inv.folderStyle == INVALID_RESOURCE_HANDLE) { + folderCellWidthPx = pxFromDp(getCellSize().x, mMetrics, scale); + folderCellHeightPx = pxFromDp(getCellSize().y, mMetrics, scale); + } + + folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx; } else { int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding) * scale); @@ -973,6 +1071,10 @@ public class DeviceProfile { folderCellWidthPx = folderChildIconSizePx + 2 * cellPaddingX; folderCellHeightPx = folderChildIconSizePx + 2 * cellPaddingY + textHeight; + folderContentPaddingLeftRight = + res.getDimensionPixelSize(R.dimen.folder_content_padding_left_right); + folderFooterHeightPx = + res.getDimensionPixelSize(R.dimen.folder_footer_height_default); } folderChildDrawablePaddingPx = Math.max(0, @@ -1172,12 +1274,16 @@ public class DeviceProfile { int hotseatBarTopPadding = hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx; - // Push icons to the side - int requiredWidth = getHotseatRequiredWidth(); - int hotseatWidth = Math.min(requiredWidth, availableWidthPx - hotseatBarEndOffset); - int sideSpacing = (availableWidthPx - hotseatWidth) / 2; + int hotseatWidth = getHotseatRequiredWidth(); + int leftSpacing = (availableWidthPx - hotseatWidth) / 2; + int rightSpacing = leftSpacing; + // Hotseat aligns to the left with nav buttons + if (hotseatBarEndOffset > 0) { + leftSpacing = inlineNavButtonsEndSpacing; + rightSpacing = availableWidthPx - hotseatWidth - leftSpacing + hotseatBorderSpace; + } - hotseatBarPadding.set(sideSpacing, hotseatBarTopPadding, sideSpacing, + hotseatBarPadding.set(leftSpacing, hotseatBarTopPadding, rightSpacing, hotseatBarBottomPadding); boolean isRtl = Utilities.isRtl(context.getResources()); @@ -1186,14 +1292,6 @@ public class DeviceProfile { } else { hotseatBarPadding.left += getAdditionalQsbSpace(); } - - if (hotseatBarEndOffset > sideSpacing) { - int diff = isRtl - ? sideSpacing - hotseatBarEndOffset - : hotseatBarEndOffset - sideSpacing; - hotseatBarPadding.left -= diff; - hotseatBarPadding.right += diff; - } } else if (isScalableGrid) { int sideSpacing = (availableWidthPx - hotseatQsbWidth) / 2; hotseatBarPadding.set(sideSpacing, @@ -1229,7 +1327,7 @@ public class DeviceProfile { private int getHotseatRequiredWidth() { int additionalQsbSpace = getAdditionalQsbSpace(); return iconSizePx * numShownHotseatIcons - + hotseatBorderSpace * (numShownHotseatIcons - 1) + + hotseatBorderSpace * (numShownHotseatIcons - (areNavButtonsInline ? 0 : 1)) + additionalQsbSpace; } @@ -1271,12 +1369,17 @@ public class DeviceProfile { * Returns the number of pixels required below OverviewActions excluding insets. */ public int getOverviewActionsClaimedSpaceBelow() { - if (isTaskbarPresent && !isGestureMode) { - // Align vertically to where nav buttons are. - return ((taskbarSize - overviewActionsHeight) / 2) + getTaskbarOffsetY(); - } + if (isTaskbarPresent) { + if (FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) { + return taskbarSize + transientTaskbarMargin * 2; + } - return isTaskbarPresent ? stashedTaskbarSize : mInsets.bottom; + return isGestureMode + ? stashedTaskbarSize + // Align vertically to where nav buttons are. + : ((taskbarSize - overviewActionsHeight) / 2) + getTaskbarOffsetY(); + } + return mInsets.bottom; } /** Gets the space that the overview actions will take, including bottom margin. */ @@ -1451,13 +1554,12 @@ public class DeviceProfile { writer.println(prefix + pxToDpStr("folderChildTextSizePx", folderChildTextSizePx)); writer.println(prefix + pxToDpStr("folderChildDrawablePaddingPx", folderChildDrawablePaddingPx)); - writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx Horizontal", - folderCellLayoutBorderSpacePx.x)); - writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx Vertical", - folderCellLayoutBorderSpacePx.y)); + writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx", + folderCellLayoutBorderSpacePx)); writer.println(prefix + pxToDpStr("folderContentPaddingLeftRight", folderContentPaddingLeftRight)); writer.println(prefix + pxToDpStr("folderTopPadding", folderContentPaddingTop)); + writer.println(prefix + pxToDpStr("folderFooterHeight", folderFooterHeightPx)); writer.println(prefix + pxToDpStr("bottomSheetTopPadding", bottomSheetTopPadding)); writer.println(prefix + "\tbottomSheetOpenDuration: " + bottomSheetOpenDuration); @@ -1524,11 +1626,7 @@ public class DeviceProfile { writer.println(prefix + pxToDpStr("extraSpace", extraSpace)); writer.println(prefix + pxToDpStr("unscaled extraSpace", extraSpace / iconScale)); - if (inv.devicePaddings != null) { - int unscaledExtraSpace = (int) (extraSpace / iconScale); - writer.println(prefix + pxToDpStr("maxEmptySpace", - inv.devicePaddings.getDevicePadding(unscaledExtraSpace).getMaxEmptySpacePx())); - } + writer.println(prefix + pxToDpStr("maxEmptySpace", maxEmptySpace)); writer.println(prefix + pxToDpStr("workspaceTopPadding", workspaceTopPadding)); writer.println(prefix + pxToDpStr("workspaceBottomPadding", workspaceBottomPadding)); @@ -1544,6 +1642,8 @@ public class DeviceProfile { overviewActionsTopMarginPx)); writer.println(prefix + pxToDpStr("overviewActionsHeight", overviewActionsHeight)); + writer.println(prefix + pxToDpStr("overviewActionsClaimedSpaceBelow", + getOverviewActionsClaimedSpaceBelow())); writer.println(prefix + pxToDpStr("overviewActionsButtonSpacing", overviewActionsButtonSpacing)); writer.println(prefix + pxToDpStr("overviewPageSpacing", overviewPageSpacing)); @@ -1589,35 +1689,6 @@ public class DeviceProfile { void onDeviceProfileChanged(DeviceProfile dp); } - /** Allows registering listeners for {@link DeviceProfile} changes. */ - public interface DeviceProfileListenable { - - /** The current device profile. */ - DeviceProfile getDeviceProfile(); - - /** Registered {@link OnDeviceProfileChangeListener} instances. */ - List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners(); - - /** Notifies listeners of a {@link DeviceProfile} change. */ - default void dispatchDeviceProfileChanged() { - DeviceProfile deviceProfile = getDeviceProfile(); - List<OnDeviceProfileChangeListener> listeners = getOnDeviceProfileChangeListeners(); - for (int i = listeners.size() - 1; i >= 0; i--) { - listeners.get(i).onDeviceProfileChanged(deviceProfile); - } - } - - /** Register listener for {@link DeviceProfile} changes. */ - default void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { - getOnDeviceProfileChangeListeners().add(listener); - } - - /** Unregister listener for {@link DeviceProfile} changes. */ - default void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { - getOnDeviceProfileChangeListeners().remove(listener); - } - } - /** * Handler that deals with ItemInfo of the views for the DeviceProfile */ @@ -1640,7 +1711,7 @@ public class DeviceProfile { private Info mInfo; private WindowBounds mWindowBounds; - private boolean mUseTwoPanels; + private boolean mIsMultiDisplay; private boolean mIsMultiWindowMode = false; private Boolean mTransposeLayoutWithOrientation; @@ -1660,8 +1731,8 @@ public class DeviceProfile { return this; } - public Builder setUseTwoPanels(boolean useTwoPanels) { - mUseTwoPanels = useTwoPanels; + public Builder setIsMultiDisplay(boolean isMultiDisplay) { + mIsMultiDisplay = isMultiDisplay; return this; } @@ -1715,7 +1786,7 @@ public class DeviceProfile { mViewScaleProvider = DEFAULT_PROVIDER; } return new DeviceProfile(mContext, mInv, mInfo, mWindowBounds, mDotRendererCache, - mIsMultiWindowMode, mTransposeLayoutWithOrientation, mUseTwoPanels, + mIsMultiWindowMode, mTransposeLayoutWithOrientation, mIsMultiDisplay, mIsGestureMode, mViewScaleProvider); } } diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java index 98ecf3a7e6..52257319f3 100644 --- a/src/com/android/launcher3/DropTargetBar.java +++ b/src/com/android/launcher3/DropTargetBar.java @@ -18,6 +18,7 @@ package com.android.launcher3; import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT; import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility; +import static com.android.launcher3.config.FeatureFlags.HOME_GARDENING_WORKSPACE_BUTTONS; import android.animation.TimeInterpolator; import android.content.Context; @@ -118,7 +119,13 @@ public class DropTargetBar extends FrameLayout lp.rightMargin = (grid.widthPx - lp.width) / 2; } lp.height = grid.dropTargetBarSizePx; - lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; + // TODO: Add tablet support for DropTargetBar when HOME_GARDENING_WORKSPACE_BUTTONS flag + // is on + if (HOME_GARDENING_WORKSPACE_BUTTONS.get()) { + lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; + } else { + lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; + } DeviceProfile dp = mLauncher.getDeviceProfile(); int horizontalPadding = dp.dropTargetHorizontalPaddingPx; diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java index 11f2020054..f94a3c5521 100644 --- a/src/com/android/launcher3/ExtendedEditText.java +++ b/src/com/android/launcher3/ExtendedEditText.java @@ -18,6 +18,7 @@ package com.android.launcher3; import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.SHOW; import android.content.Context; +import android.graphics.Rect; import android.text.TextUtils; import android.util.AttributeSet; import android.view.DragEvent; @@ -27,12 +28,17 @@ import android.widget.EditText; import com.android.launcher3.views.ActivityContext; +import java.util.HashSet; +import java.util.Set; + /** * The edit text that reports back when the back key has been pressed. * Note: AppCompatEditText doesn't fully support #displayCompletions and #onCommitCompletion */ public class ExtendedEditText extends EditText { + private final Set<OnFocusChangeListener> mOnFocusChangeListeners = new HashSet<>(); + private boolean mForceDisableSuggestions = false; /** @@ -129,4 +135,38 @@ public class ExtendedEditText extends EditText { setText(""); } } + + /** + * This method should be preferred to {@link #setOnFocusChangeListener(OnFocusChangeListener)}, + * as it allows for multiple listeners from different sources. + */ + public void addOnFocusChangeListener(OnFocusChangeListener listener) { + mOnFocusChangeListeners.add(listener); + } + + /** + * Removes the given listener from the set of registered focus listeners, or does nothing if it + * wasn't registered in the first place. + */ + public void removeOnFocusChangeListener(OnFocusChangeListener listener) { + mOnFocusChangeListeners.remove(listener); + } + + @Override + protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { + super.onFocusChanged(focused, direction, previouslyFocusedRect); + for (OnFocusChangeListener listener : mOnFocusChangeListeners) { + listener.onFocusChange(this, focused); + } + } + + /** + * Save the input, suggestion, hint states when it's on focus, and set to unfocused states. + */ + public void saveFocusedStateAndUpdateToUnfocusedState() {} + + /** + * Restore to the previous saved focused state. + */ + public void restoreToFocusedState() {} } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 6a262c3f91..a4020f9cab 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -17,7 +17,9 @@ package com.android.launcher3; import static com.android.launcher3.Utilities.dpiFromPx; +import static com.android.launcher3.config.FeatureFlags.ENABLE_DEVICE_PROFILE_LOGGING; import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME; +import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE; import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY; import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE; import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS; @@ -43,9 +45,11 @@ import android.util.TypedValue; import android.util.Xml; import android.view.Display; +import androidx.annotation.DimenRes; import androidx.annotation.IntDef; -import androidx.annotation.Nullable; +import androidx.annotation.StyleRes; import androidx.annotation.VisibleForTesting; +import androidx.annotation.XmlRes; import androidx.core.content.res.ResourcesCompat; import com.android.launcher3.icons.DotRenderer; @@ -56,6 +60,7 @@ import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.MainThreadInitializedObject; +import com.android.launcher3.util.Partner; import com.android.launcher3.util.Themes; import com.android.launcher3.util.WindowBounds; import com.android.launcher3.util.window.WindowManagerProxy; @@ -64,6 +69,8 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -106,6 +113,11 @@ public class InvariantDeviceProfile { static final int INDEX_TWO_PANEL_PORTRAIT = 2; static final int INDEX_TWO_PANEL_LANDSCAPE = 3; + /** These resources are used to override the device profile */ + private static final String RES_GRID_NUM_ROWS = "grid_num_rows"; + private static final String RES_GRID_NUM_COLUMNS = "grid_num_columns"; + private static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp"; + /** * Number of icons per row and column in the workspace. */ @@ -127,11 +139,9 @@ public class InvariantDeviceProfile { public PointF[] minCellSize; public PointF[] borderSpaces; - public int inlineNavButtonsEndSpacing; + public @DimenRes int inlineNavButtonsEndSpacing; - public PointF folderBorderSpaces; - public PointF folderCellSize; - public float folderTopPadding; + public @StyleRes int folderStyle; public float[] horizontalMargin; @@ -168,7 +178,8 @@ public class InvariantDeviceProfile { * Do not query directly. see {@link DeviceProfile#isScalableGrid}. */ protected boolean isScalable; - public int devicePaddingId; + @XmlRes + public int devicePaddingId = INVALID_RESOURCE_HANDLE; public String dbFile; public int defaultLayoutId; @@ -180,9 +191,6 @@ public class InvariantDeviceProfile { */ public List<DeviceProfile> supportedProfiles = Collections.EMPTY_LIST; - @Nullable - public DevicePaddings devicePaddings; - public Point defaultWallpaperSize; public Rect defaultWidgetPadding; @@ -196,7 +204,10 @@ public class InvariantDeviceProfile { String gridName = getCurrentGridName(context); String newGridName = initGrid(context, gridName); if (!newGridName.equals(gridName)) { - Utilities.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName).apply(); + LauncherPrefs.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName) + .apply(); + Log.d("b/258560494", "InvariantDeviceProfile - setting newGridName: " + newGridName + + ", gridName: " + gridName); } new DeviceGridState(this).writeToPrefs(context); @@ -304,8 +315,7 @@ public class InvariantDeviceProfile { } public static String getCurrentGridName(Context context) { - return Utilities.isGridOptionsEnabled(context) - ? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null) : null; + return LauncherPrefs.getPrefs(context).getString(KEY_IDP_GRID_NAME, null); } private String initGrid(Context context, String gridName) { @@ -321,6 +331,11 @@ public class InvariantDeviceProfile { return displayOption.grid.name; } + @VisibleForTesting + public static String getDefaultGridName(Context context) { + return new InvariantDeviceProfile().initGrid(context, null); + } + private void initGrid(Context context, Info displayInfo, DisplayOption displayOption, @DeviceType int deviceType) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); @@ -331,8 +346,11 @@ public class InvariantDeviceProfile { dbFile = closestProfile.dbFile; defaultLayoutId = closestProfile.defaultLayoutId; demoModeLayoutId = closestProfile.demoModeLayoutId; + numFolderRows = closestProfile.numFolderRows; numFolderColumns = closestProfile.numFolderColumns; + folderStyle = closestProfile.folderStyle; + isScalable = closestProfile.isScalable; devicePaddingId = closestProfile.devicePaddingId; this.deviceType = deviceType; @@ -355,10 +373,6 @@ public class InvariantDeviceProfile { borderSpaces = displayOption.borderSpaces; - folderBorderSpaces = displayOption.folderBorderSpaces; - folderCellSize = displayOption.folderCellSize; - folderTopPadding = displayOption.folderTopPadding; - horizontalMargin = displayOption.horizontalMargin; numShownHotseatIcons = closestProfile.numHotseatIcons; @@ -376,14 +390,6 @@ public class InvariantDeviceProfile { allAppsBorderSpaces = displayOption.allAppsBorderSpaces; allAppsIconSize = displayOption.allAppsIconSizes; allAppsIconTextSize = displayOption.allAppsIconTextSizes; - if (!Utilities.isGridOptionsEnabled(context)) { - allAppsIconSize = iconSize; - allAppsIconTextSize = iconTextSize; - } - - if (devicePaddingId != 0) { - devicePaddings = new DevicePaddings(context, devicePaddingId); - } inlineQsb = closestProfile.inlineQsb; @@ -396,7 +402,7 @@ public class InvariantDeviceProfile { SparseArray<DotRenderer> dotRendererCache = new SparseArray<>(); for (WindowBounds bounds : displayInfo.supportedBounds) { localSupportedProfiles.add(new DeviceProfile.Builder(context, this, displayInfo) - .setUseTwoPanels(deviceType == TYPE_MULTI_DISPLAY) + .setIsMultiDisplay(deviceType == TYPE_MULTI_DISPLAY) .setWindowBounds(bounds) .setDotRendererCache(dotRendererCache) .build()); @@ -418,6 +424,21 @@ public class InvariantDeviceProfile { } supportedProfiles = Collections.unmodifiableList(localSupportedProfiles); + int numMinShownHotseatIconsForTablet = supportedProfiles + .stream() + .filter(deviceProfile -> deviceProfile.isTablet) + .mapToInt(deviceProfile -> deviceProfile.numShownHotseatIcons) + .min() + .orElse(0); + + supportedProfiles + .stream() + .filter(deviceProfile -> deviceProfile.isTablet) + .forEach(deviceProfile -> { + deviceProfile.numShownHotseatIcons = numMinShownHotseatIconsForTablet; + deviceProfile.recalculateHotseatWidthAndBorderSpace(); + }); + ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName()); defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null); } @@ -433,7 +454,8 @@ public class InvariantDeviceProfile { public void setCurrentGrid(Context context, String gridName) { Context appContext = context.getApplicationContext(); - Utilities.getPrefs(appContext).edit().putString(KEY_IDP_GRID_NAME, gridName).apply(); + LauncherPrefs.getPrefs(appContext).edit().putString(KEY_IDP_GRID_NAME, gridName).apply(); + Log.d("b/258560494", "setCurrentGrid: " + gridName); MAIN_EXECUTOR.execute(() -> onConfigChanged(appContext)); } @@ -498,6 +520,10 @@ public class InvariantDeviceProfile { } } if (filteredProfiles.isEmpty()) { + if (gridName != null) { + Log.d("b/258560494", "No matching grid from for gridName: " + gridName + + ", deviceType: " + deviceType); + } // No grid found, use the default options for (DisplayOption option : profiles) { if (option.canBeDefault) { @@ -569,8 +595,24 @@ public class InvariantDeviceProfile { */ private void applyPartnerDeviceProfileOverrides(Context context, DisplayMetrics dm) { Partner p = Partner.get(context.getPackageManager()); - if (p != null) { - p.applyInvariantDeviceProfileOverrides(this, dm); + if (p == null) { + return; + } + try { + int numRows = p.getIntValue(RES_GRID_NUM_ROWS, -1); + int numColumns = p.getIntValue(RES_GRID_NUM_COLUMNS, -1); + float iconSizePx = p.getDimenValue(RES_GRID_ICON_SIZE_DP, -1); + + if (numRows > 0 && numColumns > 0) { + this.numRows = numRows; + this.numColumns = numColumns; + } + if (iconSizePx > 0) { + this.iconSize[InvariantDeviceProfile.INDEX_DEFAULT] = + Utilities.dpiFromPx(iconSizePx, dm.densityDpi); + } + } catch (Resources.NotFoundException ex) { + Log.e(TAG, "Invalid Partner grid resource!", ex); } } @@ -641,6 +683,18 @@ public class InvariantDeviceProfile { float screenHeight = config.screenHeightDp * res.getDisplayMetrics().density; int rotation = WindowManagerProxy.INSTANCE.get(context).getRotation(context); + if (Utilities.IS_DEBUG_DEVICE && ENABLE_DEVICE_PROFILE_LOGGING.get()) { + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + DisplayController.INSTANCE.get(context).dump(printWriter); + printWriter.flush(); + Log.d("b/253338238", "getDeviceProfile -" + + "\nconfig: " + config + + "\ndisplayMetrics: " + res.getDisplayMetrics() + + "\nrotation: " + rotation + + "\n" + stringWriter, + new Exception()); + } return getBestMatch(screenWidth, screenHeight, rotation); } @@ -735,6 +789,7 @@ public class InvariantDeviceProfile { private final int numFolderRows; private final int numFolderColumns; + private final @StyleRes int folderStyle; private final int numAllAppsColumns; private final int numDatabaseAllAppsColumns; @@ -745,7 +800,7 @@ public class InvariantDeviceProfile { private final boolean[] inlineQsb = new boolean[COUNT_SIZES]; - private int inlineNavButtonsEndSpacing; + private @DimenRes int inlineNavButtonsEndSpacing; private final String dbFile; private final int defaultLayoutId; @@ -766,10 +821,8 @@ public class InvariantDeviceProfile { R.styleable.GridDisplayOption_numSearchContainerColumns, numColumns); dbFile = a.getString(R.styleable.GridDisplayOption_dbFile); - defaultLayoutId = a.getResourceId(deviceType == TYPE_MULTI_DISPLAY && a.hasValue( - R.styleable.GridDisplayOption_defaultSplitDisplayLayoutId) - ? R.styleable.GridDisplayOption_defaultSplitDisplayLayoutId - : R.styleable.GridDisplayOption_defaultLayoutId, 0); + defaultLayoutId = a.getResourceId( + R.styleable.GridDisplayOption_defaultLayoutId, 0); demoModeLayoutId = a.getResourceId( R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId); @@ -797,15 +850,19 @@ public class InvariantDeviceProfile { inlineNavButtonsEndSpacing = a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing, R.dimen.taskbar_button_margin_default); + numFolderRows = a.getInt( R.styleable.GridDisplayOption_numFolderRows, numRows); numFolderColumns = a.getInt( R.styleable.GridDisplayOption_numFolderColumns, numColumns); + folderStyle = a.getResourceId(R.styleable.GridDisplayOption_folderStyle, + INVALID_RESOURCE_HANDLE); + isScalable = a.getBoolean( R.styleable.GridDisplayOption_isScalable, false); devicePaddingId = a.getResourceId( - R.styleable.GridDisplayOption_devicePaddingId, 0); + R.styleable.GridDisplayOption_devicePaddingId, INVALID_RESOURCE_HANDLE); int deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory, DEVICE_CATEGORY_ALL); @@ -846,10 +903,6 @@ public class InvariantDeviceProfile { private final PointF[] minCellSize = new PointF[COUNT_SIZES]; - private final PointF folderCellSize; - private final PointF folderBorderSpaces; - private float folderTopPadding; - private final PointF[] borderSpaces = new PointF[COUNT_SIZES]; private final float[] horizontalMargin = new float[COUNT_SIZES]; private final float[] hotseatBarBottomSpace = new float[COUNT_SIZES]; @@ -932,21 +985,6 @@ public class InvariantDeviceProfile { borderSpaceTwoPanelLandscape); borderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = new PointF(x, y); - x = a.getFloat(R.styleable.ProfileDisplayOption_folderCellWidth, - minCellSize[INDEX_DEFAULT].x); - y = a.getFloat(R.styleable.ProfileDisplayOption_folderCellHeight, - minCellSize[INDEX_DEFAULT].y); - folderCellSize = new PointF(x, y); - - float folderBorderSpace = a.getFloat(R.styleable.ProfileDisplayOption_folderBorderSpace, - borderSpace); - - x = y = folderBorderSpace; - folderBorderSpaces = new PointF(x, y); - - folderTopPadding = a.getFloat(R.styleable.ProfileDisplayOption_folderTopPadding, - folderBorderSpaces.y); - x = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellWidth, minCellSize[INDEX_DEFAULT].x); y = a.getFloat(R.styleable.ProfileDisplayOption_allAppsCellHeight, @@ -1027,7 +1065,7 @@ public class InvariantDeviceProfile { R.styleable.ProfileDisplayOption_allAppsIconSize, iconSizes[INDEX_DEFAULT]); allAppsIconSizes[INDEX_LANDSCAPE] = a.getFloat( R.styleable.ProfileDisplayOption_allAppsIconSizeLandscape, - iconSizes[INDEX_DEFAULT]); + allAppsIconSizes[INDEX_DEFAULT]); allAppsIconSizes[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat( R.styleable.ProfileDisplayOption_allAppsIconSizeTwoPanelPortrait, allAppsIconSizes[INDEX_DEFAULT]); @@ -1119,9 +1157,6 @@ public class InvariantDeviceProfile { allAppsIconTextSizes[i] = 0; allAppsBorderSpaces[i] = new PointF(); } - folderBorderSpaces = new PointF(); - folderCellSize = new PointF(); - folderTopPadding = 0f; } private DisplayOption multiply(float w) { @@ -1142,11 +1177,6 @@ public class InvariantDeviceProfile { allAppsBorderSpaces[i].x *= w; allAppsBorderSpaces[i].y *= w; } - folderBorderSpaces.x *= w; - folderBorderSpaces.y *= w; - folderCellSize.x *= w; - folderCellSize.y *= w; - folderTopPadding *= w; return this; } @@ -1169,11 +1199,6 @@ public class InvariantDeviceProfile { allAppsBorderSpaces[i].x += p.allAppsBorderSpaces[i].x; allAppsBorderSpaces[i].y += p.allAppsBorderSpaces[i].y; } - folderBorderSpaces.x += p.folderBorderSpaces.x; - folderBorderSpaces.y += p.folderBorderSpaces.y; - folderCellSize.x += p.folderCellSize.x; - folderCellSize.y += p.folderCellSize.y; - folderTopPadding += p.folderTopPadding; return this; } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index a6831aafa9..43772e4279 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -43,6 +43,7 @@ import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions; import static com.android.launcher3.anim.Interpolators.EMPHASIZED; +import static com.android.launcher3.config.FeatureFlags.SHOW_DOT_PAGINATION; import static com.android.launcher3.logging.StatsLogManager.EventEnum; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; @@ -51,6 +52,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_EXIT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONSTOP; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RECONFIGURED; import static com.android.launcher3.model.ItemInstallQueue.FLAG_ACTIVITY_PAUSED; import static com.android.launcher3.model.ItemInstallQueue.FLAG_DRAG_AND_DROP; @@ -97,6 +100,7 @@ import android.os.Trace; import android.os.UserHandle; import android.text.TextUtils; import android.text.method.TextKeyListener; +import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Log; import android.util.SparseArray; @@ -129,6 +133,7 @@ import com.android.launcher3.allapps.AllAppsRecyclerView; import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.BaseAllAppsContainerView; +import com.android.launcher3.allapps.BaseSearchConfig; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.compat.AccessibilityManagerCompat; @@ -139,6 +144,7 @@ import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.dragndrop.LauncherDragController; +import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderGridOrganizer; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.icons.BitmapRenderer; @@ -163,6 +169,7 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.notification.NotificationListener; +import com.android.launcher3.pageindicators.WorkspacePageIndicator; import com.android.launcher3.pm.PinRequestHelper; import com.android.launcher3.pm.UserCache; import com.android.launcher3.popup.ArrowPopup; @@ -177,7 +184,6 @@ import com.android.launcher3.states.RotationHelper; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.AllAppsSwipeController; -import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; import com.android.launcher3.util.ActivityResultInfo; import com.android.launcher3.util.ActivityTracker; @@ -201,9 +207,9 @@ import com.android.launcher3.views.FloatingIconView; import com.android.launcher3.views.FloatingSurfaceView; import com.android.launcher3.views.OptionsPopupView; import com.android.launcher3.views.ScrimView; -import com.android.launcher3.widget.LauncherAppWidgetHost; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; +import com.android.launcher3.widget.LauncherWidgetHolder; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.PendingAppWidgetHostView; @@ -217,7 +223,6 @@ import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.shared.LauncherExterns; import com.android.systemui.plugins.shared.LauncherOverlayManager; import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay; -import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -237,7 +242,7 @@ import java.util.stream.Stream; */ public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns, Callbacks, InvariantDeviceProfile.OnIDPChangeListener, - PluginListener<LauncherOverlayPlugin>, LauncherOverlayCallbacks { + PluginListener<LauncherOverlayPlugin> { public static final String TAG = "Launcher"; public static final ActivityTracker<Launcher> ACTIVITY_TRACKER = new ActivityTracker<>(); @@ -307,13 +312,19 @@ public class Launcher extends StatefulActivity<LauncherState> private static final FloatProperty<Hotseat> HOTSEAT_WIDGET_SCALE = HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WIDGET_TRANSITION); + private static final boolean DESKTOP_MODE_1_SUPPORTED = + "1".equals(Utilities.getSystemProperty("persist.wm.debug.desktop_mode", "0")); + + private static final boolean DESKTOP_MODE_2_SUPPORTED = + "1".equals(Utilities.getSystemProperty("persist.wm.debug.desktop_mode_2", "0")); + @Thunk Workspace<?> mWorkspace; @Thunk DragLayer mDragLayer; private WidgetManagerHelper mAppWidgetManager; - private LauncherAppWidgetHost mAppWidgetHost; + private LauncherWidgetHolder mAppWidgetHolder; private final int[] mTmpAddItemCellCoordinates = new int[2]; @@ -392,6 +403,7 @@ public class Launcher extends StatefulActivity<LauncherState> private LauncherState mPrevLauncherState; private StringCache mStringCache; + private BaseSearchConfig mBaseSearchConfig; @Override @TargetApi(Build.VERSION_CODES.S) @@ -466,7 +478,7 @@ public class Launcher extends StatefulActivity<LauncherState> InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); initDeviceProfile(idp); idp.addOnChangeListener(this); - mSharedPrefs = Utilities.getPrefs(this); + mSharedPrefs = LauncherPrefs.getPrefs(this); mIconCache = app.getIconCache(); mAccessibilityDelegate = createAccessibilityDelegate(); @@ -476,9 +488,12 @@ public class Launcher extends StatefulActivity<LauncherState> mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs); + // TODO: move the SearchConfig to SearchState when new LauncherState is created. + mBaseSearchConfig = new BaseSearchConfig(); + mAppWidgetManager = new WidgetManagerHelper(this); - mAppWidgetHost = createAppWidgetHost(); - mAppWidgetHost.startListening(); + mAppWidgetHolder = createAppWidgetHolder(); + mAppWidgetHolder.startListening(); setupViews(); crossFadeWithPreviousAppearance(); @@ -639,14 +654,6 @@ public class Launcher extends StatefulActivity<LauncherState> } /** - * Called when one handed mode activated and deactivated. - * @param activated true if one handed mode activated, false otherwise. - */ - public void onOneHandedStateChanged(boolean activated) { - mDragLayer.onOneHandedModeStateChanged(activated); - } - - /** * Returns {@code true} if a new DeviceProfile is initialized, and {@code false} otherwise. */ protected boolean initDeviceProfile(InvariantDeviceProfile idp) { @@ -687,17 +694,9 @@ public class Launcher extends StatefulActivity<LauncherState> */ @Override public void setLauncherOverlay(LauncherOverlay overlay) { - if (overlay != null) { - overlay.setOverlayCallbacks(this); - } mWorkspace.setLauncherOverlay(overlay); } - @Override - public void runOnOverlayHidden(Runnable runnable) { - getWorkspace().runOnOverlayHidden(runnable); - } - public boolean setLauncherCallbacks(LauncherCallbacks callbacks) { mLauncherCallbacks = callbacks; return true; @@ -955,7 +954,7 @@ public class Launcher extends StatefulActivity<LauncherState> AppWidgetHostView boundWidget = null; if (resultCode == RESULT_OK) { animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION; - final AppWidgetHostView layout = mAppWidgetHost.createView(this, appWidgetId, + final AppWidgetHostView layout = mAppWidgetHolder.createView(this, appWidgetId, requestArgs.getWidgetHandler().getProviderInfo(this)); boundWidget = layout; onCompleteRunnable = new Runnable() { @@ -966,7 +965,7 @@ public class Launcher extends StatefulActivity<LauncherState> } }; } else if (resultCode == RESULT_CANCELED) { - mAppWidgetHost.deleteAppWidgetId(appWidgetId); + mAppWidgetHolder.deleteAppWidgetId(appWidgetId); animationType = Workspace.CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION; } if (mDragLayer.getAnimatedView() != null) { @@ -989,7 +988,7 @@ public class Launcher extends StatefulActivity<LauncherState> } hideKeyboard(); logStopAndResume(false /* isResume */); - mAppWidgetHost.setActivityStarted(false); + mAppWidgetHolder.setActivityStarted(false); NotificationListener.removeNotificationsChangedListener(getPopupDataProvider()); } @@ -1002,7 +1001,7 @@ public class Launcher extends StatefulActivity<LauncherState> mOverlayManager.onActivityStarted(this); } - mAppWidgetHost.setActivityStarted(true); + mAppWidgetHolder.setActivityStarted(true); TraceHelper.INSTANCE.endSection(traceToken); } @@ -1022,7 +1021,7 @@ public class Launcher extends StatefulActivity<LauncherState> NotificationListener.addNotificationsChangedListener(mPopupDataProvider); DiscoveryBounce.showForHomeIfNeeded(this); - mAppWidgetHost.setActivityResumed(true); + mAppWidgetHolder.setActivityResumed(true); } private void logStopAndResume(boolean isResume) { @@ -1137,7 +1136,7 @@ public class Launcher extends StatefulActivity<LauncherState> @Override public void onStateSetEnd(LauncherState state) { super.onStateSetEnd(state); - getAppWidgetHost().setStateIsNormal(state == LauncherState.NORMAL); + getAppWidgetHolder().setStateIsNormal(state == LauncherState.NORMAL); getWorkspace().setClipChildren(!state.hasFlag(FLAG_MULTI_PAGE)); finishAutoCancelActionMode(); @@ -1184,7 +1183,6 @@ public class Launcher extends StatefulActivity<LauncherState> mOverlayManager.onActivityResumed(this); } - AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE); DragView.removeAllViews(this); TraceHelper.INSTANCE.endSection(traceToken); } @@ -1202,19 +1200,7 @@ public class Launcher extends StatefulActivity<LauncherState> if (!mDeferOverlayCallbacks) { mOverlayManager.onActivityPaused(this); } - mAppWidgetHost.setActivityResumed(false); - } - - /** - * {@code LauncherOverlayCallbacks} scroll amount. - * Indicates transition progress to -1 screen. - * @param progress From 0 to 1. - */ - @Override - public void onScrollChanged(float progress) { - if (mWorkspace != null) { - mWorkspace.onOverlayScrollChanged(progress); - } + mAppWidgetHolder.setActivityResumed(false); } /** @@ -1291,6 +1277,15 @@ public class Launcher extends StatefulActivity<LauncherState> mAllAppsController.setupViews(mScrimView, mAppsView); } + @Override + public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { + if ((SHOW_DOT_PAGINATION.get()) && WorkspacePageIndicator.class.getName().equals(name)) { + return LayoutInflater.from(context).inflate(R.layout.page_indicator_dots, + (ViewGroup) parent, false); + } + return super.onCreateView(parent, name, context, attrs); + } + /** * Creates a view representing a shortcut. * @@ -1314,7 +1309,7 @@ public class Launcher extends StatefulActivity<LauncherState> BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.app_icon, parent, false); favorite.applyFromWorkspaceItem(info); - favorite.setOnClickListener(ItemClickHandler.INSTANCE); + favorite.setOnClickListener(getItemOnClickListener()); favorite.setOnFocusChangeListener(mFocusHandler); return favorite; } @@ -1417,7 +1412,7 @@ public class Launcher extends StatefulActivity<LauncherState> if (hostView == null) { // Perform actual inflation because we're live - hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); + hostView = mAppWidgetHolder.createView(this, appWidgetId, appWidgetInfo); } LauncherAppWidgetInfo launcherInfo; @@ -1548,13 +1543,13 @@ public class Launcher extends StatefulActivity<LauncherState> return mScrimView; } - public LauncherAppWidgetHost getAppWidgetHost() { - return mAppWidgetHost; + public LauncherWidgetHolder getAppWidgetHolder() { + return mAppWidgetHolder; } - protected LauncherAppWidgetHost createAppWidgetHost() { - return new LauncherAppWidgetHost(this, - appWidgetId -> getWorkspace().removeWidget(appWidgetId)); + protected LauncherWidgetHolder createAppWidgetHolder() { + return LauncherWidgetHolder.HolderFactory.newFactory(this).newInstance( + this, appWidgetId -> getWorkspace().removeWidget(appWidgetId)); } public LauncherModel getModel() { @@ -1572,13 +1567,17 @@ public class Launcher extends StatefulActivity<LauncherState> @Override public SharedPreferences getDevicePrefs() { - return Utilities.getDevicePrefs(this); + return LauncherPrefs.getDevicePrefs(this); } public int getOrientation() { return mOldConfig.orientation; } + public BaseSearchConfig getSearchConfig() { + return mBaseSearchConfig; + } + @Override protected void onNewIntent(Intent intent) { if (Utilities.IS_RUNNING_IN_TEST_HARNESS) { @@ -1596,7 +1595,6 @@ public class Launcher extends StatefulActivity<LauncherState> && AbstractFloatingView.getTopOpenView(this) == null; boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction()); boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this); - hideKeyboard(); if (isActionMain) { if (!internalStateHandled) { @@ -1683,6 +1681,10 @@ public class Launcher extends StatefulActivity<LauncherState> outState.remove(RUNTIME_STATE_WIDGET_PANEL); } + // We close any open folders and shortcut containers that are not safe for rebind, + // and we need to make sure this state is reflected. + AbstractFloatingView.closeAllOpenViewsExcept( + this, isStarted() && !isForceInvisible(), TYPE_REBIND_SAFE); finishAutoCancelActionMode(); if (mPendingRequestArgs != null) { @@ -1711,10 +1713,11 @@ public class Launcher extends StatefulActivity<LauncherState> mRotationHelper.destroy(); try { - mAppWidgetHost.stopListening(); + mAppWidgetHolder.stopListening(); } catch (NullPointerException ex) { Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex); } + mAppWidgetHolder.destroy(); TextKeyListener.getInstance().release(); clearPendingBinds(); @@ -1886,7 +1889,7 @@ public class Launcher extends StatefulActivity<LauncherState> appWidgetId = CustomWidgetManager.INSTANCE.get(this).getWidgetIdForCustomProvider( info.componentName); } else { - appWidgetId = getAppWidgetHost().allocateAppWidgetId(); + appWidgetId = getAppWidgetHolder().allocateAppWidgetId(); } Bundle options = info.bindOptions; @@ -2000,7 +2003,7 @@ public class Launcher extends StatefulActivity<LauncherState> final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo; mWorkspace.removeWorkspaceItem(v); if (deleteFromDb) { - getModelWriter().deleteWidgetInfo(widgetInfo, getAppWidgetHost(), reason); + getModelWriter().deleteWidgetInfo(widgetInfo, getAppWidgetHolder(), reason); } } else { return false; @@ -2258,7 +2261,7 @@ public class Launcher extends StatefulActivity<LauncherState> mWorkspace.clearDropTargets(); mWorkspace.removeAllWorkspaceScreens(); - mAppWidgetHost.clearViews(); + mAppWidgetHolder.clearViews(); if (mHotseat != null) { mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout()); @@ -2565,7 +2568,7 @@ public class Launcher extends StatefulActivity<LauncherState> if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) { // Id has not been allocated yet. Allocate a new id. - item.appWidgetId = mAppWidgetHost.allocateAppWidgetId(); + item.appWidgetId = mAppWidgetHolder.allocateAppWidgetId(); item.restoreStatus |= LauncherAppWidgetInfo.FLAG_ID_ALLOCATED; // Also try to bind the widget. If the bind fails, the user will be shown @@ -2627,18 +2630,18 @@ public class Launcher extends StatefulActivity<LauncherState> // Verify that we own the widget if (appWidgetInfo == null) { FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId); - getModelWriter().deleteWidgetInfo(item, getAppWidgetHost(), removalReason); + getModelWriter().deleteWidgetInfo(item, getAppWidgetHolder(), removalReason); return null; } item.minSpanX = appWidgetInfo.minSpanX; item.minSpanY = appWidgetInfo.minSpanY; - view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo); + view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo); } else if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) && appWidgetInfo != null) { - mAppWidgetHost.addPendingView(item.appWidgetId, + mAppWidgetHolder.addPendingView(item.appWidgetId, new PendingAppWidgetHostView(this, item, mIconCache, false)); - view = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo); + view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo); } else { view = new PendingAppWidgetHostView(this, item, mIconCache, false); } @@ -2742,6 +2745,8 @@ public class Launcher extends StatefulActivity<LauncherState> getViewCache().setCacheSize(R.layout.folder_page, 2); TraceHelper.INSTANCE.endSection(traceToken); + + mWorkspace.removeExtraEmptyScreen(true); } private boolean canAnimatePageChange() { @@ -2791,16 +2796,30 @@ public class Launcher extends StatefulActivity<LauncherState> } return v; - } else { - List<ViewGroup> containers = new ArrayList<>(mWorkspace.getPanelCount() + 1); - containers.add(mWorkspace.getHotseat().getShortcutsAndWidgets()); - mWorkspace.forEachVisiblePage(page - -> containers.add(((CellLayout) page).getShortcutsAndWidgets())); + } - // Order: Preferred item by itself or in folder, then by matching package/user - return getFirstMatch(containers, preferredItem, forFolderMatch(preferredItem), - packageAndUserAndApp, forFolderMatch(packageAndUserAndApp)); + // Look for the item inside the folder at the current page + Folder folder = Folder.getOpen(this); + if (folder != null) { + View v = getFirstMatch(Collections.singletonList( + folder.getContent().getCurrentCellLayout().getShortcutsAndWidgets()), + preferredItem, + packageAndUserAndApp); + if (v == null) { + folder.close(isStarted() && !isForceInvisible()); + } else { + return v; + } } + + List<ViewGroup> containers = new ArrayList<>(mWorkspace.getPanelCount() + 1); + containers.add(mWorkspace.getHotseat().getShortcutsAndWidgets()); + mWorkspace.forEachVisiblePage(page + -> containers.add(((CellLayout) page).getShortcutsAndWidgets())); + + // Order: Preferred item by itself or in folder, then by matching package/user + return getFirstMatch(containers, preferredItem, forFolderMatch(preferredItem), + packageAndUserAndApp, forFolderMatch(packageAndUserAndApp)); } /** @@ -2853,7 +2872,16 @@ public class Launcher extends StatefulActivity<LauncherState> /** * Informs us that the overlay (-1 screen, typically), has either become visible or invisible. */ - public void onOverlayVisibilityChanged(boolean visible) {} + public void onOverlayVisibilityChanged(boolean visible) { + getStatsLogManager().logger() + .withSrcState(LAUNCHER_STATE_HOME) + .withDstState(LAUNCHER_STATE_HOME) + .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() + .setWorkspace(WorkspaceContainer.newBuilder() + .setPageIndex(visible ? 0 : -1)) + .build()) + .log(visible ? LAUNCHER_SWIPELEFT : LAUNCHER_SWIPERIGHT); + } /** * Informs us that the page transition has ended, so that we can react to the newly selected @@ -2994,7 +3022,8 @@ public class Launcher extends StatefulActivity<LauncherState> writer.println(prefix + "\tmPendingRequestArgs=" + mPendingRequestArgs + " mPendingActivityResult=" + mPendingActivityResult); writer.println(prefix + "\tmRotationHelper: " + mRotationHelper); - writer.println(prefix + "\tmAppWidgetHost.isListening: " + mAppWidgetHost.isListening()); + writer.println(prefix + "\tmAppWidgetHolder.isListening: " + + mAppWidgetHolder.isListening()); // Extra logging for general debugging mDragLayer.dump(prefix, writer); @@ -3129,6 +3158,10 @@ public class Launcher extends StatefulActivity<LauncherState> } private void updateDisallowBack() { + if (DESKTOP_MODE_1_SUPPORTED || DESKTOP_MODE_2_SUPPORTED) { + // Do not disable back in launcher when prototype behavior is enabled + return; + } LauncherRootView rv = getRootView(); if (rv != null) { boolean disableBack = getStateManager().getState() == NORMAL diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java index b858d1a13a..4e80d41402 100644 --- a/src/com/android/launcher3/LauncherAnimUtils.java +++ b/src/com/android/launcher3/LauncherAnimUtils.java @@ -218,4 +218,32 @@ public class LauncherAnimUtils { } }; } + + /** + * A property that updates the specified property within a given range of values (ie. even if + * the animator goes beyond 0..1, the interpolated value will still be bounded). + * @param <T> the specified property + */ + public static class ClampedProperty<T> extends FloatProperty<T> { + private final FloatProperty<T> mProperty; + private final float mMinValue; + private final float mMaxValue; + + public ClampedProperty(FloatProperty<T> property, float minValue, float maxValue) { + super(property.getName() + "Clamped"); + mProperty = property; + mMinValue = minValue; + mMaxValue = maxValue; + } + + @Override + public void setValue(T t, float v) { + mProperty.set(t, Utilities.boundToRange(v, mMinValue, mMaxValue)); + } + + @Override + public Float get(T t) { + return mProperty.get(t); + } + } } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index ea3f723e29..49659364b9 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -18,7 +18,7 @@ package com.android.launcher3; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED; -import static com.android.launcher3.Utilities.getDevicePrefs; +import static com.android.launcher3.LauncherPrefs.getDevicePrefs; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI; @@ -117,7 +117,7 @@ public class LauncherAppState implements SafeCloseable { observer, MODEL_EXECUTOR.getHandler()); mOnTerminateCallback.add(iconChangeTracker::close); MODEL_EXECUTOR.execute(observer::verifyIconChanged); - SharedPreferences prefs = Utilities.getPrefs(mContext); + SharedPreferences prefs = LauncherPrefs.getPrefs(mContext); prefs.registerOnSharedPreferenceChangeListener(observer); mOnTerminateCallback.add( () -> prefs.unregisterOnSharedPreferenceChangeListener(observer)); diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt new file mode 100644 index 0000000000..23ff10ad41 --- /dev/null +++ b/src/com/android/launcher3/LauncherPrefs.kt @@ -0,0 +1,20 @@ +package com.android.launcher3 + +import android.content.Context +import android.content.SharedPreferences + +object LauncherPrefs { + + @JvmStatic + fun getPrefs(context: Context): SharedPreferences { + // Use application context for shared preferences, so that we use a single cached instance + return context.applicationContext.getSharedPreferences( + LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE) + } + + @JvmStatic + fun getDevicePrefs(context: Context): SharedPreferences { + // Use application context for shared preferences, so that we use a single cached instance + return context.applicationContext.getSharedPreferences( + LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE) + }}
\ No newline at end of file diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index a20ff8c06f..767c3d986e 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -16,13 +16,13 @@ package com.android.launcher3; +import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT; import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import android.annotation.TargetApi; import android.app.backup.BackupManager; -import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.ContentProvider; @@ -35,7 +35,6 @@ import android.content.Intent; import android.content.OperationApplicationException; import android.content.SharedPreferences; import android.content.pm.ProviderInfo; -import android.content.res.Resources; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.SQLException; @@ -55,6 +54,8 @@ import android.text.TextUtils; import android.util.Log; import android.util.Xml; +import androidx.annotation.NonNull; + import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.config.FeatureFlags; @@ -69,8 +70,9 @@ import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.NoLocaleSQLiteHelper; import com.android.launcher3.util.PackageManagerHelper; +import com.android.launcher3.util.Partner; import com.android.launcher3.util.Thunk; -import com.android.launcher3.widget.LauncherAppWidgetHost; +import com.android.launcher3.widget.LauncherWidgetHolder; import org.xmlpull.v1.XmlPullParser; @@ -85,6 +87,7 @@ import java.util.Arrays; import java.util.Locale; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import java.util.stream.Collectors; public class LauncherProvider extends ContentProvider { private static final String TAG = "LauncherProvider"; @@ -103,6 +106,7 @@ public class LauncherProvider extends ContentProvider { public static final String KEY_LAYOUT_PROVIDER_AUTHORITY = "KEY_LAYOUT_PROVIDER_AUTHORITY"; private static final int TEST_WORKSPACE_LAYOUT_RES_XML = R.xml.default_test_workspace; + private static final int TEST2_WORKSPACE_LAYOUT_RES_XML = R.xml.default_test2_workspace; static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; @@ -111,7 +115,7 @@ public class LauncherProvider extends ContentProvider { private long mLastRestoreTimestamp = 0L; - private boolean mUseTestWorkspaceLayout; + private int mDefaultWorkspaceLayoutOverride = 0; /** * $ adb shell dumpsys activity provider com.android.launcher3 @@ -254,17 +258,20 @@ public class LauncherProvider extends ContentProvider { values.getAsString(Favorites.APPWIDGET_PROVIDER)); if (cn != null) { + LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder(); try { - AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost(); - int appWidgetId = widgetHost.allocateAppWidgetId(); + int appWidgetId = widgetHolder.allocateAppWidgetId(); values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId); if (!appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,cn)) { - widgetHost.deleteAppWidgetId(appWidgetId); + widgetHolder.deleteAppWidgetId(appWidgetId); return false; } } catch (RuntimeException e) { Log.e(TAG, "Failed to initialize external widget", e); return false; + } finally { + // Necessary to destroy the holder to free up possible activity context + widgetHolder.destroy(); } } else { return false; @@ -369,7 +376,7 @@ public class LauncherProvider extends ContentProvider { case LauncherSettings.Settings.METHOD_WAS_EMPTY_DB_CREATED : { Bundle result = new Bundle(); result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, - Utilities.getPrefs(getContext()).getBoolean( + LauncherPrefs.getPrefs(getContext()).getBoolean( mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)); return result; } @@ -396,11 +403,21 @@ public class LauncherProvider extends ContentProvider { return null; } case LauncherSettings.Settings.METHOD_SET_USE_TEST_WORKSPACE_LAYOUT_FLAG: { - mUseTestWorkspaceLayout = true; + switch (arg) { + case LauncherSettings.Settings.ARG_DEFAULT_WORKSPACE_LAYOUT_TEST: + mDefaultWorkspaceLayoutOverride = TEST_WORKSPACE_LAYOUT_RES_XML; + break; + case LauncherSettings.Settings.ARG_DEFAULT_WORKSPACE_LAYOUT_TEST2: + mDefaultWorkspaceLayoutOverride = TEST2_WORKSPACE_LAYOUT_RES_XML; + break; + default: + mDefaultWorkspaceLayoutOverride = 0; + break; + } return null; } case LauncherSettings.Settings.METHOD_CLEAR_USE_TEST_WORKSPACE_LAYOUT_FLAG: { - mUseTestWorkspaceLayout = false; + mDefaultWorkspaceLayoutOverride = 0; return null; } case LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES: { @@ -515,7 +532,7 @@ public class LauncherProvider extends ContentProvider { } private void clearFlagEmptyDbCreated() { - Utilities.getPrefs(getContext()).edit() + LauncherPrefs.getPrefs(getContext()).edit() .remove(mOpenHelper.getKey(EMPTY_DATABASE_CREATED)).commit(); } @@ -527,32 +544,30 @@ public class LauncherProvider extends ContentProvider { * 4) The default configuration for the particular device */ synchronized private void loadDefaultFavoritesIfNecessary() { - SharedPreferences sp = Utilities.getPrefs(getContext()); + SharedPreferences sp = LauncherPrefs.getPrefs(getContext()); if (sp.getBoolean(mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)) { Log.d(TAG, "loading default workspace"); - AppWidgetHost widgetHost = mOpenHelper.newLauncherWidgetHost(); - AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHost); + LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder(); + AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction(widgetHolder); if (loader == null) { - loader = AutoInstallsLayout.get(getContext(),widgetHost, mOpenHelper); + loader = AutoInstallsLayout.get(getContext(), widgetHolder, mOpenHelper); } if (loader == null) { final Partner partner = Partner.get(getContext().getPackageManager()); - if (partner != null && partner.hasDefaultLayout()) { - final Resources partnerRes = partner.getResources(); - int workspaceResId = partnerRes.getIdentifier(Partner.RES_DEFAULT_LAYOUT, - "xml", partner.getPackageName()); + if (partner != null) { + int workspaceResId = partner.getXmlResId(RES_PARTNER_DEFAULT_LAYOUT); if (workspaceResId != 0) { - loader = new DefaultLayoutParser(getContext(), widgetHost, - mOpenHelper, partnerRes, workspaceResId); + loader = new DefaultLayoutParser(getContext(), widgetHolder, + mOpenHelper, partner.getResources(), workspaceResId); } } } final boolean usingExternallyProvidedLayout = loader != null; if (loader == null) { - loader = getDefaultLayoutParser(widgetHost); + loader = getDefaultLayoutParser(widgetHolder); } // There might be some partially restored DB items, due to buggy restore logic in @@ -564,9 +579,10 @@ public class LauncherProvider extends ContentProvider { // Unable to load external layout. Cleanup and load the internal layout. mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase()); mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), - getDefaultLayoutParser(widgetHost)); + getDefaultLayoutParser(widgetHolder)); } clearFlagEmptyDbCreated(); + widgetHolder.destroy(); } } @@ -575,7 +591,8 @@ public class LauncherProvider extends ContentProvider { * * @return the loader if the restrictions are set and the resource exists; null otherwise. */ - private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) { + private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction( + LauncherWidgetHolder widgetHolder) { Context ctx = getContext(); final String authority; if (!TextUtils.isEmpty(mProviderAuthority)) { @@ -601,7 +618,7 @@ public class LauncherProvider extends ContentProvider { parser.setInput(new StringReader(layout)); Log.d(TAG, "Loading layout from " + authority); - return new AutoInstallsLayout(ctx, widgetHost, mOpenHelper, + return new AutoInstallsLayout(ctx, widgetHolder, mOpenHelper, ctx.getPackageManager().getResourcesForApplication(pi.applicationInfo), () -> parser, AutoInstallsLayout.TAG_WORKSPACE); } catch (Exception e) { @@ -620,17 +637,17 @@ public class LauncherProvider extends ContentProvider { .build(); } - private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) { + private DefaultLayoutParser getDefaultLayoutParser(LauncherWidgetHolder widgetHolder) { InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext()); - int defaultLayout = mUseTestWorkspaceLayout - ? TEST_WORKSPACE_LAYOUT_RES_XML : idp.defaultLayoutId; + int defaultLayout = mDefaultWorkspaceLayoutOverride > 0 + ? mDefaultWorkspaceLayoutOverride : idp.defaultLayoutId; if (getContext().getSystemService(UserManager.class).isDemoUser() && idp.demoModeLayoutId != 0) { defaultLayout = idp.demoModeLayoutId; } - return new DefaultLayoutParser(getContext(), widgetHost, + return new DefaultLayoutParser(getContext(), widgetHolder, mOpenHelper, getContext().getResources(), defaultLayout); } @@ -731,7 +748,7 @@ public class LauncherProvider extends ContentProvider { */ protected void onEmptyDbCreated() { // Set the flag for empty DB - Utilities.getPrefs(mContext).edit().putBoolean(getKey(EMPTY_DATABASE_CREATED), true) + LauncherPrefs.getPrefs(mContext).edit().putBoolean(getKey(EMPTY_DATABASE_CREATED), true) .commit(); } @@ -931,28 +948,46 @@ public class LauncherProvider extends ContentProvider { */ public void removeGhostWidgets(SQLiteDatabase db) { // Get all existing widget ids. - final AppWidgetHost host = newLauncherWidgetHost(); - final int[] allWidgets; + final LauncherWidgetHolder holder = newLauncherWidgetHolder(); try { - // Although the method was defined in O, it has existed since the beginning of time, - // so it might work on older platforms as well. - allWidgets = host.getAppWidgetIds(); - } catch (IncompatibleClassChangeError e) { - Log.e(TAG, "getAppWidgetIds not supported", e); - return; - } - final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db, - Favorites.TABLE_NAME, Favorites.APPWIDGET_ID, - "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null)); - for (int widgetId : allWidgets) { - if (!validWidgets.contains(widgetId)) { - try { - FileLog.d(TAG, "Deleting invalid widget " + widgetId); - host.deleteAppWidgetId(widgetId); - } catch (RuntimeException e) { - // Ignore + final int[] allWidgets; + try { + // Although the method was defined in O, it has existed since the beginning of + // time, so it might work on older platforms as well. + allWidgets = holder.getAppWidgetIds(); + } catch (IncompatibleClassChangeError e) { + Log.e(TAG, "getAppWidgetIds not supported", e); + // Necessary to destroy the holder to free up possible activity context + holder.destroy(); + return; + } + final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db, + Favorites.TABLE_NAME, Favorites.APPWIDGET_ID, + "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null)); + boolean isAnyWidgetRemoved = false; + for (int widgetId : allWidgets) { + if (!validWidgets.contains(widgetId)) { + try { + FileLog.d(TAG, "Deleting invalid widget " + widgetId); + holder.deleteAppWidgetId(widgetId); + isAnyWidgetRemoved = true; + } catch (RuntimeException e) { + // Ignore + } } } + if (isAnyWidgetRemoved) { + final String allWidgetsIds = Arrays.stream(allWidgets).mapToObj(String::valueOf) + .collect(Collectors.joining(",", "[", "]")); + final String validWidgetsIds = Arrays.stream( + validWidgets.getArray().toArray()).mapToObj(String::valueOf) + .collect(Collectors.joining(",", "[", "]")); + FileLog.d(TAG, "One or more widgets was removed. db_path=" + db.getPath() + + " allWidgetsIds=" + allWidgetsIds + + ", validWidgetsIds=" + validWidgetsIds); + } + } finally { + holder.destroy(); } } @@ -1053,8 +1088,12 @@ public class LauncherProvider extends ContentProvider { return mMaxItemId; } - public AppWidgetHost newLauncherWidgetHost() { - return new LauncherAppWidgetHost(mContext); + /** + * @return A new {@link LauncherWidgetHolder} based on the current context + */ + @NonNull + public LauncherWidgetHolder newLauncherWidgetHolder() { + return LauncherWidgetHolder.newInstance(mContext); } @Override diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 66195f3a1d..6ea331d485 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -94,15 +94,11 @@ public class LauncherSettings { */ public static final int ITEM_TYPE_DEEP_SHORTCUT = 6; - /** - * The favroite is a search action - */ - public static final int ITEM_TYPE_SEARCH_ACTION = 7; + // *** Below enum values are used for metrics purpose but not used in Favorites DB *** /** * Type of the item is recents task. - * TODO(hyunyoungs): move constants not related to Favorites DB to a better location. */ public static final int ITEM_TYPE_TASK = 7; @@ -112,6 +108,11 @@ public class LauncherSettings { public static final int ITEM_TYPE_QSB = 8; /** + * The favorite is a search action + */ + public static final int ITEM_TYPE_SEARCH_ACTION = 9; + + /** * The icon package name in Intent.ShortcutIconResource * <P>Type: TEXT</P> */ @@ -206,12 +207,9 @@ public class LauncherSettings { public static final int CONTAINER_BOTTOM_WIDGETS_TRAY = -112; public static final int CONTAINER_PIN_WIDGETS = -113; public static final int CONTAINER_WALLPAPERS = -114; - // Represents search results view. - public static final int CONTAINER_SEARCH_RESULTS = -106; public static final int CONTAINER_SHORTCUTS = -107; public static final int CONTAINER_SETTINGS = -108; public static final int CONTAINER_TASKSWITCHER = -109; - public static final int CONTAINER_QSB = -110; // Represents any of the extended containers implemented in non-AOSP variants. public static final int EXTENDED_CONTAINERS = -200; @@ -225,7 +223,6 @@ public class LauncherSettings { case CONTAINER_PREDICTION: return "prediction"; case CONTAINER_ALL_APPS: return "all_apps"; case CONTAINER_WIDGETS_TRAY: return "widgets_tray"; - case CONTAINER_SEARCH_RESULTS: return "search_result"; case CONTAINER_SHORTCUTS: return "shortcuts"; default: return String.valueOf(container); } @@ -376,6 +373,8 @@ public class LauncherSettings { public static final String METHOD_SET_USE_TEST_WORKSPACE_LAYOUT_FLAG = "set_use_test_workspace_layout_flag"; + public static final String ARG_DEFAULT_WORKSPACE_LAYOUT_TEST = "default_test_workspace"; + public static final String ARG_DEFAULT_WORKSPACE_LAYOUT_TEST2 = "default_test2_workspace"; public static final String METHOD_CLEAR_USE_TEST_WORKSPACE_LAYOUT_FLAG = "clear_use_test_workspace_layout_flag"; diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index 31a7d1827f..5dddc6f458 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -41,6 +41,7 @@ import com.android.launcher3.states.SpringLoadedState; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.uioverrides.states.AllAppsState; import com.android.launcher3.uioverrides.states.OverviewState; +import com.android.launcher3.views.ActivityContext; import java.util.Arrays; @@ -261,7 +262,7 @@ public abstract class LauncherState implements BaseState<LauncherState> { * * 0 means completely zoomed in, without blurs. 1 is zoomed out, with blurs. */ - public final <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable> + public final <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext> float getDepth(DEVICE_PROFILE_CONTEXT context) { return getDepth(context, BaseDraggingActivity.fromContext(context).getDeviceProfile().isMultiWindowMode); @@ -272,7 +273,7 @@ public abstract class LauncherState implements BaseState<LauncherState> { * * @see #getDepth(Context). */ - public final <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable> + public final <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext> float getDepth(DEVICE_PROFILE_CONTEXT context, boolean isMultiWindowMode) { if (isMultiWindowMode) { return 0; @@ -280,7 +281,7 @@ public abstract class LauncherState implements BaseState<LauncherState> { return getDepthUnchecked(context); } - protected <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfile.DeviceProfileListenable> + protected <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext> float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) { return 0f; } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 68c54c7667..4f5cc4a980 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -699,7 +699,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou } /** Returns true iff this PagedView's scroll amounts are initialized to each page index. */ - protected boolean pageScrollsInitialized() { + protected boolean isPageScrollsInitialized() { return mPageScrolls != null && mPageScrolls.length == getChildCount(); } @@ -708,12 +708,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou */ public void runOnPageScrollsInitialized(Runnable callback) { mOnPageScrollsInitializedCallbacks.add(callback); - if (pageScrollsInitialized()) { + if (isPageScrollsInitialized()) { onPageScrollsInitialized(); } } - private void onPageScrollsInitialized() { + protected void onPageScrollsInitialized() { for (Runnable callback : mOnPageScrollsInitializedCallbacks) { callback.run(); } @@ -727,7 +727,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou final int childCount = getChildCount(); int[] pageScrolls = mPageScrolls; boolean pageScrollChanged = false; - if (!pageScrollsInitialized()) { + if (!isPageScrollsInitialized()) { pageScrolls = new int[childCount]; pageScrollChanged = true; } @@ -772,6 +772,13 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou } if (mScroller.isFinished() && pageScrollChanged) { + // TODO(b/246283207): Remove logging once root cause of flake detected. + if (Utilities.IS_RUNNING_IN_TEST_HARNESS && !(this instanceof Workspace)) { + Log.d("b/246283207", this.getClass().getSimpleName() + "#onLayout() -> " + + "if(mScroller.isFinished() && pageScrollChanged) -> getNextPage(): " + + getNextPage() + ", getScrollForPage(getNextPage()): " + + getScrollForPage(getNextPage())); + } setCurrentPage(getNextPage()); } onPageScrollsInitialized(); @@ -1192,7 +1199,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou } public int getScrollForPage(int index) { - if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) { + if (!isPageScrollsInitialized() || index >= mPageScrolls.length || index < 0) { return 0; } else { return mPageScrolls[index]; @@ -1202,7 +1209,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou // While layout transitions are occurring, a child's position may stray from its baseline // position. This method returns the magnitude of this stray at any given time. public int getLayoutTransitionOffsetForPage(int index) { - if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) { + if (!isPageScrollsInitialized() || index >= mPageScrolls.length || index < 0) { return 0; } else { View child = getChildAt(index); diff --git a/src/com/android/launcher3/Partner.java b/src/com/android/launcher3/Partner.java deleted file mode 100644 index 2e27f32226..0000000000 --- a/src/com/android/launcher3/Partner.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2014 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.launcher3; - -import static com.android.launcher3.util.PackageManagerHelper.findSystemApk; - -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.util.DisplayMetrics; -import android.util.Log; -import android.util.Pair; - -import java.io.File; - -/** - * Utilities to discover and interact with partner customizations. There can - * only be one set of customizations on a device, and it must be bundled with - * the system. - */ -public class Partner { - - static final String TAG = "Launcher.Partner"; - - /** Marker action used to discover partner */ - private static final String - ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION"; - - public static final String RES_FOLDER = "partner_folder"; - public static final String RES_WALLPAPERS = "partner_wallpapers"; - public static final String RES_DEFAULT_LAYOUT = "partner_default_layout"; - - public static final String RES_DEFAULT_WALLPAPER_HIDDEN = "default_wallpapper_hidden"; - public static final String RES_SYSTEM_WALLPAPER_DIR = "system_wallpaper_directory"; - - public static final String RES_REQUIRE_FIRST_RUN_FLOW = "requires_first_run_flow"; - - /** These resources are used to override the device profile */ - public static final String RES_GRID_NUM_ROWS = "grid_num_rows"; - public static final String RES_GRID_NUM_COLUMNS = "grid_num_columns"; - public static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp"; - - /** - * Find and return partner details, or {@code null} if none exists. - */ - public static synchronized Partner get(PackageManager pm) { - Pair<String, Resources> apkInfo = findSystemApk(ACTION_PARTNER_CUSTOMIZATION, pm); - return apkInfo != null ? new Partner(apkInfo.first, apkInfo.second) : null; - } - - private final String mPackageName; - private final Resources mResources; - - private Partner(String packageName, Resources res) { - mPackageName = packageName; - mResources = res; - } - - public String getPackageName() { - return mPackageName; - } - - public Resources getResources() { - return mResources; - } - - public boolean hasDefaultLayout() { - int defaultLayout = getResources().getIdentifier(Partner.RES_DEFAULT_LAYOUT, - "xml", getPackageName()); - return defaultLayout != 0; - } - - public boolean hasFolder() { - int folder = getResources().getIdentifier(Partner.RES_FOLDER, - "xml", getPackageName()); - return folder != 0; - } - - public boolean hideDefaultWallpaper() { - int resId = getResources().getIdentifier(RES_DEFAULT_WALLPAPER_HIDDEN, "bool", - getPackageName()); - return resId != 0 && getResources().getBoolean(resId); - } - - public File getWallpaperDirectory() { - int resId = getResources().getIdentifier(RES_SYSTEM_WALLPAPER_DIR, "string", - getPackageName()); - return (resId != 0) ? new File(getResources().getString(resId)) : null; - } - - public boolean requiresFirstRunFlow() { - int resId = getResources().getIdentifier(RES_REQUIRE_FIRST_RUN_FLOW, "bool", - getPackageName()); - return resId != 0 && getResources().getBoolean(resId); - } - - public void applyInvariantDeviceProfileOverrides(InvariantDeviceProfile inv, DisplayMetrics dm) { - int numRows = -1; - int numColumns = -1; - float iconSize = -1; - - try { - int resId = getResources().getIdentifier(RES_GRID_NUM_ROWS, - "integer", getPackageName()); - if (resId > 0) { - numRows = getResources().getInteger(resId); - } - - resId = getResources().getIdentifier(RES_GRID_NUM_COLUMNS, - "integer", getPackageName()); - if (resId > 0) { - numColumns = getResources().getInteger(resId); - } - - resId = getResources().getIdentifier(RES_GRID_ICON_SIZE_DP, - "dimen", getPackageName()); - if (resId > 0) { - int px = getResources().getDimensionPixelSize(resId); - iconSize = Utilities.dpiFromPx((float) px, dm.densityDpi); - } - } catch (Resources.NotFoundException ex) { - Log.e(TAG, "Invalid Partner grid resource!", ex); - return; - } - - if (numRows > 0 && numColumns > 0) { - inv.numRows = numRows; - inv.numColumns = numColumns; - } - - if (iconSize > 0) { - inv.iconSize[InvariantDeviceProfile.INDEX_DEFAULT] = iconSize; - } - } -} diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java index 0ee7aae088..791cfff9b0 100644 --- a/src/com/android/launcher3/SecondaryDropTarget.java +++ b/src/com/android/launcher3/SecondaryDropTarget.java @@ -288,7 +288,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList if (widgetId != INVALID_APPWIDGET_ID) { mLauncher.setWaitingForResult( PendingRequestArgs.forWidgetInfo(widgetId, null, info)); - mLauncher.getAppWidgetHost().startConfigActivity(mLauncher, widgetId, + mLauncher.getAppWidgetHolder().startConfigActivity(mLauncher, widgetId, REQUEST_RECONFIGURE_APPWIDGET); } return null; diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java index bcd4c3f361..50ad2be505 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -98,6 +98,6 @@ public class SessionCommitReceiver extends BroadcastReceiver { } public static boolean isEnabled(Context context) { - return Utilities.getPrefs(context).getBoolean(ADD_ICON_PREFERENCE_KEY, true); + return LauncherPrefs.getPrefs(context).getBoolean(ADD_ICON_PREFERENCE_KEY, true); } } diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index 486a68f691..7a74d7ed1b 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -32,6 +32,7 @@ import android.view.View; import android.view.ViewGroup; import com.android.launcher3.CellLayout.ContainerType; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.views.ActivityContext; @@ -80,7 +81,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. final int count = getChildCount(); for (int i = 0; i < count; i++) { View child = getChildAt(i); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); if ((lp.cellX <= cellX) && (cellX < lp.cellX + lp.cellHSpan) && (lp.cellY <= cellY) && (cellY < lp.cellY + lp.cellVSpan)) { @@ -107,7 +108,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. } public void setupLp(View child) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); if (child instanceof NavigableAppWidgetHostView) { DeviceProfile profile = mActivity.getDeviceProfile(); ((NavigableAppWidgetHostView) child).getWidgetInset(profile, mTempRect); @@ -131,7 +132,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. } public void measureChild(View child) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); final DeviceProfile dp = mActivity.getDeviceProfile(); if (child instanceof NavigableAppWidgetHostView) { @@ -151,7 +152,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. // No need to add padding when cell layout border spacing is present. boolean noPaddingX = (dp.cellLayoutBorderSpacePx.x > 0 && mContainerType == WORKSPACE) - || (dp.folderCellLayoutBorderSpacePx.x > 0 && mContainerType == FOLDER) + || (dp.folderCellLayoutBorderSpacePx > 0 && mContainerType == FOLDER) || (dp.hotseatBorderSpace > 0 && mContainerType == HOTSEAT); int cellPaddingX = noPaddingX ? 0 @@ -175,7 +176,6 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); layoutChild(child); } } @@ -185,7 +185,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. * Core logic to layout a child for this ViewGroup. */ public void layoutChild(View child) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); if (child instanceof NavigableAppWidgetHostView) { NavigableAppWidgetHostView nahv = (NavigableAppWidgetHostView) child; @@ -255,7 +255,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. @Override public void drawFolderLeaveBehindForIcon(FolderIcon child) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); // While the folder is open, the position of the icon cannot change. lp.canReorder = false; if (mContainerType == HOTSEAT) { @@ -266,7 +266,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. @Override public void clearFolderLeaveBehind(FolderIcon child) { - ((CellLayout.LayoutParams) child.getLayoutParams()).canReorder = true; + ((CellLayoutLayoutParams) child.getLayoutParams()).canReorder = true; if (mContainerType == HOTSEAT) { CellLayout cl = (CellLayout) getParent(); cl.clearFolderLeaveBehind(); diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 616b08a908..d7e84f0306 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -26,20 +26,12 @@ import android.annotation.TargetApi; import android.app.ActivityManager; import android.app.Person; import android.app.WallpaperManager; -import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.res.Configuration; import android.content.res.Resources; -import android.database.ContentObserver; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.LightingColorFilter; @@ -51,7 +43,6 @@ import android.graphics.RectF; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.Build; import android.os.Build.VERSION_CODES; import android.os.DeadObjectException; @@ -71,27 +62,22 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.animation.Interpolator; -import android.widget.LinearLayout; import androidx.annotation.ChecksSdkIntAtLeast; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.core.graphics.ColorUtils; import com.android.launcher3.dragndrop.FolderAdaptiveIcon; -import com.android.launcher3.graphics.GridCustomizationsProvider; import com.android.launcher3.graphics.TintedDrawableSpan; import com.android.launcher3.icons.ShortcutCachingLogic; import com.android.launcher3.icons.ThemedIconDrawable; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; -import com.android.launcher3.model.data.SearchActionItemInfo; import com.android.launcher3.pm.ShortcutConfigActivityInfo; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.testing.shared.ResourceUtils; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.launcher3.util.Themes; import com.android.launcher3.views.ActivityContext; @@ -100,10 +86,8 @@ import com.android.launcher3.widget.PendingAddShortcutInfo; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Locale; -import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -117,8 +101,6 @@ public final class Utilities { private static final Pattern sTrimPattern = Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$"); - private static final int[] sLoc0 = new int[2]; - private static final int[] sLoc1 = new int[2]; private static final Matrix sMatrix = new Matrix(); private static final Matrix sInverseMatrix = new Matrix(); @@ -167,14 +149,6 @@ public final class Utilities { Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; } - // An intent extra to indicate the horizontal scroll of the wallpaper. - public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET"; - public static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR"; - - // An intent extra to indicate the launch source by launcher. - public static final String EXTRA_WALLPAPER_LAUNCH_SOURCE = - "com.android.wallpaper.LAUNCH_SOURCE"; - public static boolean IS_RUNNING_IN_TEST_HARNESS = ActivityManager.isRunningInTestHarness(); @@ -186,12 +160,6 @@ public final class Utilities { return Log.isLoggable(propertyName, Log.VERBOSE); } - public static boolean existsStyleWallpapers(Context context) { - ResolveInfo ri = context.getPackageManager().resolveActivity( - PackageManagerHelper.getStyleWallpapersIntent(context), 0); - return ri != null; - } - /** * Given a coordinate relative to the descendant, find the coordinate in a parent view's * coordinates. @@ -305,9 +273,9 @@ public final class Utilities { * Sets {@param out} to be same as {@param in} by rounding individual values */ public static void roundArray(float[] in, int[] out) { - for (int i = 0; i < in.length; i++) { - out[i] = Math.round(in[i]); - } + for (int i = 0; i < in.length; i++) { + out[i] = Math.round(in[i]); + } } public static void offsetPoints(float[] points, float offsetX, float offsetY) { @@ -328,40 +296,23 @@ public final class Utilities { localY < (v.getHeight() + slop); } - public static int[] getCenterDeltaInScreenSpace(View v0, View v1) { - v0.getLocationInWindow(sLoc0); - v1.getLocationInWindow(sLoc1); - - sLoc0[0] += (v0.getMeasuredWidth() * v0.getScaleX()) / 2; - sLoc0[1] += (v0.getMeasuredHeight() * v0.getScaleY()) / 2; - sLoc1[0] += (v1.getMeasuredWidth() * v1.getScaleX()) / 2; - sLoc1[1] += (v1.getMeasuredHeight() * v1.getScaleY()) / 2; - return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]}; + public static void scaleRectFAboutCenter(RectF r, float scale) { + scaleRectFAboutCenter(r, scale, scale); } /** - * Helper method to set rectOut with rectFSrc. + * Similar to {@link #scaleRectAboutCenter(Rect, float)} except this allows different scales + * for X and Y */ - public static void setRect(RectF rectFSrc, Rect rectOut) { - rectOut.left = (int) rectFSrc.left; - rectOut.top = (int) rectFSrc.top; - rectOut.right = (int) rectFSrc.right; - rectOut.bottom = (int) rectFSrc.bottom; - } - - public static void scaleRectFAboutCenter(RectF r, float scale) { - scaleRectFAboutPivot(r, scale, r.centerX(), r.centerY()); - } - - public static void scaleRectFAboutPivot(RectF r, float scale, float px, float py) { - if (scale != 1.0f) { - r.offset(-px, -py); - r.left = r.left * scale; - r.top = r.top * scale ; - r.right = r.right * scale; - r.bottom = r.bottom * scale; - r.offset(px, py); - } + public static void scaleRectFAboutCenter(RectF r, float scaleX, float scaleY) { + float px = r.centerX(); + float py = r.centerY(); + r.offset(-px, -py); + r.left = r.left * scaleX; + r.top = r.top * scaleY; + r.right = r.right * scaleX; + r.bottom = r.bottom * scaleY; + r.offset(px, py); } public static void scaleRectAboutCenter(Rect r, float scale) { @@ -369,27 +320,14 @@ public final class Utilities { int cx = r.centerX(); int cy = r.centerY(); r.offset(-cx, -cy); - scaleRect(r, scale); - r.offset(cx, cy); - } - } - - public static void scaleRect(Rect r, float scale) { - if (scale != 1.0f) { r.left = (int) (r.left * scale + 0.5f); r.top = (int) (r.top * scale + 0.5f); r.right = (int) (r.right * scale + 0.5f); r.bottom = (int) (r.bottom * scale + 0.5f); + r.offset(cx, cy); } } - public static void insetRect(Rect r, Rect insets) { - r.left = Math.min(r.right, r.left + insets.left); - r.top = Math.min(r.bottom, r.top + insets.top); - r.right = Math.max(r.left, r.right - insets.right); - r.bottom = Math.max(r.top, r.bottom - insets.bottom); - } - public static float shrinkRect(Rect r, float scaleX, float scaleY) { float scale = Math.min(Math.min(scaleX, scaleY), 1.0f); if (scale < 1.0f) { @@ -405,21 +343,6 @@ public final class Utilities { } /** - * Similar to {@link #scaleRectAboutCenter(Rect, float)} except this allows different scales - * for X and Y - */ - public static void scaleRectFAboutCenter(RectF r, float scaleX, float scaleY) { - float px = r.centerX(); - float py = r.centerY(); - r.offset(-px, -py); - r.left = r.left * scaleX; - r.top = r.top * scaleY; - r.right = r.right * scaleX; - r.bottom = r.bottom * scaleY; - r.offset(px, py); - } - - /** * Maps t from one range to another range. * @param t The value to map. * @param fromMin The lower bound of the range that t is being mapped from. @@ -454,30 +377,6 @@ public final class Utilities { } /** - * Bounds parameter to the range [0, 1] - */ - public static float saturate(float a) { - return boundToRange(a, 0, 1.0f); - } - - /** - * Returns the compliment (1 - a) of the parameter. - */ - public static float comp(float a) { - return 1 - a; - } - - /** - * Returns the "probabilistic or" of a and b. (a + b - ab). - * Useful beyond probability, can be used to combine two unit progresses for example. - */ - public static float or(float a, float b) { - float satA = saturate(a); - float satB = saturate(b); - return satA + satB - (satA * satB); - } - - /** * Trims the string, removing all whitespace at the beginning and end of the string. * Non-breaking whitespaces are also removed. */ @@ -521,6 +420,11 @@ public final class Utilities { return (int) (dp * Resources.getSystem().getDisplayMetrics().density); } + /** Converts a dp value to pixels for a certain density. */ + public static int dpToPx(float dp, int densityDpi) { + float densityRatio = (float) densityDpi / DisplayMetrics.DENSITY_DEFAULT; + return (int) (dp * densityRatio); + } public static int pxFromSp(float size, DisplayMetrics metrics) { return pxFromSp(size, metrics, 1f); @@ -531,7 +435,6 @@ public final class Utilities { return ResourceUtils.roundPxValueFromFloat(value); } - public static String createDbSelectionQuery(String columnName, IntArray values) { return String.format(Locale.ENGLISH, "%s IN (%s)", columnName, values.toConcatString()); } @@ -555,18 +458,6 @@ public final class Utilities { } /** - * Using the view's bounds and icon size, calculate where the icon bounds will - * be if it was positioned at the center of the view. - */ - public static void setRectToViewCenter(View iconView, int iconSize, Rect outBounds) { - int top = (iconView.getHeight() - iconSize) / 2; - int left = (iconView.getWidth() - iconSize) / 2; - int right = left + iconSize; - int bottom = top + iconSize; - outBounds.set(left, top, right, bottom); - } - - /** * Ensures that a value is within given bounds. Specifically: * If value is less than lowerBound, return lowerBound; else if value is greater than upperBound, * return upperBound; else return value unchanged. @@ -616,18 +507,6 @@ public final class Utilities { return spanned; } - public static SharedPreferences getPrefs(Context context) { - // Use application context for shared preferences, so that we use a single cached instance - return context.getApplicationContext().getSharedPreferences( - LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE); - } - - public static SharedPreferences getDevicePrefs(Context context) { - // Use application context for shared preferences, so that we use a single cached instance - return context.getApplicationContext().getSharedPreferences( - LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE); - } - public static boolean isWallpaperSupported(Context context) { return context.getSystemService(WallpaperManager.class).isWallpaperSupported(); } @@ -641,42 +520,6 @@ public final class Utilities { || e.getCause() instanceof DeadObjectException; } - public static boolean isGridOptionsEnabled(Context context) { - return isComponentEnabled(context.getPackageManager(), - context.getPackageName(), - GridCustomizationsProvider.class.getName()); - } - - private static boolean isComponentEnabled(PackageManager pm, String pkgName, String clsName) { - ComponentName componentName = new ComponentName(pkgName, clsName); - int componentEnabledSetting = pm.getComponentEnabledSetting(componentName); - - switch (componentEnabledSetting) { - case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: - return false; - case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: - return true; - case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: - default: - // We need to get the application info to get the component's default state - try { - PackageInfo packageInfo = pm.getPackageInfo(pkgName, - PackageManager.GET_PROVIDERS | PackageManager.GET_DISABLED_COMPONENTS); - - if (packageInfo.providers != null) { - return Arrays.stream(packageInfo.providers).anyMatch( - pi -> pi.name.equals(clsName) && pi.isEnabled()); - } - - // the component is not declared in the AndroidManifest - return false; - } catch (PackageManager.NameNotFoundException e) { - // the package isn't installed on the device - return false; - } - } - } - /** * Utility method to post a runnable on the handler, skipping the synchronization barriers. */ @@ -686,12 +529,6 @@ public final class Utilities { handler.sendMessage(msg); } - public static void unregisterReceiverSafely(Context context, BroadcastReceiver receiver) { - try { - context.unregisterReceiver(receiver); - } catch (IllegalArgumentException e) {} - } - /** * Returns the full drawable for info without any flattening or pre-processing. * @@ -753,8 +590,8 @@ public final class Utilities { outObj[0] = icon; return icon; } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION - && info instanceof SearchActionItemInfo) { - return ((SearchActionItemInfo) info).bitmap.newIcon(context); + && info instanceof ItemInfoWithIcon) { + return ((ItemInfoWithIcon) info).bitmap.newIcon(context); } else { return null; } @@ -789,14 +626,6 @@ public final class Utilities { } } - /** - * @return true is the extra is either null or is of type {@param type} - */ - public static boolean isValidExtraType(Intent intent, String key, Class type) { - Object extra = intent.getParcelableExtra(key); - return extra == null || type.isInstance(extra); - } - public static float squaredHypot(float x, float y) { return x * x + y * y; } @@ -807,28 +636,6 @@ public final class Utilities { } /** - * Helper method to create a content provider - */ - public static ContentObserver newContentObserver(Handler handler, Consumer<Uri> command) { - return new ContentObserver(handler) { - @Override - public void onChange(boolean selfChange, Uri uri) { - command.accept(uri); - } - }; - } - - /** - * Compares the ratio of two quantities and returns whether that ratio is greater than the - * provided bound. Order of quantities does not matter. Bound should be a decimal representation - * of a percentage. - */ - public static boolean isRelativePercentDifferenceGreaterThan(float first, float second, - float bound) { - return (Math.abs(first - second) / Math.abs((first + second) / 2.0f)) > bound; - } - - /** * Rotates `inOutBounds` by `delta` 90-degree increments. Rotation is visually CCW. Parent * sizes represent the "space" that will rotate carrying inOutBounds along with it to determine * the final bounds. @@ -876,16 +683,6 @@ public final class Utilities { ColorUtils.blendARGB(0, color, tintAmount)); } - /** - * Sets start margin on the provided {@param view} to be {@param margin}. - * Assumes {@param view} is a child of {@link LinearLayout} - */ - public static void setStartMarginForView(View view, int margin) { - LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) view.getLayoutParams(); - lp.setMarginStart(margin); - view.setLayoutParams(lp); - } - public static Rect getViewBounds(@NonNull View v) { int[] pos = new int[2]; v.getLocationOnScreen(pos); @@ -927,11 +724,13 @@ public final class Utilities { return options; } - public static boolean bothNull(@Nullable Object a, @Nullable Object b) { - return a == null && b == null; - } - - public static boolean bothNonNull(@Nullable Object a, @Nullable Object b) { - return a != null && b != null; + /** Logs the Scale and Translate properties of a matrix. Ignores skew and perspective. */ + public static void logMatrix(String label, Matrix matrix) { + float[] matrixValues = new float[9]; + matrix.getValues(matrixValues); + Log.d(label, String.format("%s: %s\nscale (x,y) = (%f, %f)\ntranslate (x,y) = (%f, %f)", + label, matrix, matrixValues[Matrix.MSCALE_X], matrixValues[Matrix.MSCALE_Y], + matrixValues[Matrix.MTRANS_X], matrixValues[Matrix.MTRANS_Y] + )); } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index b49d64625b..483309d1cf 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -26,7 +26,6 @@ import static com.android.launcher3.LauncherState.HINT_STATE; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback; -import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT; @@ -53,12 +52,13 @@ import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.FrameLayout; import android.widget.Toast; import androidx.annotation.Nullable; @@ -67,6 +67,7 @@ import com.android.launcher3.accessibility.AccessibleDragListenerAdapter; import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dot.FolderDotInfo; import com.android.launcher3.dragndrop.DragController; @@ -106,9 +107,9 @@ import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Thunk; import com.android.launcher3.util.WallpaperOffsetInterpolator; -import com.android.launcher3.widget.LauncherAppWidgetHost; -import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener; import com.android.launcher3.widget.LauncherAppWidgetHostView; +import com.android.launcher3.widget.LauncherWidgetHolder; +import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener; import com.android.launcher3.widget.NavigableAppWidgetHostView; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; @@ -117,6 +118,7 @@ import com.android.launcher3.widget.WidgetManagerHelper; import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener; import com.android.launcher3.widget.util.WidgetSizes; import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay; +import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks; import java.util.ArrayList; import java.util.Iterator; @@ -134,7 +136,7 @@ import java.util.stream.Collectors; public class Workspace<T extends View & PageIndicator> extends PagedView<T> implements DropTarget, DragSource, View.OnTouchListener, DragController.DragListener, Insettable, StateHandler<LauncherState>, - WorkspaceLayoutManager, LauncherBindableItemsContainer { + WorkspaceLayoutManager, LauncherBindableItemsContainer, LauncherOverlayCallbacks { /** The value that {@link #mTransitionProgress} must be greater than for * {@link #transitionStateShouldAllowDrop()} to return true. */ @@ -152,6 +154,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> public static final int DEFAULT_PAGE = 0; + private final int mAllAppsIconSize; + private LayoutTransition mLayoutTransition; @Thunk final WallpaperManager mWallpaperManager; @@ -219,8 +223,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget) private float mXDown; private float mYDown; - private View mQsb; - private boolean mIsEventOverQsb; + private View mFirstPagePinnedItem; + private boolean mIsEventOverFirstPagePinnedItem; final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6; final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3; @@ -250,14 +254,12 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> // State related to Launcher Overlay private OverlayEdgeEffect mOverlayEdgeEffect; - boolean mOverlayShown = false; - private Runnable mOnOverlayHiddenCallback; + private boolean mOverlayShown = false; + private float mOverlayProgress; // 1 -> overlay completely visible, 0 -> home visible + private final List<LauncherOverlayCallbacks> mOverlayCallbacks = new ArrayList<>(); private boolean mForceDrawAdjacentPages = false; - // Total over scrollX in the overlay direction. - private float mOverlayTranslation; - // Handles workspace state transitions private final WorkspaceStateTransitionAnimation mStateTransitionAnimation; @@ -286,7 +288,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> mLauncher = Launcher.getLauncher(context); mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this); mWallpaperManager = WallpaperManager.getInstance(context); - + mAllAppsIconSize = mLauncher.getDeviceProfile().allAppsIconSizePx; mWallpaperOffset = new WallpaperOffsetInterpolator(this); setHapticFeedbackEnabled(false); @@ -322,6 +324,26 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> updateCellLayoutPadding(); updateWorkspaceWidgetsSizes(); + setPageIndicatorInset(); + } + + private void setPageIndicatorInset() { + DeviceProfile grid = mLauncher.getDeviceProfile(); + + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mPageIndicator.getLayoutParams(); + + // Set insets for page indicator + Rect padding = grid.workspacePadding; + if (grid.isVerticalBarLayout()) { + lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx; + lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx; + lp.bottomMargin = padding.bottom; + } else { + lp.leftMargin = lp.rightMargin = 0; + lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; + lp.bottomMargin = grid.hotseatBarSizePx; + } + mPageIndicator.setLayoutParams(lp); } private void updateCellLayoutPadding() { @@ -550,20 +572,22 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> // Add the first page CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, getChildCount()); - // Always add a QSB on the first screen. - if (mQsb == null) { - // In transposed layout, we add the QSB in the Grid. As workspace does not touch the - // edges, we do not need a full width QSB. - mQsb = LayoutInflater.from(getContext()) + // Always add a first page pinned widget on the first screen. + if (mFirstPagePinnedItem == null) { + // In transposed layout, we add the first page pinned widget in the Grid. + // As workspace does not touch the edges, we do not need a full + // width first page pinned widget. + mFirstPagePinnedItem = LayoutInflater.from(getContext()) .inflate(R.layout.search_container_workspace, firstPage, false); } int cellHSpan = mLauncher.getDeviceProfile().inv.numSearchContainerColumns; - CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, cellHSpan, 1); + CellLayoutLayoutParams lp = new CellLayoutLayoutParams(0, 0, cellHSpan, 1, FIRST_SCREEN_ID); lp.canReorder = false; - if (!firstPage.addViewToCellLayout(mQsb, 0, R.id.search_container_workspace, lp, true)) { + if (!firstPage.addViewToCellLayout( + mFirstPagePinnedItem, 0, R.id.search_container_workspace, lp, true)) { Log.e(TAG, "Failed to add to item at (0, 0) to CellLayout"); - mQsb = null; + mFirstPagePinnedItem = null; } } @@ -572,9 +596,9 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> // transition animations competing with us changing the scroll when we add pages disableLayoutTransitions(); - // Recycle the QSB widget - if (mQsb != null) { - ((ViewGroup) mQsb.getParent()).removeView(mQsb); + // Recycle the first page pinned widget + if (mFirstPagePinnedItem != null) { + ((ViewGroup) mFirstPagePinnedItem.getParent()).removeView(mFirstPagePinnedItem); } // Remove the pages and clear the screen models @@ -894,6 +918,10 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> return mScreenOrder; } + protected View getFirstPagePinnedItem() { + return mFirstPagePinnedItem; + } + /** * Returns the screen ID of a page that is shown together with the given page screen ID when the * two panel UI is enabled. @@ -1045,20 +1073,23 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> mXDown = ev.getX(); mYDown = ev.getY(); - if (mQsb != null) { - mTempFXY[0] = mXDown + getScrollX(); - mTempFXY[1] = mYDown + getScrollY(); - Utilities.mapCoordInSelfToDescendant(mQsb, this, mTempFXY); - mIsEventOverQsb = mQsb.getLeft() <= mTempFXY[0] && mQsb.getRight() >= mTempFXY[0] - && mQsb.getTop() <= mTempFXY[1] && mQsb.getBottom() >= mTempFXY[1]; + if (mFirstPagePinnedItem != null) { + final float[] tempFXY = new float[2]; + tempFXY[0] = mXDown; + tempFXY[1] = mYDown; + Utilities.mapCoordInSelfToDescendant(mFirstPagePinnedItem, this, tempFXY); + mIsEventOverFirstPagePinnedItem = mFirstPagePinnedItem.getLeft() <= tempFXY[0] + && mFirstPagePinnedItem.getRight() >= tempFXY[0] + && mFirstPagePinnedItem.getTop() <= tempFXY[1] + && mFirstPagePinnedItem.getBottom() >= tempFXY[1]; } else { - mIsEventOverQsb = false; + mIsEventOverFirstPagePinnedItem = false; } } @Override protected void determineScrollingStart(MotionEvent ev) { - if (!isFinishedSwitchingState() || mIsEventOverQsb) return; + if (!isFinishedSwitchingState() || mIsEventOverFirstPagePinnedItem) return; float deltaX = ev.getX() - mXDown; float absDeltaX = Math.abs(deltaX); @@ -1119,9 +1150,15 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> } public void setLauncherOverlay(LauncherOverlay overlay) { - mOverlayEdgeEffect = overlay == null ? null : new OverlayEdgeEffect(getContext(), overlay); - EdgeEffectCompat newEffect = overlay == null - ? new EdgeEffectCompat(getContext()) : mOverlayEdgeEffect; + final EdgeEffectCompat newEffect; + if (overlay == null) { + newEffect = new EdgeEffectCompat(getContext()); + mOverlayEdgeEffect = null; + } else { + newEffect = mOverlayEdgeEffect = new OverlayEdgeEffect(getContext(), overlay); + overlay.setOverlayCallbacks(this); + } + if (mIsRtl) { mEdgeGlowRight = newEffect; } else { @@ -1171,132 +1208,46 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> @Override protected boolean shouldFlingForVelocity(int velocityX) { // When the overlay is moving, the fling or settle transition is controlled by the overlay. - return Float.compare(Math.abs(mOverlayTranslation), 0) == 0 && - super.shouldFlingForVelocity(velocityX); + return Float.compare(Math.abs(mOverlayProgress), 0) == 0 + && super.shouldFlingForVelocity(velocityX); } /** * The overlay scroll is being controlled locally, just update our overlay effect */ + @Override public void onOverlayScrollChanged(float scroll) { - if (Float.compare(scroll, 1f) == 0) { + mOverlayProgress = Utilities.boundToRange(scroll, 0, 1); + if (Float.compare(mOverlayProgress, 1f) == 0) { if (!mOverlayShown) { - mLauncher.getStatsLogManager().logger() - .withSrcState(LAUNCHER_STATE_HOME) - .withDstState(LAUNCHER_STATE_HOME) - .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() - .setWorkspace( - LauncherAtom.WorkspaceContainer.newBuilder() - .setPageIndex(0)) - .build()) - .log(LAUNCHER_SWIPELEFT); - } - mOverlayShown = true; - - // Let the Launcher activity know that the overlay is now visible. - mLauncher.onOverlayVisibilityChanged(mOverlayShown); - - // Not announcing the overlay page for accessibility since it announces itself. - } else if (Float.compare(scroll, 0f) == 0) { + mOverlayShown = true; + mLauncher.onOverlayVisibilityChanged(true); + } + } else if (Float.compare(mOverlayProgress, 0f) == 0) { if (mOverlayShown) { - // TODO: this is logged unnecessarily on home gesture. - mLauncher.getStatsLogManager().logger() - .withSrcState(LAUNCHER_STATE_HOME) - .withDstState(LAUNCHER_STATE_HOME) - .withContainerInfo(LauncherAtom.ContainerInfo.newBuilder() - .setWorkspace( - LauncherAtom.WorkspaceContainer.newBuilder() - .setPageIndex(-1)) - .build()) - .log(LAUNCHER_SWIPERIGHT); - } else if (Float.compare(mOverlayTranslation, 0f) != 0) { - // When arriving to 0 overscroll from non-zero overscroll, announce page for - // accessibility since default announcements were disabled while in overscroll - // state. - // Not doing this if mOverlayShown because in that case the accessibility service - // will announce the launcher window description upon regaining focus after - // switching from the overlay screen. - announcePageForAccessibility(); + mOverlayShown = false; + mLauncher.onOverlayVisibilityChanged(false); } - mOverlayShown = false; - - // Let the Launcher activity know that the overlay is no longer visible. - mLauncher.onOverlayVisibilityChanged(mOverlayShown); - - tryRunOverlayCallback(); } - - float offset = 0f; - - scroll = Math.max(scroll - offset, 0); - scroll = Math.min(1, scroll / (1 - offset)); - - float alpha = 1 - Interpolators.DEACCEL_3.getInterpolation(scroll); - float transX = mLauncher.getDragLayer().getMeasuredWidth() * scroll; - - if (mIsRtl) { - transX = -transX; + int count = mOverlayCallbacks.size(); + for (int i = 0; i < count; i++) { + mOverlayCallbacks.get(i).onOverlayScrollChanged(mOverlayProgress); } - mOverlayTranslation = transX; - - // TODO(adamcohen): figure out a final effect here. We may need to recommend - // different effects based on device performance. On at least one relatively high-end - // device I've tried, translating the launcher causes things to get quite laggy. - mLauncher.getDragLayer().setTranslationX(transX); - mLauncher.getDragLayer().getAlphaProperty(ALPHA_INDEX_OVERLAY).setValue(alpha); } /** - * @return false if the callback is still pending + * Adds a callback for receiving overlay progress */ - private boolean tryRunOverlayCallback() { - if (mOnOverlayHiddenCallback == null) { - // Return true as no callback is pending. This is used by OnWindowFocusChangeListener - // to remove itself if multiple focus handles were added. - return true; - } - if (mOverlayShown || !hasWindowFocus()) { - return false; - } - - mOnOverlayHiddenCallback.run(); - mOnOverlayHiddenCallback = null; - return true; + public void addOverlayCallback(LauncherOverlayCallbacks callback) { + mOverlayCallbacks.add(callback); + callback.onOverlayScrollChanged(mOverlayProgress); } /** - * Runs the given callback when the minus one overlay is hidden. Specifically, it is run - * when launcher's window has focus and the overlay is no longer being shown. If a callback - * is already present, the new callback will chain off it so both are run. - * - * @return Whether the callback was deferred. + * Removes a previously added overlay progress callback */ - public boolean runOnOverlayHidden(Runnable callback) { - if (mOnOverlayHiddenCallback == null) { - mOnOverlayHiddenCallback = callback; - } else { - // Chain the new callback onto the previous callback(s). - Runnable oldCallback = mOnOverlayHiddenCallback; - mOnOverlayHiddenCallback = () -> { - oldCallback.run(); - callback.run(); - }; - } - if (!tryRunOverlayCallback()) { - ViewTreeObserver observer = getViewTreeObserver(); - if (observer != null && observer.isAlive()) { - observer.addOnWindowFocusChangeListener( - new ViewTreeObserver.OnWindowFocusChangeListener() { - @Override - public void onWindowFocusChanged(boolean hasFocus) { - if (tryRunOverlayCallback() && observer.isAlive()) { - observer.removeOnWindowFocusChangeListener(this); - } - }}); - } - return true; - } - return false; + public void removeOverlayCallback(LauncherOverlayCallbacks callback) { + mOverlayCallbacks.remove(callback); } @Override @@ -1671,8 +1622,14 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent(); } - if (child instanceof BubbleTextView && !dragOptions.isAccessibleDrag) { - dragOptions.preDragCondition = ((BubbleTextView) child).startLongPressAction(); + if (child instanceof BubbleTextView) { + BubbleTextView btv = (BubbleTextView) child; + if (!dragOptions.isAccessibleDrag) { + dragOptions.preDragCondition = btv.startLongPressAction(); + } + if (btv.isDisplaySearchResult()) { + dragOptions.preDragEndScale = (float) mAllAppsIconSize / btv.getIconSize(); + } } final DragView dv; @@ -1796,7 +1753,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> boolean willCreateUserFolder(ItemInfo info, View dropOverView, boolean considerTimeout) { if (dropOverView != null) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) dropOverView.getLayoutParams(); if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY)) { return false; } @@ -1831,7 +1788,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> } boolean willAddToExistingUserFolder(ItemInfo dragInfo, View dropOverView) { if (dropOverView != null) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) dropOverView.getLayoutParams(); if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.cellY)) { return false; } @@ -2048,7 +2005,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> } // update the item's position after drop - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) cell.getLayoutParams(); lp.cellX = lp.tmpCellX = mTargetCell[0]; lp.cellY = lp.tmpCellY = mTargetCell[1]; lp.cellHSpan = item.spanX; @@ -2074,7 +2031,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> } // If we can't find a drop location, we return the item to its original position - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) cell.getLayoutParams(); mTargetCell[0] = lp.cellX; mTargetCell[1] = lp.cellY; CellLayout layout = (CellLayout) cell.getParent().getParent(); @@ -2395,7 +2352,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> } mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], - (int) mDragViewVisualCenter[1], minSpanX, minSpanY, + (int) mDragViewVisualCenter[1], item.spanX, item.spanY, mDragTargetLayout, mTargetCell); int reorderX = mTargetCell[0]; int reorderY = mTargetCell[1]; @@ -2411,7 +2368,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX, item.spanY, child, mTargetCell); - manageReorderOnDragOver(d, targetCellDistance, nearestDropOccupied, minSpanX, minSpanY); + manageReorderOnDragOver(d, targetCellDistance, nearestDropOccupied, minSpanX, minSpanY, + reorderX, reorderY); if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER || !nearestDropOccupied) { @@ -2423,26 +2381,26 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> } protected void manageReorderOnDragOver(DragObject d, float targetCellDistance, - boolean nearestDropOccupied, int minSpanX, int minSpanY) { + boolean nearestDropOccupied, int minSpanX, int minSpanY, int reorderX, int reorderY) { ItemInfo item = d.dragInfo; final View child = (mDragInfo == null) ? null : mDragInfo.cell; - int reorderX = mTargetCell[0]; - int reorderY = mTargetCell[1]; if (!nearestDropOccupied) { + mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0], + (int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY, + child, mTargetCell, new int[2], CellLayout.MODE_SHOW_REORDER_HINT); mDragTargetLayout.visualizeDropLocation(mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, d); } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER) - && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX || mLastReorderY != reorderY) && targetCellDistance < mDragTargetLayout.getReorderRadius(mTargetCell, item.spanX, item.spanY)) { - - int[] resultSpan = new int[2]; + mReorderAlarm.cancelAlarm(); + mLastReorderX = reorderX; + mLastReorderY = reorderY; mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY, - child, mTargetCell, resultSpan, CellLayout.MODE_SHOW_REORDER_HINT); - + child, mTargetCell, new int[2], CellLayout.MODE_SHOW_REORDER_HINT); // Otherwise, if we aren't adding to or creating a folder and there's no pending // reorder, then we schedule a reorder ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter, @@ -2503,10 +2461,10 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> } private boolean isDragObjectOverSmartSpace(DragObject dragObject) { - if (mQsb == null) { + if (mFirstPagePinnedItem == null) { return false; } - getViewBoundsRelativeToWorkspace(mQsb, mTempRect); + getViewBoundsRelativeToWorkspace(mFirstPagePinnedItem, mTempRect); return mTempRect.contains(dragObject.x, dragObject.y); } @@ -2647,8 +2605,6 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], minSpanX, minSpanY, mDragTargetLayout, mTargetCell); - mLastReorderX = mTargetCell[0]; - mLastReorderY = mTargetCell[1]; mTargetCell = mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, @@ -2660,7 +2616,6 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> setDragMode(DRAG_MODE_REORDER); } - boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY; mDragTargetLayout.visualizeDropLocation(mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], dragObject); } @@ -3017,7 +2972,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> */ @Thunk int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, CellLayout layout, int[] recycle) { - return layout.findNearestArea( + return layout.findNearestAreaIgnoreOccupied( pixelX, pixelY, spanX, spanY, recycle); } @@ -3352,7 +3307,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> public void widgetsRestored(final ArrayList<LauncherAppWidgetInfo> changedInfo) { if (!changedInfo.isEmpty()) { DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo, - mLauncher.getAppWidgetHost()); + mLauncher.getAppWidgetHolder()); LauncherAppWidgetInfo item = changedInfo.get(0); final AppWidgetProviderInfo widgetInfo; @@ -3429,7 +3384,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> protected boolean canAnnouncePageDescription() { // Disable announcements while overscrolling potentially to overlay screen because if we end // up on the overlay screen, it will take care of announcing itself. - return Float.compare(mOverlayTranslation, 0f) == 0; + return Float.compare(mOverlayProgress, 0f) == 0; } @Override @@ -3478,19 +3433,19 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> */ private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener { private final ArrayList<LauncherAppWidgetInfo> mInfos; - private final LauncherAppWidgetHost mHost; + private final LauncherWidgetHolder mWidgetHolder; private final Handler mHandler; private boolean mRefreshPending; DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos, - LauncherAppWidgetHost host) { + LauncherWidgetHolder holder) { mInfos = infos; - mHost = host; + mWidgetHolder = holder; mHandler = mLauncher.mHandler; mRefreshPending = true; - mHost.addProviderChangeListener(this); + mWidgetHolder.addProviderChangeListener(this); // Force refresh after 10 seconds, if we don't get the provider changed event. // This could happen when the provider is no longer available in the app. Message msg = Message.obtain(mHandler, this); @@ -3500,7 +3455,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> @Override public void run() { - mHost.removeProviderChangeListener(this); + mWidgetHolder.removeProviderChangeListener(this); mHandler.removeCallbacks(this); if (!mRefreshPending) { diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java index 7e6e1b60de..91e12faa1d 100644 --- a/src/com/android/launcher3/WorkspaceLayoutManager.java +++ b/src/com/android/launcher3/WorkspaceLayoutManager.java @@ -19,6 +19,7 @@ import android.util.Log; import android.view.View; import android.view.ViewGroup; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.model.data.ItemInfo; @@ -111,11 +112,11 @@ public interface WorkspaceLayoutManager { } ViewGroup.LayoutParams genericLp = child.getLayoutParams(); - CellLayout.LayoutParams lp; - if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) { - lp = new CellLayout.LayoutParams(x, y, spanX, spanY); + CellLayoutLayoutParams lp; + if (genericLp == null || !(genericLp instanceof CellLayoutLayoutParams)) { + lp = new CellLayoutLayoutParams(x, y, spanX, spanY, screenId); } else { - lp = (CellLayout.LayoutParams) genericLp; + lp = (CellLayoutLayoutParams) genericLp; lp.cellX = x; lp.cellY = y; lp.cellHSpan = spanX; diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index a991c2f959..62e7ef308c 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -29,11 +29,14 @@ import static com.android.launcher3.LauncherState.FLAG_HOTSEAT_INACCESSIBLE; import static com.android.launcher3.LauncherState.HINT_STATE; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; import static com.android.launcher3.LauncherState.NORMAL; +import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.LauncherState.WORKSPACE_PAGE_INDICATOR; import static com.android.launcher3.anim.Interpolators.ACCEL_2; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.ZOOM_OUT; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; +import static com.android.launcher3.config.FeatureFlags.HOME_GARDENING_WORKSPACE_BUTTONS; +import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING; import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS; import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS; import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE; @@ -69,6 +72,8 @@ import com.android.systemui.plugins.ResourceProvider; */ public class WorkspaceStateTransitionAnimation { + private static final float FIRST_PAGE_PINNED_WIDGET_DISABLED_ALPHA = 0.3f; + private static final FloatProperty<Workspace<?>> WORKSPACE_SCALE_PROPERTY = WORKSPACE_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE); @@ -155,6 +160,30 @@ public class WorkspaceStateTransitionAnimation { float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0; propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, hotseatFadeInterpolator); + if (SHOW_HOME_GARDENING.get()) { + propertySetter.setViewAlpha( + mWorkspace.getFirstPagePinnedItem(), + state == SPRING_LOADED ? FIRST_PAGE_PINNED_WIDGET_DISABLED_ALPHA : 1, + workspaceFadeInterpolator); + propertySetter.addEndListener(success -> { + if (success) { + mWorkspace.getFirstPagePinnedItem().setClickable(state != SPRING_LOADED); + } + }); + } + + if (HOME_GARDENING_WORKSPACE_BUTTONS.get()) { + propertySetter.setViewAlpha( + mLauncher.getHotseat().getQsb(), + state == SPRING_LOADED ? 0 : 1, + workspaceFadeInterpolator); + propertySetter.addEndListener(success -> { + if (success) { + mLauncher.getHotseat().getQsb().setClickable(state != SPRING_LOADED); + } + }); + } + // Update the accessibility flags for hotseat based on launcher state. hotseat.setImportantForAccessibility( state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE) diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index 79214e896a..063b82e0d9 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -1,5 +1,7 @@ package com.android.launcher3.accessibility; +import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED; +import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK; import static com.android.launcher3.LauncherState.NORMAL; @@ -23,6 +25,7 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.PendingAddItemInfo; import com.android.launcher3.R; import com.android.launcher3.Workspace; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DragOptions.PreDragCondition; import com.android.launcher3.dragndrop.DragView; @@ -171,7 +174,11 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau mContext.getDragLayer().getDescendantRectRelativeToSelf(host, pos); ArrowPopup popup = OptionsPopupView.show(mContext, new RectF(pos), actions, false); popup.requestFocus(); - popup.setOnCloseCallback(host::requestFocus); + popup.setOnCloseCallback(() -> { + host.requestFocus(); + host.sendAccessibilityEvent(TYPE_VIEW_FOCUSED); + host.performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null); + }); return true; } else if (action == DEEP_SHORTCUTS || action == SHORTCUTS_AND_NOTIFICATIONS) { BubbleTextView btv = host instanceof BubbleTextView ? (BubbleTextView) host @@ -244,7 +251,7 @@ public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Lau } private boolean performResizeAction(int action, View host, LauncherAppWidgetInfo info) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) host.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) host.getLayoutParams(); CellLayout layout = (CellLayout) host.getParent().getParent(); layout.markCellsAsUnoccupiedForView(host); diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index 08b42cd24c..2511cada78 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -27,13 +27,11 @@ import android.widget.RelativeLayout; import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.RecyclerView; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem; -import com.android.launcher3.allapps.search.SearchAdapterProvider; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.views.AppLauncher; +import com.android.launcher3.views.ActivityContext; import java.util.ArrayList; @@ -42,20 +40,14 @@ import java.util.ArrayList; * * @param <T> Type of context inflating all apps. */ -public class ActivityAllAppsContainerView<T extends Context & AppLauncher - & DeviceProfileListenable> extends BaseAllAppsContainerView<T> { +public class ActivityAllAppsContainerView<T extends Context & ActivityContext> + extends BaseAllAppsContainerView<T> { private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 300; // Used to animate Search results out and A-Z apps in, or vice-versa. private final SearchTransitionController mSearchTransitionController; - protected SearchUiManager mSearchUiManager; - /** - * View that defines the search box. Result is rendered inside the recycler view defined in the - * base class. - */ - private View mSearchContainer; /** {@code true} when rendered view is in search state instead of the scroll state. */ private boolean mIsSearching; private boolean mRebindAdaptersAfterSearchAnimation; @@ -74,6 +66,12 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher mSearchTransitionController = new SearchTransitionController(this); } + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mSearchUiManager.initializeSearch(this); + } + public SearchUiManager getSearchUiManager() { return mSearchUiManager; } @@ -102,6 +100,16 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher } } + /** + * Sets results list for search. + * + * @param searchResultCode indicates if the result is final or intermediate for a given query + * since we can get search results from multiple sources. + */ + public void setSearchResults(ArrayList<AdapterItem> results, int searchResultCode) { + setSearchResults(results); + } + private void animateToSearchState(boolean goingToSearch) { animateToSearchState(goingToSearch, DEFAULT_SEARCH_TRANSITION_DURATION_MS); } @@ -134,11 +142,6 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher } @Override - protected final SearchAdapterProvider<?> createMainAdapterProvider() { - return mActivityContext.createSearchAdapterProvider(this); - } - - @Override public boolean shouldContainerScroll(MotionEvent ev) { // IF the MotionEvent is inside the search box, and the container keeps on receiving // touch input, container should move down. @@ -158,14 +161,6 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher } @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mSearchContainer = findViewById(R.id.search_container_all_apps); - mSearchUiManager = (SearchUiManager) mSearchContainer; - mSearchUiManager.initializeSearch(this); - } - - @Override public boolean dispatchKeyEvent(KeyEvent event) { mSearchUiManager.preDispatchKeyEvent(event); return super.dispatchKeyEvent(event); @@ -218,7 +213,9 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher removeCustomRules(rvContainer); removeCustomRules(getSearchRecyclerView()); - if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { + if (!isSearchSupported()) { + layoutWithoutSearchContainer(rvContainer, showTabs); + } else if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { alignParentTop(rvContainer, showTabs); alignParentTop(getSearchRecyclerView(), /* tabs= */ false); layoutAboveSearchContainer(rvContainer); @@ -267,14 +264,6 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher (int) (mSearchContainer.getAlpha() * 255)); } - @Override - public int getHeaderBottom() { - if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { - return super.getHeaderBottom(); - } - return super.getHeaderBottom() + mSearchContainer.getBottom(); - } - private void layoutBelowSearchContainer(View v, boolean includeTabsMargin) { if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) { return; @@ -311,7 +300,7 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher layoutParams.topMargin = includeTabsMargin ? getContext().getResources().getDimensionPixelSize( - R.dimen.all_apps_header_pill_height) + R.dimen.all_apps_header_pill_height) : 0; } @@ -332,4 +321,27 @@ public class ActivityAllAppsContainerView<T extends Context & AppLauncher return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList, adapterProviders); } + + // TODO(b/216683257): Remove when Taskbar All Apps supports search. + protected boolean isSearchSupported() { + return true; + } + + private void layoutWithoutSearchContainer(View v, boolean includeTabsMargin) { + if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) { + return; + } + + RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams(); + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); + layoutParams.topMargin = getContext().getResources().getDimensionPixelSize(includeTabsMargin + ? R.dimen.all_apps_header_pill_height + : R.dimen.all_apps_header_top_margin); + } + + @Override + public boolean isInAllApps() { + // TODO: Make this abstract + return true; + } } diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index 368a37384d..63e6d13a5c 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -32,6 +32,7 @@ import com.android.launcher3.util.ScrollableLayoutManager; import com.android.launcher3.views.ActivityContext; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; /** * The grid view adapter of all the apps. @@ -43,6 +44,32 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends public static final String TAG = "AppsGridAdapter"; private final AppsGridLayoutManager mGridLayoutMgr; + private final CopyOnWriteArrayList<OnLayoutCompletedListener> mOnLayoutCompletedListeners = + new CopyOnWriteArrayList<>(); + + /** + * Listener for {@link RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)} + */ + public interface OnLayoutCompletedListener { + void onLayoutCompleted(); + } + + /** + * Adds a {@link OnLayoutCompletedListener} to receive a callback when {@link + * RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)} is called + */ + public void addOnLayoutCompletedListener(OnLayoutCompletedListener listener) { + mOnLayoutCompletedListeners.add(listener); + } + + /** + * Removes a {@link OnLayoutCompletedListener} to not receive a callback when {@link + * RecyclerView.LayoutManager#onLayoutCompleted(RecyclerView.State)} is called + */ + public void removeOnLayoutCompletedListener(OnLayoutCompletedListener listener) { + mOnLayoutCompletedListeners.remove(listener); + } + public AllAppsGridAdapter(T activityContext, LayoutInflater inflater, AlphabeticalAppsList apps, BaseAdapterProvider[] adapterProviders) { @@ -133,6 +160,14 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends } @Override + public void onLayoutCompleted(RecyclerView.State state) { + super.onLayoutCompleted(state); + for (OnLayoutCompletedListener listener : mOnLayoutCompletedListeners) { + listener.onLayoutCompleted(); + } + } + + @Override protected int incrementTotalHeight(Adapter adapter, int position, int heightUntilLastPos) { AllAppsGridAdapter.AdapterItem item = mApps.getAdapterItems().get(position); // only account for the first icon in the row since they are the same size within a row @@ -168,8 +203,12 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends @Override public int getSpanSize(int position) { - int viewType = mApps.getAdapterItems().get(position).viewType; int totalSpans = mGridLayoutMgr.getSpanCount(); + List<AdapterItem> items = mApps.getAdapterItems(); + if (position >= items.size()) { + return totalSpans; + } + int viewType = items.get(position).viewType; if (isIconViewType(viewType)) { return totalSpans / mAppsPerRow; } else { diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index 3d06fb5d41..d308fcb3b8 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -15,7 +15,11 @@ */ package com.android.launcher3.allapps; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED; +import static com.android.launcher3.logger.LauncherAtom.ContainerInfo; +import static com.android.launcher3.logger.LauncherAtom.SearchResultContainer; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED_DOWN; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED_UNKNOWN_DIRECTION; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED_UP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END; import static com.android.launcher3.util.LogConfig.SEARCH_LOGGING; @@ -28,6 +32,7 @@ import android.util.Log; import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.ExtendedEditText; import com.android.launcher3.FastScrollRecyclerView; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; @@ -48,6 +53,7 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { protected final int mNumAppsPerRow; private final AllAppsFastScrollHelper mFastScrollHelper; + private int mCumulativeVerticalScroll; protected AlphabeticalAppsList<?> mApps; @@ -120,7 +126,7 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { StatsLogManager mgr = ActivityContext.lookupContext(getContext()).getStatsLogManager(); switch (state) { case SCROLL_STATE_DRAGGING: - mgr.logger().log(LAUNCHER_ALLAPPS_SCROLLED); + mCumulativeVerticalScroll = 0; requestFocus(); mgr.logger().sendToInteractionJankMonitor( LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this); @@ -129,10 +135,17 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { case SCROLL_STATE_IDLE: mgr.logger().sendToInteractionJankMonitor( LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END, this); + logCumulativeVerticalScroll(); break; } } + @Override + public void onScrolled(int dx, int dy) { + super.onScrolled(dx, dy); + mCumulativeVerticalScroll += dy; + } + /** * Maps the touch (from 0..1) to the adapter position that should be visible. */ @@ -245,7 +258,9 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { } public int getScrollBarTop() { - return getResources().getDimensionPixelOffset(R.dimen.all_apps_header_top_padding); + return ActivityContext.lookupContext(getContext()).getAppsView().isSearchSupported() + ? getResources().getDimensionPixelOffset(R.dimen.all_apps_header_top_padding) + : 0; } public RecyclerViewFastScroller getScrollbar() { @@ -256,4 +271,21 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { public boolean hasOverlappingRendering() { return false; } + + private void logCumulativeVerticalScroll() { + ActivityContext context = ActivityContext.lookupContext(getContext()); + StatsLogManager mgr = context.getStatsLogManager(); + ExtendedEditText editText = context.getAppsView().getSearchUiManager().getEditText(); + ContainerInfo containerInfo = ContainerInfo.newBuilder().setSearchResultContainer( + SearchResultContainer + .newBuilder() + .setQueryLength((editText == null) ? -1 : editText.length())).build(); + + // mCumulativeVerticalScroll == 0 when user comes back to original position, we don't + // know the direction of scrolling. + mgr.logger().withContainerInfo(containerInfo).log( + mCumulativeVerticalScroll == 0 ? LAUNCHER_ALLAPPS_SCROLLED_UNKNOWN_DIRECTION + : (mCumulativeVerticalScroll > 0) ? LAUNCHER_ALLAPPS_SCROLLED_DOWN + : LAUNCHER_ALLAPPS_SCROLLED_UP); + } } diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 872c4fd5cd..9930abeb12 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.allapps; +import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT; import static com.android.launcher3.LauncherState.NORMAL; @@ -39,10 +40,10 @@ import com.android.launcher3.LauncherState; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.MultiPropertyFactory; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.views.ScrimView; @@ -75,6 +76,8 @@ public class AllAppsTransitionController } }; + private static final float ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT = 0f; + public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_TRANSLATION = new FloatProperty<AllAppsTransitionController>("allAppsPullBackTranslation") { @@ -83,8 +86,7 @@ public class AllAppsTransitionController if (controller.mIsTablet) { return controller.mAppsView.getActiveRecyclerView().getTranslationY(); } else { - return controller.getAppsViewPullbackTranslationY().get( - controller.mAppsView); + return controller.getAppsViewPullbackTranslationY().getValue(); } } @@ -92,13 +94,18 @@ public class AllAppsTransitionController public void setValue(AllAppsTransitionController controller, float translation) { if (controller.mIsTablet) { controller.mAppsView.getActiveRecyclerView().setTranslationY(translation); + controller.getAppsViewPullbackTranslationY().setValue( + ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT); } else { - controller.getAppsViewPullbackTranslationY().set(controller.mAppsView, - translation); + controller.getAppsViewPullbackTranslationY().setValue(translation); + controller.mAppsView.getActiveRecyclerView().setTranslationY( + ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT); } } }; + private static final float ALL_APPS_PULL_BACK_ALPHA_DEFAULT = 1f; + public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_ALPHA = new FloatProperty<AllAppsTransitionController>("allAppsPullBackAlpha") { @@ -115,8 +122,12 @@ public class AllAppsTransitionController public void setValue(AllAppsTransitionController controller, float alpha) { if (controller.mIsTablet) { controller.mAppsView.getActiveRecyclerView().setAlpha(alpha); + controller.getAppsViewPullbackAlpha().setValue( + ALL_APPS_PULL_BACK_ALPHA_DEFAULT); } else { controller.getAppsViewPullbackAlpha().setValue(alpha); + controller.mAppsView.getActiveRecyclerView().setAlpha( + ALL_APPS_PULL_BACK_ALPHA_DEFAULT); } } }; @@ -130,6 +141,9 @@ public class AllAppsTransitionController private final Launcher mLauncher; private boolean mIsVerticalLayout; + // Whether this class should take care of closing the keyboard. + private boolean mShouldControlKeyboard; + // Animation in this class is controlled by a single variable {@link mProgress}. // Visually, it represents top y coordinate of the all apps container if multiplied with // {@link mShiftRange}. @@ -141,10 +155,8 @@ public class AllAppsTransitionController private ScrimView mScrimView; - private final MultiPropertyFactory<View> - mAppsViewTranslationYPropertyFactory = new MultiPropertyFactory<>( - "appsViewTranslationY", View.TRANSLATION_Y, Float::sum); private MultiValueAlpha mAppsViewAlpha; + private MultiPropertyFactory<View> mAppsViewTranslationY; private boolean mIsTablet; @@ -185,7 +197,7 @@ public class AllAppsTransitionController */ public void setProgress(float progress) { mProgress = progress; - getAppsViewProgressTranslationY().set(mAppsView, mProgress * mShiftRange); + getAppsViewProgressTranslationY().setValue(mProgress * mShiftRange); mLauncher.onAllAppsTransition(1 - progress); } @@ -193,20 +205,20 @@ public class AllAppsTransitionController return mProgress; } - private FloatProperty<View> getAppsViewProgressTranslationY() { - return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PROGRESS); + private MultiProperty getAppsViewProgressTranslationY() { + return mAppsViewTranslationY.get(INDEX_APPS_VIEW_PROGRESS); } - private FloatProperty<View> getAppsViewPullbackTranslationY() { - return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PULLBACK); + private MultiProperty getAppsViewPullbackTranslationY() { + return mAppsViewTranslationY.get(INDEX_APPS_VIEW_PULLBACK); } - private MultiValueAlpha.AlphaProperty getAppsViewProgressAlpha() { - return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PROGRESS); + private MultiProperty getAppsViewProgressAlpha() { + return mAppsViewAlpha.get(INDEX_APPS_VIEW_PROGRESS); } - private MultiValueAlpha.AlphaProperty getAppsViewPullbackAlpha() { - return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PULLBACK); + private MultiProperty getAppsViewPullbackAlpha() { + return mAppsViewAlpha.get(INDEX_APPS_VIEW_PULLBACK); } /** @@ -229,21 +241,21 @@ public class AllAppsTransitionController StateAnimationConfig config, PendingAnimation builder) { if (mLauncher.isInState(ALL_APPS) && !ALL_APPS.equals(toState)) { // For atomic animations, we close the keyboard immediately. - if (!config.userControlled && !FeatureFlags.ENABLE_KEYBOARD_TRANSITION_SYNC.get()) { + if (!config.userControlled && mShouldControlKeyboard) { mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard(); } builder.addEndListener(success -> { // Reset pull back progress and alpha after switching states. - ALL_APPS_PULL_BACK_TRANSLATION.set(this, 0f); - ALL_APPS_PULL_BACK_ALPHA.set(this, 1f); + ALL_APPS_PULL_BACK_TRANSLATION.set(this, ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT); + ALL_APPS_PULL_BACK_ALPHA.set(this, ALL_APPS_PULL_BACK_ALPHA_DEFAULT); // We only want to close the keyboard if the animation has completed successfully. // The reason is that with keyboard sync, if the user swipes down from All Apps with // the keyboard open and then changes their mind and swipes back up, we want the // keyboard to remain open. However an onCancel signal is sent to the listeners // (success = false), so we need to check for that. - if (config.userControlled && success) { + if (config.userControlled && success && mShouldControlKeyboard) { mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard(); } }); @@ -284,7 +296,7 @@ public class AllAppsTransitionController boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0; Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR); - setter.setFloat(getAppsViewProgressAlpha(), MultiValueAlpha.VALUE, + setter.setFloat(getAppsViewProgressAlpha(), MultiPropertyFactory.MULTI_PROPERTY_VALUE, hasAllAppsContent ? 1 : 0, allAppsFade); boolean shouldProtectHeader = @@ -303,8 +315,13 @@ public class AllAppsTransitionController mScrimView = scrimView; mAppsView = appsView; mAppsView.setScrimView(scrimView); + mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT); mAppsViewAlpha.setUpdateVisibility(true); + mAppsViewTranslationY = new MultiPropertyFactory<>( + mAppsView, VIEW_TRANSLATE_Y, APPS_VIEW_INDEX_COUNT, Float::sum); + + mShouldControlKeyboard = !mLauncher.getSearchConfig().isKeyboardSyncEnabled(); } /** @@ -321,7 +338,9 @@ public class AllAppsTransitionController private void onProgressAnimationEnd() { if (Float.compare(mProgress, 1f) == 0) { mAppsView.reset(false /* animate */); - mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard(); + if (mShouldControlKeyboard) { + mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard(); + } } } } diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index fc1b830aed..29767bf465 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -239,23 +239,24 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement mAdapterItems.addAll(mSearchResults); } else { int position = 0; + boolean addApps = true; if (mWorkProviderManager != null) { position += mWorkProviderManager.addWorkItems(mAdapterItems); - if (!mWorkProviderManager.shouldShowWorkApps()) { - return; - } + addApps = mWorkProviderManager.shouldShowWorkApps(); } - String lastSectionName = null; - for (AppInfo info : mApps) { - mAdapterItems.add(AdapterItem.asApp(info)); - - String sectionName = info.sectionName; - // Create a new section if the section names do not match - if (!sectionName.equals(lastSectionName)) { - lastSectionName = sectionName; - mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position)); + if (addApps) { + String lastSectionName = null; + for (AppInfo info : mApps) { + mAdapterItems.add(AdapterItem.asApp(info)); + + String sectionName = info.sectionName; + // Create a new section if the section names do not match + if (!sectionName.equals(lastSectionName)) { + lastSectionName = sectionName; + mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position)); + } + position++; } - position++; } } mAccessibilityResultsCount = (int) mAdapterItems.stream() diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java index f08254204e..00e89bacc5 100644 --- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.allapps; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB; @@ -25,8 +26,11 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Path.Direction; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.RectF; import android.os.Bundle; import android.os.Parcelable; import android.os.Process; @@ -34,6 +38,7 @@ import android.os.UserManager; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; +import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -47,15 +52,17 @@ import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; import com.android.launcher3.Insettable; import com.android.launcher3.InsettableFrameLayout; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider; import com.android.launcher3.allapps.search.SearchAdapterProvider; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.keyboard.FocusedItemDecorator; import com.android.launcher3.model.StringCache; import com.android.launcher3.model.data.ItemInfo; @@ -78,8 +85,8 @@ import java.util.stream.Stream; * * @param <T> Type of context inflating all apps. */ -public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext - & DeviceProfileListenable> extends SpringRelativeLayout implements DragSource, Insettable, +public abstract class BaseAllAppsContainerView<T extends Context & ActivityContext> + extends SpringRelativeLayout implements DragSource, Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener, ScrimView.ScrimDrawingController { @@ -99,15 +106,13 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte protected final List<AdapterHolder> mAH; protected final Predicate<ItemInfo> mPersonalMatcher = ItemInfoMatcher.ofUser( Process.myUserHandle()); - private final SearchAdapterProvider<?> mMainAdapterProvider; private final AllAppsStore mAllAppsStore = new AllAppsStore(); private final RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - updateHeaderScroll( - ((AllAppsRecyclerView) recyclerView).computeVerticalScrollOffset()); + updateHeaderScroll(recyclerView.computeVerticalScrollOffset()); } }; @@ -118,28 +123,38 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte protected AllAppsPagedView mViewPager; private SearchRecyclerView mSearchRecyclerView; + private SearchAdapterProvider<?> mMainAdapterProvider; protected FloatingHeaderView mHeader; - private View mBottomSheetBackground; + protected View mBottomSheetBackground; private View mBottomSheetHandleArea; + /** + * View that defines the search box. Result is rendered inside {@link #mSearchRecyclerView}. + */ + protected View mSearchContainer; + protected SearchUiManager mSearchUiManager; + protected boolean mUsingTabs; private boolean mHasWorkApps; protected RecyclerViewFastScroller mTouchHandler; protected final Point mFastScrollerOffset = new Point(); - private final int mScrimColor; + protected final int mScrimColor; private final int mHeaderProtectionColor; protected final float mHeaderThreshold; + private final Path mTmpPath = new Path(); + private final RectF mTmpRectF = new RectF(); + private float[] mBottomSheetCornerRadii; private ScrimView mScrimView; private int mHeaderColor; + private int mBottomSheetBackgroundColor; private int mTabsProtectionAlpha; protected BaseAllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mActivityContext = ActivityContext.lookupContext(context); - mMainAdapterProvider = createMainAdapterProvider(); mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor); mHeaderThreshold = getResources().getDimensionPixelSize( @@ -148,21 +163,87 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte mWorkManager = new WorkProfileManager( mActivityContext.getSystemService(UserManager.class), - this, Utilities.getPrefs(mActivityContext)); + this, LauncherPrefs.getPrefs(mActivityContext), + mActivityContext.getStatsLogManager()); mAH = Arrays.asList(null, null, null); - mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN)); - mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK)); - mAH.set(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH)); - mNavBarScrimPaint = new Paint(); mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor)); mAllAppsStore.addUpdateListener(this::onAppsUpdated); mActivityContext.addOnDeviceProfileChangeListener(this); + + // This is a focus listener that proxies focus from a view into the list view. This is to + // work around the search box from getting first focus and showing the cursor. + setOnFocusChangeListener((v, hasFocus) -> { + if (hasFocus && getActiveRecyclerView() != null) { + getActiveRecyclerView().requestFocus(); + } + }); + initContent(); + } + + /** + * Initializes the view hierarchy and internal variables. Any initialization which actually uses + * these members should be done in {@link #onFinishInflate()}. + * In terms of subclass initialization, the following would be parallel order for activity: + * initContent -> onPreCreate + * constructor/init -> onCreate + * onFinishInflate -> onPostCreate + */ + protected void initContent() { + mMainAdapterProvider = createMainAdapterProvider(); + + mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN)); + mAH.set(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK)); + mAH.set(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH)); + + getLayoutInflater().inflate(R.layout.all_apps_content, this); + mHeader = findViewById(R.id.all_apps_header); + mBottomSheetBackground = findViewById(R.id.bottom_sheet_background); + mBottomSheetHandleArea = findViewById(R.id.bottom_sheet_handle_area); + mSearchRecyclerView = findViewById(R.id.search_results_list_view); + + // Add the search box next to the header + mSearchContainer = inflateSearchBox(); + addView(mSearchContainer, indexOfChild(mHeader) + 1); + mSearchUiManager = (SearchUiManager) mSearchContainer; + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + mAH.get(AdapterHolder.SEARCH).setup(mSearchRecyclerView, + /* Filter out A-Z apps */ itemInfo -> false); + rebindAdapters(true /* force */); + float cornerRadius = Themes.getDialogCornerRadius(getContext()); + mBottomSheetCornerRadii = new float[]{ + cornerRadius, + cornerRadius, // Top left radius in px + cornerRadius, + cornerRadius, // Top right radius in px + 0, + 0, // Bottom right + 0, + 0 // Bottom left + }; + final TypedValue value = new TypedValue(); + getContext().getTheme().resolveAttribute(android.R.attr.colorBackground, value, true); + mBottomSheetBackgroundColor = value.data; + updateBackground(mActivityContext.getDeviceProfile()); + } + + /** + * Inflates the search box + */ + protected View inflateSearchBox() { + return getLayoutInflater().inflate(R.layout.search_container_all_apps, this, false); } /** Creates the adapter provider for the main section. */ - protected abstract SearchAdapterProvider<?> createMainAdapterProvider(); + protected SearchAdapterProvider<?> createMainAdapterProvider() { + return new DefaultSearchAdapterProvider(mActivityContext); + } /** The adapter provider for the main section. */ public final SearchAdapterProvider<?> getMainAdapterProvider() { @@ -191,7 +272,6 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte reset(true); } } - } @Override @@ -235,6 +315,9 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte protected void updateBackground(DeviceProfile deviceProfile) { mBottomSheetBackground.setVisibility(deviceProfile.isTablet ? View.VISIBLE : View.GONE); + // Note: For tablets, the opaque background and header protection are added in drawOnScrim. + // For the taskbar entrypoint, the scrim is drawn differently, so a static background is + // added in TaskbarAllAppsContainerView and header protection is not yet supported. } private void onAppsUpdated() { @@ -245,6 +328,10 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte mWorkManager.reset(); } } + + mActivityContext.getStatsLogManager().logger() + .withCardinality(mAllAppsStore.getApps().length) + .log(LAUNCHER_ALLAPPS_COUNT); } /** @@ -273,6 +360,13 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte @Override public boolean onInterceptTouchEvent(MotionEvent ev) { + // The AllAppsContainerView houses the QSB and is hence visible from the Workspace + // Overview states. We shouldn't intercept for the scrubber in these cases. + if (!isInAllApps()) { + mTouchHandler = null; + return false; + } + if (ev.getAction() == MotionEvent.ACTION_DOWN) { AllAppsRecyclerView rv = getActiveRecyclerView(); if (rv != null && rv.getScrollbar() != null @@ -290,6 +384,10 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte @Override public boolean onTouchEvent(MotionEvent ev) { + if (!isInAllApps()) { + return false; + } + if (ev.getAction() == MotionEvent.ACTION_DOWN) { AllAppsRecyclerView rv = getActiveRecyclerView(); if (rv != null && rv.getScrollbar() != null @@ -394,30 +492,6 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte } @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - // This is a focus listener that proxies focus from a view into the list view. This is to - // work around the search box from getting first focus and showing the cursor. - setOnFocusChangeListener((v, hasFocus) -> { - if (hasFocus && getActiveRecyclerView() != null) { - getActiveRecyclerView().requestFocus(); - } - }); - - mHeader = findViewById(R.id.all_apps_header); - mSearchRecyclerView = findViewById(R.id.search_results_list_view); - mAH.get(AdapterHolder.SEARCH).setup(mSearchRecyclerView, - /* Filter out A-Z apps */ itemInfo -> false); - rebindAdapters(true /* force */); - - mBottomSheetBackground = findViewById(R.id.bottom_sheet_background); - updateBackground(mActivityContext.getDeviceProfile()); - - mBottomSheetHandleArea = findViewById(R.id.bottom_sheet_handle_area); - } - - @Override public void onDropCompleted(View target, DragObject d, boolean success) {} @Override @@ -435,8 +509,12 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte if (grid.isVerticalBarLayout()) { setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0); } else { - setPadding(grid.allAppsLeftRightMargin, grid.allAppsTopPadding, - grid.allAppsLeftRightMargin, 0); + int topPadding = grid.allAppsTopPadding; + if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() && !grid.isTablet) { + topPadding += getResources().getDimensionPixelSize( + R.dimen.all_apps_additional_top_padding_floating_search); + } + setPadding(grid.allAppsLeftRightMargin, topPadding, grid.allAppsLeftRightMargin, 0); } InsettableFrameLayout.dispatchInsets(this, insets); @@ -498,6 +576,10 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte mAH.get(AdapterHolder.MAIN).setup(mViewPager.getChildAt(0), mPersonalMatcher); mAH.get(AdapterHolder.WORK).setup(mViewPager.getChildAt(1), mWorkManager.getMatcher()); mAH.get(AdapterHolder.WORK).mRecyclerView.setId(R.id.apps_list_view_work); + if (FeatureFlags.ENABLE_EXPANDING_PAUSE_WORK_BUTTON.get()) { + mAH.get(AdapterHolder.WORK).mRecyclerView.addOnScrollListener( + mWorkManager.newScrollListener()); + } mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN); findViewById(R.id.tab_personal) .setOnClickListener((View view) -> { @@ -532,9 +614,11 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte if (isSearching()) { getSearchRecyclerView().setVisibility(VISIBLE); getAppsRecyclerViewContainer().setVisibility(GONE); + mHeader.setVisibility(GONE); } else { getSearchRecyclerView().setVisibility(GONE); getAppsRecyclerViewContainer().setVisibility(VISIBLE); + mHeader.setVisibility(VISIBLE); } if (mHeader.isSetUp()) { mHeader.setActiveRV(getCurrentPage()); @@ -587,10 +671,10 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte mViewPager = (AllAppsPagedView) newView; mViewPager.initParentViews(this); mViewPager.getPageIndicator().setOnActivePageChangedListener(this); - if (mWorkManager.attachWorkModeSwitch()) { - mWorkManager.getWorkModeSwitch().post( - () -> mAH.get(AdapterHolder.WORK).applyPadding()); - } + + mWorkManager.reset(); + post(() -> mAH.get(AdapterHolder.WORK).applyPadding()); + } else { mWorkManager.detachWorkModeSwitch(); mViewPager = null; @@ -725,9 +809,20 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte @Override public void drawOnScrim(Canvas canvas) { - if (!mHeader.isHeaderProtectionSupported()) { - return; + boolean isTablet = mActivityContext.getDeviceProfile().isTablet; + + // Draw full background panel for tablets. + if (isTablet) { + mHeaderPaint.setColor(mBottomSheetBackgroundColor); + View panel = (View) mBottomSheetBackground; + float translationY = ((View) panel.getParent()).getTranslationY(); + mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY, + panel.getRight(), panel.getBottom()); + mTmpPath.reset(); + mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW); + canvas.drawPath(mTmpPath, mHeaderPaint); } + if (DEBUG_HEADER_PROTECTION) { mHeaderPaint.setColor(Color.MAGENTA); mHeaderPaint.setAlpha(255); @@ -735,24 +830,40 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte mHeaderPaint.setColor(mHeaderColor); mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor))); } - if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) { - int bottom = getHeaderBottom(); - FloatingHeaderView headerView = getFloatingHeaderView(); - if (!mUsingTabs) { - // Add protection which is otherwise added when tabs scroll up. - bottom += headerView.getTabsAdditionalPaddingTop(); + if (mHeaderPaint.getColor() == mScrimColor || mHeaderPaint.getColor() == 0) { + return; + } + int bottom = getHeaderBottom() + getVisibleContainerView().getPaddingTop(); + FloatingHeaderView headerView = getFloatingHeaderView(); + if (isTablet) { + // Start adding header protection if search bar or tabs will attach to the top. + if (!FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() || mUsingTabs) { + View panel = (View) mBottomSheetBackground; + float translationY = ((View) panel.getParent()).getTranslationY(); + mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY, panel.getRight(), + bottom); + mTmpPath.reset(); + mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW); + canvas.drawPath(mTmpPath, mHeaderPaint); } + } else { canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint); - int tabsHeight = headerView.getPeripheralProtectionHeight(); - if (mTabsProtectionAlpha > 0 && tabsHeight != 0) { - if (DEBUG_HEADER_PROTECTION) { - mHeaderPaint.setColor(Color.BLUE); - mHeaderPaint.setAlpha(255); - } else { - mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha)); - } - canvas.drawRect(0, bottom, canvas.getWidth(), bottom + tabsHeight, mHeaderPaint); + } + int tabsHeight = headerView.getPeripheralProtectionHeight(); + if (mTabsProtectionAlpha > 0 && tabsHeight != 0) { + if (DEBUG_HEADER_PROTECTION) { + mHeaderPaint.setColor(Color.BLUE); + mHeaderPaint.setAlpha(255); + } else { + mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha)); + } + int left = 0; + int right = canvas.getWidth(); + if (isTablet) { + left = mBottomSheetBackground.getLeft(); + right = mBottomSheetBackground.getRight(); } + canvas.drawRect(left, bottom, right, bottom + tabsHeight, mHeaderPaint); } } @@ -760,7 +871,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte * redraws header protection */ public void invalidateHeader() { - if (mScrimView != null && mHeader.isHeaderProtectionSupported()) { + if (mScrimView != null) { mScrimView.invalidate(); } } @@ -787,7 +898,14 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte BaseAdapterProvider[] adapterProviders); public int getHeaderBottom() { - return (int) getTranslationY(); + int bottom = (int) getTranslationY() + mHeader.getClipTop(); + if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { + if (mActivityContext.getDeviceProfile().isTablet) { + return bottom + mBottomSheetBackground.getTop(); + } + return bottom; + } + return bottom + mHeader.getTop(); } /** @@ -797,6 +915,16 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte return mActivityContext.getDeviceProfile().isTablet ? mBottomSheetBackground : this; } + protected void onInitializeRecyclerView(RecyclerView rv) { + rv.addOnScrollListener(mScrollListener); + } + + /** + * Returns {@code true} the All Apps UI is currently being displayed on the target surface and + * is interactive. + */ + public abstract boolean isInAllApps(); + /** Holds a {@link BaseAllAppsAdapter} and related fields. */ public class AdapterHolder { public static final int MAIN = 0; @@ -833,7 +961,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte mRecyclerView.setHasFixedSize(true); // No animations will occur when changes occur to the items in this RecyclerView. mRecyclerView.setItemAnimator(null); - mRecyclerView.addOnScrollListener(mScrollListener); + onInitializeRecyclerView(mRecyclerView); FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView); mRecyclerView.addItemDecoration(focusedItemDecorator); mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener()); diff --git a/src/com/android/launcher3/allapps/BaseSearchConfig.java b/src/com/android/launcher3/allapps/BaseSearchConfig.java new file mode 100644 index 0000000000..9f47e8d82f --- /dev/null +++ b/src/com/android/launcher3/allapps/BaseSearchConfig.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 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.launcher3.allapps; + +/** Base config values for search. */ +public class BaseSearchConfig { + public BaseSearchConfig() {} + + /** + * Returns whether to enable the synchronized keyboard transition between Home and All Apps. + */ + public boolean isKeyboardSyncEnabled() { + return false; + } +} diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java index 1cbb0f9481..c18f9e1884 100644 --- a/src/com/android/launcher3/allapps/FloatingHeaderView.java +++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java @@ -17,7 +17,6 @@ package com.android.launcher3.allapps; import android.animation.ValueAnimator; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; import android.util.ArrayMap; @@ -85,7 +84,6 @@ public class FloatingHeaderView extends LinearLayout implements // These two values are necessary to ensure that the header protection is drawn correctly. private final int mTabsAdditionalPaddingTop; private final int mTabsAdditionalPaddingBottom; - private boolean mHeaderProtectionSupported; protected ViewGroup mTabLayout; private AllAppsRecyclerView mMainRV; @@ -115,7 +113,6 @@ public class FloatingHeaderView extends LinearLayout implements // enabled or disabled, and represent the current set of all rows. private FloatingHeaderRow[] mAllRows = FloatingHeaderRow.NO_ROWS; - public FloatingHeaderView(@NonNull Context context) { this(context, null); } @@ -126,15 +123,6 @@ public class FloatingHeaderView extends LinearLayout implements .getDimensionPixelSize(R.dimen.all_apps_header_top_adjustment); mTabsAdditionalPaddingBottom = context.getResources() .getDimensionPixelSize(R.dimen.all_apps_header_bottom_adjustment); - mHeaderProtectionSupported = context.getResources().getBoolean( - R.bool.config_header_protection_supported); - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mHeaderProtectionSupported = getContext().getResources().getBoolean( - R.bool.config_header_protection_supported); } @Override @@ -364,6 +352,10 @@ public class FloatingHeaderView extends LinearLayout implements onHeightUpdated(); } + public int getClipTop() { + return mHeaderClip.top; + } + public void reset(boolean animate) { if (mAnimator.isStarted()) { mAnimator.cancel(); @@ -406,10 +398,6 @@ public class FloatingHeaderView extends LinearLayout implements return mFloatingRowsHeight; } - int getTabsAdditionalPaddingTop() { - return mTabsAdditionalPaddingTop; - } - int getTabsAdditionalPaddingBottom() { return mTabsAdditionalPaddingBottom; } @@ -450,10 +438,6 @@ public class FloatingHeaderView extends LinearLayout implements p.y = getTop() - mCurrentRV.getTop() - ((ViewGroup) mCurrentRV.getParent()).getTop(); } - public boolean isHeaderProtectionSupported() { - return mHeaderProtectionSupported; - } - @Override public boolean hasOverlappingRendering() { return false; @@ -479,10 +463,6 @@ public class FloatingHeaderView extends LinearLayout implements * Returns visible height of FloatingHeaderView contents requiring header protection */ int getPeripheralProtectionHeight() { - if (!mHeaderProtectionSupported) { - return 0; - } - // we only want to show protection when work tab is available and header is either // collapsed or animating to/from collapsed state if (mTabsHidden || mFloatingRowsCollapsed || !mHeaderCollapsed) { diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java index 20f5e7440d..5a5ba2bb3c 100644 --- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java @@ -17,7 +17,6 @@ package com.android.launcher3.allapps; import android.content.Context; import android.util.AttributeSet; -import android.view.MotionEvent; import android.view.WindowInsets; import com.android.launcher3.Launcher; @@ -42,26 +41,6 @@ public class LauncherAllAppsContainerView extends ActivityAllAppsContainerView<L } @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - // The AllAppsContainerView houses the QSB and is hence visible from the Workspace - // Overview states. We shouldn't intercept for the scrubber in these cases. - if (!mActivityContext.isInState(LauncherState.ALL_APPS)) { - mTouchHandler = null; - return false; - } - - return super.onInterceptTouchEvent(ev); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (!mActivityContext.isInState(LauncherState.ALL_APPS)) { - return false; - } - return super.onTouchEvent(ev); - } - - @Override protected int getNavBarScrimHeight(WindowInsets insets) { if (Utilities.ATLEAST_Q) { return insets.getTappableElementInsets().bottom; @@ -69,4 +48,9 @@ public class LauncherAllAppsContainerView extends ActivityAllAppsContainerView<L return insets.getStableInsetBottom(); } } + + @Override + public boolean isInAllApps() { + return mActivityContext.getStateManager().isInStableState(LauncherState.ALL_APPS); + } } diff --git a/src/com/android/launcher3/allapps/SearchTransitionController.java b/src/com/android/launcher3/allapps/SearchTransitionController.java index 11ceb0a55c..50567822a6 100644 --- a/src/com/android/launcher3/allapps/SearchTransitionController.java +++ b/src/com/android/launcher3/allapps/SearchTransitionController.java @@ -32,13 +32,13 @@ import android.graphics.drawable.Drawable; import android.util.FloatProperty; import android.util.Log; import android.view.View; +import android.view.ViewGroup; import android.view.animation.Interpolator; import com.android.launcher3.BubbleTextView; -import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.ItemInfo; /** Coordinates the transition between Search and A-Z in All Apps. */ @@ -107,9 +107,7 @@ public class SearchTransitionController { } mSearchToAzAnimator = ObjectAnimator.ofFloat(this, SEARCH_TO_AZ_PROGRESS, targetProgress); - boolean inAllApps = Launcher.getLauncher( - mAllAppsContainerView.getContext()).getStateManager().isInStableState( - LauncherState.ALL_APPS); + boolean inAllApps = mAllAppsContainerView.isInAllApps(); if (!inAllApps) { duration = 0; // Don't want to animate when coming from QSB. } @@ -126,6 +124,7 @@ public class SearchTransitionController { mSearchToAzAnimator.addListener(forSuccessCallback(onEndRunnable)); mAllAppsContainerView.getFloatingHeaderView().setFloatingRowsCollapsed(true); + mAllAppsContainerView.getFloatingHeaderView().setVisibility(VISIBLE); mAllAppsContainerView.getAppsRecyclerViewContainer().setVisibility(VISIBLE); getSearchRecyclerView().setVisibility(VISIBLE); getSearchRecyclerView().setChildAttachedConsumer(this::onSearchChildAttached); @@ -169,12 +168,13 @@ public class SearchTransitionController { /** * Updates the children views of SearchRecyclerView based on the current animation progress. * - * @return the total height of animating views (excluding any app icons). + * @return the total height of animating views (excluding at most one row of app icons). */ private int updateSearchRecyclerViewProgress() { int numSearchResultsAnimated = 0; int totalHeight = 0; int appRowHeight = 0; + boolean appRowComplete = false; Integer top = null; SearchRecyclerView searchRecyclerView = getSearchRecyclerView(); @@ -188,67 +188,91 @@ public class SearchTransitionController { top = searchResultView.getTop(); } - if (searchResultView instanceof BubbleTextView - && searchResultView.getTag() instanceof ItemInfo - && ((ItemInfo) searchResultView.getTag()).itemType == ITEM_TYPE_APPLICATION) { - // The first app icon will set appRowHeight, which will also contribute to - // totalHeight. Additional app icons should remove the appRowHeight to remain in - // the same row as the first app. - searchResultView.setY(top + totalHeight - appRowHeight); - if (appRowHeight == 0) { - appRowHeight = searchResultView.getHeight(); - totalHeight += appRowHeight; + int adapterPosition = searchRecyclerView.getChildAdapterPosition(searchResultView); + int spanIndex = getSpanIndex(searchRecyclerView, adapterPosition); + appRowComplete |= appRowHeight > 0 && spanIndex == 0; + // We don't animate the first (currently only) app row we see, as that is assumed to be + // predicted/prefix-matched apps. + boolean shouldAnimate = !isAppIcon(searchResultView) || appRowComplete; + + float contentAlpha = 1f; + float backgroundAlpha = 1f; + if (shouldAnimate) { + if (spanIndex > 0) { + // Animate this item with the previous item on the same row. + numSearchResultsAnimated--; } - // Don't scale/fade app row. - searchResultView.setScaleY(1); - searchResultView.setAlpha(1); - continue; + + // Adjust content alpha based on start progress and stagger. + float startContentFadeProgress = Math.max(0, + TOP_CONTENT_FADE_PROGRESS_START + - CONTENT_STAGGER * numSearchResultsAnimated); + float endContentFadeProgress = Math.min(1, + startContentFadeProgress + CONTENT_FADE_PROGRESS_DURATION); + contentAlpha = 1 - clampToProgress(mSearchToAzProgress, + startContentFadeProgress, endContentFadeProgress); + + // Adjust background (or decorator) alpha based on start progress and stagger. + float startBackgroundFadeProgress = Math.max(0, + TOP_BACKGROUND_FADE_PROGRESS_START + - CONTENT_STAGGER * numSearchResultsAnimated); + float endBackgroundFadeProgress = Math.min(1, + startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION); + backgroundAlpha = 1 - clampToProgress(mSearchToAzProgress, + startBackgroundFadeProgress, endBackgroundFadeProgress); + + numSearchResultsAnimated++; } - // Adjust content alpha based on start progress and stagger. - float startContentFadeProgress = Math.max(0, - TOP_CONTENT_FADE_PROGRESS_START - CONTENT_STAGGER * numSearchResultsAnimated); - float endContentFadeProgress = Math.min(1, - startContentFadeProgress + CONTENT_FADE_PROGRESS_DURATION); - searchResultView.setAlpha(1 - clampToProgress(mSearchToAzProgress, - startContentFadeProgress, endContentFadeProgress)); - - // Adjust background (or decorator) alpha based on start progress and stagger. - float startBackgroundFadeProgress = Math.max(0, - TOP_BACKGROUND_FADE_PROGRESS_START - - CONTENT_STAGGER * numSearchResultsAnimated); - float endBackgroundFadeProgress = Math.min(1, - startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION); - float backgroundAlpha = 1 - clampToProgress(mSearchToAzProgress, - startBackgroundFadeProgress, endBackgroundFadeProgress); - int adapterPosition = searchRecyclerView.getChildAdapterPosition(searchResultView); - boolean decoratorFilled = - adapterPosition != NO_POSITION - && searchRecyclerView.getApps().getAdapterItems().get(adapterPosition) + Drawable background = searchResultView.getBackground(); + if (background != null + && searchResultView instanceof ViewGroup + && FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) { + searchResultView.setAlpha(1f); + + // Apply content alpha to each child, since the view needs to be fully opaque for + // the background to show properly. + ViewGroup searchResultViewGroup = (ViewGroup) searchResultView; + for (int j = 0; j < searchResultViewGroup.getChildCount(); j++) { + searchResultViewGroup.getChildAt(j).setAlpha(contentAlpha); + } + + // Apply background alpha to the background drawable directly. + background.setAlpha((int) (255 * backgroundAlpha)); + } else { + searchResultView.setAlpha(contentAlpha); + + // Apply background alpha to decorator if possible. + if (adapterPosition != NO_POSITION) { + searchRecyclerView.getApps().getAdapterItems().get(adapterPosition) .setDecorationFillAlpha((int) (255 * backgroundAlpha)); - if (!decoratorFilled) { - // Try to adjust background alpha instead (e.g. for Search Edu card). - Drawable background = searchResultView.getBackground(); + } + + // Apply background alpha to view's background (e.g. for Search Edu card). if (background != null) { background.setAlpha((int) (255 * backgroundAlpha)); } } - float scaleY = 1 - mSearchToAzProgress; + float scaleY = 1; + if (shouldAnimate) { + scaleY = 1 - mSearchToAzProgress; + } int scaledHeight = (int) (searchResultView.getHeight() * scaleY); searchResultView.setScaleY(scaleY); // For rows with multiple elements, only count the height once and translate elements to // the same y position. int y = top + totalHeight; - int spanIndex = getSpanIndex(searchRecyclerView, adapterPosition); if (spanIndex > 0) { // Continuation of an existing row; move this item into the row. y -= scaledHeight; } else { - // Start of a new row contributes to total height and animation stagger. - numSearchResultsAnimated++; + // Start of a new row contributes to total height. totalHeight += scaledHeight; + if (!shouldAnimate) { + appRowHeight = scaledHeight; + } } searchResultView.setY(y); } @@ -274,6 +298,11 @@ public class SearchTransitionController { return adapter.getSpanIndex(adapterPosition); } + private boolean isAppIcon(View item) { + return item instanceof BubbleTextView && item.getTag() instanceof ItemInfo + && ((ItemInfo) item.getTag()).itemType == ITEM_TYPE_APPLICATION; + } + /** Called just before a child is attached to the SearchRecyclerView. */ private void onSearchChildAttached(View child) { // Avoid allocating hardware layers for alpha changes. @@ -292,6 +321,13 @@ public class SearchTransitionController { getSearchRecyclerView().getApps().getAdapterItems().get(adapterPosition) .setDecorationFillAlpha(255); } + if (child instanceof ViewGroup + && FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) { + ViewGroup childGroup = (ViewGroup) child; + for (int i = 0; i < childGroup.getChildCount(); i++) { + childGroup.getChildAt(i).setAlpha(1f); + } + } if (child.getBackground() != null) { child.getBackground().setAlpha(255); } diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java index 6138bc4a9d..228b02bbc1 100644 --- a/src/com/android/launcher3/allapps/SearchUiManager.java +++ b/src/com/android/launcher3/allapps/SearchUiManager.java @@ -64,7 +64,8 @@ public interface SearchUiManager { /** * sets highlight result's title */ - default void setFocusedResultTitle(@Nullable CharSequence title) { } + default void setFocusedResultTitle( + @Nullable CharSequence title, @Nullable CharSequence subtitle) {} /** Refresh the currently displayed list of results. */ default void refreshResults() {} diff --git a/src/com/android/launcher3/allapps/SecondaryLauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/SecondaryLauncherAllAppsContainerView.java index 0719c4342f..684e98ed96 100644 --- a/src/com/android/launcher3/allapps/SecondaryLauncherAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/SecondaryLauncherAllAppsContainerView.java @@ -42,4 +42,9 @@ public class SecondaryLauncherAllAppsContainerView extends @Override protected void updateBackground(DeviceProfile deviceProfile) {} + + @Override + public boolean isInAllApps() { + return mActivityContext.isAppDrawerShown(); + } } diff --git a/src/com/android/launcher3/allapps/WorkEduCard.java b/src/com/android/launcher3/allapps/WorkEduCard.java index 968a5566f8..b3245eec4f 100644 --- a/src/com/android/launcher3/allapps/WorkEduCard.java +++ b/src/com/android/launcher3/allapps/WorkEduCard.java @@ -26,8 +26,8 @@ import android.view.animation.AnimationUtils; import android.widget.FrameLayout; import android.widget.TextView; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.model.StringCache; import com.android.launcher3.views.ActivityContext; @@ -85,7 +85,7 @@ public class WorkEduCard extends FrameLayout implements @Override public void onClick(View view) { startAnimation(mDismissAnim); - Utilities.getPrefs(getContext()).edit().putInt(WorkProfileManager.KEY_WORK_EDU_STEP, + LauncherPrefs.getPrefs(getContext()).edit().putInt(WorkProfileManager.KEY_WORK_EDU_STEP, 1).apply(); } diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java index 15fb77cfb3..11ce738208 100644 --- a/src/com/android/launcher3/allapps/WorkModeSwitch.java +++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java @@ -15,17 +15,23 @@ */ package com.android.launcher3.allapps; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_OFF_WORK_APPS_TAP; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_FAB_BUTTON_COLLAPSE; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_FAB_BUTTON_EXTEND; import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth; +import android.animation.LayoutTransition; import android.content.Context; -import android.graphics.Insets; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; -import android.view.ViewGroup.MarginLayoutParams; import android.view.WindowInsets; -import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.core.graphics.Insets; +import androidx.core.view.WindowInsetsCompat; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; @@ -33,74 +39,84 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.KeyboardInsetAnimationCallback; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.StringCache; import com.android.launcher3.views.ActivityContext; -import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip; - /** * Work profile toggle switch shown at the bottom of AllApps work tab */ -public class WorkModeSwitch extends Button implements Insettable, View.OnClickListener, - KeyboardInsetAnimationCallback.KeyboardInsetListener, - PersonalWorkSlidingTabStrip.OnActivePageChangedListener { +public class WorkModeSwitch extends LinearLayout implements Insettable, + KeyboardInsetAnimationCallback.KeyboardInsetListener { private static final int FLAG_FADE_ONGOING = 1 << 1; private static final int FLAG_TRANSLATION_ONGOING = 1 << 2; private static final int FLAG_PROFILE_TOGGLE_ONGOING = 1 << 3; + private static final int SCROLL_THRESHOLD_DP = 10; private final Rect mInsets = new Rect(); + private final Rect mImeInsets = new Rect(); private int mFlags; - private boolean mWorkEnabled; - private boolean mOnWorkTab; + private final ActivityContext mActivityContext; + + // Threshold when user scrolls up/down to determine when should button extend/collapse + private final int mScrollThreshold; + private ImageView mIcon; + private TextView mTextView; + private final StatsLogManager mStatsLogManager; + - public WorkModeSwitch(Context context) { + public WorkModeSwitch(@NonNull Context context) { this(context, null, 0); } - public WorkModeSwitch(Context context, AttributeSet attrs) { + public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs) { this(context, attrs, 0); } - public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) { + public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP); + mActivityContext = ActivityContext.lookupContext(getContext()); + mStatsLogManager = mActivityContext.getStatsLogManager(); } @Override protected void onFinishInflate() { super.onFinishInflate(); + + mIcon = findViewById(R.id.work_icon); + mTextView = findViewById(R.id.pause_text); setSelected(true); - setOnClickListener(this); if (Utilities.ATLEAST_R) { KeyboardInsetAnimationCallback keyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this); setWindowInsetsAnimationCallback(keyboardInsetAnimationCallback); } - ActivityContext activityContext = ActivityContext.lookupContext(getContext()); - DeviceProfile grid = activityContext.getDeviceProfile(); - setInsets(grid.getInsets()); - StringCache cache = activityContext.getStringCache(); + setInsets(mActivityContext.getDeviceProfile().getInsets()); + StringCache cache = mActivityContext.getStringCache(); if (cache != null) { - setText(cache.workProfilePauseButton); + mTextView.setText(cache.workProfilePauseButton); } + + mIcon.setColorFilter(mTextView.getCurrentTextColor()); + getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING); } @Override public void setInsets(Rect insets) { mInsets.set(insets); + updateTranslationY(); MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); if (lp != null) { int bottomMargin = getResources().getDimensionPixelSize(R.dimen.work_fab_margin_bottom); DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile(); if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) { - bottomMargin <<= 1; // Double margin to add space above search bar. bottomMargin += dp.hotseatQsbHeight; } if (!dp.isGestureMode && dp.isTaskbarPresent) { bottomMargin += dp.taskbarSize; - } else { - bottomMargin += insets.bottom; } lp.bottomMargin = bottomMargin; @@ -110,74 +126,61 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile(); View parent = (View) getParent(); + int allAppsLeftRightPadding = mActivityContext.getDeviceProfile().allAppsLeftRightPadding; int size = parent.getWidth() - parent.getPaddingLeft() - parent.getPaddingRight() - - 2 * dp.allAppsLeftRightPadding; + - 2 * allAppsLeftRightPadding; int tabWidth = getTabWidth(getContext(), size); - int shift = (size - tabWidth) / 2 + dp.allAppsLeftRightPadding; + int shift = (size - tabWidth) / 2 + allAppsLeftRightPadding; setTranslationX(Utilities.isRtl(getResources()) ? shift : -shift); } @Override - public void onActivePageChanged(int page) { - mOnWorkTab = page == ActivityAllAppsContainerView.AdapterHolder.WORK; - updateVisibility(); - } - - @Override - public void onClick(View view) { - if (Utilities.ATLEAST_P && isEnabled()) { - setFlag(FLAG_PROFILE_TOGGLE_ONGOING); - ActivityContext activityContext = ActivityContext.lookupContext(getContext()); - activityContext.getStatsLogManager().logger().log(LAUNCHER_TURN_OFF_WORK_APPS_TAP); - activityContext.getAppsView().getWorkManager().setWorkProfileEnabled(false); - } - } - - @Override public boolean isEnabled() { return super.isEnabled() && getVisibility() == VISIBLE && mFlags == 0; } - /** - * Sets the enabled or disabled state of the button - */ - public void updateCurrentState(boolean isEnabled) { - removeFlag(FLAG_PROFILE_TOGGLE_ONGOING); - if (mWorkEnabled != isEnabled) { - mWorkEnabled = isEnabled; - updateVisibility(); - } - } - - private void updateVisibility() { + public void animateVisibility(boolean visible) { clearAnimation(); - if (mWorkEnabled && mOnWorkTab) { + if (visible) { setFlag(FLAG_FADE_ONGOING); setVisibility(VISIBLE); + extend(); animate().alpha(1).withEndAction(() -> removeFlag(FLAG_FADE_ONGOING)).start(); } else if (getVisibility() != GONE) { setFlag(FLAG_FADE_ONGOING); animate().alpha(0).withEndAction(() -> { removeFlag(FLAG_FADE_ONGOING); - this.setVisibility(GONE); + setVisibility(GONE); }).start(); } } @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { - if (!Utilities.ATLEAST_R) { - return insets; - } - if (insets.isVisible(WindowInsets.Type.ime())) { - Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime()); - setTranslationY(mInsets.bottom - keyboardInsets.bottom); + WindowInsetsCompat windowInsetsCompat = + WindowInsetsCompat.toWindowInsetsCompat(insets, this); + if (windowInsetsCompat.isVisible(WindowInsetsCompat.Type.ime())) { + setInsets(mImeInsets, windowInsetsCompat.getInsets(WindowInsetsCompat.Type.ime())); } else { - setTranslationY(0); + mImeInsets.setEmpty(); } - return insets; + updateTranslationY(); + return super.onApplyWindowInsets(insets); + } + + private void updateTranslationY() { + setTranslationY(-mImeInsets.bottom); + } + + @Override + public void setTranslationY(float translationY) { + // Always translate at least enough for nav bar insets. + super.setTranslationY(Math.min(translationY, -mInsets.bottom)); + } + + private void setInsets(Rect rect, Insets insets) { + rect.set(insets.left, insets.top, insets.right, insets.bottom); } @Override @@ -197,4 +200,18 @@ public class WorkModeSwitch extends Button implements Insettable, View.OnClickLi private void removeFlag(int flag) { mFlags &= ~flag; } + + public void extend() { + mTextView.setVisibility(VISIBLE); + mStatsLogManager.logger().log(LAUNCHER_WORK_FAB_BUTTON_EXTEND); + } + + public void shrink(){ + mTextView.setVisibility(GONE); + mStatsLogManager.logger().log(LAUNCHER_WORK_FAB_BUTTON_COLLAPSE); + } + + public int getScrollThreshold() { + return mScrollThreshold; + } } diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java index cfac985c2d..279f0d399c 100644 --- a/src/com/android/launcher3/allapps/WorkProfileManager.java +++ b/src/com/android/launcher3/allapps/WorkProfileManager.java @@ -17,6 +17,10 @@ package com.android.launcher3.allapps; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD; +import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.MAIN; +import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.SEARCH; +import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.WORK; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_OFF_WORK_APPS_TAP; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED; @@ -28,13 +32,18 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; +import android.view.View; import androidx.annotation.IntDef; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; +import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem; +import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip; @@ -71,6 +80,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP private final UserManager mUserManager; private final BaseAllAppsContainerView<?> mAllApps; private final Predicate<ItemInfo> mMatcher; + private final StatsLogManager mStatsLogManager; private WorkModeSwitch mWorkModeSwitch; @@ -79,11 +89,13 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP private SharedPreferences mPreferences; public WorkProfileManager( - UserManager userManager, BaseAllAppsContainerView<?> allApps, SharedPreferences prefs) { + UserManager userManager, BaseAllAppsContainerView<?> allApps, SharedPreferences prefs, + StatsLogManager statsLogManager) { mUserManager = userManager; mAllApps = allApps; mPreferences = prefs; mMatcher = mAllApps.mPersonalMatcher.negate(); + mStatsLogManager = statsLogManager; } /** @@ -104,8 +116,16 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP @Override public void onActivePageChanged(int page) { + updateWorkFAB(page); + } + + private void updateWorkFAB(int page) { if (mWorkModeSwitch != null) { - mWorkModeSwitch.onActivePageChanged(page); + if (page == MAIN || page == SEARCH) { + mWorkModeSwitch.animateVisibility(false); + } else if (page == WORK && mCurrentState == STATE_ENABLED) { + mWorkModeSwitch.animateVisibility(true); + } } } @@ -123,7 +143,12 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP getAH().mAppsList.updateAdapterItems(); } if (mWorkModeSwitch != null) { - mWorkModeSwitch.updateCurrentState(currentState == STATE_ENABLED); + updateWorkFAB(mAllApps.getCurrentPage()); + } + if (mCurrentState == STATE_ENABLED) { + attachWorkModeSwitch(); + } else if (mCurrentState == STATE_DISABLED) { + detachWorkModeSwitch(); } } @@ -140,13 +165,16 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate( R.layout.work_mode_fab, mAllApps, false); } - if (mWorkModeSwitch.getParent() != mAllApps) { + if (mWorkModeSwitch.getParent() == null) { mAllApps.addView(mWorkModeSwitch); } + if (mAllApps.getCurrentPage() != WORK) { + mWorkModeSwitch.animateVisibility(false); + } if (getAH() != null) { getAH().applyPadding(); } - mWorkModeSwitch.updateCurrentState(mCurrentState == STATE_ENABLED); + mWorkModeSwitch.setOnClickListener(this::onWorkFabClicked); return true; } /** @@ -169,7 +197,7 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP } private BaseAllAppsContainerView<?>.AdapterHolder getAH() { - return mAllApps.mAH.get(BaseAllAppsContainerView.AdapterHolder.WORK); + return mAllApps.mAH.get(WORK); } public int getCurrentState() { @@ -199,4 +227,38 @@ public class WorkProfileManager implements PersonalWorkSlidingTabStrip.OnActiveP private boolean isEduSeen() { return mPreferences.getInt(KEY_WORK_EDU_STEP, 0) != 0; } + + private void onWorkFabClicked(View view) { + if (Utilities.ATLEAST_P && mCurrentState == STATE_ENABLED && mWorkModeSwitch.isEnabled()) { + mStatsLogManager.logger().log(LAUNCHER_TURN_OFF_WORK_APPS_TAP); + setWorkProfileEnabled(false); + } + } + + public RecyclerView.OnScrollListener newScrollListener() { + return new RecyclerView.OnScrollListener() { + int totalDelta = 0; + @Override + public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState){ + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + totalDelta = 0; + } + } + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + WorkModeSwitch fab = getWorkModeSwitch(); + if (fab == null){ + return; + } + totalDelta = Utilities.boundToRange(totalDelta, + -fab.getScrollThreshold(), fab.getScrollThreshold()) + dy; + boolean isScrollAtTop = recyclerView.computeVerticalScrollOffset() == 0; + if ((isScrollAtTop || totalDelta < -fab.getScrollThreshold())) { + fab.extend(); + } else if (totalDelta > fab.getScrollThreshold()) { + fab.shrink(); + } + } + }; + } } diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java index 886460e5c7..4427a49dab 100644 --- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java @@ -15,9 +15,6 @@ */ package com.android.launcher3.allapps.search; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_QUICK_SEARCH_WITH_IME; - import android.text.Editable; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -70,7 +67,7 @@ public class AllAppsSearchBarController mInput.addTextChangedListener(this); mInput.setOnEditorActionListener(this); mInput.setOnBackKeyListener(this); - mInput.setOnFocusChangeListener(this); + mInput.addOnFocusChangeListener(this); mSearchAlgorithm = searchAlgorithm; } @@ -84,7 +81,10 @@ public class AllAppsSearchBarController mTextConversions = extractTextConversions(s); } - private static String[] extractTextConversions(CharSequence text) { + /** + * Extract text conversions from composing text and send them for search. + */ + public static String[] extractTextConversions(CharSequence text) { if (text instanceof SpannableStringBuilder) { SpannableStringBuilder spanned = (SpannableStringBuilder) text; SuggestionSpan[] suggestionSpans = @@ -122,10 +122,6 @@ public class AllAppsSearchBarController public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_GO) { - mLauncher.getStatsLogManager().logger() - .log(actionId == EditorInfo.IME_ACTION_SEARCH - ? LAUNCHER_ALLAPPS_QUICK_SEARCH_WITH_IME - : LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME); // selectFocusedView should return SearchTargetEvent that is passed onto onClick return mLauncher.getAppsView().getMainAdapterProvider().launchHighlightedItem(); } @@ -157,6 +153,7 @@ public class AllAppsSearchBarController mCallback.clearSearchResult(); mInput.reset(); mQuery = null; + mInput.removeOnFocusChangeListener(this); } /** diff --git a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java index 4fb732d5f0..20edf8a93c 100644 --- a/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java +++ b/src/com/android/launcher3/allapps/search/DefaultSearchAdapterProvider.java @@ -26,17 +26,17 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.allapps.AllAppsGridAdapter; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.views.AppLauncher; +import com.android.launcher3.views.ActivityContext; /** * Provides views for local search results. */ -public class DefaultSearchAdapterProvider extends SearchAdapterProvider<AppLauncher> { +public class DefaultSearchAdapterProvider extends SearchAdapterProvider<ActivityContext> { private final RecyclerView.ItemDecoration mDecoration; private View mHighlightedView; - public DefaultSearchAdapterProvider(AppLauncher launcher) { + public DefaultSearchAdapterProvider(ActivityContext launcher) { super(launcher); mDecoration = new RecyclerView.ItemDecoration() { @Override diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/src/com/android/launcher3/anim/AnimatedFloat.java index a1665530a3..b73621d414 100644 --- a/quickstep/src/com/android/quickstep/AnimatedFloat.java +++ b/src/com/android/launcher3/anim/AnimatedFloat.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2022 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep; +package com.android.launcher3.anim; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -99,30 +99,23 @@ public class AnimatedFloat { } /** - * Starts the animation. + * Cancels the animation. */ - public void startAnimation() { - if (mValueAnimator != null) { - mValueAnimator.start(); - } - } - public void cancelAnimation() { if (mValueAnimator != null) { mValueAnimator.cancel(); } } + /** + * Ends the animation. + */ public void finishAnimation() { if (mValueAnimator != null && mValueAnimator.isRunning()) { mValueAnimator.end(); } } - public ObjectAnimator getCurrentAnimation() { - return mValueAnimator; - } - public boolean isAnimating() { return mValueAnimator != null; } @@ -135,9 +128,9 @@ public class AnimatedFloat { } /** - * Returns the value we are animating to, or {@code null} if we are not currently animating. + * Returns whether we are currently not animating, and the animation's value matches the given. */ - public Float getEndValue() { - return mEndValue; + public boolean isSettledOnValue(float endValue) { + return !isAnimating() && value == endValue; } } diff --git a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java index 9d96365acc..3863dc1962 100644 --- a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java +++ b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java @@ -53,10 +53,21 @@ public class KeyboardInsetAnimationCallback extends WindowInsetsAnimation.Callba mView.setTranslationY(mInitialTranslation); return windowInsets; } - float progress = list.get(0).getInterpolatedFraction(); - - mView.setTranslationY( - Utilities.mapRange(progress, mInitialTranslation, mTerminalTranslation)); + WindowInsetsAnimation animation = list.get(0); + + if (animation.getDurationMillis() > -1) { + float progress = animation.getInterpolatedFraction(); + mView.setTranslationY( + Utilities.mapRange(progress, mInitialTranslation, mTerminalTranslation)); + } else { + // Manually controlled animation: Set translation to keyboard height. + int translationY = -windowInsets.getInsets(WindowInsets.Type.ime()).bottom; + if (mView.getParent() instanceof View) { + // Offset any translation of the parent (e.g. All Apps parallax). + translationY -= ((View) mView.getParent()).getTranslationY(); + } + mView.setTranslationY(translationY); + } return windowInsets; } @@ -73,6 +84,7 @@ public class KeyboardInsetAnimationCallback extends WindowInsetsAnimation.Callba @Override public void onEnd(WindowInsetsAnimation animation) { + mView.setTranslationY(mTerminalTranslation); if (mView instanceof KeyboardInsetListener) { ((KeyboardInsetListener) mView).onTranslationEnd(); } diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java index b0ed2d2277..6ba58b6a98 100644 --- a/src/com/android/launcher3/anim/PropertySetter.java +++ b/src/com/android/launcher3/anim/PropertySetter.java @@ -38,6 +38,7 @@ public abstract class PropertySetter { public void add(Animator animatorSet) { animatorSet.setDuration(0); animatorSet.start(); + animatorSet.end(); } }; diff --git a/src/com/android/launcher3/celllayout/CellLayoutLayoutParams.java b/src/com/android/launcher3/celllayout/CellLayoutLayoutParams.java new file mode 100644 index 0000000000..abd4682701 --- /dev/null +++ b/src/com/android/launcher3/celllayout/CellLayoutLayoutParams.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2022 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.launcher3.celllayout; + +import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.ViewDebug; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; + +/** + * Represents the logic of where a view is in a CellLayout and its size + */ +public class CellLayoutLayoutParams extends ViewGroup.MarginLayoutParams { + + public int screenId = -1; + + /** + * Horizontal location of the item in the grid. + */ + @ViewDebug.ExportedProperty + public int cellX; + + /** + * Vertical location of the item in the grid. + */ + @ViewDebug.ExportedProperty + public int cellY; + + /** + * Temporary horizontal location of the item in the grid during reorder + */ + public int tmpCellX; + + /** + * Temporary vertical location of the item in the grid during reorder + */ + public int tmpCellY; + + /** + * Indicates that the temporary coordinates should be used to layout the items + */ + public boolean useTmpCoords; + + /** + * Number of cells spanned horizontally by the item. + */ + @ViewDebug.ExportedProperty + public int cellHSpan; + + /** + * Number of cells spanned vertically by the item. + */ + @ViewDebug.ExportedProperty + public int cellVSpan; + + /** + * Indicates whether the item will set its x, y, width and height parameters freely, + * or whether these will be computed based on cellX, cellY, cellHSpan and cellVSpan. + */ + public boolean isLockedToGrid = true; + + /** + * Indicates whether this item can be reordered. Always true except in the case of the + * the AllApps button and QSB place holder. + */ + public boolean canReorder = true; + + // X coordinate of the view in the layout. + @ViewDebug.ExportedProperty + public int x; + // Y coordinate of the view in the layout. + @ViewDebug.ExportedProperty + public int y; + + public boolean dropped; + + public CellLayoutLayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + cellHSpan = 1; + cellVSpan = 1; + } + + public CellLayoutLayoutParams(ViewGroup.LayoutParams source) { + super(source); + cellHSpan = 1; + cellVSpan = 1; + } + + public CellLayoutLayoutParams(CellLayoutLayoutParams source) { + super(source); + this.cellX = source.cellX; + this.cellY = source.cellY; + this.cellHSpan = source.cellHSpan; + this.cellVSpan = source.cellVSpan; + this.screenId = source.screenId; + this.tmpCellX = source.tmpCellX; + this.tmpCellY = source.tmpCellY; + this.useTmpCoords = source.useTmpCoords; + } + + public CellLayoutLayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan, + int screenId) { + super(CellLayoutLayoutParams.MATCH_PARENT, CellLayoutLayoutParams.MATCH_PARENT); + this.cellX = cellX; + this.cellY = cellY; + this.cellHSpan = cellHSpan; + this.cellVSpan = cellVSpan; + this.screenId = screenId; + } + + /** + * Updates the {@link CellLayoutLayoutParams} with the right measures using their + * full/invariant device profile sizes. + */ + public void setup(int cellWidth, int cellHeight, boolean invertHorizontally, int colCount, + int rowCount, Point borderSpace, @Nullable Rect inset) { + setup(cellWidth, cellHeight, invertHorizontally, colCount, rowCount, 1.0f, 1.0f, + borderSpace, inset); + } + + /** + * Use this method, as opposed to {@link #setup(int, int, boolean, int, int, Point, Rect)}, + * if the view needs to be scaled. + * + * ie. In multi-window mode, we setup widgets so that they are measured and laid out + * using their full/invariant device profile sizes. + */ + public void setup(int cellWidth, int cellHeight, boolean invertHorizontally, int colCount, + int rowCount, float cellScaleX, float cellScaleY, Point borderSpace, + @Nullable Rect inset) { + if (isLockedToGrid) { + final int myCellHSpan = cellHSpan; + final int myCellVSpan = cellVSpan; + int myCellX = useTmpCoords ? tmpCellX : cellX; + int myCellY = useTmpCoords ? tmpCellY : cellY; + + if (invertHorizontally) { + myCellX = colCount - myCellX - cellHSpan; + } + + int hBorderSpacing = (myCellHSpan - 1) * borderSpace.x; + int vBorderSpacing = (myCellVSpan - 1) * borderSpace.y; + + float myCellWidth = ((myCellHSpan * cellWidth) + hBorderSpacing) / cellScaleX; + float myCellHeight = ((myCellVSpan * cellHeight) + vBorderSpacing) / cellScaleY; + + width = Math.round(myCellWidth) - leftMargin - rightMargin; + height = Math.round(myCellHeight) - topMargin - bottomMargin; + x = leftMargin + (myCellX * cellWidth) + (myCellX * borderSpace.x); + y = topMargin + (myCellY * cellHeight) + (myCellY * borderSpace.y); + + if (inset != null) { + x -= inset.left; + y -= inset.top; + width += inset.left + inset.right; + height += inset.top + inset.bottom; + } + } + } + + /** + * Sets the position to the provided point + */ + public void setCellXY(Point point) { + cellX = point.x; + cellY = point.y; + } + + /** + * @return the string representation of the position of the {@link CellLayoutLayoutParams} + */ + public String toString() { + return "(" + this.cellX + ", " + this.cellY + ")"; + } +} diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 50cf8d67f9..e2d81997f8 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -17,6 +17,7 @@ package com.android.launcher3.config; import android.content.Context; +import android.content.SharedPreferences; import com.android.launcher3.BuildConfig; import com.android.launcher3.Utilities; @@ -37,7 +38,8 @@ public final class FeatureFlags { public static final String FLAGS_PREF_NAME = "featureFlags"; - private FeatureFlags() { } + private FeatureFlags() { + } public static boolean showFlagTogglerUi(Context context) { return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context); @@ -61,7 +63,7 @@ public final class FeatureFlags { * To add a new flag that can be toggled through the flags UI: * * Declare a new ToggleableFlag below. Give it a unique key (e.g. "QSB_ON_FIRST_SCREEN"), - * and set a default value for the flag. This will be the default value on Debug builds. + * and set a default value for the flag. This will be the default value on Debug builds. */ public static final BooleanFlag ENABLE_INPUT_CONSUMER_REASON_LOGGING = getDebugFlag( "ENABLE_INPUT_CONSUMER_REASON_LOGGING", @@ -77,16 +79,9 @@ public final class FeatureFlags { public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag( "PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps"); - // TODO: b/206508141: Long pressing on some icons on home screen cause launcher to crash. - public static final BooleanFlag ENABLE_LOCAL_COLOR_POPUPS = getDebugFlag( - "ENABLE_LOCAL_COLOR_POPUPS", false, "Enable local color extraction for popups."); - public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag( "KEYGUARD_ANIMATION", false, "Enable animation for keyguard going away on wallpaper"); - public static final BooleanFlag ENABLE_QUICKSTEP_LIVE_TILE = getDebugFlag( - "ENABLE_QUICKSTEP_LIVE_TILE", true, "Enable live tile in Quickstep overview"); - public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag( "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps"); @@ -97,6 +92,10 @@ public final class FeatureFlags { public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER", true, "Hide header on keyboard before typing in all apps"); + public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = new DeviceFlag( + "ENABLE_EXPANDING_PAUSE_WORK_BUTTON", false, + "Expand and collapse pause work button while scrolling"); + public static final BooleanFlag ENABLE_HIDE_HEADER_STATIC = new DeviceFlag( "ENABLE_HIDE_HEADER_STATIC", false, "Hide keyboard suggestion strip"); @@ -121,6 +120,10 @@ public final class FeatureFlags { "FOLDER_NAME_MAJORITY_RANKING", true, "Suggests folder names based on majority based ranking."); + public static final BooleanFlag INJECT_FALLBACK_APP_CORPUS_RESULTS = new DeviceFlag( + "INJECT_FALLBACK_APP_CORPUS_RESULTS", false, "Inject " + + "fallback app corpus result when AiAi fails to return it."); + public static final BooleanFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = getDebugFlag( "ASSISTANT_GIVES_LAUNCHER_FOCUS", false, "Allow Launcher to handle nav bar gestures while Assistant is running over it"); @@ -154,17 +157,22 @@ public final class FeatureFlags { "ENABLE_SMARTSPACE_DISMISS", true, "Adds a menu option to dismiss the current Enhanced Smartspace card."); + public static final BooleanFlag ENABLE_OVERLAY_CONNECTION_OPTIM = getDebugFlag( + "ENABLE_OVERLAY_CONNECTION_OPTIM", + false, + "Enable optimizing overlay service connection"); + /** * Enables region sampling for text color: Needs system health assessment before turning on */ - public static final BooleanFlag ENABLE_REGION_SAMPLING = getDebugFlag( + public static final BooleanFlag ENABLE_REGION_SAMPLING = getDebugFlag( "ENABLE_REGION_SAMPLING", false, "Enable region sampling to determine color of text on screen."); public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS = getDebugFlag( - "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false, - "Always use hardware optimization for folder animations."); + "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false, + "Always use hardware optimization for folder animations."); public static final BooleanFlag SEPARATE_RECENTS_ACTIVITY = getDebugFlag( "SEPARATE_RECENTS_ACTIVITY", false, @@ -199,10 +207,6 @@ public final class FeatureFlags { public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = new DeviceFlag( "ENABLE_ENFORCED_ROUNDED_CORNERS", true, "Enforce rounded corners on all App Widgets"); - public static final BooleanFlag ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER = new DeviceFlag( - "ENABLE_LOCAL_RECOMMENDED_WIDGETS_FILTER", true, - "Enables a local filter for recommended widgets."); - public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false, "Sends a notification whenever launcher encounters an uncaught exception."); @@ -238,21 +242,40 @@ public final class FeatureFlags { "ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", false, "Enables One Search box in Taskbar All Apps."); + public static final BooleanFlag ENABLE_TASKBAR_IN_OVERVIEW = getDebugFlag( + "ENABLE_TASKBAR_IN_OVERVIEW", true, + "Enables accessing the system Taskbar in overview."); + public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag( "ENABLE_SPLIT_FROM_WORKSPACE", true, "Enable initiating split screen from workspace."); + public static final BooleanFlag ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS = + getDebugFlag("ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", false, + "Enable splitting from fullscreen app with keyboard shortcuts"); + + public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag( + "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", false, + "Enable initiating split screen from workspace to workspace."); + public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag( "ENABLE_NEW_MIGRATION_LOGIC", true, "Enable the new grid migration logic, keeping pages when src < dest"); + public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag( + "ENABLE_WIDGET_HOST_IN_BACKGROUND", false, + "Enable background widget updates listening for widget holder"); + public static final BooleanFlag ENABLE_ONE_SEARCH_MOTION = new DeviceFlag( "ENABLE_ONE_SEARCH_MOTION", true, "Enables animations in OneSearch."); - public static final BooleanFlag ENABLE_KEYBOARD_TRANSITION_SYNC = new DeviceFlag( - "ENABLE_KEYBOARD_TRANSITION_SYNC", IS_STUDIO_BUILD, - "Enable option to synchronize the keyboard open and close animations when transitioning" - + " between home and all apps"); + public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = new DeviceFlag( + "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", false, + "Enable option to replace decorator-based search result backgrounds with drawables"); + + public static final BooleanFlag TWO_PREDICTED_ROWS_ALL_APPS_SEARCH = new DeviceFlag( + "TWO_PREDICTED_ROWS_ALL_APPS_SEARCH", false, + "Use 2 rows of app predictions in All Apps search zero-state"); public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = new DeviceFlag( "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", true, @@ -282,22 +305,96 @@ public final class FeatureFlags { "In foldables, when reordering the icons and widgets, is now going to use both sides"); public static final BooleanFlag ENABLE_WIDGET_PICKER_DEPTH = new DeviceFlag( - "ENABLE_WIDGET_PICKER_DEPTH", false, "Enable changing depth in widget picker."); + "ENABLE_WIDGET_PICKER_DEPTH", true, "Enable changing depth in widget picker."); - public static final BooleanFlag SHOW_DELIGHTFUL_PAGINATION_FOLDER = new DeviceFlag( - "SHOW_DELIGHTFUL_PAGINATION_FOLDER", false, - "Enable showing the new 'delightful pagination'" - + " which is a brand new animation for folder pagination"); + public static final BooleanFlag ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH = getDebugFlag( + "ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", false, + "Allow bottom sheet depth to be smaller than 1 for multi-display devices."); + + public static final BooleanFlag SCROLL_TOP_TO_RESET = new DeviceFlag( + "SCROLL_TOP_TO_RESET", true, "Bring up IME and focus on " + + "input when scroll to top if 'Always show keyboard' is enabled or in prefix state"); public static final BooleanFlag POPUP_MATERIAL_U = new DeviceFlag( "POPUP_MATERIAL_U", false, "Switch popup UX to use material U"); + public static final BooleanFlag SHOW_HOME_GARDENING = getDebugFlag( + "SHOW_HOME_GARDENING", false, + "Show the new home gardening mode"); + + public static final BooleanFlag HOME_GARDENING_WORKSPACE_BUTTONS = getDebugFlag( + "HOME_GARDENING_WORKSPACE_BUTTONS", false, + "Change workspace edit buttons to reflect home gardening"); + + public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V2 = getDebugFlag( + "ENABLE_DOWNLOAD_APP_UX_V2", false, "Updates the download app UX" + + " to have better visuals"); + + public static final BooleanFlag ENABLE_TASKBAR_REVISED_THRESHOLDS = getDebugFlag( + "ENABLE_TASKBAR_REVISED_THRESHOLDS", true, + "Uses revised thresholds for transient taskbar."); + + public static final BooleanFlag FORCE_PERSISTENT_TASKBAR = getDebugFlag( + "FORCE_PERSISTENT_TASKBAR", false, "Forces taskbar to be persistent, even in gesture" + + " nav mode and when transient taskbar is enabled."); + + public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag( + "FOLDABLE_SINGLE_PAGE", false, + "Use a single page for the workspace"); + + public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag( + "ENABLE_TRANSIENT_TASKBAR", false, "Enables transient taskbar."); + + public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag( + "SECONDARY_DRAG_N_DROP_TO_PIN", false, + "Enable dragging and dropping to pin apps within secondary display"); + + public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag( + "SHOW_DOT_PAGINATION", false, "Enable showing dot pagination in workspace"); + + public static final BooleanFlag LARGE_SCREEN_WIDGET_PICKER = getDebugFlag( + "LARGE_SCREEN_WIDGET_PICKER", false, "Enable new widget picker that takes " + + "advantage of large screen format"); + + public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag( + "ENABLE_NEW_GESTURE_NAV_TUTORIAL", false, + "Enable the redesigned gesture navigation tutorial"); + + public static final BooleanFlag ENABLE_DEVICE_PROFILE_LOGGING = new DeviceFlag( + "ENABLE_DEVICE_PROFILE_LOGGING", false, "Allows DeviceProfile logging"); + + public static final BooleanFlag ENABLE_LAUNCH_FROM_STAGED_APP = getDebugFlag( + "ENABLE_LAUNCH_FROM_STAGED_APP", false, + "Enable the ability to tap a staged app during split select to launch it in full screen" + ); + + public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag( + "ENABLE_FORCED_MONO_ICON", false, + "Enable the ability to generate monochromatic icons, if it is not provided by the app" + ); + + public static final BooleanFlag ENABLE_TASKBAR_EDU_TOOLTIP = getDebugFlag( + "ENABLE_TASKBAR_EDU_TOOLTIP", false, + "Enable the tooltip version of the Taskbar education flow."); + + public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag( + "ENABLE_MULTI_INSTANCE", false, + "Enables creation and filtering of multiple task instances in overview"); + public static void initialize(Context context) { synchronized (sDebugFlags) { for (DebugFlag flag : sDebugFlags) { flag.initialize(context); } - sDebugFlags.sort((f1, f2) -> f1.key.compareToIgnoreCase(f2.key)); + + sDebugFlags.sort((f1, f2) -> { + // Sort first by any prefs that the user has changed, then alphabetically. + int changeComparison = Boolean.compare(f2.mHasBeenChangedAtLeastOnce, + f1.mHasBeenChangedAtLeastOnce); + return changeComparison != 0 + ? changeComparison + : f1.key.compareToIgnoreCase(f2.key); + }); } } @@ -353,6 +450,7 @@ public final class FeatureFlags { public static class DebugFlag extends BooleanFlag { public final String description; + protected boolean mHasBeenChangedAtLeastOnce; protected boolean mCurrentValue; public DebugFlag(String key, boolean defaultValue, String description) { @@ -370,8 +468,10 @@ public final class FeatureFlags { } public void initialize(Context context) { - mCurrentValue = context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE) - .getBoolean(key, defaultValue); + SharedPreferences prefs = + context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE); + mHasBeenChangedAtLeastOnce = prefs.contains(key); + mCurrentValue = prefs.getBoolean(key, defaultValue); } @Override diff --git a/src/com/android/launcher3/config/FlagTogglerPrefUi.java b/src/com/android/launcher3/config/FlagTogglerPrefUi.java index 6729f7434f..2eb6e6df9a 100644 --- a/src/com/android/launcher3/config/FlagTogglerPrefUi.java +++ b/src/com/android/launcher3/config/FlagTogglerPrefUi.java @@ -52,12 +52,17 @@ public final class FlagTogglerPrefUi { public void putBoolean(String key, boolean value) { for (DebugFlag flag : FeatureFlags.getDebugFlags()) { if (flag.key.equals(key)) { - SharedPreferences.Editor editor = mContext.getSharedPreferences( - FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit(); - if (value == flag.defaultValue) { + SharedPreferences prefs = mContext.getSharedPreferences( + FLAGS_PREF_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + // We keep the key in the prefs even if it has the default value, because it's a + // signal that it has been changed at one point. + if (!prefs.contains(key) && value == flag.defaultValue) { editor.remove(key).apply(); + flag.mHasBeenChangedAtLeastOnce = false; } else { editor.putBoolean(key, value).apply(); + flag.mHasBeenChangedAtLeastOnce = true; } updateMenu(); } diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index 05b1984887..4906c1dc31 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -23,6 +23,7 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_EXTERNAL_ITEM_START; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY; import android.annotation.TargetApi; import android.app.ActivityOptions; @@ -53,6 +54,8 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.widget.TextView; +import androidx.annotation.Nullable; + import com.android.launcher3.BaseActivity; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Launcher; @@ -61,16 +64,17 @@ import com.android.launcher3.R; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.WidgetItem; +import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.pm.PinRequestHelper; import com.android.launcher3.util.PackageManagerHelper; -import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.views.AbstractSlideInView; import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.widget.AddItemWidgetsBottomSheet; -import com.android.launcher3.widget.LauncherAppWidgetHost; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; +import com.android.launcher3.widget.LauncherWidgetHolder; import com.android.launcher3.widget.NavigableAppWidgetHostView; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; @@ -78,6 +82,7 @@ import com.android.launcher3.widget.WidgetCell; import com.android.launcher3.widget.WidgetCellPreview; import com.android.launcher3.widget.WidgetImageView; import com.android.launcher3.widget.WidgetManagerHelper; +import com.android.launcher3.widget.WidgetSections; import java.util.function.Supplier; @@ -105,7 +110,8 @@ public class AddItemActivity extends BaseActivity private WidgetCell mWidgetCell; // Widget request specific options. - private LauncherAppWidgetHost mAppWidgetHost; + @Nullable + private LauncherWidgetHolder mAppWidgetHolder = null; private WidgetManagerHelper mAppWidgetManager; private int mPendingBindWidgetId; private Bundle mWidgetOptions; @@ -139,7 +145,7 @@ public class AddItemActivity extends BaseActivity mAccessibilityManager = getApplicationContext().getSystemService(AccessibilityManager.class); - PackageUserKey targetApp = null; + final PackageItemInfo targetApp; switch (mRequest.getRequestType()) { case PinItemRequest.REQUEST_TYPE_SHORTCUT: targetApp = setupShortcut(); @@ -147,6 +153,9 @@ public class AddItemActivity extends BaseActivity case PinItemRequest.REQUEST_TYPE_APPWIDGET: targetApp = setupWidget(); break; + default: + targetApp = null; + break; } if (targetApp == null) { // TODO: show error toast? @@ -154,7 +163,7 @@ public class AddItemActivity extends BaseActivity return; } ApplicationInfo info = new PackageManagerHelper(this) - .getApplicationInfo(targetApp.mPackageName, targetApp.mUser, 0); + .getApplicationInfo(targetApp.packageName, targetApp.user, 0); if (info == null) { finish(); return; @@ -174,7 +183,10 @@ public class AddItemActivity extends BaseActivity // Set the label synchronously instead of via IconCache as this is the first thing // user sees TextView widgetAppName = findViewById(R.id.widget_appName); - widgetAppName.setText(info.loadLabel(getPackageManager())); + WidgetSections.WidgetSection section = targetApp.widgetCategory == NO_CATEGORY ? null + : WidgetSections.getWidgetSections(this).get(targetApp.widgetCategory); + widgetAppName.setText(section == null ? info.loadLabel(getPackageManager()) + : getString(section.mSectionTitle)); mSlideInView = findViewById(R.id.add_item_bottom_sheet); mSlideInView.addOnCloseListener(this); @@ -263,19 +275,18 @@ public class AddItemActivity extends BaseActivity } } - private PackageUserKey setupShortcut() { + private PackageItemInfo setupShortcut() { PinShortcutRequestActivityInfo shortcutInfo = new PinShortcutRequestActivityInfo(mRequest, this); mWidgetCell.getWidgetView().setTag(new PendingAddShortcutInfo(shortcutInfo)); applyWidgetItemAsync( () -> new WidgetItem(shortcutInfo, mApp.getIconCache(), getPackageManager())); - return new PackageUserKey( - mRequest.getShortcutInfo().getPackage(), + return new PackageItemInfo(mRequest.getShortcutInfo().getPackage(), mRequest.getShortcutInfo().getUserHandle()); } - private PackageUserKey setupWidget() { - LauncherAppWidgetProviderInfo widgetInfo = LauncherAppWidgetProviderInfo + private PackageItemInfo setupWidget() { + final LauncherAppWidgetProviderInfo widgetInfo = LauncherAppWidgetProviderInfo .fromProviderInfo(this, mRequest.getAppWidgetProviderInfo(this)); if (widgetInfo.minSpanX > mIdp.numColumns || widgetInfo.minSpanY > mIdp.numRows) { // Cannot add widget @@ -284,7 +295,7 @@ public class AddItemActivity extends BaseActivity mWidgetCell.setRemoteViewsPreview(PinItemDragListener.getPreview(mRequest)); mAppWidgetManager = new WidgetManagerHelper(this); - mAppWidgetHost = new LauncherAppWidgetHost(this); + mAppWidgetHolder = LauncherWidgetHolder.newInstance(this); PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(widgetInfo, CONTAINER_PIN_WIDGETS); @@ -294,7 +305,8 @@ public class AddItemActivity extends BaseActivity mWidgetCell.getWidgetView().setTag(pendingInfo); applyWidgetItemAsync(() -> new WidgetItem(widgetInfo, mIdp, mApp.getIconCache())); - return new PackageUserKey(widgetInfo.provider.getPackageName(), widgetInfo.getUser()); + return WidgetsModel.newPendingItemInfo(this, widgetInfo.getComponent(), + widgetInfo.getUser()); } private void applyWidgetItemAsync(final Supplier<WidgetItem> itemProvider) { @@ -338,7 +350,7 @@ public class AddItemActivity extends BaseActivity return; } - mPendingBindWidgetId = mAppWidgetHost.allocateAppWidgetId(); + mPendingBindWidgetId = mAppWidgetHolder.allocateAppWidgetId(); AppWidgetProviderInfo widgetProviderInfo = mRequest.getAppWidgetProviderInfo(this); boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( mPendingBindWidgetId, widgetProviderInfo, mWidgetOptions); @@ -349,7 +361,7 @@ public class AddItemActivity extends BaseActivity } // request bind widget - mAppWidgetHost.startBindFlow(this, mPendingBindWidgetId, + mAppWidgetHolder.startBindFlow(this, mPendingBindWidgetId, mRequest.getAppWidgetProviderInfo(this), REQUEST_BIND_APPWIDGET); } @@ -363,6 +375,15 @@ public class AddItemActivity extends BaseActivity } @Override + public void onDestroy() { + super.onDestroy(); + if (mAppWidgetHolder != null) { + // Necessary to destroy the holder to free up possible activity context + mAppWidgetHolder.destroy(); + } + } + + @Override public void onBackPressed() { logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_BACK); mSlideInView.close(/* animate= */ true); @@ -378,7 +399,7 @@ public class AddItemActivity extends BaseActivity acceptWidget(widgetId); } else { // Simply wait it out. - mAppWidgetHost.deleteAppWidgetId(widgetId); + mAppWidgetHolder.deleteAppWidgetId(widgetId); mPendingBindWidgetId = -1; } return; diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index 8616f35011..5368397c6d 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -31,6 +31,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; +import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -90,6 +91,8 @@ public abstract class DragController<T extends ActivityContext> protected boolean mIsInPreDrag; + private final int DRAG_VIEW_SCALE_DURATION_MS = 500; + /** * Interface to receive notifications when a drag starts or stops */ @@ -214,6 +217,15 @@ public abstract class DragController<T extends ActivityContext> mOptions.preDragCondition.onPreDragEnd(mDragObject, true /* dragStarted*/); } mIsInPreDrag = false; + if (mOptions.preDragEndScale != 0) { + mDragObject.dragView + .animate() + .scaleX(mOptions.preDragEndScale) + .scaleY(mOptions.preDragEndScale) + .setInterpolator(Interpolators.EMPHASIZED) + .setDuration(DRAG_VIEW_SCALE_DURATION_MS) + .start(); + } mDragObject.dragView.onDragStart(); for (DragListener listener : new ArrayList<>(mListeners)) { listener.onDragStart(mDragObject, mOptions); @@ -295,9 +307,9 @@ public abstract class DragController<T extends ActivityContext> } else if (mIsInPreDrag) { animateDragViewToOriginalPosition(null, null, -1); } + mDragObject.dragView.clearAnimation(); mDragObject.dragView = null; } - // Only end the drag if we are not deferred if (!isDeferred) { callOnDragEnd(); diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index 8eeca7d6d8..366870b4c2 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -43,26 +43,28 @@ import android.view.accessibility.AccessibilityManager; import android.view.animation.Interpolator; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.CellLayout; import com.android.launcher3.DropTargetBar; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.ShortcutAndWidgetContainer; +import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; +import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.SpringProperty; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.folder.Folder; import com.android.launcher3.graphics.Scrim; import com.android.launcher3.keyboard.ViewGroupFocusHelper; -import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; +import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks; import java.util.ArrayList; /** * A ViewGroup that coordinates dragging across its descendants */ -public class DragLayer extends BaseDragLayer<Launcher> { +public class DragLayer extends BaseDragLayer<Launcher> implements LauncherOverlayCallbacks { public static final int ALPHA_INDEX_OVERLAY = 0; private static final int ALPHA_CHANNEL_COUNT = 1; @@ -70,6 +72,8 @@ public class DragLayer extends BaseDragLayer<Launcher> { public static final int ANIMATION_END_DISAPPEAR = 0; public static final int ANIMATION_END_REMAIN_VISIBLE = 2; + private final boolean mIsRtl; + private DragController mDragController; // Variables relating to animation of views after drop @@ -100,6 +104,7 @@ public class DragLayer extends BaseDragLayer<Launcher> { setChildrenDrawingOrderEnabled(true); mFocusIndicatorHelper = new ViewGroupFocusHelper(this); + mIsRtl = Utilities.isRtl(getResources()); } /** @@ -109,6 +114,7 @@ public class DragLayer extends BaseDragLayer<Launcher> { mDragController = dragController; recreateControllers(); mWorkspaceDragScrim = new Scrim(this); + workspace.addOverlayCallback(this); } @Override @@ -237,7 +243,7 @@ public class DragLayer extends BaseDragLayer<Launcher> { View anchorView) { ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent(); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); parentChildren.measureChild(child); parentChildren.layoutChild(child); @@ -467,13 +473,15 @@ public class DragLayer extends BaseDragLayer<Launcher> { return mWorkspaceDragScrim; } - /** - * Called when one handed mode state changed. - * @param activated true if one handed mode activated, false otherwise. - */ - public void onOneHandedModeStateChanged(boolean activated) { - for (TouchController controller : mControllers) { - controller.onOneHandedModeStateChanged(activated); + @Override + public void onOverlayScrollChanged(float progress) { + float alpha = 1 - Interpolators.DEACCEL_3.getInterpolation(progress); + float transX = getMeasuredWidth() * progress; + + if (mIsRtl) { + transX = -transX; } + setTranslationX(transX); + getAlphaProperty(ALPHA_INDEX_OVERLAY).setValue(alpha); } } diff --git a/src/com/android/launcher3/dragndrop/DragOptions.java b/src/com/android/launcher3/dragndrop/DragOptions.java index e8ff8da058..1ff433541e 100644 --- a/src/com/android/launcher3/dragndrop/DragOptions.java +++ b/src/com/android/launcher3/dragndrop/DragOptions.java @@ -40,6 +40,12 @@ public class DragOptions { /** Determines when a pre-drag should transition to a drag. By default, this is immediate. */ public PreDragCondition preDragCondition = null; + /** + * A drag scale that scales the original drag view size when the preDragCondition is met (or + * is ignored if preDragEndScale is 0). + */ + public float preDragEndScale; + /** Scale of the icons over the workspace icon size. */ public float intrinsicIconScaleFactor = 1f; diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index 09fe740d23..f54d05dbdc 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -568,7 +568,8 @@ public abstract class DragView<T extends Context & ActivityContext> extends Fram .setSpring(new SpringForce(0) .setDampingRatio(DAMPENING_RATIO) .setStiffness(STIFFNESS)); - mDelta = view.getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP; + mDelta = Math.min( + range, view.getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP); } public void animateToPos(float value) { diff --git a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java index fb8a1bc99e..08e50dd96d 100644 --- a/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java +++ b/src/com/android/launcher3/dragndrop/SpringLoadedDragController.java @@ -20,12 +20,14 @@ import com.android.launcher3.Alarm; import com.android.launcher3.CellLayout; import com.android.launcher3.Launcher; import com.android.launcher3.OnAlarmListener; +import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; public class SpringLoadedDragController implements OnAlarmListener { // how long the user must hover over a mini-screen before it unshrinks - final long ENTER_SPRING_LOAD_HOVER_TIME = 500; - final long ENTER_SPRING_LOAD_CANCEL_HOVER_TIME = 950; + private static final long ENTER_SPRING_LOAD_HOVER_TIME = 500; + private static final long ENTER_SPRING_LOAD_HOVER_TIME_IN_TEST = 1500; + private static final long ENTER_SPRING_LOAD_CANCEL_HOVER_TIME = 950; Alarm mAlarm; @@ -39,6 +41,13 @@ public class SpringLoadedDragController implements OnAlarmListener { mAlarm.setOnAlarmListener(this); } + private long getEnterSpringLoadHoverTime() { + // Some TAPL tests are flaky on Cuttlefish with a low waiting time + return Utilities.IS_RUNNING_IN_TEST_HARNESS + ? ENTER_SPRING_LOAD_HOVER_TIME_IN_TEST + : ENTER_SPRING_LOAD_HOVER_TIME; + } + public void cancel() { mAlarm.cancelAlarm(); } @@ -46,8 +55,8 @@ public class SpringLoadedDragController implements OnAlarmListener { // Set a new alarm to expire for the screen that we are hovering over now public void setAlarm(CellLayout cl) { mAlarm.cancelAlarm(); - mAlarm.setAlarm((cl == null) ? ENTER_SPRING_LOAD_CANCEL_HOVER_TIME : - ENTER_SPRING_LOAD_HOVER_TIME); + mAlarm.setAlarm((cl == null) ? ENTER_SPRING_LOAD_CANCEL_HOVER_TIME + : getEnterSpringLoadHoverTime()); mScreen = cl; } diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 7e1491287f..94eea3598e 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -282,7 +282,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mFolderName = findViewById(R.id.folder_name); mFolderName.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp.folderLabelTextSizePx); mFolderName.setOnBackKeyListener(this); - mFolderName.setOnFocusChangeListener(this); mFolderName.setOnEditorActionListener(this); mFolderName.setSelectAllOnFocus(true); mFolderName.setInputType(mFolderName.getInputType() @@ -292,7 +291,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mFolderName.forceDisableSuggestions(true); mFooter = findViewById(R.id.folder_footer); - mFooterHeight = getResources().getDimensionPixelSize(R.dimen.folder_label_height); + mFooterHeight = dp.folderFooterHeightPx; if (Utilities.ATLEAST_R) { mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this); @@ -457,6 +456,13 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo // the folder itself. requestFocus(); super.onAttachedToWindow(); + mFolderName.addOnFocusChangeListener(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mFolderName.removeOnFocusChangeListener(this); } @Override @@ -1167,14 +1173,6 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo mContent.setFixedSize(contentWidth, contentHeight); mContent.measure(contentAreaWidthSpec, contentAreaHeightSpec); - if (mContent.getChildCount() > 0) { - int cellIconGap = (mContent.getPageAt(0).getCellWidth() - - mActivityContext.getDeviceProfile().iconSizePx) / 2; - mFooter.setPadding(mContent.getPaddingLeft() + cellIconGap, - mFooter.getPaddingTop(), - mContent.getPaddingRight() + cellIconGap, - mFooter.getPaddingBottom()); - } mFooter.measure(contentAreaWidthSpec, MeasureSpec.makeMeasureSpec(mFooterHeight, MeasureSpec.EXACTLY)); diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java index 61ffd9d00c..05ad57acd4 100644 --- a/src/com/android/launcher3/folder/FolderAnimationManager.java +++ b/src/com/android/launcher3/folder/FolderAnimationManager.java @@ -43,6 +43,7 @@ import com.android.launcher3.R; import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PropertyResetListener; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; @@ -167,9 +168,11 @@ public class FolderAnimationManager { final int paddingOffsetY = (int) (mContent.getPaddingTop() * initialScale); int initialX = folderIconPos.left + mFolder.getPaddingLeft() - + mPreviewBackground.getOffsetX() - paddingOffsetX - previewItemOffsetX; + + Math.round(mPreviewBackground.getOffsetX() * scaleRelativeToDragLayer) + - paddingOffsetX - previewItemOffsetX; int initialY = folderIconPos.top + mFolder.getPaddingTop() - + mPreviewBackground.getOffsetY() - paddingOffsetY; + + Math.round(mPreviewBackground.getOffsetY() * scaleRelativeToDragLayer) + - paddingOffsetY; final float xDistance = initialX - lp.x; final float yDistance = initialY - lp.y; @@ -215,6 +218,7 @@ public class FolderAnimationManager { final int footerStartDelay; if (isLargeFolder()) { if (mIsOpening) { + mFolder.mFooter.setAlpha(0); footerAlphaDuration = LARGE_FOLDER_FOOTER_DURATION; footerStartDelay = mDuration - footerAlphaDuration; } else { @@ -232,9 +236,9 @@ public class FolderAnimationManager { mFolder, startRect, endRect, finalRadius, !mIsOpening)); // Create reveal animator for the folder content (capture the top 4 icons 2x2) - int width = mDeviceProfile.folderCellLayoutBorderSpacePx.x + int width = mDeviceProfile.folderCellLayoutBorderSpacePx + mDeviceProfile.folderCellWidthPx * 2; - int height = mDeviceProfile.folderCellLayoutBorderSpacePx.y + int height = mDeviceProfile.folderCellLayoutBorderSpacePx + mDeviceProfile.folderCellHeightPx * 2; int page = mIsOpening ? mContent.getCurrentPage() : mContent.getDestinationPage(); int left = mContent.getPaddingLeft() + page * lp.width; @@ -311,7 +315,7 @@ public class FolderAnimationManager { addPreviewItemAnimators(a, initialScale / scaleRelativeToDragLayer, // Background can have a scaled radius in drag and drop mode, so we need to add the // difference to keep the preview items centered. - previewItemOffsetX + radiusDiff, radiusDiff); + (int) (previewItemOffsetX / scaleRelativeToDragLayer) + radiusDiff, radiusDiff); return a; } @@ -341,7 +345,7 @@ public class FolderAnimationManager { ShortcutAndWidgetContainer cwc = mContent.getPageAt(0).getShortcutsAndWidgets(); for (int i = 0; i < numItemsInPreview; ++i) { final BubbleTextView btv = itemsInPreview.get(i); - CellLayout.LayoutParams btvLp = (CellLayout.LayoutParams) btv.getLayoutParams(); + CellLayoutLayoutParams btvLp = (CellLayoutLayoutParams) btv.getLayoutParams(); // Calculate the final values in the LayoutParams. btvLp.isLockedToGrid = true; diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 33e090285a..dd00f07807 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -57,6 +57,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.dot.FolderDotInfo; import com.android.launcher3.dragndrop.BaseItemDragListener; import com.android.launcher3.dragndrop.DragLayer; @@ -277,7 +278,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel public void onDragEnter(ItemInfo dragInfo) { if (mFolder.isDestroyed() || !willAcceptItem(dragInfo)) return; - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) getLayoutParams(); CellLayout cl = (CellLayout) getParent().getParent(); mBackground.animateToAccept(cl, lp.cellX, lp.cellY); @@ -615,11 +616,14 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel public void drawDot(Canvas canvas) { if (!mForceHideDot && ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0)) { Rect iconBounds = mDotParams.iconBounds; - - Utilities.setRectToViewCenter(this, mActivity.getDeviceProfile().iconSizePx, - iconBounds); - iconBounds.offsetTo(iconBounds.left, getPaddingTop()); - float iconScale = (float) mBackground.previewSize / iconBounds.width(); + // FolderIcon draws the icon to be top-aligned (with padding) & horizontally-centered + int iconSize = mActivity.getDeviceProfile().iconSizePx; + iconBounds.left = (getWidth() - iconSize) / 2; + iconBounds.right = iconBounds.left + iconSize; + iconBounds.top = getPaddingTop(); + iconBounds.bottom = iconBounds.top + iconSize; + + float iconScale = (float) mBackground.previewSize / iconSize; Utilities.scaleRectAboutCenter(iconBounds, iconScale); // If we are animating to the accepting state, animate the dot out. diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java index 3d5aef5f0b..141388f3c5 100644 --- a/src/com/android/launcher3/folder/FolderPagedView.java +++ b/src/com/android/launcher3/folder/FolderPagedView.java @@ -41,6 +41,7 @@ import com.android.launcher3.PagedView; import com.android.launcher3.R; import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Utilities; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.keyboard.ViewGroupFocusHelper; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -112,6 +113,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> implements Cli public void setFolder(Folder folder) { mFolder = folder; mPageIndicator = folder.findViewById(R.id.folder_page_indicator); + mPageIndicator.setShouldAutoHide(false); initParentViews(folder); } @@ -202,7 +204,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> implements Cli public void addViewForRank(View view, WorkspaceItemInfo item, int rank) { int pageNo = rank / mOrganizer.getMaxItemsPerPage(); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) view.getLayoutParams(); lp.setCellXY(mOrganizer.getPosForRank(rank)); getPageAt(pageNo).addViewToCellLayout(view, -1, item.getViewId(), lp, true); } @@ -218,10 +220,10 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> implements Cli textView.setOnClickListener(ItemClickHandler.INSTANCE); textView.setOnLongClickListener(mFolder); textView.setOnFocusChangeListener(mFocusIndicatorHelper); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) textView.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) textView.getLayoutParams(); if (lp == null) { - textView.setLayoutParams(new CellLayout.LayoutParams( - item.cellX, item.cellY, item.spanX, item.spanY)); + textView.setLayoutParams(new CellLayoutLayoutParams( + item.cellX, item.cellY, item.spanX, item.spanY, item.screenId)); } else { lp.cellX = item.cellX; lp.cellY = item.cellY; @@ -314,7 +316,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> implements Cli } if (v != null) { - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams(); + CellLayoutLayoutParams lp = (CellLayoutLayoutParams) v.getLayoutParams(); ItemInfo info = (ItemInfo) v.getTag(); lp.setCellXY(mOrganizer.getPosForRank(rank)); currentPage.addViewToCellLayout(v, -1, info.getViewId(), lp, true); @@ -363,7 +365,7 @@ public class FolderPagedView extends PagedView<PageIndicatorDots> implements Cli public int findNearestArea(int pixelX, int pixelY) { int pageIndex = getNextPage(); CellLayout page = getPageAt(pageIndex); - page.findNearestArea(pixelX, pixelY, 1, 1, sTmpArray); + page.findNearestAreaIgnoreOccupied(pixelX, pixelY, 1, 1, sTmpArray); if (mFolder.isLayoutRtl()) { sTmpArray[0] = page.getCountX() - sTmpArray[0] - 1; } diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java index c28bab51f4..feadafaf50 100644 --- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java +++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java @@ -1,6 +1,6 @@ package com.android.launcher3.graphics; -import static com.android.launcher3.Utilities.getPrefs; +import static com.android.launcher3.LauncherPrefs.getPrefs; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.Themes.KEY_THEMED_ICONS; import static com.android.launcher3.util.Themes.isThemedIconEnabled; diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index c1bab544cb..e7b0446741 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -63,6 +63,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.Hotseat; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.InvariantDeviceProfile; @@ -72,6 +73,7 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.WorkspaceLayoutManager; +import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.icons.BaseIconFactory; @@ -98,8 +100,8 @@ import com.android.launcher3.util.window.WindowManagerProxy; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.widget.BaseLauncherAppWidgetHostView; -import com.android.launcher3.widget.LauncherAppWidgetHost; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; +import com.android.launcher3.widget.LauncherWidgetHolder; import com.android.launcher3.widget.LocalColorExtractor; import com.android.launcher3.widget.NavigableAppWidgetHostView; import com.android.launcher3.widget.custom.CustomWidgetManager; @@ -173,6 +175,7 @@ public class LauncherPreviewRenderer extends ContextWrapper } } + private final List<OnDeviceProfileChangeListener> mDpChangeListeners = new ArrayList<>(); private final Handler mUiHandler; private final Context mContext; private final InvariantDeviceProfile mIdp; @@ -330,6 +333,11 @@ public class LauncherPreviewRenderer extends ContextWrapper } @Override + public List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners() { + return mDpChangeListeners; + } + + @Override public Hotseat getHotseat() { return mHotseat; } @@ -532,8 +540,8 @@ public class LauncherPreviewRenderer extends ContextWrapper CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID); View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false); - CellLayout.LayoutParams lp = - new CellLayout.LayoutParams(0, 0, firstScreen.getCountX(), 1); + CellLayoutLayoutParams lp = new CellLayoutLayoutParams(0, 0, firstScreen.getCountX(), + 1, FIRST_SCREEN_ID); lp.canReorder = false; firstScreen.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true); } @@ -553,7 +561,7 @@ public class LauncherPreviewRenderer extends ContextWrapper private class LauncherPreviewAppWidgetHost extends AppWidgetHost { private LauncherPreviewAppWidgetHost(Context context) { - super(context, LauncherAppWidgetHost.APPWIDGET_HOST_ID); + super(context, LauncherWidgetHolder.APPWIDGET_HOST_ID); } @Override diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index 0eb86b1cb4..de47cb5057 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -17,31 +17,43 @@ package com.android.launcher3.graphics; +import static com.android.launcher3.anim.Interpolators.EMPHASIZED; +import static com.android.launcher3.anim.Interpolators.LINEAR; +import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; +import android.os.SystemClock; import android.util.Property; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.util.Themes; +import com.android.launcher3.util.window.RefreshRateTracker; + +import java.util.WeakHashMap; +import java.util.function.Function; /** * Extension of {@link FastBitmapDrawable} which shows a progress bar around the icon. */ -public class PreloadIconDrawable extends FastBitmapDrawable { +public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable { private static final Property<PreloadIconDrawable, Float> INTERNAL_STATE = new Property<PreloadIconDrawable, Float>(Float.TYPE, "internalStateProgress") { @@ -62,17 +74,26 @@ public class PreloadIconDrawable extends FastBitmapDrawable { private static final int DISABLED_ICON_ALPHA = (int) (0.6f * MAX_PAINT_ALPHA); private static final long DURATION_SCALE = 500; + private static final long SCALE_AND_ALPHA_ANIM_DURATION = 500; // The smaller the number, the faster the animation would be. // Duration = COMPLETE_ANIM_FRACTION * DURATION_SCALE private static final float COMPLETE_ANIM_FRACTION = 0.3f; - private static final float SMALL_SCALE = 0.7f; + private static final float SMALL_SCALE = ENABLE_DOWNLOAD_APP_UX_V2.get() ? 0.867f : 0.7f; private static final float PROGRESS_STROKE_SCALE = 0.075f; private static final int PRELOAD_ACCENT_COLOR_INDEX = 0; private static final int PRELOAD_BACKGROUND_COLOR_INDEX = 1; + private static final int ALPHA_DURATION_MILLIS = 3000; + private static final float OVERLAY_ALPHA_RANGE = 127.5f; + private static final long WAVE_MOTION_DELAY_FACTOR_MILLIS = 100; + private static final WeakHashMap<Integer, PorterDuffColorFilter> COLOR_FILTER_MAP = + new WeakHashMap<>(); + public static final Function<Integer, PorterDuffColorFilter> FILTER_FACTORY = + currArgb -> new PorterDuffColorFilter(currArgb, PorterDuff.Mode.SRC_ATOP); + private final Matrix mTmpMatrix = new Matrix(); private final PathMeasure mPathMeasure = new PathMeasure(); @@ -92,10 +113,14 @@ public class PreloadIconDrawable extends FastBitmapDrawable { private int mTrackAlpha; private float mTrackLength; - private float mIconScale; private boolean mRanFinishAnimation; + private final int mRefreshRateMillis; + private final AnimatedFloat mIconScale = new AnimatedFloat(this::invalidateSelf); + private final AnimatedFloat mOverlayAlpha = new AnimatedFloat(this::updateOverlayAlpha); + private boolean mShouldAnimateScaleAndAlpha; + // Progress of the internal state. [0, 1] indicates the fraction of completed progress, // [1, (1 + COMPLETE_ANIM_FRACTION)] indicates the progress of zoom animation. private float mInternalStateProgress; @@ -109,14 +134,16 @@ public class PreloadIconDrawable extends FastBitmapDrawable { info, IconPalette.getPreloadProgressColor(context, info.bitmap.color), getPreloadColors(context), - Utilities.isDarkTheme(context)); + Utilities.isDarkTheme(context), + getRefreshRateMillis(context)); } public PreloadIconDrawable( ItemInfoWithIcon info, int indicatorColor, int[] preloadColors, - boolean isDarkMode) { + boolean isDarkMode, + int refreshRateMillis) { super(info.bitmap); mItem = info; mShapePath = GraphicsUtils.getShapePath(DEFAULT_PATH_SIZE); @@ -130,6 +157,13 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mSystemAccentColor = preloadColors[PRELOAD_ACCENT_COLOR_INDEX]; mSystemBackgroundColor = preloadColors[PRELOAD_BACKGROUND_COLOR_INDEX]; mIsDarkMode = isDarkMode; + mRefreshRateMillis = refreshRateMillis; + + // If it's a pending app we will animate scale and alpha when it's no longer pending. + if (ENABLE_DOWNLOAD_APP_UX_V2.get() && info.getProgressLevel() == 0) { + mShouldAnimateScaleAndAlpha = true; + mOverlayAlpha.updateValue(127); + } setLevel(info.getProgressLevel()); setIsStartable(info.isAppStartable()); @@ -175,14 +209,21 @@ public class PreloadIconDrawable extends FastBitmapDrawable { canvas.drawPath(mScaledProgressPath, mProgressPaint); int saveCount = canvas.save(); - canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY()); + canvas.scale( + mIconScale.value, mIconScale.value, bounds.exactCenterX(), bounds.exactCenterY()); super.drawInternal(canvas, bounds); canvas.restoreToCount(saveCount); + + if (ENABLE_DOWNLOAD_APP_UX_V2.get() && mInternalStateProgress == 0) { + reschedule(); + } } @Override protected void updateFilter() { - setAlpha(mIsDisabled ? DISABLED_ICON_ALPHA : MAX_PAINT_ALPHA); + if (!ENABLE_DOWNLOAD_APP_UX_V2.get()) { + setAlpha(mIsDisabled ? DISABLED_ICON_ALPHA : MAX_PAINT_ALPHA); + } } /** @@ -237,7 +278,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mCurrentAnim = ObjectAnimator.ofFloat(this, INTERNAL_STATE, finalProgress); mCurrentAnim.setDuration( (long) ((finalProgress - mInternalStateProgress) * DURATION_SCALE)); - mCurrentAnim.setInterpolator(Interpolators.LINEAR); + mCurrentAnim.setInterpolator(LINEAR); if (isFinish) { mCurrentAnim.addListener(new AnimatorListenerAdapter() { @Override @@ -253,13 +294,13 @@ public class PreloadIconDrawable extends FastBitmapDrawable { /** * Sets the internal progress and updates the UI accordingly * for progress <= 0: - * - icon in the small scale and disabled state - * - progress track is visible + * - icon with pending motion + * - progress track is not visible * - progress bar is not visible - * for 0 < progress < 1 - * - icon in the small scale and disabled state + * for progress < 1 + * - icon without pending motion * - progress track is visible - * - progress bar is visible with dominant color. Progress bar is drawn as a fraction of + * - progress bar is visible. Progress bar is drawn as a fraction of * {@link #mScaledTrackPath}. * @see PathMeasure#getSegment(float, float, Path, boolean) * for 1 <= progress < (1 + COMPLETE_ANIM_FRACTION) @@ -271,29 +312,47 @@ public class PreloadIconDrawable extends FastBitmapDrawable { * - only icon is drawn in normal state */ private void setInternalProgress(float progress) { + // Animate scale and alpha from pending to downloading state. + if (ENABLE_DOWNLOAD_APP_UX_V2.get() + && mShouldAnimateScaleAndAlpha && mInternalStateProgress == 0 && progress > 0) { + Animator iconScaleAnimator = mIconScale.animateToValue(SMALL_SCALE); + iconScaleAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION); + iconScaleAnimator.setInterpolator(EMPHASIZED); + iconScaleAnimator.start(); + + Animator overlayAlphaAnimator = mOverlayAlpha.animateToValue(0); + overlayAlphaAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION); + overlayAlphaAnimator.setInterpolator(EMPHASIZED); + overlayAlphaAnimator.start(); + } + mInternalStateProgress = progress; if (progress <= 0) { - mIconScale = SMALL_SCALE; + mIconScale.updateValue(ENABLE_DOWNLOAD_APP_UX_V2.get() ? 1 : SMALL_SCALE); mScaledTrackPath.reset(); mTrackAlpha = MAX_PAINT_ALPHA; - } - - if (progress < 1 && progress > 0) { + } else if (progress < 1) { mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true); - mIconScale = SMALL_SCALE; + if (ENABLE_DOWNLOAD_APP_UX_V2.get()) { + mPathMeasure.getSegment(0, mTrackLength, mScaledTrackPath, true); + } + + if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || !mShouldAnimateScaleAndAlpha) { + mIconScale.updateValue(SMALL_SCALE); + } mTrackAlpha = MAX_PAINT_ALPHA; - } else if (progress >= 1) { + } else { setIsDisabled(mItem.isDisabled()); mScaledTrackPath.set(mScaledProgressPath); float fraction = (progress - 1) / COMPLETE_ANIM_FRACTION; if (fraction >= 1) { // Animation has completed - mIconScale = 1; + mIconScale.updateValue(1); mTrackAlpha = 0; } else { mTrackAlpha = Math.round((1 - fraction) * MAX_PAINT_ALPHA); - mIconScale = SMALL_SCALE + (1 - SMALL_SCALE) * fraction; + mIconScale.updateValue(SMALL_SCALE + (1 - SMALL_SCALE) * fraction); } } invalidateSelf(); @@ -310,6 +369,10 @@ public class PreloadIconDrawable extends FastBitmapDrawable { return preloadColors; } + private static int getRefreshRateMillis(Context context) { + return RefreshRateTracker.getSingleFrameMs(context); + } + /** * Returns a FastBitmapDrawable with the icon. */ @@ -325,7 +388,76 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mItem, mIndicatorColor, new int[] {mSystemAccentColor, mSystemBackgroundColor}, - mIsDarkMode); + mIsDarkMode, + mRefreshRateMillis); + } + + @Override + public void run() { + if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || mInternalStateProgress > 0) { + return; + } + if (!applyPendingIconOverlay()) { + reschedule(); + } + } + + @Override + public boolean setVisible(boolean visible, boolean restart) { + boolean result = super.setVisible(visible, restart); + if (visible) { + reschedule(); + } else { + unscheduleSelf(this); + } + return result; + } + + private void reschedule() { + unscheduleSelf(this); + + if (!isVisible()) { + return; + } + + final long upTime = SystemClock.uptimeMillis(); + scheduleSelf(this, upTime - ((upTime % mRefreshRateMillis)) + mRefreshRateMillis); + } + + + /** + * Apply an overlay on the pending icon with cascading motion based on its position. + * Returns {@code true} if the icon alpha is updated, so that we re-draw. + */ + private boolean applyPendingIconOverlay() { + long waveMotionDelay = (mItem.cellX * WAVE_MOTION_DELAY_FACTOR_MILLIS) + + (mItem.cellY * WAVE_MOTION_DELAY_FACTOR_MILLIS); + long time = SystemClock.uptimeMillis(); + float newAlpha = Utilities.mapBoundToRange( + (float) (time + waveMotionDelay) % ALPHA_DURATION_MILLIS, + 0, + ALPHA_DURATION_MILLIS, + 0, + MAX_PAINT_ALPHA, + LINEAR); + if (newAlpha > OVERLAY_ALPHA_RANGE) { + newAlpha = (OVERLAY_ALPHA_RANGE - (newAlpha % OVERLAY_ALPHA_RANGE)); + } + + boolean invalidate = false; + if ((int) mOverlayAlpha.value != newAlpha) { + mOverlayAlpha.updateValue(newAlpha); + invalidate = true; + } + return invalidate; + } + + private void updateOverlayAlpha() { + int overlayColor = mIsDarkMode ? 0 : 255; + int currArgb = + Color.argb((int) mOverlayAlpha.value, overlayColor, overlayColor, overlayColor); + mPaint.setColorFilter(COLOR_FILTER_MAP.computeIfAbsent(currArgb, FILTER_FACTORY)); + invalidateSelf(); } protected static class PreloadIconConstantState extends FastBitmapConstantState { @@ -335,6 +467,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable { protected final int[] mPreloadColors; protected final boolean mIsDarkMode; protected final int mLevel; + protected final int mRefreshRateMillis; public PreloadIconConstantState( Bitmap bitmap, @@ -342,13 +475,15 @@ public class PreloadIconDrawable extends FastBitmapDrawable { ItemInfoWithIcon info, int indicatorColor, int[] preloadColors, - boolean isDarkMode) { + boolean isDarkMode, + int refreshRateMillis) { super(bitmap, iconColor); mInfo = info; mIndicatorColor = indicatorColor; mPreloadColors = preloadColors; mIsDarkMode = isDarkMode; mLevel = info.getProgressLevel(); + mRefreshRateMillis = refreshRateMillis; } @Override @@ -357,7 +492,8 @@ public class PreloadIconDrawable extends FastBitmapDrawable { mInfo, mIndicatorColor, mPreloadColors, - mIsDarkMode); + mIsDarkMode, + mRefreshRateMillis); } } } diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index 287b9760fe..85c0a7a565 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -50,7 +50,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext; import com.android.launcher3.model.BgDataModel; -import com.android.launcher3.model.GridSizeMigrationTaskV2; +import com.android.launcher3.model.GridSizeMigrationUtil; import com.android.launcher3.model.LoaderTask; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.RunnableList; @@ -241,10 +241,10 @@ public class PreviewSurfaceRenderer { @WorkerThread private boolean doGridMigrationIfNecessary() { - if (!GridSizeMigrationTaskV2.needsToMigrate(mContext, mIdp)) { + if (!GridSizeMigrationUtil.needsToMigrate(mContext, mIdp)) { return false; } - return GridSizeMigrationTaskV2.migrateGridIfNeeded(mContext, mIdp); + return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, mIdp); } @UiThread diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index 5508c49410..57fa8a256b 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -16,7 +16,10 @@ package com.android.launcher3.icons; +import static com.android.launcher3.config.FeatureFlags.ENABLE_FORCED_MONO_ICON; + import android.content.Context; +import android.graphics.drawable.Drawable; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.graphics.IconShape; @@ -68,6 +71,8 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { private LauncherIcons next; + private MonochromeIconFactory mMonochromeIconFactory; + protected LauncherIcons(Context context, int fillResIconDpi, int iconBitmapSize, int poolId) { super(context, fillResIconDpi, iconBitmapSize, IconShape.getShape().enableShapeDetection()); mMonoIconEnabled = Themes.isThemedIconEnabled(context); @@ -91,6 +96,18 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { } @Override + protected Drawable getMonochromeDrawable(Drawable base) { + Drawable mono = super.getMonochromeDrawable(base); + if (mono != null || !ENABLE_FORCED_MONO_ICON.get()) { + return mono; + } + if (mMonochromeIconFactory == null) { + mMonochromeIconFactory = new MonochromeIconFactory(mIconBitmapSize); + } + return mMonochromeIconFactory.wrap(base); + } + + @Override public void close() { recycle(); } diff --git a/src/com/android/launcher3/icons/MonochromeIconFactory.java b/src/com/android/launcher3/icons/MonochromeIconFactory.java new file mode 100644 index 0000000000..511dcc736e --- /dev/null +++ b/src/com/android/launcher3/icons/MonochromeIconFactory.java @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2022 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.launcher3.icons; + +import static android.graphics.Paint.FILTER_BITMAP_FLAG; + +import android.annotation.TargetApi; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.BlendMode; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.AdaptiveIconDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; + +import androidx.annotation.WorkerThread; + +import com.android.launcher3.icons.BaseIconFactory.ClippedMonoDrawable; + +import java.nio.ByteBuffer; + +/** + * Utility class to generate monochrome icons version for a given drawable. + */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) +public class MonochromeIconFactory extends Drawable { + + private final Bitmap mFlatBitmap; + private final Canvas mFlatCanvas; + private final Paint mCopyPaint; + + private final Bitmap mAlphaBitmap; + private final Canvas mAlphaCanvas; + private final byte[] mPixels; + + private final int mBitmapSize; + private final int mEdgePixelLength; + + private final Paint mDrawPaint; + private final Rect mSrcRect; + + MonochromeIconFactory(int iconBitmapSize) { + float extraFactor = AdaptiveIconDrawable.getExtraInsetFraction(); + float viewPortScale = 1 / (1 + 2 * extraFactor); + mBitmapSize = Math.round(iconBitmapSize * 2 * viewPortScale); + mPixels = new byte[mBitmapSize * mBitmapSize]; + mEdgePixelLength = mBitmapSize * (mBitmapSize - iconBitmapSize) / 2; + + mFlatBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ARGB_8888); + mFlatCanvas = new Canvas(mFlatBitmap); + + mAlphaBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ALPHA_8); + mAlphaCanvas = new Canvas(mAlphaBitmap); + + mDrawPaint = new Paint(FILTER_BITMAP_FLAG); + mDrawPaint.setColor(Color.WHITE); + mSrcRect = new Rect(0, 0, mBitmapSize, mBitmapSize); + + mCopyPaint = new Paint(FILTER_BITMAP_FLAG); + mCopyPaint.setBlendMode(BlendMode.SRC); + + // Crate a color matrix which converts the icon to grayscale and then uses the average + // of RGB components as the alpha component. + ColorMatrix satMatrix = new ColorMatrix(); + satMatrix.setSaturation(0); + float[] vals = satMatrix.getArray(); + vals[15] = vals[16] = vals[17] = .3333f; + vals[18] = vals[19] = 0; + mCopyPaint.setColorFilter(new ColorMatrixColorFilter(vals)); + } + + private void drawDrawable(Drawable drawable) { + if (drawable != null) { + drawable.setBounds(0, 0, mBitmapSize, mBitmapSize); + drawable.draw(mFlatCanvas); + } + } + + /** + * Creates a monochrome version of the provided drawable + */ + @WorkerThread + public Drawable wrap(Drawable icon) { + if (icon instanceof AdaptiveIconDrawable) { + AdaptiveIconDrawable aid = (AdaptiveIconDrawable) icon; + mFlatCanvas.drawColor(Color.BLACK); + drawDrawable(aid.getBackground()); + drawDrawable(aid.getForeground()); + generateMono(); + return new ClippedMonoDrawable(this); + } else { + mFlatCanvas.drawColor(Color.WHITE); + drawDrawable(icon); + generateMono(); + return this; + } + } + + @WorkerThread + private void generateMono() { + mAlphaCanvas.drawBitmap(mFlatBitmap, 0, 0, mCopyPaint); + + // Scale the end points: + ByteBuffer buffer = ByteBuffer.wrap(mPixels); + buffer.rewind(); + mAlphaBitmap.copyPixelsToBuffer(buffer); + + int min = 0xFF; + int max = 0; + for (byte b : mPixels) { + min = Math.min(min, b & 0xFF); + max = Math.max(max, b & 0xFF); + } + + if (min < max) { + // rescale pixels to increase contrast + float range = max - min; + + // In order to check if the colors should be flipped, we just take the average color + // of top and bottom edge which should correspond to be background color. If the edge + // colors have more opacity, we flip the colors; + int sum = 0; + for (int i = 0; i < mEdgePixelLength; i++) { + sum += (mPixels[i] & 0xFF); + sum += (mPixels[mPixels.length - 1 - i] & 0xFF); + } + float edgeAverage = sum / (mEdgePixelLength * 2f); + float edgeMapped = (edgeAverage - min) / range; + boolean flipColor = edgeMapped > .5f; + + for (int i = 0; i < mPixels.length; i++) { + int p = mPixels[i] & 0xFF; + int p2 = Math.round((p - min) * 0xFF / range); + mPixels[i] = flipColor ? (byte) (255 - p2) : (byte) (p2); + } + buffer.rewind(); + mAlphaBitmap.copyPixelsFromBuffer(buffer); + } + } + + @Override + public void draw(Canvas canvas) { + canvas.drawBitmap(mAlphaBitmap, mSrcRect, getBounds(), mDrawPaint); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int i) { + mDrawPaint.setAlpha(i); + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + mDrawPaint.setColorFilter(colorFilter); + } +} diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java index d5a79dde08..bb7248fea7 100644 --- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java +++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java @@ -16,7 +16,7 @@ package com.android.launcher3.icons; -import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_SHORTCUTS; +import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS; import android.content.ComponentName; import android.content.Context; @@ -32,6 +32,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.icons.BaseIconFactory.IconOptions; import com.android.launcher3.icons.cache.CachingLogic; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.Themes; @@ -76,8 +77,8 @@ public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> { Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon( context, info, LauncherAppState.getIDP(context).fillResIconDpi); if (unbadgedDrawable == null) return BitmapInfo.LOW_RES_INFO; - return new BitmapInfo(li.createScaledBitmapWithoutShadow(unbadgedDrawable), - Themes.getColorAccent(context)); + return li.createBadgedIconBitmap(unbadgedDrawable, + new IconOptions().setExtractedColor(Themes.getColorAccent(context))); } } @@ -100,7 +101,7 @@ public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> { * Launcher specific checks */ public static Drawable getIcon(Context context, ShortcutInfo shortcutInfo, int density) { - if (GO_DISABLE_SHORTCUTS) { + if (GO_DISABLE_WIDGETS) { return null; } try { diff --git a/src/com/android/launcher3/logging/InstanceId.java b/src/com/android/launcher3/logging/InstanceId.java index 3c4a644053..5bbe07c9ad 100644 --- a/src/com/android/launcher3/logging/InstanceId.java +++ b/src/com/android/launcher3/logging/InstanceId.java @@ -47,7 +47,6 @@ public final class InstanceId implements Parcelable { this(in.readInt()); } - @VisibleForTesting public int getId() { return mId; } diff --git a/src/com/android/launcher3/logging/KeyboardStateManager.java b/src/com/android/launcher3/logging/KeyboardStateManager.java index 3103af1bd4..6dc0a0be22 100644 --- a/src/com/android/launcher3/logging/KeyboardStateManager.java +++ b/src/com/android/launcher3/logging/KeyboardStateManager.java @@ -24,6 +24,7 @@ import android.os.SystemClock; */ public class KeyboardStateManager { private long mUpdatedTime; + private int mImeHeight; public enum KeyboardState { NO_IME_ACTION, @@ -58,4 +59,18 @@ public class KeyboardStateManager { mUpdatedTime = SystemClock.elapsedRealtime(); mKeyboardState = keyboardState; } + + /** + * Returns keyboard's current height. + */ + public int getImeHeight() { + return mImeHeight; + } + + /** + * Setter method to set keyboard height. + */ + public void setImeHeight(int imeHeight) { + mImeHeight = imeHeight; + } } diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 22627b4ac2..2159c6b68f 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -32,9 +32,12 @@ import com.android.launcher3.logger.LauncherAtom.ContainerInfo; import com.android.launcher3.logger.LauncherAtom.FromState; import com.android.launcher3.logger.LauncherAtom.ToState; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.util.IntArray; import com.android.launcher3.util.ResourceBasedOverride; import com.android.launcher3.views.ActivityContext; +import java.util.List; + /** * Handles the user event logging in R+. * @@ -555,6 +558,20 @@ public class StatsLogManager implements ResourceBasedOverride { + "result page etc.") LAUNCHER_ALLAPPS_SCROLLED(985), + @UiEvent(doc = "User scrolled up on one of the all apps surfaces such as A-Z list, search " + + "result page etc.") + LAUNCHER_ALLAPPS_SCROLLED_UP(1229), + + @UiEvent(doc = + "User scrolled down on one of the all apps surfaces such as A-Z list, search " + + "result page etc.") + LAUNCHER_ALLAPPS_SCROLLED_DOWN(1230), + + @UiEvent(doc = "User scrolled on one of the all apps surfaces such as A-Z list, search " + + "result page etc and we don't know the direction since user came back to " + + "original position from which they scrolled.") + LAUNCHER_ALLAPPS_SCROLLED_UNKNOWN_DIRECTION(1231), + @UiEvent(doc = "User tapped taskbar home button") LAUNCHER_TASKBAR_HOME_BUTTON_TAP(1003), @@ -598,7 +615,22 @@ public class StatsLogManager implements ResourceBasedOverride { LAUNCHER_APP_ICON_MENU_SPLIT_RIGHT_BOTTOM(1199), @UiEvent(doc = "User has invoked split to left half from an app icon menu") - LAUNCHER_APP_ICON_MENU_SPLIT_LEFT_TOP(1200) + LAUNCHER_APP_ICON_MENU_SPLIT_LEFT_TOP(1200), + + @UiEvent(doc = "Number of apps in A-Z list (personal and work profile)") + LAUNCHER_ALLAPPS_COUNT(1225), + + @UiEvent(doc = "User has invoked split to right half with a keyboard shortcut.") + LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_RIGHT_BOTTOM(1232), + + @UiEvent(doc = "User has invoked split to left half with a keyboard shortcut.") + LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP(1233), + + @UiEvent(doc = "User has collapsed the work FAB button by swiping down") + LAUNCHER_WORK_FAB_BUTTON_COLLAPSE(1276), + + @UiEvent(doc = "User has collapsed the work FAB button by swiping up") + LAUNCHER_WORK_FAB_BUTTON_EXTEND(1277), ; // ADD MORE @@ -720,6 +752,13 @@ public class StatsLogManager implements ResourceBasedOverride { } /** + * Sets cardinality of log message. + */ + default StatsLogger withCardinality(int cardinality) { + return this; + } + + /** * Builds the final message and logs it as {@link EventEnum}. */ default void log(EventEnum event) { @@ -746,7 +785,8 @@ public class StatsLogManager implements ResourceBasedOverride { FAIL(4), COLD_USERWAITING(5), ATOMIC(6), - CONTROLLED(7); + CONTROLLED(7), + CACHED(8); private final int mId; LatencyType(int id) { @@ -756,7 +796,6 @@ public class StatsLogManager implements ResourceBasedOverride { public int getId() { return mId; } - } /** @@ -789,6 +828,13 @@ public class StatsLogManager implements ResourceBasedOverride { } /** + * Sets sub event type. + */ + default StatsLatencyLogger withSubEventType(int type) { + return this; + } + + /** * Sets packageId of log message. */ default StatsLatencyLogger withPackageId(int packageId) { @@ -803,6 +849,77 @@ public class StatsLogManager implements ResourceBasedOverride { } /** + * Helps to construct and log impression event. + */ + public interface StatsImpressionLogger { + + enum State { + UNKNOWN(0), + ALLAPPS(1), + SEARCHBOX_WIDGET(2); + private final int mLauncherState; + + State(int id) { + this.mLauncherState = id; + } + + public int getLauncherState() { + return mLauncherState; + } + } + + /** + * Sets {@link InstanceId} of log message. + */ + default StatsImpressionLogger withInstanceId(InstanceId instanceId) { + return this; + } + + /** + * Sets {@link State} of impression event. + */ + default StatsImpressionLogger withState(State state) { + return this; + } + + /** + * Sets query length of the event. + */ + default StatsImpressionLogger withQueryLength(int queryLength) { + return this; + } + + /** + * Sets list of {@link com.android.app.search.ResultType} for the impression event. + */ + default StatsImpressionLogger withResultType(IntArray resultType) { + return this; + } + + /** + * Sets list of count for each of {@link com.android.app.search.ResultType} for the + * impression event. + */ + default StatsImpressionLogger withResultCount(IntArray resultCount) { + return this; + } + + /** + * Sets list of boolean for each of {@link com.android.app.search.ResultType} that indicates + * if this result is above keyboard or not for the impression event. + */ + default StatsImpressionLogger withAboveKeyboard(List<Boolean> aboveKeyboard) { + return this; + } + + /** + * Builds the final message and logs it as {@link EventEnum}. + */ + default void log(EventEnum event) { + } + } + + /** * Returns new logger object. */ public StatsLogger logger() { @@ -825,6 +942,17 @@ public class StatsLogManager implements ResourceBasedOverride { } /** + * Returns new impression logger object. + */ + public StatsImpressionLogger impressionLogger() { + StatsImpressionLogger logger = createImpressionLogger(); + if (mInstanceId != null) { + logger.withInstanceId(mInstanceId); + } + return logger; + } + + /** * Returns a singleton KeyboardStateManager. */ public KeyboardStateManager keyboardStateManager() { @@ -844,6 +972,11 @@ public class StatsLogManager implements ResourceBasedOverride { }; } + protected StatsImpressionLogger createImpressionLogger() { + return new StatsImpressionLogger() { + }; + } + /** * Sets InstanceId to every new {@link StatsLogger} object returned by {@link #logger()} when * not-null. diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 6da948ce9d..8f85bfbd3d 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -18,7 +18,6 @@ package com.android.launcher3.model; import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR; import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY; -import static com.android.launcher3.testing.shared.TestProtocol.INCORRECT_INFO_UPDATED; import android.content.ComponentName; import android.content.Context; @@ -39,7 +38,6 @@ import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.pm.PackageInstallInfo; -import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.FlagOp; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.SafeCloseable; @@ -275,14 +273,8 @@ public class AllAppsList { } public void updateIconsAndLabels(HashSet<String> packages, UserHandle user) { - if (TestProtocol.sDebugTracing) { - Log.i(INCORRECT_INFO_UPDATED, "updateIconsAndLabels: packages=" + packages); - } for (AppInfo info : data) { if (info.user.equals(user) && packages.contains(info.componentName.getPackageName())) { - if (TestProtocol.sDebugTracing) { - Log.i(INCORRECT_INFO_UPDATED, "updateIconsAndLabels: updating info=" + info); - } mIconCache.updateTitleAndIcon(info); info.sectionName = mIndex.computeSectionName(info.title); mDataChanged = true; diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java index 5b6f9f62a5..74a2c5d4b5 100644 --- a/src/com/android/launcher3/model/BaseModelUpdateTask.java +++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java @@ -118,8 +118,7 @@ public abstract class BaseModelUpdateTask implements ModelUpdateTask { } public void bindExtraContainerItems(@NonNull final FixedContainerItems item) { - FixedContainerItems copy = item.clone(); - scheduleCallbackTask(c -> c.bindExtraContainerItems(copy)); + scheduleCallbackTask(c -> c.bindExtraContainerItems(item)); } public void bindDeepShortcuts(@NonNull final BgDataModel dataModel) { diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index ffb0f2f40e..b0f6e13ae3 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -17,7 +17,7 @@ package com.android.launcher3.model; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY; -import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_SHORTCUTS; +import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS; import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED; import static java.util.stream.Collectors.groupingBy; @@ -286,7 +286,7 @@ public class BgDataModel { * shortcuts and unpinning any extra shortcuts. */ public synchronized void updateShortcutPinnedState(Context context, UserHandle user) { - if (GO_DISABLE_SHORTCUTS) { + if (GO_DISABLE_WIDGETS) { return; } @@ -433,26 +433,9 @@ public class BgDataModel { public final int containerId; public final List<ItemInfo> items; - public FixedContainerItems(int containerId) { - this(containerId, new ArrayList<>()); - } - public FixedContainerItems(int containerId, List<ItemInfo> items) { this.containerId = containerId; - this.items = items; - } - - @Override - public FixedContainerItems clone() { - return new FixedContainerItems(containerId, new ArrayList<>(items)); - } - - public void setItems(List<ItemInfo> newItems) { - items.clear(); - newItems.forEach(item -> { - item.container = containerId; - items.add(item); - }); + this.items = Collections.unmodifiableList(items); } } diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java index 46f0b0b155..85d54c0d1c 100644 --- a/src/com/android/launcher3/model/DeviceGridState.java +++ b/src/com/android/launcher3/model/DeviceGridState.java @@ -29,7 +29,7 @@ import android.content.SharedPreferences; import android.text.TextUtils; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.Utilities; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.logging.StatsLogManager.LauncherEvent; import java.util.Locale; @@ -58,7 +58,7 @@ public class DeviceGridState implements Comparable<DeviceGridState> { } public DeviceGridState(Context context) { - SharedPreferences prefs = Utilities.getPrefs(context); + SharedPreferences prefs = LauncherPrefs.getPrefs(context); mGridSizeString = prefs.getString(KEY_WORKSPACE_SIZE, ""); mNumHotseat = prefs.getInt(KEY_HOTSEAT_COUNT, -1); mDeviceType = prefs.getInt(KEY_DEVICE_TYPE, TYPE_PHONE); @@ -90,7 +90,7 @@ public class DeviceGridState implements Comparable<DeviceGridState> { * Stores the device state to shared preferences */ public void writeToPrefs(Context context) { - Utilities.getPrefs(context).edit() + LauncherPrefs.getPrefs(context).edit() .putString(KEY_WORKSPACE_SIZE, mGridSizeString) .putInt(KEY_HOTSEAT_COUNT, mNumHotseat) .putInt(KEY_DEVICE_TYPE, mDeviceType) diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java index 341372ef31..eded5ea6a9 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java +++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java @@ -32,7 +32,6 @@ import android.util.ArrayMap; import android.util.Log; import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; @@ -64,42 +63,13 @@ import java.util.stream.Collectors; * This class takes care of shrinking the workspace (by maximum of one row and one column), as a * result of restoring from a larger device or device density change. */ -public class GridSizeMigrationTaskV2 { +public class GridSizeMigrationUtil { - private static final String TAG = "GridSizeMigrationTaskV2"; - private static final boolean DEBUG = false; + private static final String TAG = "GridSizeMigrationUtil"; + private static final boolean DEBUG = true; - private final Context mContext; - private final SQLiteDatabase mDb; - private final DbReader mSrcReader; - private final DbReader mDestReader; - - private final List<DbEntry> mHotseatItems; - private final List<DbEntry> mWorkspaceItems; - - private final List<DbEntry> mHotseatDiff; - private final List<DbEntry> mWorkspaceDiff; - - private final int mDestHotseatSize; - private final int mTrgX, mTrgY; - - @VisibleForTesting - protected GridSizeMigrationTaskV2(Context context, SQLiteDatabase db, DbReader srcReader, - DbReader destReader, int destHotseatSize, Point targetSize) { - mContext = context; - mDb = db; - mSrcReader = srcReader; - mDestReader = destReader; - - mHotseatItems = destReader.loadHotseatEntries(); - mWorkspaceItems = destReader.loadAllWorkspaceEntries(); - - mHotseatDiff = calcDiff(mSrcReader.loadHotseatEntries(), mHotseatItems); - mWorkspaceDiff = calcDiff(mSrcReader.loadAllWorkspaceEntries(), mWorkspaceItems); - mDestHotseatSize = destHotseatSize; - - mTrgX = targetSize.x; - mTrgY = targetSize.y; + private GridSizeMigrationUtil() { + // Util class should not be instantiated } /** @@ -187,9 +157,8 @@ public class GridSizeMigrationTaskV2 { context, validPackages); Point targetSize = new Point(destDeviceState.getColumns(), destDeviceState.getRows()); - GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(context, t.getDb(), - srcReader, destReader, destDeviceState.getNumHotseat(), targetSize); - task.migrate(srcDeviceState, destDeviceState); + migrate(context, t.getDb(), srcReader, destReader, destDeviceState.getNumHotseat(), + targetSize, srcDeviceState, destDeviceState); if (!migrateForPreview) { dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE); @@ -212,25 +181,66 @@ public class GridSizeMigrationTaskV2 { } } - @VisibleForTesting - protected boolean migrate(DeviceGridState srcDeviceState, DeviceGridState destDeviceState) { - if (mHotseatDiff.isEmpty() && mWorkspaceDiff.isEmpty()) { + public static boolean migrate( + @NonNull final Context context, @NonNull final SQLiteDatabase db, + @NonNull final DbReader srcReader, @NonNull final DbReader destReader, + final int destHotseatSize, @NonNull final Point targetSize, + @NonNull final DeviceGridState srcDeviceState, + @NonNull final DeviceGridState destDeviceState) { + + final List<DbEntry> srcHotseatItems = srcReader.loadHotseatEntries(); + final List<DbEntry> srcWorkspaceItems = srcReader.loadAllWorkspaceEntries(); + final List<DbEntry> dstHotseatItems = destReader.loadHotseatEntries(); + final List<DbEntry> dstWorkspaceItems = destReader.loadAllWorkspaceEntries(); + final List<DbEntry> hotseatToBeAdded = new ArrayList<>(1); + final List<DbEntry> workspaceToBeAdded = new ArrayList<>(1); + final IntArray toBeRemoved = new IntArray(); + + calcDiff(srcHotseatItems, dstHotseatItems, hotseatToBeAdded, toBeRemoved); + calcDiff(srcWorkspaceItems, dstWorkspaceItems, workspaceToBeAdded, toBeRemoved); + + final int trgX = targetSize.x; + final int trgY = targetSize.y; + + if (DEBUG) { + Log.d(TAG, "Start migration:" + + "\n Source Device:" + + srcWorkspaceItems.stream().map(DbEntry::toString).collect( + Collectors.joining(",\n", "[", "]")) + + "\n Target Device:" + + dstWorkspaceItems.stream().map(DbEntry::toString).collect( + Collectors.joining(",\n", "[", "]")) + + "\n Removing Items:" + + dstWorkspaceItems.stream().filter(entry -> + toBeRemoved.contains(entry.id)).map(DbEntry::toString).collect( + Collectors.joining(",\n", "[", "]")) + + "\n Adding Workspace Items:" + + workspaceToBeAdded.stream().map(DbEntry::toString).collect( + Collectors.joining(",\n", "[", "]")) + + "\n Adding Hotseat Items:" + + hotseatToBeAdded.stream().map(DbEntry::toString).collect( + Collectors.joining(",\n", "[", "]")) + ); + } + if (!toBeRemoved.isEmpty()) { + removeEntryFromDb(destReader.mDb, destReader.mTableName, toBeRemoved); + } + if (hotseatToBeAdded.isEmpty() && workspaceToBeAdded.isEmpty()) { return false; } // Sort the items by the reading order. - Collections.sort(mHotseatDiff); - Collections.sort(mWorkspaceDiff); + Collections.sort(hotseatToBeAdded); + Collections.sort(workspaceToBeAdded); // Migrate hotseat - HotseatPlacementSolution hotseatSolution = new HotseatPlacementSolution(mDb, mSrcReader, - mDestReader, mContext, mDestHotseatSize, mHotseatItems, mHotseatDiff); - hotseatSolution.find(); + solveHotseatPlacement(db, srcReader, + destReader, context, destHotseatSize, dstHotseatItems, hotseatToBeAdded); // Migrate workspace. // First we create a collection of the screens List<Integer> screens = new ArrayList<>(); - for (int screenId = 0; screenId <= mDestReader.mLastScreenId; screenId++) { + for (int screenId = 0; screenId <= destReader.mLastScreenId; screenId++) { screens.add(screenId); } @@ -245,55 +255,47 @@ public class GridSizeMigrationTaskV2 { if (DEBUG) { Log.d(TAG, "Migrating " + screenId); } - GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader, - mDestReader, mContext, screenId, mTrgX, mTrgY, mWorkspaceDiff, false); - workspaceSolution.find(); - if (mWorkspaceDiff.isEmpty()) { + solveGridPlacement(db, srcReader, + destReader, context, screenId, trgX, trgY, workspaceToBeAdded, false); + if (workspaceToBeAdded.isEmpty()) { break; } } // In case the new grid is smaller, there might be some leftover items that don't fit on // any of the screens, in this case we add them to new screens until all of them are placed. - int screenId = mDestReader.mLastScreenId + 1; - while (!mWorkspaceDiff.isEmpty()) { - GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader, - mDestReader, mContext, screenId, mTrgX, mTrgY, mWorkspaceDiff, - preservePages); - workspaceSolution.find(); + int screenId = destReader.mLastScreenId + 1; + while (!workspaceToBeAdded.isEmpty()) { + solveGridPlacement(db, srcReader, + destReader, context, screenId, trgX, trgY, workspaceToBeAdded, preservePages); screenId++; } return true; } - /** Return what's in the src but not in the dest */ - private static List<DbEntry> calcDiff(List<DbEntry> src, List<DbEntry> dest) { - Map<String, Integer> destIdSet = new HashMap<>(); - for (DbEntry entry : dest) { - String entryID = entry.getEntryMigrationId(); - if (destIdSet.containsKey(entryID)) { - destIdSet.put(entryID, destIdSet.get(entryID) + 1); - } else { - destIdSet.put(entryID, 1); + /** + * Calculate the differences between {@code src} (denoted by A) and {@code dest} + * (denoted by B). + * All DbEntry in A - B will be added to {@code toBeAdded} + * All DbEntry.id in B - A will be added to {@code toBeRemoved} + */ + private static void calcDiff(@NonNull final List<DbEntry> src, + @NonNull final List<DbEntry> dest, @NonNull final List<DbEntry> toBeAdded, + @NonNull final IntArray toBeRemoved) { + src.forEach(entry -> { + if (!dest.contains(entry)) { + toBeAdded.add(entry); } - } - List<DbEntry> diff = new ArrayList<>(); - for (DbEntry entry : src) { - String entryID = entry.getEntryMigrationId(); - if (destIdSet.containsKey(entryID)) { - Integer count = destIdSet.get(entryID); - if (count <= 0) { - diff.add(entry); - destIdSet.remove(entryID); - } else { - destIdSet.put(entryID, count - 1); + }); + dest.forEach(entry -> { + if (!src.contains(entry)) { + toBeRemoved.add(entry.id); + if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { + entry.mFolderItems.values().forEach(ids -> ids.forEach(toBeRemoved::add)); } - } else { - diff.add(entry); } - } - return diff; + }); } private static void insertEntryInDb(SQLiteDatabase db, Context context, DbEntry entry, @@ -365,144 +367,88 @@ public class GridSizeMigrationTaskV2 { return validPackages; } - protected static class GridPlacementSolution { - - private final SQLiteDatabase mDb; - private final DbReader mSrcReader; - private final DbReader mDestReader; - private final Context mContext; - private final GridOccupancy mOccupied; - private final int mScreenId; - private final int mTrgX; - private final int mTrgY; - private final List<DbEntry> mSortedItemsToPlace; - private final boolean mMatchingScreenIdOnly; - - private int mNextStartX; - private int mNextStartY; - - GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, DbReader destReader, - Context context, int screenId, int trgX, int trgY, List<DbEntry> sortedItemsToPlace, - boolean matchingScreenIdOnly) { - mDb = db; - mSrcReader = srcReader; - mDestReader = destReader; - mContext = context; - mOccupied = new GridOccupancy(trgX, trgY); - mScreenId = screenId; - mTrgX = trgX; - mTrgY = trgY; - mNextStartX = 0; - mNextStartY = mScreenId == 0 && FeatureFlags.QSB_ON_FIRST_SCREEN - ? 1 /* smartspace */ : 0; - List<DbEntry> existedEntries = mDestReader.mWorkspaceEntriesByScreenId.get(screenId); - if (existedEntries != null) { - for (DbEntry entry : existedEntries) { - mOccupied.markCells(entry, true); - } - } - mSortedItemsToPlace = sortedItemsToPlace; - mMatchingScreenIdOnly = matchingScreenIdOnly; - } - - public void find() { - Iterator<DbEntry> iterator = mSortedItemsToPlace.iterator(); - while (iterator.hasNext()) { - final DbEntry entry = iterator.next(); - if (mMatchingScreenIdOnly && entry.screenId < mScreenId) continue; - if (mMatchingScreenIdOnly && entry.screenId > mScreenId) break; - if (entry.minSpanX > mTrgX || entry.minSpanY > mTrgY) { - iterator.remove(); - continue; - } - if (findPlacement(entry)) { - insertEntryInDb(mDb, mContext, entry, mSrcReader.mTableName, - mDestReader.mTableName); - iterator.remove(); - } + private static void solveGridPlacement(@NonNull final SQLiteDatabase db, + @NonNull final DbReader srcReader, @NonNull final DbReader destReader, + @NonNull final Context context, final int screenId, final int trgX, final int trgY, + @NonNull final List<DbEntry> sortedItemsToPlace, final boolean matchingScreenIdOnly) { + final GridOccupancy occupied = new GridOccupancy(trgX, trgY); + final Point trg = new Point(trgX, trgY); + final Point next = new Point(0, screenId == 0 && FeatureFlags.QSB_ON_FIRST_SCREEN + ? 1 /* smartspace */ : 0); + List<DbEntry> existedEntries = destReader.mWorkspaceEntriesByScreenId.get(screenId); + if (existedEntries != null) { + for (DbEntry entry : existedEntries) { + occupied.markCells(entry, true); } } - - /** - * Search for the next possible placement of an icon. (mNextStartX, mNextStartY) serves as - * a memoization of last placement, we can start our search for next placement from there - * to speed up the search. - */ - private boolean findPlacement(DbEntry entry) { - for (int y = mNextStartY; y < mTrgY; y++) { - for (int x = mNextStartX; x < mTrgX; x++) { - boolean fits = mOccupied.isRegionVacant(x, y, entry.spanX, entry.spanY); - boolean minFits = mOccupied.isRegionVacant(x, y, entry.minSpanX, - entry.minSpanY); - if (minFits) { - entry.spanX = entry.minSpanX; - entry.spanY = entry.minSpanY; - } - if (fits || minFits) { - entry.screenId = mScreenId; - entry.cellX = x; - entry.cellY = y; - mOccupied.markCells(entry, true); - mNextStartX = x + entry.spanX; - mNextStartY = y; - return true; - } - } - mNextStartX = 0; + Iterator<DbEntry> iterator = sortedItemsToPlace.iterator(); + while (iterator.hasNext()) { + final DbEntry entry = iterator.next(); + if (matchingScreenIdOnly && entry.screenId < screenId) continue; + if (matchingScreenIdOnly && entry.screenId > screenId) break; + if (entry.minSpanX > trgX || entry.minSpanY > trgY) { + iterator.remove(); + continue; + } + if (findPlacementForEntry(entry, next, trg, occupied, screenId)) { + insertEntryInDb(db, context, entry, srcReader.mTableName, destReader.mTableName); + iterator.remove(); } - return false; } } - protected static class HotseatPlacementSolution { - - private final SQLiteDatabase mDb; - private final DbReader mSrcReader; - private final DbReader mDestReader; - private final Context mContext; - private final HotseatOccupancy mOccupied; - private final List<DbEntry> mItemsToPlace; - - HotseatPlacementSolution(SQLiteDatabase db, DbReader srcReader, DbReader destReader, - Context context, int hotseatSize, List<DbEntry> placedHotseatItems, - List<DbEntry> itemsToPlace) { - mDb = db; - mSrcReader = srcReader; - mDestReader = destReader; - mContext = context; - mOccupied = new HotseatOccupancy(hotseatSize); - for (DbEntry entry : placedHotseatItems) { - mOccupied.markCells(entry, true); - } - mItemsToPlace = itemsToPlace; - } - - public void find() { - for (int i = 0; i < mOccupied.mCells.length; i++) { - if (!mOccupied.mCells[i] && !mItemsToPlace.isEmpty()) { - DbEntry entry = mItemsToPlace.remove(0); - entry.screenId = i; - // These values does not affect the item position, but we should set them - // to something other than -1. - entry.cellX = i; - entry.cellY = 0; - insertEntryInDb(mDb, mContext, entry, mSrcReader.mTableName, - mDestReader.mTableName); - mOccupied.markCells(entry, true); + /** + * Search for the next possible placement of an icon. (mNextStartX, mNextStartY) serves as + * a memoization of last placement, we can start our search for next placement from there + * to speed up the search. + */ + private static boolean findPlacementForEntry(@NonNull final DbEntry entry, + @NonNull final Point next, @NonNull final Point trg, + @NonNull final GridOccupancy occupied, final int screenId) { + for (int y = next.y; y < trg.y; y++) { + for (int x = next.x; x < trg.x; x++) { + boolean fits = occupied.isRegionVacant(x, y, entry.spanX, entry.spanY); + boolean minFits = occupied.isRegionVacant(x, y, entry.minSpanX, + entry.minSpanY); + if (minFits) { + entry.spanX = entry.minSpanX; + entry.spanY = entry.minSpanY; + } + if (fits || minFits) { + entry.screenId = screenId; + entry.cellX = x; + entry.cellY = y; + occupied.markCells(entry, true); + next.set(x + entry.spanX, y); + return true; } } + next.set(0, next.y); } + return false; + } - private class HotseatOccupancy { - - private final boolean[] mCells; - - private HotseatOccupancy(int hotseatSize) { - mCells = new boolean[hotseatSize]; - } - - private void markCells(ItemInfo item, boolean value) { - mCells[item.screenId] = value; + private static void solveHotseatPlacement(@NonNull final SQLiteDatabase db, + @NonNull final DbReader srcReader, @NonNull final DbReader destReader, + @NonNull final Context context, final int hotseatSize, + @NonNull final List<DbEntry> placedHotseatItems, + @NonNull final List<DbEntry> itemsToPlace) { + + final boolean[] occupied = new boolean[hotseatSize]; + for (DbEntry entry : placedHotseatItems) { + occupied[entry.screenId] = true; + } + + for (int i = 0; i < occupied.length; i++) { + if (!occupied[i] && !itemsToPlace.isEmpty()) { + DbEntry entry = itemsToPlace.remove(0); + entry.screenId = i; + // These values does not affect the item position, but we should set them + // to something other than -1. + entry.cellX = i; + entry.cellY = 0; + insertEntryInDb(db, context, entry, srcReader.mTableName, destReader.mTableName); + occupied[entry.screenId] = true; } } } @@ -515,8 +461,6 @@ public class GridSizeMigrationTaskV2 { private final Set<String> mValidPackages; private int mLastScreenId = -1; - private final ArrayList<DbEntry> mHotseatEntries = new ArrayList<>(); - private final ArrayList<DbEntry> mWorkspaceEntries = new ArrayList<>(); private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId = new ArrayMap<>(); @@ -528,7 +472,8 @@ public class GridSizeMigrationTaskV2 { mValidPackages = validPackages; } - protected ArrayList<DbEntry> loadHotseatEntries() { + protected List<DbEntry> loadHotseatEntries() { + final List<DbEntry> hotseatEntries = new ArrayList<>(); Cursor c = queryWorkspace( new String[]{ LauncherSettings.Favorites._ID, // 0 @@ -577,14 +522,15 @@ public class GridSizeMigrationTaskV2 { entriesToRemove.add(entry.id); continue; } - mHotseatEntries.add(entry); + hotseatEntries.add(entry); } removeEntryFromDb(mDb, mTableName, entriesToRemove); c.close(); - return mHotseatEntries; + return hotseatEntries; } - protected ArrayList<DbEntry> loadAllWorkspaceEntries() { + protected List<DbEntry> loadAllWorkspaceEntries() { + final List<DbEntry> workspaceEntries = new ArrayList<>(); Cursor c = queryWorkspace( new String[]{ LauncherSettings.Favorites._ID, // 0 @@ -599,10 +545,6 @@ public class GridSizeMigrationTaskV2 { LauncherSettings.Favorites.APPWIDGET_ID}, // 9 LauncherSettings.Favorites.CONTAINER + " = " + LauncherSettings.Favorites.CONTAINER_DESKTOP); - return loadWorkspaceEntries(c); - } - - private ArrayList<DbEntry> loadWorkspaceEntries(Cursor c) { final int indexId = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); final int indexItemType = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); final int indexScreen = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); @@ -678,7 +620,7 @@ public class GridSizeMigrationTaskV2 { entriesToRemove.add(entry.id); continue; } - mWorkspaceEntries.add(entry); + workspaceEntries.add(entry); if (!mWorkspaceEntriesByScreenId.containsKey(entry.screenId)) { mWorkspaceEntriesByScreenId.put(entry.screenId, new ArrayList<>()); } @@ -686,7 +628,7 @@ public class GridSizeMigrationTaskV2 { } removeEntryFromDb(mDb, mTableName, entriesToRemove); c.close(); - return mWorkspaceEntries; + return workspaceEntries; } private int getFolderItemsCount(DbEntry entry) { @@ -762,12 +704,12 @@ public class GridSizeMigrationTaskV2 { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DbEntry entry = (DbEntry) o; - return Objects.equals(mIntent, entry.mIntent); + return Objects.equals(getEntryMigrationId(), entry.getEntryMigrationId()); } @Override public int hashCode() { - return Objects.hash(mIntent); + return Objects.hash(getEntryMigrationId()); } public void updateContentValues(ContentValues values) { diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index b644b6b408..1d6971e27d 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -349,7 +349,7 @@ public class LoaderTask implements Runnable { final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context); boolean clearDb = false; - if (!GridSizeMigrationTaskV2.migrateGridIfNeeded(context)) { + if (!GridSizeMigrationUtil.migrateGridIfNeeded(context)) { // Migration failed. Clear workspace. clearDb = true; } diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java index 1ced0b16f4..c21fc38cfb 100644 --- a/src/com/android/launcher3/model/ModelUtils.java +++ b/src/com/android/launcher3/model/ModelUtils.java @@ -15,8 +15,6 @@ */ package com.android.launcher3.model; -import static com.android.launcher3.Utilities.isValidExtraType; - import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -149,4 +147,12 @@ public class ModelUtils { info.intent = launchIntent; return info; } + + /** + * @return true if the extra is either null or is of type {@param type} + */ + private static boolean isValidExtraType(Intent intent, String key, Class type) { + Object extra = intent.getParcelableExtra(key); + return extra == null || type.isInstance(extra); + } } diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index 0a68d4aa34..f444bd5718 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -48,7 +48,7 @@ import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.Executors; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LooperExecutor; -import com.android.launcher3.widget.LauncherAppWidgetHost; +import com.android.launcher3.widget.LauncherWidgetHolder; import java.util.ArrayList; import java.util.Arrays; @@ -333,13 +333,13 @@ public class ModelWriter { /** * Deletes the widget info and the widget id. */ - public void deleteWidgetInfo(final LauncherAppWidgetInfo info, LauncherAppWidgetHost host, + public void deleteWidgetInfo(final LauncherAppWidgetInfo info, LauncherWidgetHolder holder, @Nullable final String reason) { notifyDelete(Collections.singleton(info)); - if (host != null && !info.isCustomWidget() && info.isWidgetIdAllocated()) { + if (holder != null && !info.isCustomWidget() && info.isWidgetIdAllocated()) { // Deleting an app widget ID is a void call but writes to disk before returning // to the caller... - enqueueDeleteRunnable(() -> host.deleteAppWidgetId(info.appWidgetId)); + enqueueDeleteRunnable(() -> holder.deleteAppWidgetId(info.appWidgetId)); } deleteItemFromDatabase(info, reason); } diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index 466f63f5d0..2dd44a4000 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -21,7 +21,6 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION; -import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SEARCH_RESULTS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SETTINGS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_TASKSWITCHER; @@ -39,8 +38,10 @@ import static com.android.launcher3.shortcuts.ShortcutKey.EXTRA_SHORTCUT_ID; import android.content.ComponentName; import android.content.ContentValues; import android.content.Intent; +import android.net.Uri; import android.os.Process; import android.os.UserHandle; +import android.provider.Settings; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -52,7 +53,6 @@ import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logger.LauncherAtom.AllAppsContainer; import com.android.launcher3.logger.LauncherAtom.ContainerInfo; import com.android.launcher3.logger.LauncherAtom.PredictionContainer; -import com.android.launcher3.logger.LauncherAtom.SearchResultContainer; import com.android.launcher3.logger.LauncherAtom.SettingsContainer; import com.android.launcher3.logger.LauncherAtom.Shortcut; import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer; @@ -61,6 +61,7 @@ import com.android.launcher3.logger.LauncherAtom.WallpapersContainer; import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers; import com.android.launcher3.model.ModelWriter; import com.android.launcher3.util.ContentWriter; +import com.android.launcher3.util.SettingsCache; import java.util.Optional; @@ -74,6 +75,9 @@ public class ItemInfo { // An id that doesn't match any item, including predicted apps with have an id=NO_ID public static final int NO_MATCHING_ID = Integer.MIN_VALUE; + /** Hidden field Settings.Secure.NAV_BAR_KIDS_MODE */ + private static final Uri NAV_BAR_KIDS_MODE = Settings.Secure.getUriFor("nav_bar_kids_mode"); + /** * The id in the settings database for this item */ @@ -350,9 +354,11 @@ public class ItemInfo { break; case ITEM_TYPE_TASK: itemBuilder - .setTask(LauncherAtom.Task.newBuilder() - .setComponentName(getTargetComponent().flattenToShortString()) - .setIndex(screenId)); + .setTask(nullableComponent + .map(component -> LauncherAtom.Task.newBuilder() + .setComponentName(component.flattenToShortString()) + .setIndex(screenId)) + .orElse(LauncherAtom.Task.newBuilder())); break; default: break; @@ -388,6 +394,9 @@ public class ItemInfo { protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() { LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder(); itemBuilder.setIsWork(!Process.myUserHandle().equals(user)); + SettingsCache settingsCache = SettingsCache.INSTANCE.getNoCreate(); + boolean isKidsMode = settingsCache != null && settingsCache.getValue(NAV_BAR_KIDS_MODE, 0); + itemBuilder.setIsKidsMode(isKidsMode); itemBuilder.setRank(rank); return itemBuilder; } @@ -428,10 +437,6 @@ public class ItemInfo { return ContainerInfo.newBuilder() .setPredictionContainer(PredictionContainer.getDefaultInstance()) .build(); - case CONTAINER_SEARCH_RESULTS: - return ContainerInfo.newBuilder() - .setSearchResultContainer(SearchResultContainer.getDefaultInstance()) - .build(); case CONTAINER_SHORTCUTS: return ContainerInfo.newBuilder() .setShortcutsContainer(ShortcutsContainer.getDefaultInstance()) @@ -448,10 +453,12 @@ public class ItemInfo { return ContainerInfo.newBuilder() .setWallpapersContainer(WallpapersContainer.getDefaultInstance()) .build(); - case EXTENDED_CONTAINERS: - return ContainerInfo.newBuilder() - .setExtendedContainers(getExtendedContainer()) - .build(); + default: + if (container <= EXTENDED_CONTAINERS) { + return ContainerInfo.newBuilder() + .setExtendedContainers(getExtendedContainer()) + .build(); + } } return ContainerInfo.getDefaultInstance(); } diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java deleted file mode 100644 index 04042ea6fa..0000000000 --- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (C) 2021 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.launcher3.model.data; - -import static com.android.launcher3.LauncherSettings.Favorites.EXTENDED_CONTAINERS; - -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.graphics.drawable.Icon; -import android.os.Process; -import android.os.UserHandle; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherSettings; -import com.android.launcher3.logger.LauncherAtom.ItemInfo; -import com.android.launcher3.logger.LauncherAtom.SearchActionItem; - -/** - * Represents a SearchAction with in launcher - */ -public class SearchActionItemInfo extends ItemInfoWithIcon implements WorkspaceItemFactory { - - public static final int FLAG_SHOULD_START = 1 << 1; - public static final int FLAG_SHOULD_START_FOR_RESULT = FLAG_SHOULD_START | 1 << 2; - public static final int FLAG_BADGE_WITH_PACKAGE = 1 << 3; - public static final int FLAG_PRIMARY_ICON_FROM_TITLE = 1 << 4; - public static final int FLAG_BADGE_WITH_COMPONENT_NAME = 1 << 5; - public static final int FLAG_ALLOW_PINNING = 1 << 6; - public static final int FLAG_SEARCH_IN_APP = 1 << 7; - - private String mFallbackPackageName; - private int mFlags = 0; - private Icon mIcon; - - // If true title does not contain any personal info and eligible for logging. - private boolean mIsPersonalTitle; - private Intent mIntent; - - private PendingIntent mPendingIntent; - - public SearchActionItemInfo(Icon icon, String packageName, UserHandle user, - CharSequence title, boolean isPersonalTitle) { - mIsPersonalTitle = isPersonalTitle; - this.itemType = LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION; - this.user = user == null ? Process.myUserHandle() : user; - this.title = title; - this.container = EXTENDED_CONTAINERS; - mFallbackPackageName = packageName; - mIcon = icon; - } - - private SearchActionItemInfo(SearchActionItemInfo info) { - super(info); - } - - @Override - public void copyFrom(@NonNull com.android.launcher3.model.data.ItemInfo info) { - super.copyFrom(info); - SearchActionItemInfo itemInfo = (SearchActionItemInfo) info; - this.mFallbackPackageName = itemInfo.mFallbackPackageName; - this.mIcon = itemInfo.mIcon; - this.mFlags = itemInfo.mFlags; - this.mIsPersonalTitle = itemInfo.mIsPersonalTitle; - } - - /** - * Returns if multiple flags are all available. - */ - public boolean hasFlags(int flags) { - return (mFlags & flags) != 0; - } - - public void setFlags(int flags) { - mFlags |= flags; - } - - @Override - @Nullable - public Intent getIntent() { - return mIntent; - } - - /** - * Setter for mIntent with assertion for null value mPendingIntent - */ - public void setIntent(Intent intent) { - if (mPendingIntent != null && intent != null) { - throw new RuntimeException( - "SearchActionItemInfo can only have either an Intent or a PendingIntent"); - } - mIntent = intent; - } - - public PendingIntent getPendingIntent() { - return mPendingIntent; - } - - /** - * Setter of mPendingIntent with assertion for null value mIntent - */ - public void setPendingIntent(PendingIntent pendingIntent) { - if (mIntent != null && pendingIntent != null) { - throw new RuntimeException( - "SearchActionItemInfo can only have either an Intent or a PendingIntent"); - } - mPendingIntent = pendingIntent; - } - - @Nullable - public Icon getIcon() { - return mIcon; - } - - @Override - public ItemInfoWithIcon clone() { - return new SearchActionItemInfo(this); - } - - @NonNull - @Override - public ItemInfo buildProto(@Nullable FolderInfo fInfo) { - SearchActionItem.Builder itemBuilder = SearchActionItem.newBuilder() - .setPackageName(mFallbackPackageName); - - if (!mIsPersonalTitle) { - itemBuilder.setTitle(title.toString()); - } - return getDefaultItemInfoBuilder() - .setSearchActionItem(itemBuilder) - .setContainerInfo(getContainerInfo()) - .build(); - } - - /** - * Returns true if result supports drag/drop to home screen - */ - public boolean supportsPinning() { - return hasFlags(FLAG_ALLOW_PINNING) && getIntentPackageName() != null; - } - - /** - * Creates a {@link WorkspaceItemInfo} coorsponding to search action to be stored in launcher db - */ - @Override - public WorkspaceItemInfo makeWorkspaceItem(Context context) { - WorkspaceItemInfo info = new WorkspaceItemInfo(); - info.title = title; - info.bitmap = bitmap; - info.intent = mIntent; - - if (hasFlags(FLAG_SHOULD_START_FOR_RESULT)) { - info.options |= WorkspaceItemInfo.FLAG_START_FOR_RESULT; - } - LauncherAppState app = LauncherAppState.getInstance(context); - app.getModel().updateAndBindWorkspaceItem(() -> { - PackageItemInfo pkgInfo = new PackageItemInfo(getIntentPackageName(), user); - app.getIconCache().getTitleAndIconForApp(pkgInfo, false); - info.bitmap = info.bitmap.withBadgeInfo(pkgInfo.bitmap); - return info; - }); - return info; - } - - @Nullable - private String getIntentPackageName() { - if (mIntent != null) { - if (mIntent.getPackage() != null) return mIntent.getPackage(); - return mFallbackPackageName; - } - return null; - } -} diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java index b4cb0eef6e..c324ce3cf5 100644 --- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java +++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java @@ -16,7 +16,7 @@ package com.android.launcher3.pageindicators; -import static com.android.launcher3.config.FeatureFlags.SHOW_DELIGHTFUL_PAGINATION_FOLDER; +import static com.android.launcher3.config.FeatureFlags.SHOW_DOT_PAGINATION; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -29,29 +29,36 @@ import android.graphics.Canvas; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Paint.Style; +import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Looper; import android.util.AttributeSet; -import android.util.Property; +import android.util.FloatProperty; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewOutlineProvider; import android.view.animation.Interpolator; import android.view.animation.OvershootInterpolator; +import androidx.annotation.Nullable; + +import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.anim.Interpolators; import com.android.launcher3.util.Themes; /** * {@link PageIndicator} which shows dots per page. The active page is shown with the current * accent color. */ -public class PageIndicatorDots extends View implements PageIndicator { +public class PageIndicatorDots extends View implements Insettable, PageIndicator { private static final float SHIFT_PER_ANIMATION = 0.5f; private static final float SHIFT_THRESHOLD = 0.1f; private static final long ANIMATION_DURATION = 150; + private static final int PAGINATION_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay(); + private static final int ALPHA_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration(); private static final int ENTER_ANIMATION_START_DELAY = 300; private static final int ENTER_ANIMATION_STAGGERED_DELAY = 150; @@ -60,42 +67,55 @@ public class PageIndicatorDots extends View implements PageIndicator { private static final int PAGE_INDICATOR_ALPHA = 255; private static final int DOT_ALPHA = 128; private static final int DOT_GAP_FACTOR = 3; - private static final float DOT_GAP_FACTOR_FLOAT = 3.8f; + private static final int VISIBLE_ALPHA = 1; + private static final int INVISIBLE_ALPHA = 0; + private Paint mPaginationPaint; // This value approximately overshoots to 1.5 times the original size. private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f; - private static final float INDICATOR_ROTATION = 180f; - private static final RectF sTempRect = new RectF(); - private static final Property<PageIndicatorDots, Float> CURRENT_POSITION - = new Property<PageIndicatorDots, Float>(float.class, "current_position") { - @Override - public Float get(PageIndicatorDots obj) { - return obj.mCurrentPosition; - } + private static final FloatProperty<PageIndicatorDots> CURRENT_POSITION = + new FloatProperty<PageIndicatorDots>("current_position") { + @Override + public Float get(PageIndicatorDots obj) { + return obj.mCurrentPosition; + } - @Override - public void set(PageIndicatorDots obj, Float pos) { - obj.mCurrentPosition = pos; - obj.invalidate(); - obj.invalidateOutline(); - } - }; + @Override + public void setValue(PageIndicatorDots obj, float pos) { + obj.mCurrentPosition = pos; + obj.invalidate(); + obj.invalidateOutline(); + } + }; + + private static final FloatProperty<PageIndicatorDots> PAGINATION_ALPHA = + new FloatProperty<PageIndicatorDots>("pagination_alpha") { + @Override + public Float get(PageIndicatorDots obj) { + return obj.getAlpha(); + } - private final Paint mPaginationPaint; - private final Drawable mPageIndicatorDrawable; + @Override + public void setValue(PageIndicatorDots obj, float alpha) { + obj.setAlpha(alpha); + obj.invalidate(); + } + }; + + private final Handler mDelayedPaginationFadeHandler = new Handler(Looper.getMainLooper()); private final float mDotRadius; private final float mCircleGap; - private final float mPageIndicatorSize; - private final float mPageIndicatorRadius; private final boolean mIsRtl; private int mNumPages; private int mActivePage; private int mCurrentScroll; private int mTotalScroll; + private boolean mShouldAutoHide = true; + private int mToAlpha; /** * The current position of the active dot including the animation progress. @@ -109,9 +129,12 @@ public class PageIndicatorDots extends View implements PageIndicator { private float mCurrentPosition; private float mFinalPosition; private ObjectAnimator mAnimator; + private @Nullable ObjectAnimator mAlphaAnimator; private float[] mEntryAnimationRadiusFactors; + private Runnable mHidePaginationRunnable = () -> animatePaginationToAlpha(INVISIBLE_ALPHA); + public PageIndicatorDots(Context context) { this(context, null); } @@ -127,31 +150,17 @@ public class PageIndicatorDots extends View implements PageIndicator { mPaginationPaint.setStyle(Style.FILL); mPaginationPaint.setColor(Themes.getAttrColor(context, R.attr.folderPaginationColor)); mDotRadius = getResources().getDimension(R.dimen.page_indicator_dot_size) / 2; - - - if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) { - mPageIndicatorSize = getResources().getDimension( - R.dimen.page_indicator_size); - mPageIndicatorRadius = mPageIndicatorSize / 2; - mPageIndicatorDrawable = context.getDrawable(R.drawable.page_indicator); - mPageIndicatorDrawable.setBounds(0, 0, (int) mPageIndicatorSize, - (int) mPageIndicatorSize); - mCircleGap = DOT_GAP_FACTOR_FLOAT * mDotRadius; - - } else { - mPageIndicatorSize = 0; - mPageIndicatorRadius = 0; - mPageIndicatorDrawable = null; - mCircleGap = DOT_GAP_FACTOR * mDotRadius; - } - if (!SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) { - setOutlineProvider(new MyOutlineProver()); - } + mCircleGap = DOT_GAP_FACTOR * mDotRadius; + setOutlineProvider(new MyOutlineProver()); mIsRtl = Utilities.isRtl(getResources()); } @Override public void setScroll(int currentScroll, int totalScroll) { + if (SHOW_DOT_PAGINATION.get()) { + animatePaginationToAlpha(VISIBLE_ALPHA); + } + if (mNumPages <= 1) { mCurrentScroll = 0; return; @@ -161,12 +170,7 @@ public class PageIndicatorDots extends View implements PageIndicator { currentScroll = totalScroll - currentScroll; } - if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) { - mCurrentScroll = currentScroll; - mTotalScroll = totalScroll; - invalidate(); - return; - } + mTotalScroll = totalScroll; int scrollPerPage = totalScroll / (mNumPages - 1); int pageToLeft = currentScroll / scrollPerPage; @@ -177,15 +181,79 @@ public class PageIndicatorDots extends View implements PageIndicator { if (currentScroll < pageToLeftScroll + scrollThreshold) { // scroll is within the left page's threshold animateToPosition(pageToLeft); + if (SHOW_DOT_PAGINATION.get()) { + hideAfterDelay(); + } } else if (currentScroll > pageToRightScroll - scrollThreshold) { // scroll is far enough from left page to go to the right page animateToPosition(pageToLeft + 1); + if (SHOW_DOT_PAGINATION.get()) { + hideAfterDelay(); + } } else { // scroll is between left and right page animateToPosition(pageToLeft + SHIFT_PER_ANIMATION); } } + @Override + public void setShouldAutoHide(boolean shouldAutoHide) { + mShouldAutoHide = shouldAutoHide; + if (shouldAutoHide && this.getAlpha() > INVISIBLE_ALPHA) { + hideAfterDelay(); + } else if (!shouldAutoHide) { + mDelayedPaginationFadeHandler.removeCallbacksAndMessages(null); + } + } + + private void hideAfterDelay() { + mDelayedPaginationFadeHandler.removeCallbacksAndMessages(null); + mDelayedPaginationFadeHandler.postDelayed(mHidePaginationRunnable, PAGINATION_FADE_DELAY); + } + + private void animatePaginationToAlpha(int alpha) { + if (alpha == mToAlpha) { + // Ignore the new animation if it is going to the same alpha as the current animation. + return; + } + mToAlpha = alpha; + + if (mAlphaAnimator != null) { + mAlphaAnimator.cancel(); + } + mAlphaAnimator = ObjectAnimator.ofFloat(this, PAGINATION_ALPHA, + alpha); + mAlphaAnimator.setDuration(ALPHA_ANIMATE_DURATION); + mAlphaAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mAlphaAnimator = null; + } + }); + mAlphaAnimator.start(); + + } + + /** + * Pauses all currently running animations. + */ + @Override + public void pauseAnimations() { + if (mAlphaAnimator != null) { + mAlphaAnimator.pause(); + } + } + + /** + * Force-ends all currently running or paused animations. + */ + @Override + public void skipAnimationsToEnd() { + if (mAlphaAnimator != null) { + mAlphaAnimator.end(); + } + } + private void animateToPosition(float position) { mFinalPosition = position; if (Math.abs(mCurrentPosition - mFinalPosition) < SHIFT_THRESHOLD) { @@ -281,6 +349,10 @@ public class PageIndicatorDots extends View implements PageIndicator { @Override protected void onDraw(Canvas canvas) { + if ((mShouldAutoHide && mTotalScroll == 0) || mNumPages < 2) { + return; + } + // Draw all page indicators; float circleGap = mCircleGap; float startX = (getWidth() - (mNumPages * circleGap) + mDotRadius) / 2; @@ -296,91 +368,22 @@ public class PageIndicatorDots extends View implements PageIndicator { } for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) { mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA); - if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) { - if (i != mActivePage) { - canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i], - mPaginationPaint); - } else { - drawPageIndicator(canvas, mEntryAnimationRadiusFactors[i]); - } - } else { - canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i], - mPaginationPaint); - } + canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i], + mPaginationPaint); x += circleGap; } } else { // Here we draw the dots mPaginationPaint.setAlpha(DOT_ALPHA); for (int i = 0; i < mNumPages; i++) { - if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) { - canvas.drawCircle(x, y, getRadius(x), mPaginationPaint); - } else { - canvas.drawCircle(x, y, mDotRadius, mPaginationPaint); - } + canvas.drawCircle(x, y, mDotRadius, mPaginationPaint); x += circleGap; } // Here we draw the current page indicator mPaginationPaint.setAlpha(PAGE_INDICATOR_ALPHA); - if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) { - drawPageIndicator(canvas, 1); - } else { - canvas.drawRoundRect(getActiveRect(), mDotRadius, mDotRadius, mPaginationPaint); - } - } - } - - /** - * Draws the page indicator, denoting the currently selected page - * - * @param canvas is used to draw the page indicator and to rotate it as we scroll - * @param scale is used to set the scale of our canvas - */ - private void drawPageIndicator(Canvas canvas, float scale) { - RectF currRect = getActiveRect(); - - // saves the canvas so we can later restore it to its original scale - canvas.save(); - - // Moves the canvas to start at the top left corner of the page indicator - canvas.translate(currRect.left, currRect.top); - - // Scales the canvas in place to animate the indicator on entry - canvas.scale(scale, scale, mPageIndicatorRadius, mPageIndicatorRadius); - - int scrollPerPage = getScrollPerPage(); - // This IF is to avoid division by 0 - if (scrollPerPage != 0) { - int delta = mCurrentScroll % scrollPerPage; - canvas.rotate((INDICATOR_ROTATION * delta) / scrollPerPage, - mPageIndicatorRadius, mPageIndicatorRadius); - } - - mPageIndicatorDrawable.draw(canvas); - canvas.restore(); - } - - /** - * Returns the radius of the circle based on how close the page indicator is to it - * - * @param dotPositionX is the position the dot is located at in the x-axis - */ - private float getRadius(float dotPositionX) { - - float startXIndicator = - ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2) - getOffset(); - float indicatorPosition = startXIndicator + getIndicatorScrollDistance() - + mPageIndicatorRadius; - - // If the indicator gets close enough to a dot then we change the radius - // of the dot based on how close the indicator is to it. - float dotDistance = Math.abs(indicatorPosition - dotPositionX); - if (dotDistance <= mCircleGap) { - return Utilities.mapToRange(dotDistance, 0, mCircleGap, 0f, mDotRadius, - Interpolators.LINEAR); + canvas.drawRoundRect(getActiveRect(), mDotRadius, mDotRadius, mPaginationPaint); } - return mDotRadius; } private RectF getActiveRect() { @@ -389,29 +392,21 @@ public class PageIndicatorDots extends View implements PageIndicator { float diameter = 2 * mDotRadius; float startX; - if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) { - startX = ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2) - getOffset(); - sTempRect.top = (getHeight() - mPageIndicatorSize) * 0.5f; - sTempRect.bottom = (getHeight() + mPageIndicatorSize) * 0.5f; - sTempRect.left = startX + getIndicatorScrollDistance(); - sTempRect.right = sTempRect.left + mPageIndicatorSize; + startX = ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2); + sTempRect.top = (getHeight() * 0.5f) - mDotRadius; + sTempRect.bottom = (getHeight() * 0.5f) + mDotRadius; + sTempRect.left = startX + (startCircle * mCircleGap); + sTempRect.right = sTempRect.left + diameter; + + if (delta < SHIFT_PER_ANIMATION) { + // dot is capturing the right circle. + sTempRect.right += delta * mCircleGap * 2; } else { - startX = ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2); - sTempRect.top = (getHeight() * 0.5f) - mDotRadius; - sTempRect.bottom = (getHeight() * 0.5f) + mDotRadius; - sTempRect.left = startX + (startCircle * mCircleGap); - sTempRect.right = sTempRect.left + diameter; - - if (delta < SHIFT_PER_ANIMATION) { - // dot is capturing the right circle. - sTempRect.right += delta * mCircleGap * 2; - } else { - // Dot is leaving the left circle. - sTempRect.right += mCircleGap; - - delta -= SHIFT_PER_ANIMATION; - sTempRect.left += delta * mCircleGap * 2; - } + // Dot is leaving the left circle. + sTempRect.right += mCircleGap; + + delta -= SHIFT_PER_ANIMATION; + sTempRect.left += delta * mCircleGap * 2; } if (mIsRtl) { @@ -423,29 +418,6 @@ public class PageIndicatorDots extends View implements PageIndicator { return sTempRect; } - /** - * The offset between the radius of the dot and the midpoint of the indicator so that - * the indicator is centered in with the indicator circles - */ - private float getOffset() { - return mPageIndicatorRadius - mDotRadius; - } - - /** - * Returns an int that is the amount we need to scroll per page - */ - private int getScrollPerPage() { - return mNumPages > 1 ? mTotalScroll / (mNumPages - 1) : 0; - } - - /** - * The current scroll adjusted for the distance the indicator needs to travel on the screen - */ - private float getIndicatorScrollDistance() { - int scrollPerPage = getScrollPerPage(); - return scrollPerPage != 0 ? ((float) mCurrentScroll / scrollPerPage) * mCircleGap : 0; - } - private class MyOutlineProver extends ViewOutlineProvider { @Override @@ -483,4 +455,12 @@ public class PageIndicatorDots extends View implements PageIndicator { } } } + + /** + * We need to override setInsets to prevent InsettableFrameLayout from applying different + * margins on the pagination. + */ + @Override + public void setInsets(Rect insets) { + } } diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java index 87ae890894..bde4e525a1 100644 --- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java +++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java @@ -14,12 +14,9 @@ import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; import android.util.Property; -import android.view.Gravity; import android.view.View; import android.view.ViewConfiguration; -import android.widget.FrameLayout; -import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; import com.android.launcher3.R; @@ -258,21 +255,11 @@ public class WorkspacePageIndicator extends View implements Insettable, PageIndi } } + /** + * We need to override setInsets to prevent InsettableFrameLayout from applying different + * margins on the page indicator. + */ @Override public void setInsets(Rect insets) { - DeviceProfile grid = mLauncher.getDeviceProfile(); - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); - - if (grid.isVerticalBarLayout()) { - Rect padding = grid.workspacePadding; - lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx; - lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx; - lp.bottomMargin = padding.bottom; - } else { - lp.leftMargin = lp.rightMargin = 0; - lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; - lp.bottomMargin = grid.hotseatBarSizePx; - } - setLayoutParams(lp); } } diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java index 16bb868f65..150bca4058 100644 --- a/src/com/android/launcher3/pm/InstallSessionHelper.java +++ b/src/com/android/launcher3/pm/InstallSessionHelper.java @@ -16,7 +16,7 @@ package com.android.launcher3.pm; -import static com.android.launcher3.Utilities.getPrefs; +import static com.android.launcher3.LauncherPrefs.getPrefs; import android.content.Context; import android.content.pm.ApplicationInfo; diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 196cc56be7..9a745ab9f4 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -21,14 +21,12 @@ import static androidx.core.content.ContextCompat.getColorStateList; import static com.android.launcher3.anim.Interpolators.ACCELERATED_EASE; import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE; import static com.android.launcher3.anim.Interpolators.LINEAR; -import static com.android.launcher3.config.FeatureFlags.ENABLE_LOCAL_COLOR_POPUPS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.annotation.TargetApi; import android.content.Context; import android.content.res.Resources; import android.graphics.Color; @@ -36,15 +34,12 @@ import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; -import android.os.Build; import android.util.AttributeSet; import android.util.Pair; -import android.util.SparseIntArray; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.animation.Interpolator; import android.widget.FrameLayout; @@ -52,21 +47,17 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.InsettableFrameLayout; -import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.Workspace; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.util.Themes; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; -import com.android.launcher3.widget.LocalColorExtractor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.List; /** * A container for shortcuts to deep links and notifications associated with an app. @@ -89,10 +80,6 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> protected int CLOSE_CHILD_FADE_START_DELAY = 0; protected int CLOSE_CHILD_FADE_DURATION = 140; - // Index used to get background color when using local wallpaper color extraction, - private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_neutral2_800; - private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50; - protected final Rect mTempRect = new Rect(); protected final LayoutInflater mInflater; @@ -124,10 +111,8 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> // The rect string of the view that the arrow is attached to, in screen reference frame. protected int mArrowColor; - protected final List<LocalColorExtractor> mColorExtractors; protected final float mElevation; - private final int mBackgroundColor; private final String mIterateChildrenTag; @@ -140,8 +125,8 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> mActivityContext = ActivityContext.lookupContext(context); mIsRtl = Utilities.isRtl(getResources()); - mBackgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary); - mArrowColor = mBackgroundColor; + int backgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary); + mArrowColor = backgroundColor; mElevation = getResources().getDimension(R.dimen.deep_shortcuts_elevation); // Initialize arrow view @@ -158,25 +143,18 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius); mRoundedTop = new GradientDrawable(); - mRoundedTop.setColor(mBackgroundColor); + mRoundedTop.setColor(backgroundColor); mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius}); mRoundedBottom = new GradientDrawable(); - mRoundedBottom.setColor(mBackgroundColor); + mRoundedBottom.setColor(backgroundColor); mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius, smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius}); mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children); - boolean shouldUseColorExtraction = mActivityContext.shouldUseColorExtractionForPopup(); - if (shouldUseColorExtraction && Utilities.ATLEAST_S && ENABLE_LOCAL_COLOR_POPUPS.get()) { - mColorExtractors = new ArrayList<>(); - } else { - mColorExtractors = null; - } - - if (shouldUseColorExtraction) { + if (mActivityContext.shouldUseColorExtractionForPopup()) { mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second, R.color.popup_shade_third}; } else { @@ -220,11 +198,6 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> } /** - * Called when all view inflation and reordering in complete. - */ - protected void onInflationComplete(boolean isReversed) { } - - /** * Set the margins and radius of backgrounds after views are properly ordered. */ public void assignMarginsAndBackgrounds(ViewGroup viewGroup) { @@ -271,13 +244,9 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> backgroundColor = colors[numVisibleChild % colors.length]; } - if (!ENABLE_LOCAL_COLOR_POPUPS.get()) { - // Arrow color matches the first child or the last child. - if (!mIsAboveIcon && numVisibleChild == 0 && viewGroup == this) { - mArrowColor = backgroundColor; - } else if (mIsAboveIcon) { - mArrowColor = backgroundColor; - } + // Arrow color matches the first child or the last child. + if (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this)) { + mArrowColor = backgroundColor; } if (view instanceof ViewGroup && mIterateChildrenTag.equals(view.getTag())) { @@ -301,10 +270,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> } } - if (!ENABLE_LOCAL_COLOR_POPUPS.get()) { - setChildColor(view, backgroundColor, colorAnimator); - } - + setChildColor(view, backgroundColor, colorAnimator); numVisibleChild++; } } @@ -320,85 +286,6 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> return view instanceof DeepShortcutView; } - @TargetApi(Build.VERSION_CODES.S) - private int getExtractedColor(SparseIntArray colors) { - int index = Utilities.isDarkTheme(getContext()) - ? DARK_COLOR_EXTRACTION_INDEX - : LIGHT_COLOR_EXTRACTION_INDEX; - return colors.get(index, mBackgroundColor); - } - - protected void addPreDrawForColorExtraction(Launcher launcher) { - getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - getViewTreeObserver().removeOnPreDrawListener(this); - initColorExtractionLocations(launcher); - return true; - } - }); - } - - /** - * Returns list of child views that will receive local color extraction treatment. - * Note: Order should match the view hierarchy. - */ - protected List<View> getChildrenForColorExtraction() { - return Collections.emptyList(); - } - - private void initColorExtractionLocations(Launcher launcher) { - if (mColorExtractors == null) { - return; - } - Workspace<?> workspace = launcher.getWorkspace(); - if (workspace == null) { - return; - } - - boolean firstVisibleChild = true; - int screenId = workspace.getScreenIdForPageIndex(workspace.getCurrentPage()); - DragLayer dragLayer = launcher.getDragLayer(); - - final View[] viewAlignedWithArrow = new View[1]; - - // Order matters here, since we need the arrow to match the color of its adjacent view. - for (final View view : getChildrenForColorExtraction()) { - if (view != null && view.getVisibility() == VISIBLE) { - Rect pos = new Rect(); - dragLayer.getDescendantRectRelativeToSelf(view, pos); - if (!pos.isEmpty()) { - LocalColorExtractor extractor = LocalColorExtractor.newInstance(launcher); - extractor.setWorkspaceLocation(pos, dragLayer, screenId); - extractor.setListener(extractedColors -> { - AnimatorSet colors = new AnimatorSet(); - int newColor = getExtractedColor(extractedColors); - setChildColor(view, newColor, colors); - int numChildren = view instanceof ViewGroup - ? ((ViewGroup) view).getChildCount() : 0; - for (int i = 0; i < numChildren; ++i) { - View childView = ((ViewGroup) view).getChildAt(i); - setChildColor(childView, newColor, colors); - } - if (viewAlignedWithArrow[0] == view) { - mArrowColor = newColor; - updateArrowColor(); - } - colors.setDuration(150); - view.post(colors::start); - }); - mColorExtractors.add(extractor); - - if (mIsAboveIcon || firstVisibleChild) { - viewAlignedWithArrow[0] = view; - } - firstVisibleChild = false; - } - } - } - - } - /** * Sets the background color of the child. */ @@ -425,7 +312,6 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> if (reverseOrder) { reverseOrder(viewsToFlip); } - onInflationComplete(reverseOrder); assignMarginsAndBackgrounds(this); if (shouldAddArrow()) { addArrow(); @@ -438,7 +324,6 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> */ public void show() { setupForDisplay(); - onInflationComplete(false); assignMarginsAndBackgrounds(this); if (shouldAddArrow()) { addArrow(); @@ -819,9 +704,6 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> if (mOnCloseCallback != null) { mOnCloseCallback.run(); } - if (mColorExtractors != null) { - mColorExtractors.forEach(e -> e.setListener(null)); - } } /** diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 8e7a10ca24..4da588e839 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -69,7 +69,6 @@ import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -236,13 +235,6 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext> mPopupItemDragHandler = new LauncherPopupItemDragHandler(launcher, this); mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(launcher); launcher.getDragController().addDragListener(this); - addPreDrawForColorExtraction(launcher); - } - - @Override - protected List<View> getChildrenForColorExtraction() { - return Arrays.asList(mSystemShortcutContainer, mWidgetContainer, mDeepShortcutContainer, - mNotificationContainer); } private void initializeSystemShortcuts(List<SystemShortcut> shortcuts) { diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index 48b3acfbf1..5e97b2dedd 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -36,6 +36,7 @@ import androidx.annotation.NonNull; import com.android.launcher3.AppWidgetsRestoredReceiver; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherProvider.DatabaseHelper; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; @@ -47,6 +48,7 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.LogConfig; +import com.android.launcher3.widget.LauncherWidgetHolder; import java.io.InvalidObjectException; import java.util.Arrays; @@ -85,7 +87,7 @@ public class RestoreDbTask { // Set is pending to false irrespective of the result, so that it doesn't get // executed again. - Utilities.getPrefs(context).edit().remove(RESTORED_DEVICE_TYPE).commit(); + LauncherPrefs.getPrefs(context).edit().remove(RESTORED_DEVICE_TYPE).commit(); idp.reinitializeAfterRestore(context); } @@ -238,7 +240,7 @@ public class RestoreDbTask { } // If restored from a single display backup, remove gaps between screenIds - if (Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE) + if (LauncherPrefs.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE) != TYPE_MULTI_DISPLAY) { removeScreenIdGaps(db); } @@ -337,7 +339,7 @@ public class RestoreDbTask { } public static boolean isPending(Context context) { - return Utilities.getPrefs(context).contains(RESTORED_DEVICE_TYPE); + return LauncherPrefs.getPrefs(context).contains(RESTORED_DEVICE_TYPE); } /** @@ -345,17 +347,20 @@ public class RestoreDbTask { */ public static void setPending(Context context) { FileLog.d(TAG, "Restore data received through full backup "); - Utilities.getPrefs(context).edit() + LauncherPrefs.getPrefs(context).edit() .putInt(RESTORED_DEVICE_TYPE, new DeviceGridState(context).getDeviceType()) .commit(); } private void restoreAppWidgetIdsIfExists(Context context) { - SharedPreferences prefs = Utilities.getPrefs(context); + SharedPreferences prefs = LauncherPrefs.getPrefs(context); if (prefs.contains(APPWIDGET_OLD_IDS) && prefs.contains(APPWIDGET_IDS)) { + LauncherWidgetHolder holder = LauncherWidgetHolder.newInstance(context); AppWidgetsRestoredReceiver.restoreAppWidgetIds(context, IntArray.fromConcatString(prefs.getString(APPWIDGET_OLD_IDS, "")).toArray(), - IntArray.fromConcatString(prefs.getString(APPWIDGET_IDS, "")).toArray()); + IntArray.fromConcatString(prefs.getString(APPWIDGET_IDS, "")).toArray(), + holder); + holder.destroy(); } else { FileLog.d(TAG, "No app widget ids to restore."); } @@ -366,7 +371,7 @@ public class RestoreDbTask { public static void setRestoredAppWidgetIds(Context context, @NonNull int[] oldIds, @NonNull int[] newIds) { - Utilities.getPrefs(context).edit() + LauncherPrefs.getPrefs(context).edit() .putString(APPWIDGET_OLD_IDS, IntArray.wrap(oldIds).toConcatString()) .putString(APPWIDGET_IDS, IntArray.wrap(newIds).toConcatString()) .commit(); diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java index 23ee251772..f2952041f7 100644 --- a/src/com/android/launcher3/qsb/QsbContainerView.java +++ b/src/com/android/launcher3/qsb/QsbContainerView.java @@ -43,8 +43,8 @@ import androidx.annotation.Nullable; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.FragmentWithPreview; import com.android.launcher3.widget.util.WidgetSizes; @@ -200,7 +200,7 @@ public class QsbContainerView extends FrameLayout { Context context = getContext(); AppWidgetManager widgetManager = AppWidgetManager.getInstance(context); - int widgetId = Utilities.getPrefs(context).getInt(mKeyWidgetId, -1); + int widgetId = LauncherPrefs.getPrefs(context).getInt(mKeyWidgetId, -1); AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId); boolean isWidgetBound = (widgetInfo != null) && widgetInfo.provider.equals(mWidgetInfo.provider); @@ -244,7 +244,7 @@ public class QsbContainerView extends FrameLayout { } private void saveWidgetId(int widgetId) { - Utilities.getPrefs(getContext()).edit().putInt(mKeyWidgetId, widgetId).apply(); + LauncherPrefs.getPrefs(getContext()).edit().putInt(mKeyWidgetId, widgetId).apply(); } @Override diff --git a/src/com/android/launcher3/search/SearchCallback.java b/src/com/android/launcher3/search/SearchCallback.java index 495a303a7e..cf7ab1033a 100644 --- a/src/com/android/launcher3/search/SearchCallback.java +++ b/src/com/android/launcher3/search/SearchCallback.java @@ -24,6 +24,11 @@ import java.util.ArrayList; */ public interface SearchCallback<T> { + // Search Result Codes + int UNKNOWN = 0; + int INTERMEDIATE = 1; + int FINAL = 2; + /** * Called when the search from primary source is complete. * @@ -32,6 +37,17 @@ public interface SearchCallback<T> { void onSearchResult(String query, ArrayList<T> items); /** + * Called when the search from primary source is complete. + * + * @param items list of search results + * @param searchResultCode indicates if the result is final or intermediate for a given query + * since we can get search results from multiple sources. + */ + default void onSearchResult(String query, ArrayList<T> items, int searchResultCode) { + onSearchResult(query, items); + } + + /** * Called when the search results should be cleared. */ void clearSearchResult(); diff --git a/src/com/android/launcher3/search/StringMatcherUtility.java b/src/com/android/launcher3/search/StringMatcherUtility.java index acab52bbe8..c66f3a19e4 100644 --- a/src/com/android/launcher3/search/StringMatcherUtility.java +++ b/src/com/android/launcher3/search/StringMatcherUtility.java @@ -24,8 +24,8 @@ import java.text.Collator; public class StringMatcherUtility { /** - * Returns {@code true} is {@code query} is a prefix substring of a complete word/phrase in - * {@code target}. + * Returns {@code true} if {@code query} is a prefix of a substring in {@code target}. How to + * break target to valid substring is defined in the given {@code matcher}. */ public static boolean matches(String query, String target, StringMatcher matcher) { int queryLength = query.length(); @@ -50,7 +50,7 @@ public class StringMatcherUtility { thisType = nextType; nextType = i < (targetLength - 1) ? Character.getType(target.codePointAt(i + 1)) : Character.UNASSIGNED; - if (isBreak(thisType, lastType, nextType) + if (matcher.isBreak(thisType, lastType, nextType) && matcher.matches(query, target.substring(i, i + queryLength))) { return true; } @@ -59,52 +59,6 @@ public class StringMatcherUtility { } /** - * Returns true if the current point should be a break point. Following cases - * are considered as break points: - * 1) Any non space character after a space character - * 2) Any digit after a non-digit character - * 3) Any capital character after a digit or small character - * 4) Any capital character before a small character - */ - private static boolean isBreak(int thisType, int prevType, int nextType) { - switch (prevType) { - case Character.UNASSIGNED: - case Character.SPACE_SEPARATOR: - case Character.LINE_SEPARATOR: - case Character.PARAGRAPH_SEPARATOR: - return true; - } - switch (thisType) { - case Character.UPPERCASE_LETTER: - if (nextType == Character.UPPERCASE_LETTER) { - return true; - } - // Follow through - case Character.TITLECASE_LETTER: - // Break point if previous was not a upper case - return prevType != Character.UPPERCASE_LETTER; - case Character.LOWERCASE_LETTER: - // Break point if previous was not a letter. - return prevType > Character.OTHER_LETTER || prevType <= Character.UNASSIGNED; - case Character.DECIMAL_DIGIT_NUMBER: - case Character.LETTER_NUMBER: - case Character.OTHER_NUMBER: - // Break point if previous was not a number - return !(prevType == Character.DECIMAL_DIGIT_NUMBER - || prevType == Character.LETTER_NUMBER - || prevType == Character.OTHER_NUMBER); - case Character.MATH_SYMBOL: - case Character.CURRENCY_SYMBOL: - case Character.OTHER_PUNCTUATION: - case Character.DASH_PUNCTUATION: - // Always a break point for a symbol - return true; - default: - return false; - } - } - - /** * Performs locale sensitive string comparison using {@link Collator}. */ public static class StringMatcher { @@ -142,6 +96,75 @@ public class StringMatcherUtility { public static StringMatcher getInstance() { return new StringMatcher(); } + + /** + * Returns true if the current point should be a break point. + * + * Following cases are considered as break points: + * 1) Any non space character after a space character + * 2) Any digit after a non-digit character + * 3) Any capital character after a digit or small character + * 4) Any capital character before a small character + * + * E.g., "YouTube" matches the input "you" and "tube", but not "out". + */ + protected boolean isBreak(int thisType, int prevType, int nextType) { + switch (prevType) { + case Character.UNASSIGNED: + case Character.SPACE_SEPARATOR: + case Character.LINE_SEPARATOR: + case Character.PARAGRAPH_SEPARATOR: + return true; + } + switch (thisType) { + case Character.UPPERCASE_LETTER: + if (nextType == Character.UPPERCASE_LETTER) { + return true; + } + // Follow through + case Character.TITLECASE_LETTER: + // Break point if previous was not a upper case + return prevType != Character.UPPERCASE_LETTER; + case Character.LOWERCASE_LETTER: + // Break point if previous was not a letter. + return prevType > Character.OTHER_LETTER || prevType <= Character.UNASSIGNED; + case Character.DECIMAL_DIGIT_NUMBER: + case Character.LETTER_NUMBER: + case Character.OTHER_NUMBER: + // Break point if previous was not a number + return !(prevType == Character.DECIMAL_DIGIT_NUMBER + || prevType == Character.LETTER_NUMBER + || prevType == Character.OTHER_NUMBER); + case Character.MATH_SYMBOL: + case Character.CURRENCY_SYMBOL: + case Character.OTHER_PUNCTUATION: + case Character.DASH_PUNCTUATION: + // Always a break point for a symbol + return true; + default: + return false; + } + } + } + + /** + * Subclass of {@code StringMatcher} using simple space break for prefix matching. + * E.g., "YouTube" matches the input "you". "Play Store" matches the input "play". + */ + public static class StringMatcherSpace extends StringMatcher { + + public static StringMatcherSpace getInstance() { + return new StringMatcherSpace(); + } + + /** + * The first character or any character after a space is considered as a break point. + * Returns true if the current point should be a break point. + */ + @Override + protected boolean isBreak(int thisType, int prevType, int nextType) { + return prevType == Character.UNASSIGNED || prevType == Character.SPACE_SEPARATOR; + } } /** diff --git a/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java b/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java index a0ed77e38f..f03c62ac5c 100644 --- a/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java +++ b/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java @@ -168,15 +168,18 @@ public class PinnedAppsAdapter extends BaseAdapter implements OnSharedPreference mPrefs.unregisterOnSharedPreferenceChangeListener(this); } - private void update(ItemInfo info, Function<ComponentKey, Boolean> op) { + /** + * Pins or unpins apps from home screen + */ + public void update(ItemInfo info, Function<ComponentKey, Boolean> op) { ComponentKey key = new ComponentKey(info.getTargetComponent(), info.user); if (op.apply(key)) { createFilteredAppsList(); Set<ComponentKey> copy = new HashSet<>(mPinnedApps); Executors.MODEL_EXECUTOR.submit(() -> mPrefs.edit().putStringSet(PINNED_APPS_KEY, - copy.stream().map(this::encode).collect(Collectors.toSet())) - .apply()); + copy.stream().map(this::encode).collect(Collectors.toSet())) + .apply()); } } @@ -210,6 +213,13 @@ public class PinnedAppsAdapter extends BaseAdapter implements OnSharedPreference mPinnedApps.contains(new ComponentKey(info.getTargetComponent(), info.user))); } + /** + * Pins app to home screen + */ + public void addPinnedApp(ItemInfo info) { + update(info, mPinnedApps::add); + } + private class PinUnPinShortcut extends SystemShortcut<SecondaryDisplayLauncher> { private final boolean mIsPinned; diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java index a55f7e3b69..a2353d8259 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java @@ -18,6 +18,9 @@ package com.android.launcher3.secondarydisplay; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Intent; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; @@ -26,13 +29,21 @@ import android.view.inputmethod.InputMethodManager; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.BubbleTextView; +import com.android.launcher3.DragSource; +import com.android.launcher3.DropTarget; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.allapps.ActivityAllAppsContainerView; +import com.android.launcher3.dragndrop.DragController; +import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.dragndrop.DraggableView; +import com.android.launcher3.graphics.DragPreviewProvider; +import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.StringCache; import com.android.launcher3.model.data.AppInfo; @@ -40,6 +51,7 @@ import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; +import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.OnboardingPrefs; @@ -52,11 +64,11 @@ import java.util.HashMap; * Launcher activity for secondary displays */ public class SecondaryDisplayLauncher extends BaseDraggingActivity - implements BgDataModel.Callbacks { + implements BgDataModel.Callbacks, DragController.DragListener { private LauncherModel mModel; - private BaseDragLayer mDragLayer; + private SecondaryDragController mDragController; private ActivityAllAppsContainerView<SecondaryDisplayLauncher> mAppsView; private View mAppsButton; @@ -69,11 +81,14 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity private boolean mBindingItems = false; private SecondaryDisplayPredictions mSecondaryDisplayPredictions; + private final int[] mTempXY = new int[2]; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mModel = LauncherAppState.getInstance(this).getModel(); - mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this)); + mDragController = new SecondaryDragController(this); + mOnboardingPrefs = new OnboardingPrefs<>(this, LauncherPrefs.getPrefs(this)); mSecondaryDisplayPredictions = SecondaryDisplayPredictions.newInstance(this); if (getWindow().getDecorView().isAttachedToWindow()) { initUi(); @@ -86,6 +101,12 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity initUi(); } + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + this.getDragController().removeDragListener(this); + } + private void initUi() { if (mDragLayer != null) { return; @@ -106,6 +127,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity mAppsView = findViewById(R.id.apps_view); mAppsButton = findViewById(R.id.all_apps_button); + mDragController.addDragListener(this); mPopupDataProvider = new PopupDataProvider( mAppsView.getAppsStore()::updateNotificationDots); @@ -113,6 +135,12 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity } @Override + protected void onPause() { + super.onPause(); + mDragController.cancelDrag(); + } + + @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -129,12 +157,21 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity showAppDrawer(false); } + public DragController getDragController() { + return mDragController; + } + @Override public void onBackPressed() { if (finishAutoCancelActionMode()) { return; } + if (mDragController.isDragging()) { + mDragController.cancelDrag(); + return; + } + // Note: There should be at most one log per method call. This is enforced implicitly // by using if-else statements. AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this); @@ -202,7 +239,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity float closeR = Themes.getDialogCornerRadius(this); float startR = mAppsButton.getWidth() / 2f; - float[] buttonPos = new float[] { startR, startR}; + float[] buttonPos = new float[]{startR, startR}; mDragLayer.getDescendantCoordRelativeToSelf(mAppsButton, buttonPos); mDragLayer.mapCoordInSelfToDescendant(mAppsView, buttonPos); final Animator animator = ViewAnimationUtils.createCircularReveal(mAppsView, @@ -236,6 +273,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity @Override public void startBinding() { mBindingItems = true; + mDragController.cancelDrag(); } @Override @@ -266,6 +304,10 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity } } + public SecondaryDisplayPredictions getSecondaryDisplayPredictions() { + return mSecondaryDisplayPredictions; + } + @Override public StringCache getStringCache() { return mStringCache; @@ -291,7 +333,9 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity if (v.getWindowToken() == null) return; Object tag = v.getTag(); - if (tag instanceof ItemInfo) { + if (tag instanceof ItemClickProxy) { + ((ItemClickProxy) tag).onItemClicked(v); + } else if (tag instanceof ItemInfo) { ItemInfo item = (ItemInfo) tag; Intent intent; if (item instanceof ItemInfoWithIcon @@ -308,4 +352,101 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity startActivitySafely(v, intent, item); } } + + /** + * Core functionality for beginning a drag operation for an item that will be dropped within + * the secondary display grid home screen + */ + public void beginDragShared(View child, DragSource source, DragOptions options) { + Object dragObject = child.getTag(); + if (!(dragObject instanceof ItemInfo)) { + String msg = "Drag started with a view that has no tag set. This " + + "will cause a crash (issue 11627249) down the line. " + + "View: " + child + " tag: " + child.getTag(); + throw new IllegalStateException(msg); + } + beginDragShared(child, source, (ItemInfo) dragObject, + new DragPreviewProvider(child), options); + } + + private void beginDragShared(View child, DragSource source, + ItemInfo dragObject, DragPreviewProvider previewProvider, DragOptions options) { + + float iconScale = 1f; + if (child instanceof BubbleTextView) { + FastBitmapDrawable icon = ((BubbleTextView) child).getIcon(); + if (icon != null) { + iconScale = icon.getAnimatedScale(); + } + } + + // clear pressed state if necessary + child.clearFocus(); + child.setPressed(false); + if (child instanceof BubbleTextView) { + BubbleTextView icon = (BubbleTextView) child; + icon.clearPressedBackground(); + } + + DraggableView draggableView = null; + if (child instanceof DraggableView) { + draggableView = (DraggableView) child; + } + + final View contentView = previewProvider.getContentView(); + final float scale; + // The draggable drawable follows the touch point around on the screen + final Drawable drawable; + if (contentView == null) { + drawable = previewProvider.createDrawable(); + scale = previewProvider.getScaleAndPosition(drawable, mTempXY); + } else { + drawable = null; + scale = previewProvider.getScaleAndPosition(contentView, mTempXY); + } + int halfPadding = previewProvider.previewPadding / 2; + int dragLayerX = mTempXY[0]; + int dragLayerY = mTempXY[1]; + + Point dragVisualizeOffset = null; + Rect dragRect = new Rect(); + if (draggableView != null) { + draggableView.getSourceVisualDragBounds(dragRect); + dragLayerY += dragRect.top; + dragVisualizeOffset = new Point(-halfPadding, halfPadding); + } + if (contentView != null) { + mDragController.startDrag( + contentView, + draggableView, + dragLayerX, + dragLayerY, + source, + dragObject, + dragVisualizeOffset, + dragRect, + scale * iconScale, + scale, + options); + } else { + mDragController.startDrag( + drawable, + draggableView, + dragLayerX, + dragLayerY, + source, + dragObject, + dragVisualizeOffset, + dragRect, + scale * iconScale, + scale, + options); + } + } + + @Override + public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { } + + @Override + public void onDragEnd() { } } diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java index a58916ad80..21c50d38e8 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java @@ -16,8 +16,10 @@ package com.android.launcher3.secondarydisplay; import android.content.Context; +import android.view.View; import com.android.launcher3.R; +import com.android.launcher3.allapps.ActivityAllAppsContainerView; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.util.ResourceBasedOverride; @@ -45,4 +47,12 @@ public class SecondaryDisplayPredictions implements ResourceBasedOverride { */ public void setPredictedApps(BgDataModel.FixedContainerItems item) { } + + /** + * Set long click listener for predicted apps in top of app drawer. + */ + public void setLongClickListener( + ActivityAllAppsContainerView<?> appsView, + View.OnLongClickListener onIconLongClickListener) { + } } diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java new file mode 100644 index 0000000000..9bf27642ef --- /dev/null +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2022 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.launcher3.secondarydisplay; + +import android.content.res.Resources; +import android.graphics.Point; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.HapticFeedbackConstants; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.DragSource; +import com.android.launcher3.DropTarget; +import com.android.launcher3.R; +import com.android.launcher3.accessibility.DragViewStateAnnouncer; +import com.android.launcher3.dragndrop.DragController; +import com.android.launcher3.dragndrop.DragDriver; +import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.dragndrop.DragView; +import com.android.launcher3.dragndrop.DraggableView; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.testing.shared.TestProtocol; + +/** + * Drag controller for Secondary Launcher activity + */ +public class SecondaryDragController extends DragController<SecondaryDisplayLauncher> { + + private static final boolean PROFILE_DRAWING_DURING_DRAG = false; + + public SecondaryDragController(SecondaryDisplayLauncher secondaryLauncher) { + super(secondaryLauncher); + } + + @Override + protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view, + DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source, + ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale, + float dragViewScaleOnDrop, DragOptions options) { + + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DROP_TARGET, "5"); + } + + if (PROFILE_DRAWING_DURING_DRAG) { + android.os.Debug.startMethodTracing("Launcher"); + } + mActivity.hideKeyboard(); + + mOptions = options; + if (mOptions.simulatedDndStartPoint != null) { + mLastTouch.x = mMotionDown.x = mOptions.simulatedDndStartPoint.x; + mLastTouch.y = mMotionDown.y = mOptions.simulatedDndStartPoint.y; + } + + final int registrationX = mMotionDown.x - dragLayerX; + final int registrationY = mMotionDown.y - dragLayerY; + + final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left; + final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top; + + mLastDropTarget = null; + + mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext()); + mDragObject.originalView = originalView; + + mIsInPreDrag = mOptions.preDragCondition != null + && !mOptions.preDragCondition.shouldStartDrag(0); + + final Resources res = mActivity.getResources(); + final float scaleDps = mIsInPreDrag + ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f; + + final DragView dragView = mDragObject.dragView = drawable != null + ? new SecondaryDragView( + mActivity, + drawable, + registrationX, + registrationY, + initialDragViewScale, + dragViewScaleOnDrop, + scaleDps) + : new SecondaryDragView( + mActivity, + view, + view.getMeasuredWidth(), + view.getMeasuredHeight(), + registrationX, + registrationY, + initialDragViewScale, + dragViewScaleOnDrop, + scaleDps); + dragView.setItemInfo(dragInfo); + mDragObject.dragComplete = false; + + mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft); + mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop); + + mDragDriver = DragDriver.create(this, mOptions, ev -> { + }); + if (!mOptions.isAccessibleDrag) { + mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView); + } + + mDragObject.dragSource = source; + mDragObject.dragInfo = dragInfo; + mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy(); + + if (dragOffset != null) { + dragView.setDragVisualizeOffset(new Point(dragOffset)); + } + if (dragRegion != null) { + dragView.setDragRegion(new Rect(dragRegion)); + } + + mActivity.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + dragView.show(mLastTouch.x, mLastTouch.y); + mDistanceSinceScroll = 0; + + if (!mIsInPreDrag) { + callOnDragStart(); + } else if (mOptions.preDragCondition != null) { + mOptions.preDragCondition.onPreDragStart(mDragObject); + } + + handleMoveEvent(mLastTouch.x, mLastTouch.y); + return dragView; + } + + @Override + protected void exitDrag() { } + + @Override + protected DropTarget getDefaultDropTarget(int[] dropCoordinates) { + DropTarget target = new DropTarget() { + @Override + public boolean isDropEnabled() { + return true; + } + + @Override + public void onDrop(DragObject dragObject, DragOptions options) { + ((SecondaryDragLayer) mActivity.getDragLayer()).getPinnedAppsAdapter().addPinnedApp( + dragObject.dragInfo); + dragObject.dragView.remove(); + } + + @Override + public void onDragEnter(DragObject dragObject) { + if (getDistanceDragged() > mActivity.getResources().getDimensionPixelSize( + R.dimen.drag_distanceThreshold)) { + mActivity.showAppDrawer(false); + AbstractFloatingView.closeAllOpenViews(mActivity); + } + } + + @Override + public void onDragOver(DragObject dragObject) { } + + @Override + public void onDragExit(DragObject dragObject) { } + + @Override + public boolean acceptDrop(DragObject dragObject) { + return true; + } + + @Override + public void prepareAccessibilityDrop() { } + + @Override + public void getHitRectRelativeToDragLayer(Rect outRect) { } + }; + return target; + } +} diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java index c79d70dacc..c8455b8a2b 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java @@ -29,17 +29,23 @@ import android.widget.GridView; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DropTarget; import com.android.launcher3.R; import com.android.launcher3.allapps.ActivityAllAppsContainerView; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; +import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.util.TouchController; import com.android.launcher3.views.BaseDragLayer; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; /** * DragLayer for Secondary launcher @@ -59,7 +65,8 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> @Override public void recreateControllers() { - mControllers = new TouchController[] {new CloseAllAppsTouchController()}; + mControllers = new TouchController[]{new CloseAllAppsTouchController(), + mActivity.getDragController()}; } /** @@ -72,7 +79,8 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> mAppsView = findViewById(R.id.apps_view); mAppsView.setOnIconLongClickListener(this::onIconLongClicked); - + mActivity.getSecondaryDisplayPredictions() + .setLongClickListener(mAppsView, this::onIconLongClicked); // Setup workspace mWorkspace = findViewById(R.id.workspace_grid); mPinnedAppsAdapter = new PinnedAppsAdapter(mActivity, mAppsView.getAppsStore(), @@ -166,6 +174,10 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> } } + public PinnedAppsAdapter getPinnedAppsAdapter() { + return mPinnedAppsAdapter; + } + private boolean onIconLongClicked(View v) { if (!(v instanceof BubbleTextView)) { return false; @@ -183,16 +195,58 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher> if (popupDataProvider == null) { return false; } + + List<SystemShortcut> systemShortcuts = new ArrayList<>(); + + // Hide redundant pin shortcut for app drawer icons if drag-n-drop is enabled. + if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) { + systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v)); + } + systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v)); + final PopupContainerWithArrow container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate( R.layout.popup_container, mActivity.getDragLayer(), false); container.populateAndShow((BubbleTextView) v, popupDataProvider.getShortcutCountForItem(item), - Collections.emptyList(), - Arrays.asList(mPinnedAppsAdapter.getSystemShortcut(item, v), - APP_INFO.getShortcut(mActivity, item, v))); - v.getParent().requestDisallowInterceptTouchEvent(true); + Collections.emptyList(), systemShortcuts); + container.requestFocus(); + + if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) { + return true; + } + + DragOptions options = new DragOptions(); + DeviceProfile grid = mActivity.getDeviceProfile(); + options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx; + options.preDragCondition = container.createPreDragCondition(false); + if (options.preDragCondition == null) { + options.preDragCondition = new DragOptions.PreDragCondition() { + private DragView<SecondaryDisplayLauncher> mDragView; + + @Override + public boolean shouldStartDrag(double distanceDragged) { + return mDragView != null && mDragView.isAnimationFinished(); + } + + @Override + public void onPreDragStart(DropTarget.DragObject dragObject) { + mDragView = dragObject.dragView; + if (!shouldStartDrag(0)) { + mDragView.setOnAnimationEndCallback(() -> { + mActivity.beginDragShared(v, mActivity.getAppsView(), options); + }); + } + } + + @Override + public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) { + mDragView = null; + } + }; + } + mActivity.beginDragShared(v, mActivity.getAppsView(), options); return true; } } diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragView.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragView.java new file mode 100644 index 0000000000..0168b8fc0d --- /dev/null +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragView.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 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.launcher3.secondarydisplay; + +import android.graphics.drawable.Drawable; +import android.view.View; + +import com.android.launcher3.R; +import com.android.launcher3.dragndrop.DragView; + +/** + * A DragView drawn/used by the Secondary Launcher activity. + */ +public class SecondaryDragView extends DragView<SecondaryDisplayLauncher> { + + public SecondaryDragView(SecondaryDisplayLauncher launcher, + Drawable drawable, + int registrationX, int registrationY, float initialScale, float scaleOnDrop, + float finalScaleDps) { + super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop, + finalScaleDps); + } + + public SecondaryDragView(SecondaryDisplayLauncher launcher, View content, int width, int height, + int registrationX, int registrationY, float initialScale, float scaleOnDrop, + float finalScaleDps) { + super(launcher, content, width, height, registrationX, registrationY, initialScale, + scaleOnDrop, finalScaleDps); + } + + @Override + public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) { + Runnable onAnimationEnd = () -> { + if (onCompleteRunnable != null) { + onCompleteRunnable.run(); + } + mActivity.getDragLayer().removeView(this); + }; + + duration = Math.max(duration, + getResources().getInteger(R.integer.config_dropAnimMinDuration)); + + animate() + .translationX(toTouchX - mRegistrationX) + .translationY(toTouchY - mRegistrationY) + .scaleX(mScaleOnDrop) + .scaleY(mScaleOnDrop) + .withEndAction(onAnimationEnd) + .setDuration(duration) + .start(); + } +} diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java index 6057586fca..c81214e67b 100644 --- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java +++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java @@ -59,8 +59,8 @@ import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceViewHolder; import androidx.preference.SwitchPreference; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.config.FlagTogglerPrefUi; import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher; @@ -392,7 +392,8 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { onboardingPref.setTitle(title); onboardingPref.setSummary("Tap to reset"); onboardingPref.setOnPreferenceClickListener(preference -> { - SharedPreferences.Editor sharedPrefsEdit = Utilities.getPrefs(getContext()).edit(); + SharedPreferences.Editor sharedPrefsEdit = LauncherPrefs.getPrefs(getContext()) + .edit(); for (String key : keys) { sharedPrefsEdit.remove(key); } diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java index 49d27b7ed4..7ab3013da1 100644 --- a/src/com/android/launcher3/settings/SettingsActivity.java +++ b/src/com/android/launcher3/settings/SettingsActivity.java @@ -18,6 +18,7 @@ package com.android.launcher3.settings; import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS; +import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD; import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY; import android.content.Intent; @@ -45,12 +46,14 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.states.RotationHelper; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; +import com.android.launcher3.util.DisplayController; import java.util.Collections; import java.util.List; @@ -112,7 +115,8 @@ public class SettingsActivity extends FragmentActivity // Display the fragment as the main content. fm.beginTransaction().replace(R.id.content_frame, f).commit(); } - Utilities.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this); + LauncherPrefs.getPrefs(getApplicationContext()) + .registerOnSharedPreferenceChangeListener(this); } /** @@ -207,7 +211,11 @@ public class SettingsActivity extends FragmentActivity PreferenceScreen screen = getPreferenceScreen(); for (int i = screen.getPreferenceCount() - 1; i >= 0; i--) { Preference preference = screen.getPreference(i); - if (!initPreference(preference)) { + if (initPreference(preference)) { + if (IS_STUDIO_BUILD && preference == mDeveloperOptionPref) { + preference.setOrder(0); + } + } else { screen.removePreference(preference); } } @@ -260,15 +268,14 @@ public class SettingsActivity extends FragmentActivity return !WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS; case ALLOW_ROTATION_PREFERENCE_KEY: - DeviceProfile deviceProfile = InvariantDeviceProfile.INSTANCE.get( - getContext()).getDeviceProfile(getContext()); - if (deviceProfile.isTablet) { + DisplayController.Info info = + DisplayController.INSTANCE.get(getContext()).getInfo(); + if (info.isTablet(info.realBounds)) { // Launcher supports rotation by default. No need to show this setting. return false; } // Initialize the UI once - preference.setDefaultValue( - RotationHelper.getAllowRotationDefaultValue(deviceProfile)); + preference.setDefaultValue(RotationHelper.getAllowRotationDefaultValue(info)); return true; case FLAGS_PREFERENCE_KEY: diff --git a/src/com/android/launcher3/shortcuts/ShortcutRequest.java b/src/com/android/launcher3/shortcuts/ShortcutRequest.java index 07d3292e3e..5291ce4620 100644 --- a/src/com/android/launcher3/shortcuts/ShortcutRequest.java +++ b/src/com/android/launcher3/shortcuts/ShortcutRequest.java @@ -16,7 +16,7 @@ package com.android.launcher3.shortcuts; -import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_SHORTCUTS; +import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS; import android.content.ComponentName; import android.content.Context; @@ -46,7 +46,7 @@ public class ShortcutRequest { | ShortcutQuery.FLAG_MATCH_MANIFEST; public static final int PINNED = ShortcutQuery.FLAG_MATCH_PINNED; - private final ShortcutQuery mQuery = GO_DISABLE_SHORTCUTS ? null : new ShortcutQuery(); + private final ShortcutQuery mQuery = GO_DISABLE_WIDGETS ? null : new ShortcutQuery(); private final Context mContext; private final UserHandle mUserHandle; @@ -73,7 +73,7 @@ public class ShortcutRequest { * @return A list of ShortcutInfo's associated with the given package. */ public ShortcutRequest forPackage(String packageName, @Nullable List<String> shortcutIds) { - if (!GO_DISABLE_SHORTCUTS && packageName != null) { + if (!GO_DISABLE_WIDGETS && packageName != null) { mQuery.setPackage(packageName); mQuery.setShortcutIds(shortcutIds); } @@ -81,7 +81,7 @@ public class ShortcutRequest { } public ShortcutRequest withContainer(@Nullable ComponentName activity) { - if (!GO_DISABLE_SHORTCUTS) { + if (!GO_DISABLE_WIDGETS) { if (activity == null) { mFailed = true; } else { @@ -92,7 +92,7 @@ public class ShortcutRequest { } public QueryResult query(int flags) { - if (GO_DISABLE_SHORTCUTS || mFailed) { + if (GO_DISABLE_WIDGETS || mFailed) { return QueryResult.DEFAULT; } mQuery.setQueryFlags(flags); @@ -108,7 +108,7 @@ public class ShortcutRequest { public static class QueryResult extends ArrayList<ShortcutInfo> { - static final QueryResult DEFAULT = new QueryResult(GO_DISABLE_SHORTCUTS); + static final QueryResult DEFAULT = new QueryResult(GO_DISABLE_WIDGETS); private final boolean mWasSuccess; diff --git a/src/com/android/launcher3/statemanager/BaseState.java b/src/com/android/launcher3/statemanager/BaseState.java index 32378b8384..239042550a 100644 --- a/src/com/android/launcher3/statemanager/BaseState.java +++ b/src/com/android/launcher3/statemanager/BaseState.java @@ -18,7 +18,7 @@ package com.android.launcher3.statemanager; import android.content.Context; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; +import com.android.launcher3.views.ActivityContext; /** * Interface representing a state of a StatefulActivity @@ -37,7 +37,7 @@ public interface BaseState<T extends BaseState> { /** * @return How long the animation to this state should take (or from this state to NORMAL). */ - <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable> + <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext> int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState); /** diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java index 86277a790e..ad1e7f02b5 100644 --- a/src/com/android/launcher3/statemanager/StateManager.java +++ b/src/com/android/launcher3/statemanager/StateManager.java @@ -342,7 +342,6 @@ public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> { public void onAnimationSuccess(Animator animator) { onStateTransitionEnd(state); } - }; } @@ -377,12 +376,16 @@ public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> { } public void moveToRestState() { + moveToRestState(shouldAnimateStateChange()); + } + + public void moveToRestState(boolean isAnimated) { if (mConfig.currentAnimation != null && mConfig.userControlled) { // The user is doing something. Lets not mess it up return; } if (mState.shouldDisableRestore()) { - goToState(getRestState()); + goToState(getRestState(), isAnimated); // Reset history mLastStableState = mBaseState; } diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java index 2a890c3d1f..520f33ca74 100644 --- a/src/com/android/launcher3/statemanager/StatefulActivity.java +++ b/src/com/android/launcher3/statemanager/StatefulActivity.java @@ -231,4 +231,10 @@ public abstract class StatefulActivity<STATE_TYPE extends BaseState<STATE_TYPE>> * etc.) */ protected abstract void onHandleConfigurationChanged(); + + /** + * Enter staged split directly from the current running app. + * @param leftOrTop if the staged split will be positioned left or top. + */ + public void enterStageSplitFromRunningApp(boolean leftOrTop) { } } diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java index b94ea0707b..e5b4ebae1d 100644 --- a/src/com/android/launcher3/states/RotationHelper.java +++ b/src/com/android/launcher3/states/RotationHelper.java @@ -35,8 +35,7 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.android.launcher3.BaseActivity; -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Utilities; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.util.DisplayController; /** @@ -50,11 +49,11 @@ public class RotationHelper implements OnSharedPreferenceChangeListener, /** * Returns the default value of {@link #ALLOW_ROTATION_PREFERENCE_KEY} preference. */ - public static boolean getAllowRotationDefaultValue(DeviceProfile deviceProfile) { + public static boolean getAllowRotationDefaultValue(DisplayController.Info info) { // If the device's pixel density was scaled (usually via settings for A11y), use the // original dimensions to determine if rotation is allowed of not. - float originalSmallestWidth = dpiFromPx( - Math.min(deviceProfile.widthPx, deviceProfile.heightPx), DENSITY_DEVICE_STABLE); + float originalSmallestWidth = dpiFromPx(Math.min(info.currentSize.x, info.currentSize.y), + DENSITY_DEVICE_STABLE); return originalSmallestWidth >= MIN_TABLET_WIDTH; } @@ -99,16 +98,17 @@ public class RotationHelper implements OnSharedPreferenceChangeListener, new Handler(UI_HELPER_EXECUTOR.getLooper(), this::setOrientationAsync); } - private void setIgnoreAutoRotateSettings(boolean ignoreAutoRotateSettings) { + private void setIgnoreAutoRotateSettings(boolean ignoreAutoRotateSettings, + DisplayController.Info info) { // On large devices we do not handle auto-rotate differently. mIgnoreAutoRotateSettings = ignoreAutoRotateSettings; if (!mIgnoreAutoRotateSettings) { if (mSharedPrefs == null) { - mSharedPrefs = Utilities.getPrefs(mActivity); + mSharedPrefs = LauncherPrefs.getPrefs(mActivity); mSharedPrefs.registerOnSharedPreferenceChangeListener(this); } mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, - getAllowRotationDefaultValue(mActivity.getDeviceProfile())); + getAllowRotationDefaultValue(info)); } else { if (mSharedPrefs != null) { mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this); @@ -122,7 +122,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener, if (mDestroyed || mIgnoreAutoRotateSettings) return; boolean wasRotationEnabled = mHomeRotationEnabled; mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, - getAllowRotationDefaultValue(mActivity.getDeviceProfile())); + getAllowRotationDefaultValue(mActivity.getDeviceProfile().getDisplayInfo())); if (mHomeRotationEnabled != wasRotationEnabled) { notifyChange(); } @@ -132,7 +132,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener, public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) { boolean ignoreAutoRotateSettings = info.isTablet(info.realBounds); if (mIgnoreAutoRotateSettings != ignoreAutoRotateSettings) { - setIgnoreAutoRotateSettings(ignoreAutoRotateSettings); + setIgnoreAutoRotateSettings(ignoreAutoRotateSettings, info); notifyChange(); } } @@ -169,7 +169,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener, mInitialized = true; DisplayController displayController = DisplayController.INSTANCE.get(mActivity); DisplayController.Info info = displayController.getInfo(); - setIgnoreAutoRotateSettings(info.isTablet(info.realBounds)); + setIgnoreAutoRotateSettings(info.isTablet(info.realBounds), info); displayController.addChangeListener(this); notifyChange(); } diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java index 3286afb67c..f5d511c7d3 100644 --- a/src/com/android/launcher3/states/SpringLoadedState.java +++ b/src/com/android/launcher3/states/SpringLoadedState.java @@ -15,6 +15,7 @@ */ package com.android.launcher3.states; +import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; import android.content.Context; @@ -44,6 +45,11 @@ public class SpringLoadedState extends LauncherState { @Override public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) { + + if (SHOW_HOME_GARDENING.get()) { + return super.getWorkspaceScaleAndTranslation(launcher); + } + DeviceProfile grid = launcher.getDeviceProfile(); Workspace<?> ws = launcher.getWorkspace(); if (ws.getChildCount() == 0) { @@ -62,6 +68,9 @@ public class SpringLoadedState extends LauncherState { @Override protected float getDepthUnchecked(Context context) { + if (SHOW_HOME_GARDENING.get()) { + return 0; + } return 0.5f; } @@ -72,6 +81,10 @@ public class SpringLoadedState extends LauncherState { @Override public float getWorkspaceBackgroundAlpha(Launcher launcher) { + if (SHOW_HOME_GARDENING.get()) { + return 0; + } + return 0.2f; } } diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 269baf00bb..acb7eb38a2 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -47,7 +47,9 @@ import com.android.launcher3.testing.shared.WorkspaceCellCenterRequest; import com.android.launcher3.util.ResourceBasedOverride; import com.android.launcher3.widget.picker.WidgetsFullSheet; +import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.function.Function; import java.util.function.Supplier; @@ -214,11 +216,15 @@ public class TestInformationHandler implements ResourceBasedOverride { } case TestProtocol.REQUEST_HAS_TIS: { - response.putBoolean( - TestProtocol.REQUEST_HAS_TIS, false); + response.putBoolean(TestProtocol.REQUEST_HAS_TIS, false); return response; } + case TestProtocol.REQUEST_ALL_APPS_TOP_PADDING: { + return getLauncherUIProperty(Bundle::putInt, + l -> l.getAppsView().getActiveRecyclerView().getClipBounds().top); + } + default: return null; } @@ -261,17 +267,24 @@ public class TestInformationHandler implements ResourceBasedOverride { */ private static <S, T> Bundle getUIProperty( BundleSetter<T> bundleSetter, Function<S, T> provider, Supplier<S> targetSupplier) { + return getFromExecutorSync(MAIN_EXECUTOR, () -> { + S target = targetSupplier.get(); + if (target == null) { + return null; + } + T value = provider.apply(target); + Bundle response = new Bundle(); + bundleSetter.set(response, TestProtocol.TEST_INFO_RESPONSE_FIELD, value); + return response; + }); + } + + /** + * Executes the callback on the executor and waits for the result + */ + protected static <T> T getFromExecutorSync(ExecutorService executor, Callable<T> callback) { try { - return MAIN_EXECUTOR.submit(() -> { - S target = targetSupplier.get(); - if (target == null) { - return null; - } - T value = provider.apply(target); - Bundle response = new Bundle(); - bundleSetter.set(response, TestProtocol.TEST_INFO_RESPONSE_FIELD, value); - return response; - }).get(); + return executor.submit(callback).get(); } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } diff --git a/src/com/android/launcher3/testing/shared/TestProtocol.java b/src/com/android/launcher3/testing/shared/TestProtocol.java index 5116b01ba5..f5ee91b297 100644 --- a/src/com/android/launcher3/testing/shared/TestProtocol.java +++ b/src/com/android/launcher3/testing/shared/TestProtocol.java @@ -84,6 +84,10 @@ public final class TestProtocol { public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list"; public static final String REQUEST_ENABLE_MANUAL_TASKBAR_STASHING = "enable-taskbar-stashing"; public static final String REQUEST_DISABLE_MANUAL_TASKBAR_STASHING = "disable-taskbar-stashing"; + public static final String REQUEST_ENABLE_BLOCK_TIMEOUT = "enable-block-timeout"; + public static final String REQUEST_DISABLE_BLOCK_TIMEOUT = "disable-block-timeout"; + public static final String REQUEST_ENABLE_TRANSIENT_TASKBAR = "enable-transient-taskbar"; + public static final String REQUEST_DISABLE_TRANSIENT_TASKBAR = "disable-transient-taskbar"; public static final String REQUEST_UNSTASH_TASKBAR_IF_STASHED = "unstash-taskbar-if-stashed"; public static final String REQUEST_STASHED_TASKBAR_HEIGHT = "stashed-taskbar-height"; public static final String REQUEST_RECREATE_TASKBAR = "recreate-taskbar"; @@ -102,6 +106,7 @@ public final class TestProtocol { public static final String REQUEST_STOP_EVENT_LOGGING = "stop-event-logging"; public static final String REQUEST_CLEAR_DATA = "clear-data"; public static final String REQUEST_USE_TEST_WORKSPACE_LAYOUT = "use-test-workspace-layout"; + public static final String REQUEST_USE_TEST2_WORKSPACE_LAYOUT = "use-test2-workspace-layout"; public static final String REQUEST_USE_DEFAULT_WORKSPACE_LAYOUT = "use-default-workspace-layout"; public static final String REQUEST_HOTSEAT_ICON_NAMES = "get-hotseat-icon-names"; @@ -112,6 +117,9 @@ public final class TestProtocol { "get-activities-created-count"; public static final String REQUEST_GET_ACTIVITIES = "get-activities"; public static final String REQUEST_HAS_TIS = "has-touch-interaction-service"; + public static final String REQUEST_TASKBAR_ALL_APPS_TOP_PADDING = + "taskbar-all-apps-top-padding"; + public static final String REQUEST_ALL_APPS_TOP_PADDING = "all-apps-top-padding"; public static final String REQUEST_WORKSPACE_CELL_LAYOUT_SIZE = "workspace-cell-layout-size"; public static final String REQUEST_WORKSPACE_CELL_CENTER = "workspace-cell-center"; @@ -124,6 +132,8 @@ public final class TestProtocol { "get-grid-task-size-rect-for-tablet"; public static final String REQUEST_GET_OVERVIEW_PAGE_SPACING = "get-overview-page-spacing"; public static final String REQUEST_ENABLE_ROTATION = "enable_rotation"; + public static final String REQUEST_ENABLE_SUGGESTION = "enable-suggestion"; + public static final String REQUEST_MODEL_QUEUE_CLEARED = "model-queue-cleared"; public static boolean sDebugTracing = false; public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing"; @@ -138,7 +148,7 @@ public final class TestProtocol { public static final String NULL_INT_SET = "b/200572078"; public static final String MISSING_PROMISE_ICON = "b/202985412"; public static final String TASKBAR_IN_APP_STATE = "b/227657604"; - public static final String INCORRECT_INFO_UPDATED = "b/239465630"; + public static final String NPE_TRANSIENT_TASKBAR = "b/257549303"; public static final String REQUEST_EMULATE_DISPLAY = "emulate-display"; public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display"; diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index b4be06159a..b7e01057b9 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -17,8 +17,6 @@ package com.android.launcher3.touch; import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET; import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER; @@ -27,10 +25,8 @@ import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SA import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED; import android.app.AlertDialog; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.content.IntentSender; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller.SessionInfo; import android.os.Process; @@ -56,7 +52,6 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.model.data.SearchActionItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.shortcuts.ShortcutKey; @@ -105,8 +100,8 @@ public class ItemClickHandler { if (v instanceof PendingAppWidgetHostView) { onClickPendingWidget((PendingAppWidgetHostView) v, launcher); } - } else if (tag instanceof SearchActionItemInfo) { - onClickSearchAction(launcher, (SearchActionItemInfo) tag); + } else if (tag instanceof ItemClickProxy) { + ((ItemClickProxy) tag).onItemClicked(v); } } @@ -310,42 +305,6 @@ public class ItemClickHandler { startAppShortcutOrInfoActivity(v, shortcut, launcher); } - /** - * Event handler for a {@link SearchActionItemInfo} click - */ - public static void onClickSearchAction(Launcher launcher, SearchActionItemInfo itemInfo) { - if (itemInfo.getIntent() != null) { - if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT)) { - launcher.startActivityForResult(itemInfo.getIntent(), 0); - } else { - launcher.startActivity(itemInfo.getIntent()); - } - } else if (itemInfo.getPendingIntent() != null) { - try { - PendingIntent pendingIntent = itemInfo.getPendingIntent(); - if (!itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START)) { - pendingIntent.send(); - } else if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SHOULD_START_FOR_RESULT)) { - launcher.startIntentSenderForResult(pendingIntent.getIntentSender(), 0, null, 0, - 0, 0); - } else { - launcher.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); - } - } catch (PendingIntent.CanceledException | IntentSender.SendIntentException e) { - Toast.makeText(launcher, - launcher.getResources().getText(R.string.shortcut_not_available), - Toast.LENGTH_SHORT).show(); - } - } - if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SEARCH_IN_APP)) { - launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log( - LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH); - } else { - launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log( - LAUNCHER_APP_LAUNCH_TAP); - } - } - private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity"); @@ -386,4 +345,15 @@ public class ItemClickHandler { } launcher.startActivitySafely(v, intent, item); } + + /** + * Interface to indicate that an item will handle the click itself. + */ + public interface ItemClickProxy { + + /** + * Called when the item is clicked + */ + void onItemClicked(View view); + } } diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index 9afca4f380..097823b078 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -30,6 +30,7 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT; +import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN; import android.content.res.Resources; @@ -265,20 +266,32 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { } @Override - public float getTaskMenuX(float x, View thumbnailView, int overScroll, - DeviceProfile deviceProfile) { - return thumbnailView.getMeasuredWidth() + x; + public float getTaskMenuX(float x, View thumbnailView, + DeviceProfile deviceProfile, float taskInsetMargin) { + return thumbnailView.getMeasuredWidth() + x - taskInsetMargin; } @Override - public float getTaskMenuY(float y, View thumbnailView, int overScroll) { - return y + overScroll + - (thumbnailView.getMeasuredHeight() - thumbnailView.getMeasuredWidth()) / 2f; + public float getTaskMenuY(float y, View thumbnailView, int stagePosition, + View taskMenuView, float taskInsetMargin) { + BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams(); + int taskMenuWidth = lp.width; + if (stagePosition == STAGE_POSITION_UNDEFINED) { + return y + taskInsetMargin + + (thumbnailView.getMeasuredHeight() - taskMenuWidth) / 2f; + } else { + return y + taskInsetMargin; + } } @Override - public int getTaskMenuWidth(View view, DeviceProfile deviceProfile) { - return view.getMeasuredWidth(); + public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile, + @StagePosition int stagePosition) { + if (stagePosition == SplitConfigurationOptions.STAGE_POSITION_UNDEFINED) { + return thumbnailView.getMeasuredWidth(); + } else { + return thumbnailView.getMeasuredHeight(); + } } @Override @@ -300,17 +313,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { } @Override - public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) { - BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams(); - lp.topMargin += margin; - } - - @Override - public PointF getAdditionalInsetForTaskMenu(float margin) { - return new PointF(margin, 0); - } - - @Override public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth, int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile, View[] thumbnailViews, int desiredTaskId, View banner) { @@ -376,19 +378,6 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { return isRtl ? 1 : -1; } - @Override - public void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView, - DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView) { - float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically - ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent) - : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent); - FrameLayout.LayoutParams snapshotParams = - (FrameLayout.LayoutParams) primarySnaphotView.getLayoutParams(); - float additionalOffset = (taskView.getHeight() - snapshotParams.topMargin) - * topLeftTaskPlusDividerPercent; - taskMenuView.setY(taskMenuView.getY() + additionalOffset); - } - /* -------------------- */ @Override @@ -424,8 +413,8 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { // In fake land/seascape, the placeholder always needs to go to the "top" of the device, // which is the same bounds as 0 rotation. int width = dp.widthPx; - int insetThickness = dp.getInsets().top; - out.set(0, 0, width, placeholderHeight + insetThickness); + int insetSizeAdjustment = getPlaceholderSizeAdjustment(dp); + out.set(0, 0, width, placeholderHeight + insetSizeAdjustment); out.inset(placeholderInset, 0); // Adjust the top to account for content off screen. This will help to animate the view in @@ -442,11 +431,19 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { float onScreenRectCenterY, float fullscreenScaleX, float fullscreenScaleY, int drawableWidth, int drawableHeight, DeviceProfile dp, @StagePosition int stagePosition) { - float inset = dp.getInsets().top; - out.setX(Math.round(onScreenRectCenterX / fullscreenScaleX - - 1.0f * drawableWidth / 2)); - out.setY(Math.round((onScreenRectCenterY + (inset / 2f)) / fullscreenScaleY - - 1.0f * drawableHeight / 2)); + float insetAdjustment = getPlaceholderSizeAdjustment(dp) / 2f; + out.setX(onScreenRectCenterX / fullscreenScaleX + - 1.0f * drawableWidth / 2); + out.setY((onScreenRectCenterY + insetAdjustment) / fullscreenScaleY + - 1.0f * drawableHeight / 2); + } + + /** + * The split placeholder comes with a default inset to buffer the icon from the top of the + * screen. But if the device already has a large inset (from cutouts etc), use that instead. + */ + private int getPlaceholderSizeAdjustment(DeviceProfile dp) { + return Math.max(dp.getInsets().top - dp.splitPlaceholderInset, 0); } @Override @@ -504,9 +501,9 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { DeviceProfile dp, boolean isRtl) { int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx; int totalThumbnailHeight = parentHeight - spaceAboveSnapshot; - int dividerBar = splitBoundsConfig.appsStackedVertically - ? (int) (splitBoundsConfig.dividerHeightPercent * parentHeight) - : (int) (splitBoundsConfig.dividerWidthPercent * parentWidth); + int dividerBar = Math.round(totalThumbnailHeight * (splitBoundsConfig.appsStackedVertically + ? splitBoundsConfig.dividerHeightPercent + : splitBoundsConfig.dividerWidthPercent)); int primarySnapshotHeight; int primarySnapshotWidth; int secondarySnapshotHeight; diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java index cbcb70013a..623446288f 100644 --- a/src/com/android/launcher3/touch/PagedOrientationHandler.java +++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java @@ -184,9 +184,12 @@ public interface PagedOrientationHandler { * taskMenu width is the same size as the thumbnail width (what got set below in * getTaskMenuWidth()), so we directly use that in the calculations. */ - float getTaskMenuX(float x, View thumbnailView, int overScroll, DeviceProfile deviceProfile); - float getTaskMenuY(float y, View thumbnailView, int overScroll); - int getTaskMenuWidth(View view, DeviceProfile deviceProfile); + float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile, + float taskInsetMargin); + float getTaskMenuY(float y, View thumbnailView, int stagePosition, + View taskMenuView, float taskInsetMargin); + int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile, + @StagePosition int stagePosition); /** * Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items * inside task menu view. @@ -200,16 +203,6 @@ public interface PagedOrientationHandler { */ void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp, LinearLayout viewGroup, DeviceProfile deviceProfile); - /** - * Adjusts margins for the entire task menu view itself, which comprises of both app title and - * shortcut options. - */ - void setTaskMenuAroundTaskView(LinearLayout taskView, float margin); - /** - * Since the task menu layout is manually positioned on top of recents view, this method returns - * additional adjustments to the positioning based on fake land/seascape - */ - PointF getAdditionalInsetForTaskMenu(float margin); /** * Calculates the position where a Digital Wellbeing Banner should be placed on its parent @@ -231,14 +224,6 @@ public interface PagedOrientationHandler { int getTaskDragDisplacementFactor(boolean isRtl); /** - * Calls the corresponding {@link View#setX(float)} or {@link View#setY(float)} - * on {@param taskMenuView} by taking the space needed by {@param primarySnapshotView} into - * account. - * This is expected to only be called for secondary (bottom/right) tasks. - */ - void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView, - DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView); - /** * Maps the velocity from the coordinate plane of the foreground app to that * of Launcher's (which now will always be portrait) */ diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index bc1b6345b4..316cf0eab1 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -50,12 +50,12 @@ import android.widget.LinearLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.Utilities; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; -import com.android.launcher3.views.BaseDragLayer; import java.util.List; @@ -264,26 +264,28 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { } @Override - public float getTaskMenuX(float x, View thumbnailView, int overScroll, - DeviceProfile deviceProfile) { + public float getTaskMenuX(float x, View thumbnailView, + DeviceProfile deviceProfile, float taskInsetMargin) { if (deviceProfile.isLandscape) { - return x + overScroll + return x + taskInsetMargin + (thumbnailView.getMeasuredWidth() - thumbnailView.getMeasuredHeight()) / 2f; } else { - return x + overScroll; + return x + taskInsetMargin; } } @Override - public float getTaskMenuY(float y, View thumbnailView, int overScroll) { - return y; + public float getTaskMenuY(float y, View thumbnailView, int stagePosition, + View taskMenuView, float taskInsetMargin) { + return y + taskInsetMargin; } @Override - public int getTaskMenuWidth(View view, DeviceProfile deviceProfile) { + public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile, + @StagePosition int stagePosition) { return deviceProfile.isLandscape && !deviceProfile.isTablet - ? view.getMeasuredHeight() - : view.getMeasuredWidth(); + ? thumbnailView.getMeasuredHeight() + : thumbnailView.getMeasuredWidth(); } @Override @@ -304,38 +306,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { } @Override - public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) { - BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams(); - lp.topMargin += margin; - lp.leftMargin += margin; - } - - @Override - public PointF getAdditionalInsetForTaskMenu(float margin) { - return new PointF(0, 0); - } - - @Override - public void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView, - DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView) { - float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically - ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent) - : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent); - FrameLayout.LayoutParams snapshotParams = - (FrameLayout.LayoutParams) primarySnaphotView.getLayoutParams(); - float additionalOffset; - if (deviceProfile.isLandscape) { - additionalOffset = (taskView.getWidth() - snapshotParams.leftMargin) - * topLeftTaskPlusDividerPercent; - taskMenuView.setX(taskMenuView.getX() + additionalOffset); - } else { - additionalOffset = (taskView.getHeight() - snapshotParams.topMargin) - * topLeftTaskPlusDividerPercent; - taskMenuView.setY(taskMenuView.getY() + additionalOffset); - } - } - - @Override public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth, int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile, View[] thumbnailViews, int desiredTaskId, View banner) { @@ -444,13 +414,9 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { int screenWidth = dp.widthPx; int screenHeight = dp.heightPx; boolean pinToRight = stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT; - int insetThickness; - if (!dp.isLandscape) { - insetThickness = dp.getInsets().top; - } else { - insetThickness = pinToRight ? dp.getInsets().right : dp.getInsets().left; - } - out.set(0, 0, screenWidth, placeholderHeight + insetThickness); + int insetSizeAdjustment = getPlaceholderSizeAdjustment(dp, pinToRight); + + out.set(0, 0, screenWidth, placeholderHeight + insetSizeAdjustment); if (!dp.isLandscape) { // portrait, phone or tablet - spans width of screen, nothing else to do out.inset(placeholderInset, 0); @@ -495,25 +461,37 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { int drawableWidth, int drawableHeight, DeviceProfile dp, @StagePosition int stagePosition) { boolean pinToRight = stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT; + float insetAdjustment = getPlaceholderSizeAdjustment(dp, pinToRight) / 2f; if (!dp.isLandscape) { - float inset = dp.getInsets().top; - out.setX(Math.round(onScreenRectCenterX / fullscreenScaleX - - 1.0f * drawableWidth / 2)); - out.setY(Math.round((onScreenRectCenterY + (inset / 2f)) / fullscreenScaleY - - 1.0f * drawableHeight / 2)); + out.setX(onScreenRectCenterX / fullscreenScaleX + - 1.0f * drawableWidth / 2); + out.setY((onScreenRectCenterY + insetAdjustment) / fullscreenScaleY + - 1.0f * drawableHeight / 2); } else { if (pinToRight) { - float inset = dp.getInsets().right; - out.setX(Math.round((onScreenRectCenterX - (inset / 2f)) / fullscreenScaleX - - 1.0f * drawableWidth / 2)); + out.setX((onScreenRectCenterX - insetAdjustment) / fullscreenScaleX + - 1.0f * drawableWidth / 2); } else { - float inset = dp.getInsets().left; - out.setX(Math.round((onScreenRectCenterX + (inset / 2f)) / fullscreenScaleX - - 1.0f * drawableWidth / 2)); + out.setX((onScreenRectCenterX + insetAdjustment) / fullscreenScaleX + - 1.0f * drawableWidth / 2); } - out.setY(Math.round(onScreenRectCenterY / fullscreenScaleY - - 1.0f * drawableHeight / 2)); + out.setY(onScreenRectCenterY / fullscreenScaleY + - 1.0f * drawableHeight / 2); + } + } + + /** + * The split placeholder comes with a default inset to buffer the icon from the top of the + * screen. But if the device already has a large inset (from cutouts etc), use that instead. + */ + private int getPlaceholderSizeAdjustment(DeviceProfile dp, boolean pinToRight) { + int insetThickness; + if (!dp.isLandscape) { + insetThickness = dp.getInsets().top; + } else { + insetThickness = pinToRight ? dp.getInsets().right : dp.getInsets().left; } + return Math.max(insetThickness - dp.splitPlaceholderInset, 0); } @Override @@ -524,7 +502,9 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { out.setRotation(getDegreesRotated()); int distanceToEdge; if ((DisplayController.getNavigationMode(out.getContext()) == THREE_BUTTONS) - && (dp.isTwoPanels || dp.isTablet)) { + && (dp.isTwoPanels || dp.isTablet) + // If taskbar is in overview, overview action has dedicated space above nav buttons + && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) { // If 3-button nav is active, align the splitInstructionsView with it. distanceToEdge = dp.getTaskbarOffsetY() + ((dp.taskbarSize - splitInstructionsHeight) / 2); @@ -561,8 +541,12 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { int insetCorrectionX = (dp.getInsets().right - dp.getInsets().left) / 2; // Adjust for any insets on the bottom edge int insetCorrectionY = dp.getInsets().bottom; + // Adjust for taskbar in overview + int taskbarCorrectionY = + dp.isTaskbarPresent && FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get() + ? dp.taskbarSize : 0; out.setTranslationX(insetCorrectionX + threeButtonNavShift); - out.setTranslationY(-distanceToEdge + insetCorrectionY); + out.setTranslationY(-distanceToEdge + insetCorrectionY - taskbarCorrectionY); FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams(); lp.gravity = CENTER_HORIZONTAL | BOTTOM; out.setLayoutParams(lp); @@ -601,7 +585,6 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { @Override public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, SplitBounds splitInfo, int desiredStagePosition) { - boolean isLandscape = dp.isLandscape; float topLeftTaskPercent = splitInfo.appsStackedVertically ? splitInfo.topTaskPercent : splitInfo.leftTaskPercent; @@ -609,17 +592,25 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { ? splitInfo.dividerHeightPercent : splitInfo.dividerWidthPercent; + int deviceHeightWithoutTaskbar = dp.availableHeightPx - dp.taskbarSize; + float scale = (float) outRect.height() / deviceHeightWithoutTaskbar; + float topTaskHeight = dp.availableHeightPx * topLeftTaskPercent; + float scaledTopTaskHeight = topTaskHeight * scale; + float dividerHeight = dp.availableHeightPx * dividerBarPercent; + float scaledDividerHeight = dividerHeight * scale; + if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) { - if (isLandscape) { - outRect.right = outRect.left + (int) (outRect.width() * topLeftTaskPercent); + if (splitInfo.appsStackedVertically) { + outRect.bottom = Math.round(outRect.top + scaledTopTaskHeight); } else { - outRect.bottom = outRect.top + (int) (outRect.height() * topLeftTaskPercent); + outRect.right = outRect.left + Math.round(outRect.width() * topLeftTaskPercent); } } else { - if (isLandscape) { - outRect.left += (int) (outRect.width() * (topLeftTaskPercent + dividerBarPercent)); + if (splitInfo.appsStackedVertically) { + outRect.top += Math.round(scaledTopTaskHeight + scaledDividerHeight); } else { - outRect.top += (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent)); + outRect.left += Math.round(outRect.width() + * (topLeftTaskPercent + dividerBarPercent)); } } } @@ -630,9 +621,9 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { DeviceProfile dp, boolean isRtl) { int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx; int totalThumbnailHeight = parentHeight - spaceAboveSnapshot; - int dividerBar = splitBoundsConfig.appsStackedVertically - ? (int) (splitBoundsConfig.dividerHeightPercent * parentHeight) - : (int) (splitBoundsConfig.dividerWidthPercent * parentWidth); + int dividerBar = Math.round(splitBoundsConfig.appsStackedVertically + ? splitBoundsConfig.dividerHeightPercent * dp.availableHeightPx + : splitBoundsConfig.dividerWidthPercent * parentWidth); int primarySnapshotHeight; int primarySnapshotWidth; int secondarySnapshotHeight; @@ -641,7 +632,7 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { splitBoundsConfig.topTaskPercent : splitBoundsConfig.leftTaskPercent; if (dp.isLandscape) { primarySnapshotHeight = totalThumbnailHeight; - primarySnapshotWidth = (int) (parentWidth * taskPercent); + primarySnapshotWidth = Math.round(parentWidth * taskPercent); secondarySnapshotHeight = totalThumbnailHeight; secondarySnapshotWidth = parentWidth - primarySnapshotWidth - dividerBar; @@ -655,13 +646,29 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { } secondarySnapshot.setTranslationY(spaceAboveSnapshot); } else { + int deviceHeightWithoutTaskbar = dp.availableHeightPx - dp.taskbarSize; + float scale = (float) totalThumbnailHeight / deviceHeightWithoutTaskbar; + float topTaskHeight = dp.availableHeightPx * taskPercent; + float finalDividerHeight = dividerBar * scale; + float scaledTopTaskHeight = topTaskHeight * scale; primarySnapshotWidth = parentWidth; - primarySnapshotHeight = (int) (totalThumbnailHeight * taskPercent); + primarySnapshotHeight = Math.round(scaledTopTaskHeight); secondarySnapshotWidth = parentWidth; - secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar; - int translationY = primarySnapshotHeight + spaceAboveSnapshot + dividerBar; + secondarySnapshotHeight = Math.round(totalThumbnailHeight - primarySnapshotHeight + - finalDividerHeight); + float translationY = primarySnapshotHeight + spaceAboveSnapshot + finalDividerHeight; secondarySnapshot.setTranslationY(translationY); + + FrameLayout.LayoutParams primaryParams = + (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams(); + FrameLayout.LayoutParams secondaryParams = + (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams(); + secondaryParams.topMargin = 0; + primaryParams.topMargin = spaceAboveSnapshot; + + // Reset unused translations + primarySnapshot.setTranslationY(0); secondarySnapshot.setTranslationX(0); primarySnapshot.setTranslationX(0); } diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java index 55bb5e85e5..05683bd11b 100644 --- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java @@ -24,6 +24,7 @@ import static android.view.Gravity.START; import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; +import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN; import android.content.res.Resources; @@ -33,7 +34,6 @@ import android.util.Pair; import android.view.Surface; import android.view.View; import android.widget.FrameLayout; -import android.widget.LinearLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; @@ -85,26 +85,22 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler { } @Override - public float getTaskMenuX(float x, View thumbnailView, int overScroll, - DeviceProfile deviceProfile) { - return x; + public float getTaskMenuX(float x, View thumbnailView, + DeviceProfile deviceProfile, float taskInsetMargin) { + return x + taskInsetMargin; } @Override - public float getTaskMenuY(float y, View thumbnailView, int overScroll) { - return y + overScroll + - (thumbnailView.getMeasuredHeight() + thumbnailView.getMeasuredWidth()) / 2f; - } - - @Override - public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) { - BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams(); - lp.bottomMargin += margin; - } - - @Override - public PointF getAdditionalInsetForTaskMenu(float margin) { - return new PointF(-margin, margin); + public float getTaskMenuY(float y, View thumbnailView, int stagePosition, + View taskMenuView, float taskInsetMargin) { + BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams(); + int taskMenuWidth = lp.width; + if (stagePosition == STAGE_POSITION_UNDEFINED) { + return y + taskInsetMargin + + (thumbnailView.getMeasuredHeight() + taskMenuWidth) / 2f; + } else { + return y + taskMenuWidth + taskInsetMargin; + } } @Override @@ -121,9 +117,9 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler { // the screen. This is to preserve consistency when the user rotates: From the user's POV, // the primary should always be on the left. if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) { - outRect.top += (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent)); + outRect.top += (int) (outRect.height() * ((1 - topLeftTaskPercent))); } else { - outRect.bottom = outRect.top + (int) (outRect.height() * topLeftTaskPercent); + outRect.bottom -= (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent)); } } @@ -266,6 +262,49 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler { secondaryIconView.setLayoutParams(secondaryIconParams); } + @Override + public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot, + int parentWidth, int parentHeight, SplitBounds splitBoundsConfig, DeviceProfile dp, + boolean isRtl) { + FrameLayout.LayoutParams primaryParams = + (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams(); + FrameLayout.LayoutParams secondaryParams = + (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams(); + + // Swap the margins that are set in TaskView#setRecentsOrientedState() + secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx; + primaryParams.topMargin = 0; + + // Measure and layout the thumbnails bottom up, since the primary is on the visual left + // (portrait bottom) and secondary is on the right (portrait top) + int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx; + int totalThumbnailHeight = parentHeight - spaceAboveSnapshot; + int dividerBar = Math.round(totalThumbnailHeight * (splitBoundsConfig.appsStackedVertically + ? splitBoundsConfig.dividerHeightPercent + : splitBoundsConfig.dividerWidthPercent)); + int primarySnapshotHeight; + int primarySnapshotWidth; + int secondarySnapshotHeight; + int secondarySnapshotWidth; + + float taskPercent = splitBoundsConfig.appsStackedVertically ? + splitBoundsConfig.topTaskPercent : splitBoundsConfig.leftTaskPercent; + primarySnapshotWidth = parentWidth; + primarySnapshotHeight = (int) (totalThumbnailHeight * (taskPercent)); + + secondarySnapshotWidth = parentWidth; + secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar; + secondarySnapshot.setTranslationY(0); + primarySnapshot.setTranslationY(secondarySnapshotHeight + spaceAboveSnapshot + dividerBar); + primarySnapshot.measure( + View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY)); + secondarySnapshot.measure( + View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY), + View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight, + View.MeasureSpec.EXACTLY)); + } + /* ---------- The following are only used by TaskViewTouchHandler. ---------- */ @Override diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java index 6cb021bc42..96ae4a32fd 100644 --- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java +++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java @@ -44,6 +44,7 @@ import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; +import com.android.launcher3.util.TouchUtil; /** * Helper class to handle touch on empty space in workspace and show options popup on long press @@ -105,6 +106,11 @@ public class WorkspaceTouchListener extends GestureDetector.SimpleOnGestureListe if (handleLongPress) { mLongPressState = STATE_REQUESTED; mTouchDownPoint.set(ev.getX(), ev.getY()); + // Mouse right button's ACTION_DOWN should immediately show menu + if (TouchUtil.isMouseRightClickDownOrMove(ev)) { + maybeShowMenu(); + return true; + } } mWorkspace.onTouchEvent(ev); @@ -185,6 +191,10 @@ public class WorkspaceTouchListener extends GestureDetector.SimpleOnGestureListe @Override public void onLongPress(MotionEvent event) { + maybeShowMenu(); + } + + private void maybeShowMenu() { if (mLongPressState == STATE_REQUESTED) { TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Workspace.longPress"); if (canHandleLongPress()) { diff --git a/src/com/android/launcher3/util/BgObjectWithLooper.java b/src/com/android/launcher3/util/BgObjectWithLooper.java index 1483c43a11..adc3c7d885 100644 --- a/src/com/android/launcher3/util/BgObjectWithLooper.java +++ b/src/com/android/launcher3/util/BgObjectWithLooper.java @@ -15,10 +15,15 @@ */ package com.android.launcher3.util; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Handler; import android.os.Looper; import androidx.annotation.WorkerThread; +import java.util.function.Consumer; + /** * Utility class to define an object which does most of it's processing on a * dedicated background thread. @@ -43,4 +48,16 @@ public abstract class BgObjectWithLooper { */ @WorkerThread protected abstract void onInitialized(Looper looper); + + /** + * Helper method to create a content provider + */ + protected static ContentObserver newContentObserver(Handler handler, Consumer<Uri> command) { + return new ContentObserver(handler) { + @Override + public void onChange(boolean selfChange, Uri uri) { + command.accept(uri); + } + }; + } } diff --git a/src/com/android/launcher3/util/DimensionUtils.kt b/src/com/android/launcher3/util/DimensionUtils.kt new file mode 100644 index 0000000000..758b3a962f --- /dev/null +++ b/src/com/android/launcher3/util/DimensionUtils.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 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.launcher3.util + +import android.content.res.Resources +import android.graphics.Point +import android.view.ViewGroup +import com.android.launcher3.DeviceProfile +import com.android.launcher3.R + +object DimensionUtils { + /** + * Point where x is width, and y is height of taskbar based on provided [deviceProfile] + * x or y could also be -1 to indicate there is no dimension specified + */ + @JvmStatic + fun getTaskbarPhoneDimensions(deviceProfile: DeviceProfile, res: Resources, + isPhoneMode: Boolean): Point { + val p = Point() + // Taskbar for large screen + if (!isPhoneMode) { + p.x = ViewGroup.LayoutParams.MATCH_PARENT + p.y = deviceProfile.taskbarSize + return p + } + + // Taskbar on phone using gesture nav, it will always be stashed + if (deviceProfile.isGestureMode) { + p.x = ViewGroup.LayoutParams.MATCH_PARENT + p.y = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size) + return p + } + + // Taskbar on phone, portrait + if (!deviceProfile.isLandscape) { + p.x = ViewGroup.LayoutParams.MATCH_PARENT + p.y = res.getDimensionPixelSize(R.dimen.taskbar_size) + return p + } + + // Taskbar on phone, landscape + p.x = res.getDimensionPixelSize(R.dimen.taskbar_size) + p.y = ViewGroup.LayoutParams.MATCH_PARENT + return p + } +}
\ No newline at end of file diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index e57c88d98c..c52890fd18 100644 --- a/src/com/android/launcher3/util/DisplayController.java +++ b/src/com/android/launcher3/util/DisplayController.java @@ -20,6 +20,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static com.android.launcher3.Utilities.dpiFromPx; +import static com.android.launcher3.config.FeatureFlags.ENABLE_TRANSIENT_TASKBAR; +import static com.android.launcher3.config.FeatureFlags.FORCE_PERSISTENT_TASKBAR; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter; import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH; @@ -41,6 +43,7 @@ import android.view.Display; import androidx.annotation.AnyThread; import androidx.annotation.UiThread; +import androidx.annotation.VisibleForTesting; import com.android.launcher3.Utilities; import com.android.launcher3.util.window.CachedDisplayInfo; @@ -62,6 +65,7 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { private static final String TAG = "DisplayController"; private static final boolean DEBUG = false; + private static boolean sTransientTaskbarStatusForTests; public static final MainThreadInitializedObject<DisplayController> INSTANCE = new MainThreadInitializedObject<>(DisplayController::new); @@ -123,6 +127,37 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { return INSTANCE.get(context).getInfo().navigationMode; } + /** + * Returns whether taskbar is transient. + */ + public static boolean isTransientTaskbar(Context context) { + return INSTANCE.get(context).isTransientTaskbar(); + } + + /** + * Returns whether taskbar is transient. + */ + public boolean isTransientTaskbar() { + // TODO(b/258604917): When running in test harness, use !sTransientTaskbarStatusForTests + // once tests are updated to expect new persistent behavior such as not allowing long press + // to stash. + if (!Utilities.IS_RUNNING_IN_TEST_HARNESS && FORCE_PERSISTENT_TASKBAR.get()) { + return false; + } + return getInfo().navigationMode == NavigationMode.NO_BUTTON + && (Utilities.IS_RUNNING_IN_TEST_HARNESS + ? sTransientTaskbarStatusForTests + : ENABLE_TRANSIENT_TASKBAR.get()); + } + + /** + * Enables transient taskbar status for tests. + */ + @VisibleForTesting + public static void enableTransientTaskbarForTests(boolean enable) { + sTransientTaskbarStatusForTests = enable; + } + @Override public void close() { mDestroyed = true; diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java index ee1d1ff361..5abf95c000 100644 --- a/src/com/android/launcher3/util/LogConfig.java +++ b/src/com/android/launcher3/util/LogConfig.java @@ -50,4 +50,9 @@ public class LogConfig { * When turned on, we enable web suggest appSearch related logging. */ public static final String WEB_APP_SEARCH_LOGGING = "WebAppSearchLogging"; + + /** + * When turned on, we enable quick launch v2 related logging. + */ + public static final String QUICK_LAUNCH_V2 = "QuickLaunchV2"; } diff --git a/src/com/android/launcher3/util/MultiPropertyFactory.java b/src/com/android/launcher3/util/MultiPropertyFactory.java index e7a7785323..f34c4c2451 100644 --- a/src/com/android/launcher3/util/MultiPropertyFactory.java +++ b/src/com/android/launcher3/util/MultiPropertyFactory.java @@ -16,10 +16,13 @@ package com.android.launcher3.util; -import android.util.ArrayMap; +import android.animation.Animator; +import android.animation.ObjectAnimator; import android.util.FloatProperty; import android.util.Log; -import android.util.Property; + +import java.io.PrintWriter; +import java.util.Arrays; /** * Allows to combine multiple values set by several sources. @@ -35,15 +38,30 @@ import android.util.Property; */ public class MultiPropertyFactory<T> { + public static final FloatProperty<MultiPropertyFactory<?>.MultiProperty> MULTI_PROPERTY_VALUE = + new FloatProperty<MultiPropertyFactory<?>.MultiProperty>("value") { + + @Override + public Float get(MultiPropertyFactory<?>.MultiProperty property) { + return property.mValue; + } + + @Override + public void setValue(MultiPropertyFactory<?>.MultiProperty property, float value) { + property.setValue(value); + } + }; + private static final boolean DEBUG = false; private static final String TAG = "MultiPropertyFactory"; - private final String mName; - private final ArrayMap<Integer, MultiProperty> mProperties = new ArrayMap<>(); + private final MultiPropertyFactory<?>.MultiProperty[] mProperties; // This is an optimization for cases when set is called repeatedly with the same setterIndex. private float mAggregationOfOthers = 0f; - private Integer mLastIndexSet = -1; - private final Property<T, Float> mProperty; + private int mLastIndexSet = -1; + + protected final T mTarget; + private final FloatProperty<T> mProperty; private final FloatBiFunction mAggregator; /** @@ -56,72 +74,119 @@ public class MultiPropertyFactory<T> { float apply(float a, float b); } - public MultiPropertyFactory(String name, Property<T, Float> property, + public MultiPropertyFactory(T target, FloatProperty<T> property, int size, FloatBiFunction aggregator) { - mName = name; + this(target, property, size, aggregator, 0); + } + + public MultiPropertyFactory(T target, FloatProperty<T> property, int size, + FloatBiFunction aggregator, float defaultPropertyValue) { + mTarget = target; mProperty = property; mAggregator = aggregator; + + mProperties = new MultiPropertyFactory<?>.MultiProperty[size]; + for (int i = 0; i < size; i++) { + mProperties[i] = new MultiProperty(i, defaultPropertyValue); + } } /** Returns the [MultiFloatProperty] associated with [inx], creating it if not present. */ - public MultiProperty get(Integer index) { - return mProperties.computeIfAbsent(index, - (k) -> new MultiProperty(index, mName + "_" + index)); + public MultiProperty get(int index) { + return (MultiProperty) mProperties[index]; + } + + @Override + public String toString() { + return Arrays.deepToString(mProperties); + } + + /** + * Dumps the alpha channel values to the given PrintWriter + * + * @param prefix String to be used before every line + * @param pw PrintWriter where the logs should be dumped + * @param label String used to help identify this object + * @param alphaIndexLabels Strings that represent each alpha channel, these should be entered + * in the order of the indexes they represent, starting from 0. + */ + public void dump(String prefix, PrintWriter pw, String label, String... alphaIndexLabels) { + pw.println(prefix + label); + + String innerPrefix = prefix + '\t'; + for (int i = 0; i < alphaIndexLabels.length; i++) { + if (i >= mProperties.length) { + pw.println(innerPrefix + alphaIndexLabels[i] + " given for alpha index " + i + + " however there are only " + mProperties.length + " alpha channels."); + continue; + } + pw.println(innerPrefix + alphaIndexLabels[i] + "=" + get(i).getValue()); + } } /** * Each [setValue] will be aggregated with the other properties values created by the * corresponding factory. */ - class MultiProperty extends FloatProperty<T> { + public class MultiProperty { + private final int mInx; - private float mValue = 0f; + private final float mDefaultValue; + private float mValue; - MultiProperty(int inx, String name) { - super(name); + MultiProperty(int inx, float defaultValue) { mInx = inx; + mDefaultValue = defaultValue; + mValue = defaultValue; } - @Override - public void setValue(T obj, float newValue) { + public void setValue(float newValue) { if (mLastIndexSet != mInx) { - mAggregationOfOthers = 0f; - mProperties.forEach((key, property) -> { - if (key != mInx) { + mAggregationOfOthers = mDefaultValue; + for (MultiPropertyFactory<?>.MultiProperty other : mProperties) { + if (other.mInx != mInx) { mAggregationOfOthers = - mAggregator.apply(mAggregationOfOthers, property.mValue); + mAggregator.apply(mAggregationOfOthers, other.mValue); } - }); + } + mLastIndexSet = mInx; } float lastAggregatedValue = mAggregator.apply(mAggregationOfOthers, newValue); mValue = newValue; - apply(obj, lastAggregatedValue); + apply(lastAggregatedValue); if (DEBUG) { - Log.d(TAG, "name=" + mName - + " newValue=" + newValue + " mInx=" + mInx - + " aggregated=" + lastAggregatedValue + " others= " + mProperties); + Log.d(TAG, "name=" + mProperty.getName() + + " target=" + mTarget.getClass() + + " newValue=" + newValue + + " mInx=" + mInx + + " aggregated=" + lastAggregatedValue + + " others= " + Arrays.deepToString(mProperties)); } } - @Override - public Float get(T object) { - // The scale of the view should match mLastAggregatedValue. Still, if it has been - // changed without using this property, it can differ. As this get method is usually - // used to set the starting point on an animation, this would result in some jumps - // when the view scale is different than the last aggregated value. To stay on the - // safe side, let's return the real view scale. - return mProperty.get(object); + public float getValue() { + return mValue; } @Override public String toString() { return String.valueOf(mValue); } + + /** + * Creates and returns an Animator from the current value to the given value. Future + * animator on the same target automatically cancels the previous one. + */ + public Animator animateToValue(float value) { + ObjectAnimator animator = ObjectAnimator.ofFloat(this, MULTI_PROPERTY_VALUE, value); + animator.setAutoCancel(true); + return animator; + } } - protected void apply(T object, float value) { - mProperty.set(object, value); + protected void apply(float value) { + mProperty.set(mTarget, value); } } diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java index 4b46a0a04c..ac016a8595 100644 --- a/src/com/android/launcher3/util/MultiValueAlpha.java +++ b/src/com/android/launcher3/util/MultiValueAlpha.java @@ -16,62 +16,24 @@ package com.android.launcher3.util; -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.util.FloatProperty; +import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA; + import android.view.View; import com.android.launcher3.anim.AlphaUpdateListener; -import java.io.PrintWriter; -import java.util.Arrays; -import java.util.function.Consumer; - /** * Utility class to handle separating a single value as a factor of multiple values */ -public class MultiValueAlpha { - - public static final FloatProperty<AlphaProperty> VALUE = - new FloatProperty<AlphaProperty>("value") { - - @Override - public Float get(AlphaProperty alphaProperty) { - return alphaProperty.mValue; - } - - @Override - public void setValue(AlphaProperty object, float value) { - object.setValue(value); - } - }; +public class MultiValueAlpha extends MultiPropertyFactory<View> { - private final View mView; - private final AlphaProperty[] mMyProperties; + private static final FloatBiFunction ALPHA_AGGREGATOR = (a, b) -> a * b; - private int mValidMask; // Whether we should change from INVISIBLE to VISIBLE and vice versa at low alpha values. private boolean mUpdateVisibility; public MultiValueAlpha(View view, int size) { - mView = view; - mMyProperties = new AlphaProperty[size]; - - mValidMask = 0; - for (int i = 0; i < size; i++) { - int myMask = 1 << i; - mValidMask |= myMask; - mMyProperties[i] = new AlphaProperty(myMask); - } - } - - @Override - public String toString() { - return Arrays.toString(mMyProperties); - } - - public AlphaProperty getProperty(int index) { - return mMyProperties[index]; + super(view, VIEW_ALPHA, size, ALPHA_AGGREGATOR, 1f); } /** Sets whether we should update between INVISIBLE and VISIBLE based on alpha. */ @@ -79,97 +41,11 @@ public class MultiValueAlpha { mUpdateVisibility = updateVisibility; } - /** - * Dumps the alpha channel values to the given PrintWriter - * - * @param prefix String to be used before every line - * @param pw PrintWriter where the logs should be dumped - * @param label String used to help identify this object - * @param alphaIndexLabels Strings that represent each alpha channel, these should be entered - * in the order of the indexes they represent, starting from 0. - */ - public void dump(String prefix, PrintWriter pw, String label, String... alphaIndexLabels) { - pw.println(prefix + label); - - String innerPrefix = prefix + '\t'; - for (int i = 0; i < alphaIndexLabels.length; i++) { - if (i >= mMyProperties.length) { - pw.println(innerPrefix + alphaIndexLabels[i] + " given for alpha index " + i - + " however there are only " + mMyProperties.length + " alpha channels."); - continue; - } - pw.println(innerPrefix + alphaIndexLabels[i] + "=" + getProperty(i).getValue()); - } - } - - public class AlphaProperty { - - private final int mMyMask; - - private float mValue = 1; - // Factor of all other alpha channels, only valid if mMyMask is present in mValidMask. - private float mOthers = 1; - - private Consumer<Float> mConsumer; - - AlphaProperty(int myMask) { - mMyMask = myMask; - } - - public void setValue(float value) { - if (mValue == value) { - return; - } - - if ((mValidMask & mMyMask) == 0) { - // Our cache value is not correct, recompute it. - mOthers = 1; - for (AlphaProperty prop : mMyProperties) { - if (prop != this) { - mOthers *= prop.mValue; - } - } - } - - // Since we have changed our value, all other caches except our own need to be - // recomputed. Change mValidMask to indicate the new valid caches (only our own). - mValidMask = mMyMask; - mValue = value; - - final float alpha = mOthers * mValue; - mView.setAlpha(alpha); - if (mUpdateVisibility) { - AlphaUpdateListener.updateVisibility(mView); - } - if (mConsumer != null) { - mConsumer.accept(mValue); - } - } - - public float getValue() { - return mValue; - } - - public void setConsumer(Consumer<Float> consumer) { - mConsumer = consumer; - if (mConsumer != null) { - mConsumer.accept(mValue); - } - } - - @Override - public String toString() { - return Float.toString(mValue); - } - - /** - * Creates and returns an Animator from the current value to the given value. Future - * animator on the same target automatically cancels the previous one. - */ - public Animator animateToValue(float value) { - ObjectAnimator animator = ObjectAnimator.ofFloat(this, VALUE, value); - animator.setAutoCancel(true); - return animator; + @Override + protected void apply(float value) { + super.apply(value); + if (mUpdateVisibility) { + AlphaUpdateListener.updateVisibility(mTarget); } } } diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java index d942b7a8a5..f4893c7602 100644 --- a/src/com/android/launcher3/util/OnboardingPrefs.java +++ b/src/com/android/launcher3/util/OnboardingPrefs.java @@ -41,7 +41,7 @@ public class OnboardingPrefs<T extends ActivityContext> { public static final String SEARCH_KEYBOARD_EDU_SEEN = "launcher.search_edu_seen"; public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count"; public static final String SEARCH_ONBOARDING_COUNT = "launcher.search_onboarding_count"; - public static final String TASKBAR_EDU_SEEN = "launcher.taskbar_edu_seen"; + public static final String TASKBAR_EDU_SEEN = "launcher.taskbar_edu_seen2"; public static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count"; public static final String QSB_SEARCH_ONBOARDING_CARD_DISMISSED = "launcher.qsb_edu_dismiss"; // When adding a new key, add it here as well, to be able to reset it from Developer Options. diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 12e8b54547..140440eee2 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -16,8 +16,6 @@ package com.android.launcher3.util; -import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; - import android.app.AppOpsManager; import android.content.ActivityNotFoundException; import android.content.ComponentName; @@ -31,7 +29,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.graphics.Rect; import android.net.Uri; import android.os.Build; @@ -40,7 +37,6 @@ import android.os.PatternMatcher; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; -import android.util.Pair; import android.widget.Toast; import androidx.annotation.NonNull; @@ -296,25 +292,6 @@ public class PackageManagerHelper { } /** - * Finds a system apk which had a broadcast receiver listening to a particular action. - * @param action intent action used to find the apk - * @return a pair of apk package name and the resources. - */ - public static Pair<String, Resources> findSystemApk(String action, PackageManager pm) { - final Intent intent = new Intent(action); - for (ResolveInfo info : pm.queryBroadcastReceivers(intent, MATCH_SYSTEM_ONLY)) { - final String packageName = info.activityInfo.packageName; - try { - final Resources res = pm.getResourcesForApplication(packageName); - return Pair.create(packageName, res); - } catch (NameNotFoundException e) { - Log.w(TAG, "Failed to find resources for " + packageName); - } - } - return null; - } - - /** * Returns true if the intent is a valid launch intent for a launcher activity of an app. * This is used to identify shortcuts which are different from the ones exposed by the * applications' manifest file. diff --git a/src/com/android/launcher3/util/Partner.java b/src/com/android/launcher3/util/Partner.java new file mode 100644 index 0000000000..220ab566aa --- /dev/null +++ b/src/com/android/launcher3/util/Partner.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2014 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.launcher3.util; + +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.util.Log; +import android.util.Pair; + +/** + * Utilities to discover and interact with partner customizations. There can + * only be one set of customizations on a device, and it must be bundled with + * the system. + */ +public class Partner { + + static final String TAG = "Launcher.Partner"; + + /** Marker action used to discover partner */ + private static final String + ACTION_PARTNER_CUSTOMIZATION = "com.android.launcher3.action.PARTNER_CUSTOMIZATION"; + + /** + * Find and return partner details, or {@code null} if none exists. + */ + public static Partner get(PackageManager pm) { + return get(pm, ACTION_PARTNER_CUSTOMIZATION); + } + + /** + * Find and return partner details, or {@code null} if none exists. + */ + public static Partner get(PackageManager pm, String action) { + Pair<String, Resources> apkInfo = findSystemApk(action, pm); + return apkInfo != null ? new Partner(apkInfo.first, apkInfo.second) : null; + } + + private final String mPackageName; + private final Resources mResources; + + private Partner(String packageName, Resources res) { + mPackageName = packageName; + mResources = res; + } + + public String getPackageName() { + return mPackageName; + } + + public Resources getResources() { + return mResources; + } + + /** + * Returns the xml resource Id for the provided name, or 0 is the resource is not found + */ + public int getXmlResId(String layoutName) { + return getResources().getIdentifier(layoutName, "xml", getPackageName()); + } + + /** + * Returns the integer resource value for the provided resource name, + * or default value if the resource name is not present + */ + public int getIntValue(String resName, int defaultValue) { + int resId = getResources().getIdentifier(resName, "integer", getPackageName()); + return resId > 0 ? getResources().getInteger(resId) : defaultValue; + } + + /** + * Returns the dimension value for the provided resource name, + * or default value if the resource name is not present + */ + public float getDimenValue(String resName, int defaultValue) { + int resId = getResources().getIdentifier(resName, "dimen", getPackageName()); + return resId > 0 ? getResources().getDimension(resId) : defaultValue; + } + + /** + * Finds a system apk which had a broadcast receiver listening to a particular action. + * @param action intent action used to find the apk + * @return a pair of apk package name and the resources. + */ + private static Pair<String, Resources> findSystemApk(String action, PackageManager pm) { + final Intent intent = new Intent(action); + for (ResolveInfo info : pm.queryBroadcastReceivers(intent, MATCH_SYSTEM_ONLY)) { + final String packageName = info.activityInfo.packageName; + try { + final Resources res = pm.getResourcesForApplication(packageName); + return Pair.create(packageName, res); + } catch (NameNotFoundException e) { + Log.w(TAG, "Failed to find resources for " + packageName); + } + } + return null; + } +} diff --git a/src/com/android/launcher3/util/ScrollableLayoutManager.java b/src/com/android/launcher3/util/ScrollableLayoutManager.java index 17eaefda18..9bc4ddce38 100644 --- a/src/com/android/launcher3/util/ScrollableLayoutManager.java +++ b/src/com/android/launcher3/util/ScrollableLayoutManager.java @@ -44,8 +44,6 @@ public class ScrollableLayoutManager extends GridLayoutManager { * whereas widgets will have strictly increasing values * sample values: 0, 10, 50, 60, 110 */ - - // private int[] mTotalHeightCache = new int[1]; private int mLastValidHeightIndex = 0; @@ -62,16 +60,23 @@ public class ScrollableLayoutManager extends GridLayoutManager { @Override public void layoutDecorated(@NonNull View child, int left, int top, int right, int bottom) { super.layoutDecorated(child, left, top, right, bottom); - mCachedSizes.put( - mRv.getChildViewHolder(child).getItemViewType(), child.getMeasuredHeight()); + updateCachedSize(child); } @Override public void layoutDecoratedWithMargins(@NonNull View child, int left, int top, int right, int bottom) { super.layoutDecoratedWithMargins(child, left, top, right, bottom); - mCachedSizes.put( - mRv.getChildViewHolder(child).getItemViewType(), child.getMeasuredHeight()); + updateCachedSize(child); + } + + private void updateCachedSize(@NonNull View child) { + int viewType = mRv.getChildViewHolder(child).getItemViewType(); + int size = child.getMeasuredHeight(); + if (mCachedSizes.get(viewType, -1) != size) { + invalidateScrollCache(); + } + mCachedSizes.put(viewType, size); } @Override diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java index 79cafa04a2..91cf835287 100644 --- a/src/com/android/launcher3/util/ShortcutUtil.java +++ b/src/com/android/launcher3/util/ShortcutUtil.java @@ -34,7 +34,7 @@ public class ShortcutUtil { * Returns true when we should show depp shortcuts in shortcut menu for the item. */ public static boolean supportsDeepShortcuts(ItemInfo info) { - return isActive(info) && isApp(info) && !WidgetsModel.GO_DISABLE_SHORTCUTS; + return isActive(info) && isApp(info) && !WidgetsModel.GO_DISABLE_WIDGETS; } /** diff --git a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java index 4dfa5ccdeb..0a23506692 100644 --- a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java +++ b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java @@ -52,4 +52,15 @@ public class SimpleBroadcastReceiver extends BroadcastReceiver { } context.registerReceiver(this, filter, flags); } + + /** + * Unregisters the receiver ignoring any errors + */ + public void unregisterReceiverSafely(Context context) { + try { + context.unregisterReceiver(this); + } catch (IllegalArgumentException e) { + // It was probably never registered or already unregistered. Ignore. + } + } } diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java index 88e1b22bab..19a39483e1 100644 --- a/src/com/android/launcher3/util/SplitConfigurationOptions.java +++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java @@ -100,6 +100,7 @@ public final class SplitConfigurationOptions { * with the same name/functionality in wm.shell.util (which launcher3 cannot be built against) * * If you make changes here, consider making the same changes there + * TODO(b/254378592): We really need to consolidate this */ public static class SplitBounds { public final Rect leftTopBounds; @@ -181,4 +182,12 @@ public final class SplitConfigurationOptions { ? LAUNCHER_APP_ICON_MENU_SPLIT_LEFT_TOP : LAUNCHER_APP_ICON_MENU_SPLIT_RIGHT_BOTTOM; } + + public static @StagePosition int getOppositeStagePosition(@StagePosition int position) { + if (position == STAGE_POSITION_UNDEFINED) { + return position; + } + return position == STAGE_POSITION_TOP_OR_LEFT ? STAGE_POSITION_BOTTOM_OR_RIGHT + : STAGE_POSITION_TOP_OR_LEFT; + } } diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java index 1728f4d0d2..585bea93ad 100644 --- a/src/com/android/launcher3/util/Themes.java +++ b/src/com/android/launcher3/util/Themes.java @@ -30,6 +30,7 @@ import android.util.AttributeSet; import android.util.SparseArray; import android.util.TypedValue; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.icons.GraphicsUtils; @@ -73,7 +74,7 @@ public class Themes { * Returns true if workspace icon theming is enabled */ public static boolean isThemedIconEnabled(Context context) { - return Utilities.getPrefs(context).getBoolean(KEY_THEMED_ICONS, false); + return LauncherPrefs.getPrefs(context).getBoolean(KEY_THEMED_ICONS, false); } public static String getDefaultBodyFont(Context context) { diff --git a/src/com/android/launcher3/util/TouchController.java b/src/com/android/launcher3/util/TouchController.java index 9c397c0f74..fc1d819f78 100644 --- a/src/com/android/launcher3/util/TouchController.java +++ b/src/com/android/launcher3/util/TouchController.java @@ -32,10 +32,5 @@ public interface TouchController { */ boolean onControllerInterceptTouchEvent(MotionEvent ev); - /** - * Called when one handed mode state changed - */ - default void onOneHandedModeStateChanged(boolean activated) { } - default void dump(String prefix, PrintWriter writer) { } } diff --git a/src/com/android/launcher3/util/TouchUtil.java b/src/com/android/launcher3/util/TouchUtil.java new file mode 100644 index 0000000000..b18a2ef485 --- /dev/null +++ b/src/com/android/launcher3/util/TouchUtil.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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.launcher3.util; + +import android.view.InputDevice; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; + +/** Util class for touch event. */ +public final class TouchUtil { + + private TouchUtil() {} + + /** + * Detect ACTION_DOWN or ACTION_MOVE from mouse right button. Note that we cannot detect + * ACTION_UP from mouse's right button because, in that case, + * {@link MotionEvent#getButtonState()} returns 0 for any mouse button (right, middle, right). + */ + public static boolean isMouseRightClickDownOrMove(@NonNull MotionEvent event) { + return event.isFromSource(InputDevice.SOURCE_MOUSE) + && ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0); + } +} diff --git a/quickstep/src/com/android/quickstep/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java index 211bd08b33..932bcfc292 100644 --- a/quickstep/src/com/android/quickstep/util/VibratorWrapper.java +++ b/src/com/android/launcher3/util/VibratorWrapper.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.quickstep.util; +package com.android.launcher3.util; import static android.os.VibrationEffect.createPredefined; import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED; @@ -51,8 +51,6 @@ public class VibratorWrapper { public static final VibrationEffect EFFECT_CLICK = createPredefined(VibrationEffect.EFFECT_CLICK); - public static final VibrationEffect EFFECT_TEXTURE_TICK = - VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK); /** * Haptic when entering overview. diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index dd5b22eb84..79b4cb4da4 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -17,44 +17,71 @@ package com.android.launcher3.views; import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; +import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; +import android.app.ActivityOptions; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.ContextWrapper; +import android.content.Intent; +import android.content.pm.LauncherApps; import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.IBinder; +import android.os.Process; +import android.os.StrictMode; +import android.os.UserHandle; +import android.util.Log; +import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.View.AccessibilityDelegate; import android.view.WindowInsets; import android.view.WindowInsetsController; import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; import androidx.annotation.Nullable; +import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.ActivityAllAppsContainerView; -import com.android.launcher3.allapps.search.SearchAdapterProvider; import com.android.launcher3.dot.DotInfo; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.logger.LauncherAtom; +import com.android.launcher3.logging.InstanceId; +import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.StringCache; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupDataProvider; +import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.OnboardingPrefs; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Preconditions; +import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.ViewCache; +import java.util.List; + /** * An interface to be used along with a context for various activities in Launcher. This allows a * generic class to depend on Context subclass instead of an Activity. */ public interface ActivityContext { + String TAG = "ActivityContext"; + default boolean finishAutoCancelActionMode() { return false; } @@ -117,6 +144,28 @@ public interface ActivityContext { DeviceProfile getDeviceProfile(); + /** Registered {@link OnDeviceProfileChangeListener} instances. */ + List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners(); + + /** Notifies listeners of a {@link DeviceProfile} change. */ + default void dispatchDeviceProfileChanged() { + DeviceProfile deviceProfile = getDeviceProfile(); + List<OnDeviceProfileChangeListener> listeners = getOnDeviceProfileChangeListeners(); + for (int i = listeners.size() - 1; i >= 0; i--) { + listeners.get(i).onDeviceProfileChanged(deviceProfile); + } + } + + /** Register listener for {@link DeviceProfile} changes. */ + default void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { + getOnDeviceProfileChangeListeners().add(listener); + } + + /** Unregister listener for {@link DeviceProfile} changes. */ + default void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) { + getOnDeviceProfileChangeListeners().remove(listener); + } + default ViewCache getViewCache() { return new ViewCache(); } @@ -162,32 +211,6 @@ public interface ActivityContext { return false; } - /** - * Returns the ActivityContext associated with the given Context, or throws an exception if - * the Context is not associated with any ActivityContext. - */ - static <T extends Context & ActivityContext> T lookupContext(Context context) { - T activityContext = lookupContextNoThrow(context); - if (activityContext == null) { - throw new IllegalArgumentException("Cannot find ActivityContext in parent tree"); - } - return activityContext; - } - - /** - * Returns the ActivityContext associated with the given Context, or null if - * the Context is not associated with any ActivityContext. - */ - static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) { - if (context instanceof ActivityContext) { - return (T) context; - } else if (context instanceof ContextWrapper) { - return lookupContextNoThrow(((ContextWrapper) context).getBaseContext()); - } else { - return null; - } - } - default View.OnClickListener getItemOnClickListener() { return v -> { // No op. @@ -205,16 +228,6 @@ public interface ActivityContext { } /** - * Creates and returns {@link SearchAdapterProvider} for build variant specific search result - * views. - */ - @Nullable - default SearchAdapterProvider<?> createSearchAdapterProvider( - ActivityAllAppsContainerView<?> appsView) { - return null; - } - - /** * Hides the keyboard if it is visible */ default void hideKeyboard() { @@ -256,4 +269,187 @@ public interface ActivityContext { }); } } + + /** + * Safely starts an activity. + * + * @param v View starting the activity. + * @param intent Base intent being launched. + * @param item Item associated with the view. + * @return {@code true} if the activity starts successfully. + */ + default boolean startActivitySafely( + View v, Intent intent, @Nullable ItemInfo item) { + + Context context = (Context) this; + if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) { + Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show(); + return false; + } + + Bundle optsBundle = (v != null) ? getActivityLaunchOptions(v, item).toBundle() : null; + UserHandle user = item == null ? null : item.user; + + // Prepare intent + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (v != null) { + intent.setSourceBounds(Utilities.getViewBounds(v)); + } + try { + boolean isShortcut = (item instanceof WorkspaceItemInfo) + && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT + || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) + && !((WorkspaceItemInfo) item).isPromise(); + if (isShortcut) { + // Shortcuts need some special checks due to legacy reasons. + startShortcutIntentSafely(intent, optsBundle, item); + } else if (user == null || user.equals(Process.myUserHandle())) { + // Could be launching some bookkeeping activity + context.startActivity(intent, optsBundle); + } else { + context.getSystemService(LauncherApps.class).startMainActivity( + intent.getComponent(), user, intent.getSourceBounds(), optsBundle); + } + if (item != null) { + InstanceId instanceId = new InstanceIdSequence().newInstanceId(); + logAppLaunch(getStatsLogManager(), item, instanceId); + } + return true; + } catch (NullPointerException | ActivityNotFoundException | SecurityException e) { + Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); + Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e); + } + return false; + } + + /** Returns {@code true} if an app launch is blocked due to safe mode. */ + default boolean isAppBlockedForSafeMode() { + return false; + } + + /** + * Creates and logs a new app launch event. + */ + default void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info, + InstanceId instanceId) { + statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId) + .log(LAUNCHER_APP_LAUNCH_TAP); + } + + /** + * Returns launch options for an Activity. + * + * @param v View initiating a launch. + * @param item Item associated with the view. + */ + default ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { + int left = 0, top = 0; + int width = v.getMeasuredWidth(), height = v.getMeasuredHeight(); + if (v instanceof BubbleTextView) { + // Launch from center of icon, not entire view + Drawable icon = ((BubbleTextView) v).getIcon(); + if (icon != null) { + Rect bounds = icon.getBounds(); + left = (width - bounds.width()) / 2; + top = v.getPaddingTop(); + width = bounds.width(); + height = bounds.height(); + } + } + ActivityOptions options = + ActivityOptions.makeClipRevealAnimation(v, left, top, width, height); + + options.setLaunchDisplayId( + (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId() + : Display.DEFAULT_DISPLAY); + RunnableList callback = new RunnableList(); + return new ActivityOptionsWrapper(options, callback); + } + + /** + * Safely launches an intent for a shortcut. + * + * @param intent Intent to start. + * @param optsBundle Optional launch arguments. + * @param info Shortcut information. + */ + default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) { + try { + StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy(); + try { + // Temporarily disable deathPenalty on all default checks. For eg, shortcuts + // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure + // is enabled by default on NYC. + StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll() + .penaltyLog().build()); + + if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { + String id = ((WorkspaceItemInfo) info).getDeepShortcutId(); + String packageName = intent.getPackage(); + startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user); + } else { + // Could be launching some bookkeeping activity + ((Context) this).startActivity(intent, optsBundle); + } + } finally { + StrictMode.setVmPolicy(oldPolicy); + } + } catch (SecurityException e) { + if (!onErrorStartingShortcut(intent, info)) { + throw e; + } + } + } + + /** + * A wrapper around the platform method with Launcher specific checks. + */ + default void startShortcut(String packageName, String id, Rect sourceBounds, + Bundle startActivityOptions, UserHandle user) { + if (GO_DISABLE_WIDGETS) { + return; + } + try { + ((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id, + sourceBounds, startActivityOptions, user); + } catch (SecurityException | IllegalStateException e) { + Log.e(TAG, "Failed to start shortcut", e); + } + } + + /** + * Invoked when a shortcut fails to launch. + * @param intent Shortcut intent that failed to start. + * @param info Shortcut information. + * @return {@code true} if the error is handled by this callback. + */ + default boolean onErrorStartingShortcut(Intent intent, ItemInfo info) { + return false; + } + + /** + * Returns the ActivityContext associated with the given Context, or throws an exception if + * the Context is not associated with any ActivityContext. + */ + static <T extends Context & ActivityContext> T lookupContext(Context context) { + T activityContext = lookupContextNoThrow(context); + if (activityContext == null) { + throw new IllegalArgumentException("Cannot find ActivityContext in parent tree"); + } + return activityContext; + } + + /** + * Returns the ActivityContext associated with the given Context, or null if + * the Context is not associated with any ActivityContext. + */ + static <T extends Context & ActivityContext> T lookupContextNoThrow(Context context) { + if (context instanceof ActivityContext) { + return (T) context; + } else if (context instanceof ContextWrapper) { + return lookupContextNoThrow(((ContextWrapper) context).getBaseContext()); + } else { + return null; + } + } } diff --git a/src/com/android/launcher3/views/AllAppsButton.java b/src/com/android/launcher3/views/AllAppsButton.java deleted file mode 100644 index ab8e5dbff6..0000000000 --- a/src/com/android/launcher3/views/AllAppsButton.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2022 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.launcher3.views; - -import android.content.Context; -import android.graphics.Bitmap; -import android.util.AttributeSet; -import android.view.ContextThemeWrapper; - -import com.android.launcher3.BubbleTextView; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.R; -import com.android.launcher3.icons.FastBitmapDrawable; - -/** - * Button in Taskbar that opens All Apps. - */ -public class AllAppsButton extends BubbleTextView { - - public AllAppsButton(Context context) { - this(context, null); - } - - public AllAppsButton(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public AllAppsButton(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - Context theme = new ContextThemeWrapper(context, R.style.AllAppsButtonTheme); - Bitmap bitmap = LauncherAppState.getInstance(context).getIconCache().getIconFactory() - .createScaledBitmapWithShadow(theme.getDrawable(R.drawable.ic_all_apps_button)); - setIcon(new FastBitmapDrawable(bitmap)); - setContentDescription(context.getString(R.string.all_apps_button_label)); - } -} diff --git a/src/com/android/launcher3/views/AppLauncher.java b/src/com/android/launcher3/views/AppLauncher.java deleted file mode 100644 index dc07e45e11..0000000000 --- a/src/com/android/launcher3/views/AppLauncher.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2022 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.launcher3.views; - -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; -import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_SHORTCUTS; - -import android.app.ActivityOptions; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.content.pm.LauncherApps; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Process; -import android.os.StrictMode; -import android.os.UserHandle; -import android.util.Log; -import android.view.Display; -import android.view.View; -import android.widget.Toast; - -import androidx.annotation.Nullable; - -import com.android.launcher3.BubbleTextView; -import com.android.launcher3.LauncherSettings; -import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.logging.InstanceId; -import com.android.launcher3.logging.InstanceIdSequence; -import com.android.launcher3.logging.StatsLogManager; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.util.ActivityOptionsWrapper; -import com.android.launcher3.util.PackageManagerHelper; -import com.android.launcher3.util.RunnableList; - -/** An {@link ActivityContext} that can also launch app activities and shortcuts safely. */ -public interface AppLauncher extends ActivityContext { - - String TAG = "AppLauncher"; - - /** - * Safely starts an activity. - * - * @param v View starting the activity. - * @param intent Base intent being launched. - * @param item Item associated with the view. - * @return {@code true} if the activity starts successfully. - */ - default boolean startActivitySafely( - View v, Intent intent, @Nullable ItemInfo item) { - - Context context = (Context) this; - if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) { - Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show(); - return false; - } - - Bundle optsBundle = (v != null) ? getActivityLaunchOptions(v, item).toBundle() : null; - UserHandle user = item == null ? null : item.user; - - // Prepare intent - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - if (v != null) { - intent.setSourceBounds(Utilities.getViewBounds(v)); - } - try { - boolean isShortcut = (item instanceof WorkspaceItemInfo) - && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT - || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) - && !((WorkspaceItemInfo) item).isPromise(); - if (isShortcut) { - // Shortcuts need some special checks due to legacy reasons. - startShortcutIntentSafely(intent, optsBundle, item); - } else if (user == null || user.equals(Process.myUserHandle())) { - // Could be launching some bookkeeping activity - context.startActivity(intent, optsBundle); - } else { - context.getSystemService(LauncherApps.class).startMainActivity( - intent.getComponent(), user, intent.getSourceBounds(), optsBundle); - } - if (item != null) { - InstanceId instanceId = new InstanceIdSequence().newInstanceId(); - logAppLaunch(getStatsLogManager(), item, instanceId); - } - return true; - } catch (NullPointerException | ActivityNotFoundException | SecurityException e) { - Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); - Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e); - } - return false; - } - - /** Returns {@code true} if an app launch is blocked due to safe mode. */ - default boolean isAppBlockedForSafeMode() { - return false; - } - - /** - * Creates and logs a new app launch event. - */ - default void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info, - InstanceId instanceId) { - statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId) - .log(LAUNCHER_APP_LAUNCH_TAP); - } - - /** - * Returns launch options for an Activity. - * - * @param v View initiating a launch. - * @param item Item associated with the view. - */ - default ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { - int left = 0, top = 0; - int width = v.getMeasuredWidth(), height = v.getMeasuredHeight(); - if (v instanceof BubbleTextView) { - // Launch from center of icon, not entire view - Drawable icon = ((BubbleTextView) v).getIcon(); - if (icon != null) { - Rect bounds = icon.getBounds(); - left = (width - bounds.width()) / 2; - top = v.getPaddingTop(); - width = bounds.width(); - height = bounds.height(); - } - } - ActivityOptions options = - ActivityOptions.makeClipRevealAnimation(v, left, top, width, height); - - options.setLaunchDisplayId( - (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId() - : Display.DEFAULT_DISPLAY); - RunnableList callback = new RunnableList(); - return new ActivityOptionsWrapper(options, callback); - } - - /** - * Safely launches an intent for a shortcut. - * - * @param intent Intent to start. - * @param optsBundle Optional launch arguments. - * @param info Shortcut information. - */ - default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) { - try { - StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy(); - try { - // Temporarily disable deathPenalty on all default checks. For eg, shortcuts - // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure - // is enabled by default on NYC. - StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll() - .penaltyLog().build()); - - if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) { - String id = ((WorkspaceItemInfo) info).getDeepShortcutId(); - String packageName = intent.getPackage(); - startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user); - } else { - // Could be launching some bookkeeping activity - ((Context) this).startActivity(intent, optsBundle); - } - } finally { - StrictMode.setVmPolicy(oldPolicy); - } - } catch (SecurityException e) { - if (!onErrorStartingShortcut(intent, info)) { - throw e; - } - } - } - - /** - * A wrapper around the platform method with Launcher specific checks. - */ - default void startShortcut(String packageName, String id, Rect sourceBounds, - Bundle startActivityOptions, UserHandle user) { - if (GO_DISABLE_SHORTCUTS) { - return; - } - try { - ((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id, - sourceBounds, startActivityOptions, user); - } catch (SecurityException | IllegalStateException e) { - Log.e(TAG, "Failed to start shortcut", e); - } - } - - /** - * Invoked when a shortcut fails to launch. - * @param intent Shortcut intent that failed to start. - * @param info Shortcut information. - * @return {@code true} if the error is handled by this callback. - */ - default boolean onErrorStartingShortcut(Intent intent, ItemInfo info) { - return false; - } -} diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java index 8d16a8d982..73c5ad457b 100644 --- a/src/com/android/launcher3/views/ArrowTipView.java +++ b/src/com/android/launcher3/views/ArrowTipView.java @@ -162,6 +162,7 @@ public class ArrowTipView extends AbstractFloatingView { params.gravity = gravity; params.leftMargin = mArrowMinOffset + grid.getInsets().left; params.rightMargin = mArrowMinOffset + grid.getInsets().right; + params.width = LayoutParams.MATCH_PARENT; LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mArrowView.getLayoutParams(); lp.gravity = gravity; diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java index 800b1f6ad7..8ff68880a6 100644 --- a/src/com/android/launcher3/views/BaseDragLayer.java +++ b/src/com/android/launcher3/views/BaseDragLayer.java @@ -22,7 +22,6 @@ import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs; -import android.app.WallpaperManager; import android.content.Context; import android.graphics.Insets; import android.graphics.Rect; @@ -41,8 +40,8 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.Utilities; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.launcher3.util.MultiValueAlpha; -import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.TouchController; import java.io.PrintWriter; @@ -108,7 +107,6 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext> protected final T mActivity; private final MultiValueAlpha mMultiValueAlpha; - private final WallpaperManager mWallpaperManager; // All the touch controllers for the view protected TouchController[] mControllers; @@ -121,9 +119,8 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext> public BaseDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) { super(context, attrs); - mActivity = (T) ActivityContext.lookupContext(context); + mActivity = ActivityContext.lookupContext(context); mMultiValueAlpha = new MultiValueAlpha(this, alphaChannelCount); - mWallpaperManager = context.getSystemService(WallpaperManager.class); } /** @@ -502,8 +499,8 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext> return new LayoutParams(p); } - public AlphaProperty getAlphaProperty(int index) { - return mMultiValueAlpha.getProperty(index); + public MultiProperty getAlphaProperty(int index) { + return mMultiValueAlpha.get(index); } public void dump(String prefix, PrintWriter writer) { diff --git a/src/com/android/launcher3/views/IconButtonView.java b/src/com/android/launcher3/views/IconButtonView.java new file mode 100644 index 0000000000..dd48c99c7d --- /dev/null +++ b/src/com/android/launcher3/views/IconButtonView.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 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.launcher3.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BlendMode; +import android.graphics.BlendModeColorFilter; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.AttributeSet; + +import com.android.launcher3.BubbleTextView; +import com.android.launcher3.icons.BaseIconFactory; +import com.android.launcher3.icons.FastBitmapDrawable; +import com.android.launcher3.icons.LauncherIcons; + +/** + * Button in Taskbar that shows a tinted background and foreground. + */ +public class IconButtonView extends BubbleTextView { + + private static final int[] ATTRS = {android.R.attr.icon}; + + public IconButtonView(Context context) { + this(context, null); + } + + public IconButtonView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public IconButtonView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, ATTRS, defStyle, 0); + Drawable fg = a.getDrawable(0); + a.recycle(); + + ColorStateList tintList = getBackgroundTintList(); + int tint = tintList == null ? Color.WHITE : tintList.getDefaultColor(); + + if (fg == null) { + fg = new ColorDrawable(Color.TRANSPARENT); + } + try (BaseIconFactory factory = LauncherIcons.obtain(context)) { + setIcon(new IconDrawable(factory.getWhiteShadowLayer(), tint, fg)); + } + } + + private static class IconDrawable extends FastBitmapDrawable { + + private final Drawable mFg; + + @TargetApi(Build.VERSION_CODES.TIRAMISU) + IconDrawable(Bitmap b, int colorBg, Drawable fg) { + super(b); + mPaint.setColorFilter(new BlendModeColorFilter(colorBg, BlendMode.SRC_IN)); + mFg = fg; + } + + @Override + protected void drawInternal(Canvas canvas, Rect bounds) { + super.drawInternal(canvas, bounds); + mFg.draw(canvas); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + mFg.setBounds(bounds); + } + } +} diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index d30192542f..5b57e22d81 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -15,9 +15,6 @@ */ package com.android.launcher3.views; -import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR; -import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_LAUNCH_SOURCE; -import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS; @@ -51,6 +48,7 @@ import com.android.launcher3.popup.ArrowPopup; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.widget.picker.WidgetsFullSheet; import java.util.ArrayList; @@ -62,6 +60,13 @@ import java.util.List; public class OptionsPopupView extends ArrowPopup<Launcher> implements OnClickListener, OnLongClickListener { + // An intent extra to indicate the horizontal scroll of the wallpaper. + private static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET"; + private static final String EXTRA_WALLPAPER_FLAVOR = "com.android.launcher3.WALLPAPER_FLAVOR"; + // An intent extra to indicate the launch source by launcher. + private static final String EXTRA_WALLPAPER_LAUNCH_SOURCE = + "com.android.wallpaper.LAUNCH_SOURCE"; + private final ArrayMap<View, OptionItem> mItemMap = new ArrayMap<>(); private RectF mTargetRect; private boolean mShouldAddArrow; @@ -134,14 +139,13 @@ public class OptionsPopupView extends ArrowPopup<Launcher> mTargetRect.roundOut(outPos); } - public static OptionsPopupView show( - Launcher launcher, RectF targetRect, List<OptionItem> items, boolean shouldAddArrow) { + public static OptionsPopupView show(ActivityContext launcher, RectF targetRect, + List<OptionItem> items, boolean shouldAddArrow) { return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */); } - public static OptionsPopupView show( - Launcher launcher, RectF targetRect, List<OptionItem> items, boolean shouldAddArrow, - int width) { + public static OptionsPopupView show(ActivityContext launcher, RectF targetRect, + List<OptionItem> items, boolean shouldAddArrow, int width) { OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater() .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false); popup.mTargetRect = targetRect; @@ -160,30 +164,20 @@ public class OptionsPopupView extends ArrowPopup<Launcher> popup.mItemMap.put(view, item); } - popup.addPreDrawForColorExtraction(launcher); popup.show(); return popup; } - @Override - protected List<View> getChildrenForColorExtraction() { - int childCount = getChildCount(); - ArrayList<View> children = new ArrayList<>(childCount); - for (int i = 0; i < childCount; ++i) { - children.add(getChildAt(i)); - } - return children; - } - /** * Returns the list of supported actions */ public static ArrayList<OptionItem> getOptions(Launcher launcher) { ArrayList<OptionItem> options = new ArrayList<>(); - int resString = Utilities.existsStyleWallpapers(launcher) ? - R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text; - int resDrawable = Utilities.existsStyleWallpapers(launcher) ? - R.drawable.ic_palette : R.drawable.ic_wallpaper; + boolean styleWallpaperExists = styleWallpapersExists(launcher); + int resString = styleWallpaperExists + ? R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text; + int resDrawable = styleWallpaperExists + ? R.drawable.ic_palette : R.drawable.ic_wallpaper; options.add(new OptionItem(launcher, resString, resDrawable, @@ -251,7 +245,7 @@ public class OptionsPopupView extends ArrowPopup<Launcher> .putExtra(EXTRA_WALLPAPER_OFFSET, launcher.getWorkspace().getWallpaperOffsetForCenterPage()) .putExtra(EXTRA_WALLPAPER_LAUNCH_SOURCE, "app_launched_launcher"); - if (!Utilities.existsStyleWallpapers(launcher)) { + if (!styleWallpapersExists(launcher)) { intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "wallpaper_only"); } else { intent.putExtra(EXTRA_WALLPAPER_FLAVOR, "focus_wallpaper"); @@ -299,4 +293,9 @@ public class OptionsPopupView extends ArrowPopup<Launcher> this.clickListener = clickListener; } } + + private static boolean styleWallpapersExists(Context context) { + return context.getPackageManager().resolveActivity( + PackageManagerHelper.getStyleWallpapersIntent(context), 0) != null; + } } diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java index e582114fc9..86b341953f 100644 --- a/src/com/android/launcher3/views/Snackbar.java +++ b/src/com/android/launcher3/views/Snackbar.java @@ -31,6 +31,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.compat.AccessibilityManagerCompat; @@ -97,7 +98,11 @@ public class Snackbar extends AbstractFloatingView { dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right, absoluteMaxWidth); params.width = minWidth; - params.setMargins(0, 0, 0, marginBottom + insets.bottom); + DeviceProfile deviceProfile = activity.getDeviceProfile(); + params.setMargins(0, 0, 0, marginBottom + + (deviceProfile.isTaskbarPresent + ? deviceProfile.taskbarSize + deviceProfile.getTaskbarOffsetY() + : insets.bottom)); TextView labelView = snackbar.findViewById(R.id.label); String labelText = res.getString(labelStringResId); diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java index 3e80699f59..9c21ea2bb7 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java @@ -16,281 +16,87 @@ package com.android.launcher3.widget; -import static android.app.Activity.RESULT_CANCELED; +import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID; import android.appwidget.AppWidgetHost; -import android.appwidget.AppWidgetHostView; -import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; -import android.content.ActivityNotFoundException; import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.util.SparseArray; -import android.widget.RemoteViews; -import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.android.launcher3.BaseActivity; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.model.WidgetsModel; -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.testing.TestLogging; -import com.android.launcher3.testing.shared.TestProtocol; -import com.android.launcher3.widget.custom.CustomWidgetManager; import java.util.ArrayList; import java.util.function.IntConsumer; - /** * Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView} * which correctly captures all long-press events. This ensures that users can * always pick up and move widgets. */ -public class LauncherAppWidgetHost extends AppWidgetHost { - - private static final int FLAG_LISTENING = 1; - private static final int FLAG_STATE_IS_NORMAL = 1 << 1; - private static final int FLAG_ACTIVITY_STARTED = 1 << 2; - private static final int FLAG_ACTIVITY_RESUMED = 1 << 3; - private static final int FLAGS_SHOULD_LISTEN = - FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED | FLAG_ACTIVITY_RESUMED; - // TODO(b/191735836): Replace with ActivityOptions.KEY_SPLASH_SCREEN_STYLE when un-hidden - private static final String KEY_SPLASH_SCREEN_STYLE = "android.activity.splashScreenStyle"; - // TODO(b/191735836): Replace with SplashScreen.SPLASH_SCREEN_STYLE_EMPTY when un-hidden - private static final int SPLASH_SCREEN_STYLE_EMPTY = 0; - - public static final int APPWIDGET_HOST_ID = 1024; - - private final ArrayList<ProviderChangedListener> mProviderChangeListeners = new ArrayList<>(); - private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>(); - private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>(); - private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>(); - private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>(); +class LauncherAppWidgetHost extends AppWidgetHost { + @NonNull + private final ArrayList<LauncherWidgetHolder.ProviderChangedListener> + mProviderChangeListeners = new ArrayList<>(); + @NonNull private final Context mContext; - private int mFlags = FLAG_STATE_IS_NORMAL; - private IntConsumer mAppWidgetRemovedCallback = null; + @Nullable + private final IntConsumer mAppWidgetRemovedCallback; - public LauncherAppWidgetHost(Context context) { - this(context, null); - } + @NonNull + private final LauncherWidgetHolder mHolder; - public LauncherAppWidgetHost(Context context, - IntConsumer appWidgetRemovedCallback) { + public LauncherAppWidgetHost(@NonNull Context context, + @Nullable IntConsumer appWidgetRemovedCallback, @NonNull LauncherWidgetHolder holder) { super(context, APPWIDGET_HOST_ID); mContext = context; mAppWidgetRemovedCallback = appWidgetRemovedCallback; - } - - @Override - protected LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId, - AppWidgetProviderInfo appWidget) { - final LauncherAppWidgetHostView view; - if (mPendingViews.get(appWidgetId) != null) { - view = mPendingViews.get(appWidgetId); - mPendingViews.remove(appWidgetId); - } else if (mDeferredViews.get(appWidgetId) != null) { - // In case the widget view is deferred, we will simply return the deferred view as - // opposed to instantiate a new instance of LauncherAppWidgetHostView since launcher - // already added the former to the workspace. - view = mDeferredViews.get(appWidgetId); - } else { - view = new LauncherAppWidgetHostView(context); - } - mViews.put(appWidgetId, view); - return view; - } - - @Override - public void startListening() { - if (WidgetsModel.GO_DISABLE_WIDGETS) { - return; - } - mFlags |= FLAG_LISTENING; - try { - super.startListening(); - } catch (Exception e) { - if (!Utilities.isBinderSizeError(e)) { - throw new RuntimeException(e); - } - // We're willing to let this slide. The exception is being caused by the list of - // RemoteViews which is being passed back. The startListening relationship will - // have been established by this point, and we will end up populating the - // widgets upon bind anyway. See issue 14255011 for more context. - } - - // We go in reverse order and inflate any deferred or cached widget - for (int i = mViews.size() - 1; i >= 0; i--) { - LauncherAppWidgetHostView view = mViews.valueAt(i); - if (view instanceof DeferredAppWidgetHostView) { - view.reInflate(); - } - if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { - final int appWidgetId = mViews.keyAt(i); - if (view == mDeferredViews.get(appWidgetId)) { - // If the widget view was deferred, we'll need to call super.createView here - // to make the binder call to system process to fetch cumulative updates to this - // widget, as well as setting up this view for future updates. - super.createView(view.mLauncher, appWidgetId, view.getAppWidgetInfo()); - // At this point #onCreateView should have been called, which in turn returned - // the deferred view. There's no reason to keep the reference anymore, so we - // removed it here. - mDeferredViews.remove(appWidgetId); - } - } - } - } - - @Override - public void stopListening() { - if (WidgetsModel.GO_DISABLE_WIDGETS) { - return; - } - mFlags &= ~FLAG_LISTENING; - super.stopListening(); - } - - public boolean isListening() { - return (mFlags & FLAG_LISTENING) != 0; - } - - /** - * Sets or unsets a flag the can change whether the widget host should be in the listening - * state. - */ - private void setShouldListenFlag(int flag, boolean on) { - if (on) { - mFlags |= flag; - } else { - mFlags &= ~flag; - } - - final boolean listening = isListening(); - if (!listening && (mFlags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN) { - // Postpone starting listening until all flags are on. - startListening(); - } else if (listening && (mFlags & FLAG_ACTIVITY_STARTED) == 0) { - // Postpone stopping listening until the activity is stopped. - stopListening(); - } - } - - /** - * Registers an "entering/leaving Normal state" event. - */ - public void setStateIsNormal(boolean isNormal) { - setShouldListenFlag(FLAG_STATE_IS_NORMAL, isNormal); + mHolder = holder; } /** - * Registers an "activity started/stopped" event. + * Add a listener that is triggered when the providers of the widgets are changed + * @param listener The listener that notifies when the providers changed */ - public void setActivityStarted(boolean isStarted) { - setShouldListenFlag(FLAG_ACTIVITY_STARTED, isStarted); + public void addProviderChangeListener( + @NonNull LauncherWidgetHolder.ProviderChangedListener listener) { + mProviderChangeListeners.add(listener); } /** - * Registers an "activity paused/resumed" event. + * Remove the specified listener from the host + * @param listener The listener that is to be removed from the host */ - public void setActivityResumed(boolean isResumed) { - setShouldListenFlag(FLAG_ACTIVITY_RESUMED, isResumed); + public void removeProviderChangeListener( + LauncherWidgetHolder.ProviderChangedListener listener) { + mProviderChangeListeners.remove(listener); } @Override - public int allocateAppWidgetId() { - if (WidgetsModel.GO_DISABLE_WIDGETS) { - return AppWidgetManager.INVALID_APPWIDGET_ID; - } - - return super.allocateAppWidgetId(); - } - - public void addProviderChangeListener(ProviderChangedListener callback) { - mProviderChangeListeners.add(callback); - } - - public void removeProviderChangeListener(ProviderChangedListener callback) { - mProviderChangeListeners.remove(callback); - } - protected void onProvidersChanged() { if (!mProviderChangeListeners.isEmpty()) { - for (ProviderChangedListener callback : new ArrayList<>(mProviderChangeListeners)) { + for (LauncherWidgetHolder.ProviderChangedListener callback : + new ArrayList<>(mProviderChangeListeners)) { callback.notifyWidgetProvidersChanged(); } } } - public void addPendingView(int appWidgetId, PendingAppWidgetHostView view) { - mPendingViews.put(appWidgetId, view); - } - - public AppWidgetHostView createView(Context context, int appWidgetId, - LauncherAppWidgetProviderInfo appWidget) { - if (appWidget.isCustomWidget()) { - LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context); - lahv.setAppWidget(0, appWidget); - CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv); - return lahv; - } else if ((mFlags & FLAG_LISTENING) == 0) { - // Since the launcher hasn't started listening to widget updates, we can't simply call - // super.createView here because the later will make a binder call to retrieve - // RemoteViews from system process. - // TODO: have launcher always listens to widget updates in background so that this - // check can be removed altogether. - if (FeatureFlags.ENABLE_CACHED_WIDGET.get() - && mCachedRemoteViews.get(appWidgetId) != null) { - // We've found RemoteViews from cache for this widget, so we will instantiate a - // widget host view and populate it with the cached RemoteViews. - final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context); - view.setAppWidget(appWidgetId, appWidget); - view.updateAppWidget(mCachedRemoteViews.get(appWidgetId)); - mDeferredViews.put(appWidgetId, view); - mViews.put(appWidgetId, view); - return view; - } else { - // When cache misses, a placeholder for the widget will be returned instead. - DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context); - view.setAppWidget(appWidgetId, appWidget); - mViews.put(appWidgetId, view); - return view; - } - } else { - try { - return super.createView(context, appWidgetId, appWidget); - } catch (Exception e) { - if (!Utilities.isBinderSizeError(e)) { - throw new RuntimeException(e); - } - - // If the exception was thrown while fetching the remote views, let the view stay. - // This will ensure that if the widget posts a valid update later, the view - // will update. - LauncherAppWidgetHostView view = mViews.get(appWidgetId); - if (view == null) { - view = onCreateView(mContext, appWidgetId, appWidget); - } - view.setAppWidget(appWidgetId, appWidget); - view.switchToErrorView(); - return view; - } - } + @Override + @NonNull + public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId, + AppWidgetProviderInfo appWidget) { + return mHolder.onCreateView(context, appWidgetId, appWidget); } /** * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk. */ @Override - protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) { + protected void onProviderChanged(int appWidgetId, @NonNull AppWidgetProviderInfo appWidget) { LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo.fromProviderInfo( mContext, appWidget); super.onProviderChanged(appWidgetId, info); @@ -304,6 +110,7 @@ public class LauncherAppWidgetHost extends AppWidgetHost { * * @param appWidgetId TODO: make this override when SDK is updated */ + @Override public void onAppWidgetRemoved(int appWidgetId) { if (mAppWidgetRemovedCallback == null) { return; @@ -311,92 +118,12 @@ public class LauncherAppWidgetHost extends AppWidgetHost { mAppWidgetRemovedCallback.accept(appWidgetId); } - @Override - public void deleteAppWidgetId(int appWidgetId) { - super.deleteAppWidgetId(appWidgetId); - mViews.remove(appWidgetId); - } - + /** + * The same as super.clearViews(), except with the scope exposed + */ @Override public void clearViews() { super.clearViews(); - if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { - // First, we clear any previously cached content from existing widgets - mCachedRemoteViews.clear(); - mDeferredViews.clear(); - // Then we proceed to cache the content from the widgets - for (int i = 0; i < mViews.size(); i++) { - final int appWidgetId = mViews.keyAt(i); - final LauncherAppWidgetHostView view = mViews.get(appWidgetId); - mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews); - } - } - mViews.clear(); - } - - public void startBindFlow(BaseActivity activity, - int appWidgetId, AppWidgetProviderInfo info, int requestCode) { - - if (WidgetsModel.GO_DISABLE_WIDGETS) { - sendActionCancelled(activity, requestCode); - return; - } - - Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND) - .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) - .putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.provider) - .putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE, info.getProfile()); - // TODO: we need to make sure that this accounts for the options bundle. - // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options); - activity.startActivityForResult(intent, requestCode); - } - - /** - * Launches an app widget's configuration activity. - * @param activity The activity from which to launch the configuration activity - * @param widgetId The id of the bound app widget to be configured - * @param requestCode An optional request code to be returned with the result - */ - public void startConfigActivity(BaseDraggingActivity activity, int widgetId, int requestCode) { - if (WidgetsModel.GO_DISABLE_WIDGETS) { - sendActionCancelled(activity, requestCode); - return; - } - - try { - TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: startConfigActivity"); - startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, - getConfigurationActivityOptions(activity, widgetId)); - } catch (ActivityNotFoundException | SecurityException e) { - Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); - sendActionCancelled(activity, requestCode); - } } - /** - * Returns an {@link android.app.ActivityOptions} bundle from the {code activity} for launching - * the configuration of the {@code widgetId} app widget, or null of options cannot be produced. - */ - @Nullable - private Bundle getConfigurationActivityOptions(BaseDraggingActivity activity, int widgetId) { - LauncherAppWidgetHostView view = mViews.get(widgetId); - if (view == null) return null; - Object tag = view.getTag(); - if (!(tag instanceof ItemInfo)) return null; - Bundle bundle = activity.getActivityLaunchOptions(view, (ItemInfo) tag).toBundle(); - bundle.putInt(KEY_SPLASH_SCREEN_STYLE, SPLASH_SCREEN_STYLE_EMPTY); - return bundle; - } - - private void sendActionCancelled(final BaseActivity activity, final int requestCode) { - new Handler().post(() -> activity.onActivityResult(requestCode, RESULT_CANCELED, null)); - } - - /** - * Listener for getting notifications on provider changes. - */ - public interface ProviderChangedListener { - - void notifyWidgetProvidersChanged(); - } } diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index fc1e880373..bc3889fd26 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -92,10 +92,6 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView // The following member variables are only used during drag-n-drop. private boolean mIsInDragMode = false; - /** The drag content width which is only set when the drag content scale is not 1f. */ - private int mDragContentWidth = 0; - /** The drag content height which is only set when the drag content scale is not 1f. */ - private int mDragContentHeight = 0; private boolean mTrackingWidgetUpdate = false; @@ -314,27 +310,9 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView } } - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (mIsInDragMode && mDragContentWidth > 0 && mDragContentHeight > 0 - && getChildCount() == 1) { - measureChild(getChildAt(0), MeasureSpec.getSize(mDragContentWidth), - MeasureSpec.getSize(mDragContentHeight)); - } - } - /** Starts the drag mode. */ public void startDrag() { mIsInDragMode = true; - // In the case of dragging a scaled preview from widgets picker, we should reuse the - // previously measured dimension from WidgetCell#measureAndComputeWidgetPreviewScale, which - // measures the dimension of a widget preview without its parent's bound before scaling - // down. - if ((getScaleX() != 1f || getScaleY() != 1f) && getChildCount() == 1) { - mDragContentWidth = getChildAt(0).getMeasuredWidth(); - mDragContentHeight = getChildAt(0).getMeasuredHeight(); - } } /** Handles a drag event occurred on a workspace page corresponding to the {@code screenId}. */ @@ -347,8 +325,6 @@ public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView /** Ends the drag mode. */ public void endDrag() { mIsInDragMode = false; - mDragContentWidth = 0; - mDragContentHeight = 0; requestLayout(); } diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java new file mode 100644 index 0000000000..d7235ade3c --- /dev/null +++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java @@ -0,0 +1,508 @@ +/** + * Copyright (C) 2022 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.launcher3.widget; + +import static android.app.Activity.RESULT_CANCELED; + +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + +import android.appwidget.AppWidgetHost; +import android.appwidget.AppWidgetHostView; +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.SparseArray; +import android.widget.RemoteViews; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.launcher3.BaseActivity; +import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.model.WidgetsModel; +import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.testing.TestLogging; +import com.android.launcher3.testing.shared.TestProtocol; +import com.android.launcher3.util.ResourceBasedOverride; +import com.android.launcher3.widget.custom.CustomWidgetManager; + +import java.util.function.IntConsumer; + +/** + * A wrapper for LauncherAppWidgetHost. This class is created so the AppWidgetHost could run in + * background. + */ +public class LauncherWidgetHolder { + public static final int APPWIDGET_HOST_ID = 1024; + + private static final int FLAG_LISTENING = 1; + private static final int FLAG_STATE_IS_NORMAL = 1 << 1; + private static final int FLAG_ACTIVITY_STARTED = 1 << 2; + private static final int FLAG_ACTIVITY_RESUMED = 1 << 3; + private static final int FLAGS_SHOULD_LISTEN = + FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED | FLAG_ACTIVITY_RESUMED; + + @NonNull + private final Context mContext; + + @NonNull + private final AppWidgetHost mWidgetHost; + + @NonNull + private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>(); + @NonNull + private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>(); + @NonNull + private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>(); + @NonNull + private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>(); + + private int mFlags = FLAG_STATE_IS_NORMAL; + + // TODO(b/191735836): Replace with ActivityOptions.KEY_SPLASH_SCREEN_STYLE when un-hidden + private static final String KEY_SPLASH_SCREEN_STYLE = "android.activity.splashScreenStyle"; + // TODO(b/191735836): Replace with SplashScreen.SPLASH_SCREEN_STYLE_EMPTY when un-hidden + private static final int SPLASH_SCREEN_STYLE_EMPTY = 0; + + protected LauncherWidgetHolder(@NonNull Context context, + @Nullable IntConsumer appWidgetRemovedCallback) { + mContext = context; + mWidgetHost = createHost(context, appWidgetRemovedCallback); + } + + protected AppWidgetHost createHost( + Context context, @Nullable IntConsumer appWidgetRemovedCallback) { + return new LauncherAppWidgetHost(context, appWidgetRemovedCallback, this); + } + + /** + * Starts listening to the widget updates from the server side + */ + public void startListening() { + if (WidgetsModel.GO_DISABLE_WIDGETS) { + return; + } + setListeningFlag(true); + try { + mWidgetHost.startListening(); + } catch (Exception e) { + if (!Utilities.isBinderSizeError(e)) { + throw new RuntimeException(e); + } + // We're willing to let this slide. The exception is being caused by the list of + // RemoteViews which is being passed back. The startListening relationship will + // have been established by this point, and we will end up populating the + // widgets upon bind anyway. See issue 14255011 for more context. + } + + // We go in reverse order and inflate any deferred or cached widget + for (int i = mViews.size() - 1; i >= 0; i--) { + LauncherAppWidgetHostView view = mViews.valueAt(i); + if (view instanceof DeferredAppWidgetHostView) { + view.reInflate(); + } + if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { + final int appWidgetId = mViews.keyAt(i); + if (view == mDeferredViews.get(appWidgetId)) { + // If the widget view was deferred, we'll need to call super.createView here + // to make the binder call to system process to fetch cumulative updates to this + // widget, as well as setting up this view for future updates. + mWidgetHost.createView(view.mLauncher, appWidgetId, + view.getAppWidgetInfo()); + // At this point #onCreateView should have been called, which in turn returned + // the deferred view. There's no reason to keep the reference anymore, so we + // removed it here. + mDeferredViews.remove(appWidgetId); + } + } + } + } + + /** + * Registers an "activity started/stopped" event. + */ + public void setActivityStarted(boolean isStarted) { + setShouldListenFlag(FLAG_ACTIVITY_STARTED, isStarted); + } + + /** + * Registers an "activity paused/resumed" event. + */ + public void setActivityResumed(boolean isResumed) { + setShouldListenFlag(FLAG_ACTIVITY_RESUMED, isResumed); + } + + /** + * Set the NORMAL state of the widget host + * @param isNormal True if setting the host to be in normal state, false otherwise + */ + public void setStateIsNormal(boolean isNormal) { + setShouldListenFlag(FLAG_STATE_IS_NORMAL, isNormal); + } + + /** + * Delete the specified app widget from the host + * @param appWidgetId The ID of the app widget to be deleted + */ + public void deleteAppWidgetId(int appWidgetId) { + mWidgetHost.deleteAppWidgetId(appWidgetId); + mViews.remove(appWidgetId); + } + + /** + * Add the pending view to the host for complete configuration in further steps + * @param appWidgetId The ID of the specified app widget + * @param view The {@link PendingAppWidgetHostView} of the app widget + */ + public void addPendingView(int appWidgetId, @NonNull PendingAppWidgetHostView view) { + mPendingViews.put(appWidgetId, view); + } + + /** + * @param appWidgetId The app widget id of the specified widget + * @return The {@link PendingAppWidgetHostView} of the widget if it exists, null otherwise + */ + @Nullable + protected PendingAppWidgetHostView getPendingView(int appWidgetId) { + return mPendingViews.get(appWidgetId); + } + + protected void removePendingView(int appWidgetId) { + mPendingViews.remove(appWidgetId); + } + + /** + * Called when the launcher is destroyed + */ + public void destroy() { + // No-op + } + + /** + * @return The allocated app widget id if allocation is successful, returns -1 otherwise + */ + public int allocateAppWidgetId() { + if (WidgetsModel.GO_DISABLE_WIDGETS) { + return AppWidgetManager.INVALID_APPWIDGET_ID; + } + + return mWidgetHost.allocateAppWidgetId(); + } + + /** + * Add a listener that is triggered when the providers of the widgets are changed + * @param listener The listener that notifies when the providers changed + */ + public void addProviderChangeListener(@NonNull ProviderChangedListener listener) { + LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost; + tempHost.addProviderChangeListener(listener); + } + + /** + * Remove the specified listener from the host + * @param listener The listener that is to be removed from the host + */ + public void removeProviderChangeListener(ProviderChangedListener listener) { + LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost; + tempHost.removeProviderChangeListener(listener); + } + + /** + * Starts the configuration activity for the widget + * @param activity The activity in which to start the configuration page + * @param widgetId The ID of the widget + * @param requestCode The request code + */ + public void startConfigActivity(@NonNull BaseDraggingActivity activity, int widgetId, + int requestCode) { + if (WidgetsModel.GO_DISABLE_WIDGETS) { + sendActionCancelled(activity, requestCode); + return; + } + + try { + TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: startConfigActivity"); + mWidgetHost.startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, + getConfigurationActivityOptions(activity, widgetId)); + } catch (ActivityNotFoundException | SecurityException e) { + Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); + sendActionCancelled(activity, requestCode); + } + } + + private void sendActionCancelled(final BaseActivity activity, final int requestCode) { + MAIN_EXECUTOR.execute( + () -> activity.onActivityResult(requestCode, RESULT_CANCELED, null)); + } + + /** + * Returns an {@link android.app.ActivityOptions} bundle from the {code activity} for launching + * the configuration of the {@code widgetId} app widget, or null of options cannot be produced. + */ + @Nullable + protected Bundle getConfigurationActivityOptions(@NonNull BaseDraggingActivity activity, + int widgetId) { + LauncherAppWidgetHostView view = mViews.get(widgetId); + if (view == null) return null; + Object tag = view.getTag(); + if (!(tag instanceof ItemInfo)) return null; + Bundle bundle = activity.getActivityLaunchOptions(view, (ItemInfo) tag).toBundle(); + bundle.putInt(KEY_SPLASH_SCREEN_STYLE, SPLASH_SCREEN_STYLE_EMPTY); + return bundle; + } + + /** + * Starts the binding flow for the widget + * @param activity The activity for which to bind the widget + * @param appWidgetId The ID of the widget + * @param info The {@link AppWidgetProviderInfo} of the widget + * @param requestCode The request code + */ + public void startBindFlow(@NonNull BaseActivity activity, + int appWidgetId, @NonNull AppWidgetProviderInfo info, int requestCode) { + if (WidgetsModel.GO_DISABLE_WIDGETS) { + sendActionCancelled(activity, requestCode); + return; + } + + Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND) + .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + .putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.provider) + .putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER_PROFILE, info.getProfile()); + // TODO: we need to make sure that this accounts for the options bundle. + // intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options); + activity.startActivityForResult(intent, requestCode); + } + + /** + * Stop the host from listening to the widget updates + */ + public void stopListening() { + if (WidgetsModel.GO_DISABLE_WIDGETS) { + return; + } + + mWidgetHost.stopListening(); + setListeningFlag(false); + } + + protected void setListeningFlag(final boolean isListening) { + if (isListening) { + mFlags |= FLAG_LISTENING; + return; + } + mFlags &= ~FLAG_LISTENING; + } + + /** + * Delete the host + */ + public void deleteHost() { + mWidgetHost.deleteHost(); + } + + /** + * @return The app widget ids + */ + @NonNull + public int[] getAppWidgetIds() { + return mWidgetHost.getAppWidgetIds(); + } + + /** + * Create a view for the specified app widget + * @param context The activity context for which the view is created + * @param appWidgetId The ID of the widget + * @param appWidget The {@link LauncherAppWidgetProviderInfo} of the widget + * @return A view for the widget + */ + @NonNull + public AppWidgetHostView createView(@NonNull Context context, int appWidgetId, + @NonNull LauncherAppWidgetProviderInfo appWidget) { + if (appWidget.isCustomWidget()) { + LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context); + lahv.setAppWidget(0, appWidget); + CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv); + return lahv; + } else if ((mFlags & FLAG_LISTENING) == 0) { + // Since the launcher hasn't started listening to widget updates, we can't simply call + // super.createView here because the later will make a binder call to retrieve + // RemoteViews from system process. + // TODO: have launcher always listens to widget updates in background so that this + // check can be removed altogether. + if (FeatureFlags.ENABLE_CACHED_WIDGET.get() + && mCachedRemoteViews.get(appWidgetId) != null) { + // We've found RemoteViews from cache for this widget, so we will instantiate a + // widget host view and populate it with the cached RemoteViews. + final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context); + view.setAppWidget(appWidgetId, appWidget); + view.updateAppWidget(mCachedRemoteViews.get(appWidgetId)); + mDeferredViews.put(appWidgetId, view); + mViews.put(appWidgetId, view); + return view; + } else { + // When cache misses, a placeholder for the widget will be returned instead. + DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context); + view.setAppWidget(appWidgetId, appWidget); + mViews.put(appWidgetId, view); + return view; + } + } else { + try { + return mWidgetHost.createView(context, appWidgetId, appWidget); + } catch (Exception e) { + if (!Utilities.isBinderSizeError(e)) { + throw new RuntimeException(e); + } + + // If the exception was thrown while fetching the remote views, let the view stay. + // This will ensure that if the widget posts a valid update later, the view + // will update. + LauncherAppWidgetHostView view = mViews.get(appWidgetId); + if (view == null) { + view = onCreateView(mContext, appWidgetId, appWidget); + } + view.setAppWidget(appWidgetId, appWidget); + view.switchToErrorView(); + return view; + } + } + } + + /** + * Listener for getting notifications on provider changes. + */ + public interface ProviderChangedListener { + /** + * Notify the listener that the providers have changed + */ + void notifyWidgetProvidersChanged(); + } + + /** + * Called to return a proper view when creating a view + * @param context The context for which the widget view is created + * @param appWidgetId The ID of the added widget + * @param appWidget The provider info of the added widget + * @return A view for the specified app widget + */ + @NonNull + public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId, + AppWidgetProviderInfo appWidget) { + final LauncherAppWidgetHostView view; + if (getPendingView(appWidgetId) != null) { + view = getPendingView(appWidgetId); + removePendingView(appWidgetId); + } else if (mDeferredViews.get(appWidgetId) != null) { + // In case the widget view is deferred, we will simply return the deferred view as + // opposed to instantiate a new instance of LauncherAppWidgetHostView since launcher + // already added the former to the workspace. + view = mDeferredViews.get(appWidgetId); + } else { + view = new LauncherAppWidgetHostView(context); + } + mViews.put(appWidgetId, view); + return view; + } + + /** + * Clears all the views from the host + */ + public void clearViews() { + LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost; + tempHost.clearViews(); + if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) { + // First, we clear any previously cached content from existing widgets + mCachedRemoteViews.clear(); + mDeferredViews.clear(); + // Then we proceed to cache the content from the widgets + for (int i = 0; i < mViews.size(); i++) { + final int appWidgetId = mViews.keyAt(i); + final LauncherAppWidgetHostView view = mViews.get(appWidgetId); + mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews); + } + } + mViews.clear(); + } + + /** + * @return True if the host is listening to the updates, false otherwise + */ + public boolean isListening() { + return (mFlags & FLAG_LISTENING) != 0; + } + + /** + * Sets or unsets a flag the can change whether the widget host should be in the listening + * state. + */ + private void setShouldListenFlag(int flag, boolean on) { + if (on) { + mFlags |= flag; + } else { + mFlags &= ~flag; + } + + final boolean listening = isListening(); + if (!listening && (mFlags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN) { + // Postpone starting listening until all flags are on. + startListening(); + } else if (listening && (mFlags & FLAG_ACTIVITY_STARTED) == 0) { + // Postpone stopping listening until the activity is stopped. + stopListening(); + } + } + + /** + * Returns the new LauncherWidgetHolder instance + */ + public static LauncherWidgetHolder newInstance(Context context) { + return HolderFactory.newFactory(context).newInstance(context, null); + } + + /** + * A factory class that generates new instances of {@code LauncherWidgetHolder} + */ + public static class HolderFactory implements ResourceBasedOverride { + + /** + * @param context The context of the caller + * @param appWidgetRemovedCallback The callback that is called when widgets are removed + * @return A new instance of {@code LauncherWidgetHolder} + */ + public LauncherWidgetHolder newInstance(@NonNull Context context, + @Nullable IntConsumer appWidgetRemovedCallback) { + return new LauncherWidgetHolder(context, appWidgetRemovedCallback); + } + + /** + * @param context The context of the caller + * @return A new instance of factory class for widget holders. If not specified, returning + * {@code HolderFactory} by default. + */ + public static HolderFactory newFactory(Context context) { + return Overrides.getObject( + HolderFactory.class, context, R.string.widget_holder_factory_class); + } + } +} diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java index c8d528b8e8..bbbc329c9c 100644 --- a/src/com/android/launcher3/widget/PendingItemDragHelper.java +++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java @@ -39,6 +39,7 @@ import com.android.launcher3.R; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.graphics.DragPreviewProvider; +import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.RoundDrawableWrapper; @@ -181,7 +182,8 @@ public class PendingItemDragHelper extends DragPreviewProvider { PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo; Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache()); LauncherIcons li = LauncherIcons.obtain(launcher); - preview = new FastBitmapDrawable(li.createScaledBitmapWithoutShadow(icon)); + preview = new FastBitmapDrawable( + li.createScaledBitmap(icon, BaseIconFactory.MODE_DEFAULT)); previewWidth = preview.getIntrinsicWidth(); previewHeight = preview.getIntrinsicHeight(); li.recycle(); diff --git a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java index 93132664ef..9319a9c2c4 100644 --- a/src/com/android/launcher3/widget/WidgetAddFlowHandler.java +++ b/src/com/android/launcher3/widget/WidgetAddFlowHandler.java @@ -55,7 +55,7 @@ public class WidgetAddFlowHandler implements Parcelable { public void startBindFlow(Launcher launcher, int appWidgetId, ItemInfo info, int requestCode) { launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info)); - launcher.getAppWidgetHost() + launcher.getAppWidgetHolder() .startBindFlow(launcher, appWidgetId, mProviderInfo, requestCode); } @@ -77,7 +77,7 @@ public class WidgetAddFlowHandler implements Parcelable { return false; } launcher.setWaitingForResult(PendingRequestArgs.forWidgetInfo(appWidgetId, this, info)); - launcher.getAppWidgetHost().startConfigActivity(launcher, appWidgetId, requestCode); + launcher.getAppWidgetHolder().startConfigActivity(launcher, appWidgetId, requestCode); return true; } diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java index 2796721c63..ce47d70c25 100644 --- a/src/com/android/launcher3/widget/WidgetCell.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -284,6 +284,40 @@ public class WidgetCell extends LinearLayout { ensurePreviewWithCallback(callback, cachedPreview); } + private static class ScaledAppWidgetHostView extends LauncherAppWidgetHostView { + private boolean mKeepOrigForDragging = true; + + ScaledAppWidgetHostView(Context context) { + super(context); + } + + /** + * Set if the view will keep its original scale when dragged + * @param isKeepOrig True if keep original scale when dragged, false otherwise + */ + public void setKeepOrigForDragging(boolean isKeepOrig) { + mKeepOrigForDragging = isKeepOrig; + } + + /** + * @return True if the view is set to preserve original scale when dragged, false otherwise + */ + public boolean isKeepOrigForDragging() { + return mKeepOrigForDragging; + } + + @Override + public void startDrag() { + super.startDrag(); + if (!isKeepOrigForDragging()) { + // restore to original scale when being dragged, if set to do so + setScaleToFit(1.0f); + } + // When the drag start, translations need to be set to zero to center the view + setTranslationForCentering(0f, 0f); + } + } + private void applyPreviewOnAppWidgetHostView(WidgetItem item) { if (mRemoteViewsPreview != null) { mAppWidgetHostViewPreview = createAppWidgetHostView(getContext()); @@ -299,7 +333,7 @@ public class WidgetCell extends LinearLayout { // a preview during drag & drop. And thus, we should use LauncherAppWidgetHostView, which // supports applying local color extraction during drag & drop. mAppWidgetHostViewPreview = isLauncherContext(context) - ? new LauncherAppWidgetHostView(context) + ? new ScaledAppWidgetHostView(context) : createAppWidgetHostView(context); LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(context, item.widgetInfo.clone()); @@ -398,23 +432,41 @@ public class WidgetCell extends LinearLayout { int containerWidth = (int) (mTargetPreviewWidth * mPreviewContainerScale); int containerHeight = (int) (mTargetPreviewHeight * mPreviewContainerScale); setContainerSize(containerWidth, containerHeight); + boolean shouldMeasureAndScale = false; if (mAppWidgetHostViewPreview.getChildCount() == 1) { View widgetContent = mAppWidgetHostViewPreview.getChildAt(0); ViewGroup.LayoutParams layoutParams = widgetContent.getLayoutParams(); // We only scale preview if both the width & height of the outermost view group are // not set to MATCH_PARENT. - boolean shouldScale = + shouldMeasureAndScale = layoutParams.width != MATCH_PARENT && layoutParams.height != MATCH_PARENT; - if (shouldScale) { + if (shouldMeasureAndScale) { setNoClip(mWidgetImageContainer); setNoClip(mAppWidgetHostViewPreview); mAppWidgetHostViewScale = measureAndComputeWidgetPreviewScale(); - mAppWidgetHostViewPreview.setScaleToFit(mAppWidgetHostViewScale); } } + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( - containerWidth, containerHeight, Gravity.FILL); + mTargetPreviewWidth, mTargetPreviewHeight, Gravity.FILL); mAppWidgetHostViewPreview.setLayoutParams(params); + + if (!shouldMeasureAndScale + && mAppWidgetHostViewPreview instanceof ScaledAppWidgetHostView) { + // If the view is not measured & scaled, at least one side will match the grid size, + // so it should be safe to restore the original scale once it is dragged. + ScaledAppWidgetHostView tempView = + (ScaledAppWidgetHostView) mAppWidgetHostViewPreview; + tempView.setKeepOrigForDragging(false); + tempView.setScaleToFit(mPreviewContainerScale); + } else if (!shouldMeasureAndScale) { + mAppWidgetHostViewPreview.setScaleToFit(mPreviewContainerScale); + } else { + mAppWidgetHostViewPreview.setScaleToFit(mAppWidgetHostViewScale); + } + mAppWidgetHostViewPreview.setTranslationForCentering( + -(params.width - (params.width * mPreviewContainerScale)) / 2.0f, + -(params.height - (params.height * mPreviewContainerScale)) / 2.0f); mWidgetImageContainer.addView(mAppWidgetHostViewPreview, /* index= */ 0); mWidgetImage.setVisibility(View.GONE); applyPreview(null); diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java index 46141e0bc3..b18cd471cb 100644 --- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java +++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java @@ -59,7 +59,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { // Cleanup widget id if (mWidgetLoadingId != -1) { - mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId); + mLauncher.getAppWidgetHolder().deleteAppWidgetId(mWidgetLoadingId); mWidgetLoadingId = -1; } @@ -69,7 +69,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { Log.d(TAG, "...removing widget from drag layer"); } mLauncher.getDragLayer().removeView(mInfo.boundWidget); - mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId()); + mLauncher.getAppWidgetHolder().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId()); mInfo.boundWidget = null; } } @@ -94,7 +94,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { mBindWidgetRunnable = new Runnable() { @Override public void run() { - mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId(); + mWidgetLoadingId = mLauncher.getAppWidgetHolder().allocateAppWidgetId(); if (LOGD) { Log.d(TAG, "Binding widget, id: " + mWidgetLoadingId); } @@ -116,7 +116,7 @@ public class WidgetHostViewLoader implements DragController.DragListener { if (mWidgetLoadingId == -1) { return; } - AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView( + AppWidgetHostView hostView = mLauncher.getAppWidgetHolder().createView( (Context) mLauncher, mWidgetLoadingId, pInfo); mInfo.boundWidget = hostView; diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java index da8e25c1f6..38cdb4b500 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java @@ -65,7 +65,7 @@ import com.android.launcher3.views.SpringRelativeLayout; import com.android.launcher3.views.StickyHeaderLayout; import com.android.launcher3.views.WidgetsEduView; import com.android.launcher3.widget.BaseWidgetSheet; -import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener; +import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener; import com.android.launcher3.widget.model.WidgetsListBaseEntry; import com.android.launcher3.widget.picker.search.SearchModeListener; import com.android.launcher3.widget.picker.search.WidgetsSearchBar; @@ -169,6 +169,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet private View mSearchBarContainer; private WidgetsSearchBar mSearchBar; private TextView mHeaderTitle; + private @Nullable WidgetsRecyclerView mCurrentTouchEventRecyclerView; public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @@ -321,7 +322,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - mActivityContext.getAppWidgetHost().addProviderChangeListener(this); + mActivityContext.getAppWidgetHolder().addProviderChangeListener(this); notifyWidgetProvidersChanged(); onRecommendedWidgetsBound(); } @@ -329,7 +330,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - mActivityContext.getAppWidgetHost().removeProviderChangeListener(this); + mActivityContext.getAppWidgetHolder().removeProviderChangeListener(this); mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView .removeOnAttachStateChangeListener(mBindScrollbarInSearchMode); if (mHasWorkProfile) { @@ -615,12 +616,13 @@ public class WidgetsFullSheet extends BaseWidgetSheet // Disable swipe down when recycler view is scrolling if (ev.getAction() == MotionEvent.ACTION_DOWN) { mNoIntercept = false; - RecyclerViewFastScroller scroller = getRecyclerView().getScrollbar(); + WidgetsRecyclerView recyclerView = getRecyclerView(); + RecyclerViewFastScroller scroller = recyclerView.getScrollbar(); if (scroller.getThumbOffsetY() >= 0 && getPopupContainer().isEventOverView(scroller, ev)) { mNoIntercept = true; - } else if (getPopupContainer().isEventOverView(mContent, ev)) { - mNoIntercept = !getRecyclerView().shouldContainerScroll(ev, getPopupContainer()); + } else if (getPopupContainer().isEventOverView(recyclerView, ev)) { + mNoIntercept = !recyclerView.shouldContainerScroll(ev, getPopupContainer()); } if (mSearchBar.isSearchBarFocused() @@ -641,6 +643,51 @@ public class WidgetsFullSheet extends BaseWidgetSheet return sheet; } + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return isTouchOnScrollbar(ev) || super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + return maybeHandleTouchEvent(ev) || super.onTouchEvent(ev); + } + + private boolean maybeHandleTouchEvent(MotionEvent ev) { + boolean isEventHandled = false; + + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mCurrentTouchEventRecyclerView = isTouchOnScrollbar(ev) ? getRecyclerView() : null; + } + + if (mCurrentTouchEventRecyclerView != null) { + final float offsetX = mContent.getX(); + final float offsetY = mContent.getY(); + ev.offsetLocation(-offsetX, -offsetY); + isEventHandled = mCurrentTouchEventRecyclerView.dispatchTouchEvent(ev); + ev.offsetLocation(offsetX, offsetY); + } + + if (ev.getAction() == MotionEvent.ACTION_UP + || ev.getAction() == MotionEvent.ACTION_CANCEL) { + mCurrentTouchEventRecyclerView = null; + } + + return isEventHandled; + } + + private boolean isTouchOnScrollbar(MotionEvent ev) { + final float offsetX = mContent.getX(); + final float offsetY = mContent.getY(); + WidgetsRecyclerView rv = getRecyclerView(); + + ev.offsetLocation(-offsetX, -offsetY); + boolean isOnScrollBar = rv != null && rv.getScrollbar() != null && rv.isHitOnScrollBar(ev); + ev.offsetLocation(offsetX, offsetY); + + return isOnScrollBar; + } + /** Gets the {@link WidgetsRecyclerView} which shows all widgets in {@link WidgetsFullSheet}. */ @VisibleForTesting public static WidgetsRecyclerView getWidgetsView(Launcher launcher) { diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java index 5969e3e154..698e76498a 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java @@ -127,8 +127,7 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN) { - mTouchDownOnScroller = - mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset); + mTouchDownOnScroller = isHitOnScrollBar(e); } if (mTouchDownOnScroller) { final boolean result = mScrollbar.handleTouchEvent(e, mFastScrollerOffset); @@ -144,6 +143,15 @@ public class WidgetsRecyclerView extends FastScrollRecyclerView implements OnIte } } + /** + * Detects whether a {@code MotionEvent} is on the scroll bar + * @param e The {@code MotionEvent} on the screen + * @return {@code true} if the motion is on the scroll bar + */ + boolean isHitOnScrollBar(MotionEvent e) { + return mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset); + } + @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } diff --git a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java index 49db2a0b5f..e94f3a065d 100644 --- a/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java +++ b/src/com/android/launcher3/workprofile/PersonalWorkSlidingTabStrip.java @@ -16,6 +16,7 @@ package com.android.launcher3.workprofile; import android.content.Context; +import android.content.res.TypedArray; import android.util.AttributeSet; import android.widget.Button; import android.widget.LinearLayout; @@ -24,6 +25,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; import com.android.launcher3.pageindicators.PageIndicator; import com.android.launcher3.views.ActivityContext; @@ -31,11 +33,17 @@ import com.android.launcher3.views.ActivityContext; * Supports two indicator colors, dedicated for personal and work tabs. */ public class PersonalWorkSlidingTabStrip extends LinearLayout implements PageIndicator { + private final boolean mIsAlignOnIcon; private OnActivePageChangedListener mOnActivePageChangedListener; private int mLastActivePage = 0; public PersonalWorkSlidingTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); + TypedArray typedArray = context.obtainStyledAttributes(attrs, + R.styleable.PersonalWorkSlidingTabStrip); + mIsAlignOnIcon = typedArray.getBoolean( + R.styleable.PersonalWorkSlidingTabStrip_alignOnIcon, false); + typedArray.recycle(); } /** @@ -76,7 +84,7 @@ public class PersonalWorkSlidingTabStrip extends LinearLayout implements PageInd @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (getPaddingLeft() == 0 && getPaddingRight() == 0) { + if (mIsAlignOnIcon) { // If any padding is not specified, restrict the width to emulate padding int size = MeasureSpec.getSize(widthMeasureSpec); size = getTabWidth(getContext(), size); diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherExterns.java b/src_plugins/com/android/systemui/plugins/shared/LauncherExterns.java index 13e4999623..173b4540e6 100644 --- a/src_plugins/com/android/systemui/plugins/shared/LauncherExterns.java +++ b/src_plugins/com/android/systemui/plugins/shared/LauncherExterns.java @@ -40,10 +40,4 @@ public interface LauncherExterns { * Sets the overlay on the target activity */ void setLauncherOverlay(LauncherOverlay overlay); - - /** - * Executes the command, next time the overlay is hidden - */ - void runOnOverlayHidden(Runnable runnable); - } diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java index ac02ba4528..582ab230c3 100644 --- a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java +++ b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java @@ -93,6 +93,6 @@ public interface LauncherOverlayManager extends Application.ActivityLifecycleCal interface LauncherOverlayCallbacks { - void onScrollChanged(float progress); + void onOverlayScrollChanged(float progress); } } diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java index 13ad7a4ec5..702f3430aa 100644 --- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java +++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java @@ -62,8 +62,6 @@ public class WidgetsModel { // True is the widget support is disabled. public static final boolean GO_DISABLE_WIDGETS = false; - // True is the shortcut support is disabled. - public static final boolean GO_DISABLE_SHORTCUTS = false; public static final boolean GO_DISABLE_NOTIFICATION_DOTS = false; private static final String TAG = "WidgetsModel"; diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java index c8b5e2fa37..47bf135cee 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java @@ -21,6 +21,9 @@ import android.content.pm.ShortcutInfo; import com.android.launcher3.Utilities; +/** + * A wrapper for the hidden API calls + */ public class ApiWrapper { public static final boolean TASKBAR_DRAWN_IN_PROCESS = false; diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java index a581f91f74..772a995324 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -20,11 +20,11 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAP import android.content.Context; -import com.android.launcher3.DeviceProfile.DeviceProfileListenable; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.util.Themes; +import com.android.launcher3.views.ActivityContext; /** * Definition for AllApps state @@ -40,7 +40,7 @@ public class AllAppsState extends LauncherState { } @Override - public <DEVICE_PROFILE_CONTEXT extends Context & DeviceProfileListenable> + public <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext> int getTransitionDuration(DEVICE_PROFILE_CONTEXT context, boolean isToState) { return isToState ? context.getDeviceProfile().allAppsOpenDuration diff --git a/tests/Android.bp b/tests/Android.bp index 1584308091..39bd3074a3 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -60,6 +60,7 @@ filegroup { "src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java", "src/com/android/launcher3/testcomponent/TestCommandReceiver.java", "src/com/android/launcher3/testcomponent/TestLauncherActivity.java", + "src/com/android/launcher3/testcomponent/ImeTestActivity.java", ], } diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml index 9cc3aeda1f..b17006181e 100644 --- a/tests/AndroidManifest-common.xml +++ b/tests/AndroidManifest-common.xml @@ -24,6 +24,7 @@ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/> <uses-permission android:name="android.permission.READ_LOGS"/> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/> + <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> <application android:debuggable="true" android:extractNativeLibs="true"> <uses-library android:name="android.test.runner"/> @@ -62,6 +63,17 @@ </receiver> <receiver + android:name="com.android.launcher3.testcomponent.AppWidgetWithDialog" + android:exported="true" + android:label="With Dialog"> + <intent-filter> + <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> + </intent-filter> + <meta-data android:name="android.appwidget.provider" + android:resource="@xml/appwidget_no_config"/> + </receiver> + + <receiver android:name="com.android.launcher3.testcomponent.AppWidgetDynamicColors" android:exported="true" android:label="Dynamic Colors"> @@ -268,7 +280,7 @@ </intent-filter> </activity-alias> <activity-alias android:name="Activity15" android:exported="true" - android:label="ThemeIconTestActivity" + android:label="IconThemedActivity" android:icon="@drawable/test_theme_icon" android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity"> <intent-filter> @@ -276,6 +288,26 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity-alias> + <activity + android:name="com.android.launcher3.testcomponent.DialogTestActivity" + android:label="Dialog Activity" + android:theme="@android:style/Theme.Dialog" + android:exported="true" + android:taskAffinity="com.android.launcher3.testcomponent.Affinity2"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <activity android:name="com.android.launcher3.testcomponent.ImeTestActivity" + android:label="ImeTestActivity" + android:icon="@drawable/test_theme_icon" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> <!-- [b/197780098] Disable eager initialization of Jetpack libraries. --> <provider diff --git a/tests/res/layout/test_layout_appwidget_blue.xml b/tests/res/layout/test_layout_appwidget_blue.xml index 8111978c9c..f33e57575f 100644 --- a/tests/res/layout/test_layout_appwidget_blue.xml +++ b/tests/res/layout/test_layout_appwidget_blue.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/content" android:orientation="vertical" android:background="#FF0000FF" android:layout_width="match_parent" diff --git a/tests/res/xml/shortcuts.xml b/tests/res/xml/shortcuts.xml index bdc22f98cb..94e8edd936 100644 --- a/tests/res/xml/shortcuts.xml +++ b/tests/res/xml/shortcuts.xml @@ -1,7 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <shortcuts xmlns:android="http://schemas.android.com/apk/res/android" > <shortcut - android:shortcutId="shortcut1" + android:shortcutId="shortcut1_themed" + android:icon="@drawable/test_theme_icon" android:shortcutShortLabel="@string/shortcut1"> <intent android:action="com.android.launcher3.intent.action.test_shortcut"/> </shortcut> diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt index 2c1cbdf0ce..13e56f3456 100644 --- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt +++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt @@ -20,12 +20,11 @@ import android.graphics.PointF import android.graphics.Rect import android.util.SparseArray import androidx.test.core.app.ApplicationProvider -import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER; +import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER import com.android.launcher3.util.DisplayController.Info import com.android.launcher3.util.WindowBounds import org.junit.Before import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mockito.mock import java.io.PrintWriter import java.io.StringWriter @@ -41,9 +40,6 @@ abstract class DeviceProfileBaseTest { protected var transposeLayoutWithOrientation: Boolean = false protected var useTwoPanels: Boolean = false protected var isGestureMode: Boolean = true - protected var devicePaddingsMock: DevicePaddings = mock(DevicePaddings::class.java) - protected var staticdevicePaddingsMock: DevicePaddings.DevicePadding = - mock(DevicePaddings.DevicePadding::class.java) @Before fun setUp() { @@ -82,11 +78,6 @@ abstract class DeviceProfileBaseTest { whenever(info.isTablet(any())).thenReturn(false) whenever(info.getDensityDpi()).thenReturn(420) whenever(info.smallestSizeDp(any())).thenReturn(411f) - whenever(devicePaddingsMock.getDevicePadding(anyInt())).thenReturn(staticdevicePaddingsMock) - whenever(staticdevicePaddingsMock.getWorkspaceTopPadding(anyInt())).thenReturn(95) - whenever(staticdevicePaddingsMock.getWorkspaceBottomPadding(anyInt())).thenReturn(116) - whenever(staticdevicePaddingsMock.maxEmptySpacePx) - .thenReturn(if (isVerticalBar) if (isGestureMode) 131 else 184 else 315) this.isGestureMode = isGestureMode transposeLayoutWithOrientation = true @@ -116,12 +107,9 @@ abstract class DeviceProfileBaseTest { numFolderRows = 3 numFolderColumns = 3 - folderBorderSpaces = PointF(16f, 16f) - folderTopPadding = 24f - folderCellSize = PointF(80f, 94f) + folderStyle = R.style.FolderDefaultStyle - - inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_4_5 + inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split horizontalMargin = FloatArray(4) { 22f } @@ -154,7 +142,7 @@ abstract class DeviceProfileBaseTest { inlineQsb = BooleanArray(4) { false } - devicePaddings = devicePaddingsMock + devicePaddingId = R.xml.paddings_handhelds } } @@ -171,13 +159,6 @@ abstract class DeviceProfileBaseTest { whenever(info.isTablet(any())).thenReturn(true) whenever(info.getDensityDpi()).thenReturn(320) whenever(info.smallestSizeDp(any())).thenReturn(800f) - whenever(devicePaddingsMock.getDevicePadding(anyInt())).thenReturn(staticdevicePaddingsMock) - whenever(staticdevicePaddingsMock.getWorkspaceTopPadding(anyInt())) - .thenReturn(if (isLandscape) 32 else 159) - whenever(staticdevicePaddingsMock.getWorkspaceBottomPadding(anyInt())) - .thenReturn(if (isLandscape) 72 else 203) - whenever(staticdevicePaddingsMock.maxEmptySpacePx).thenReturn(if (isLandscape) 200 else 19998) - this.isGestureMode = isGestureMode useTwoPanels = false @@ -207,9 +188,7 @@ abstract class DeviceProfileBaseTest { numFolderRows = 3 numFolderColumns = 3 - folderBorderSpaces = PointF(16f, 16f) - folderTopPadding = 24f - folderCellSize = PointF(120f, 104f) + folderStyle = R.style.FolderDefaultStyle inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5 @@ -241,7 +220,7 @@ abstract class DeviceProfileBaseTest { numAllAppsColumns = 6 isScalable = true - devicePaddingId = 2132148242 // "@xml/paddings_6x5" + devicePaddingId = R.xml.paddings_6x5 inlineQsb = booleanArrayOf( false, @@ -250,7 +229,7 @@ abstract class DeviceProfileBaseTest { false ) - devicePaddings = devicePaddingsMock + devicePaddingId = R.xml.paddings_handhelds } } @@ -267,15 +246,6 @@ abstract class DeviceProfileBaseTest { whenever(info.isTablet(any())).thenReturn(true) whenever(info.getDensityDpi()).thenReturn(420) whenever(info.smallestSizeDp(any())).thenReturn(700f) - whenever(devicePaddingsMock.getDevicePadding(anyInt())).thenReturn(staticdevicePaddingsMock) - - val topPadding = if (isLandscape) 18 else 89 - val bottomPadding = if (isLandscape) 39 else 146 - val maxEmptySpace = if (isLandscape) 131 else 236 - whenever(staticdevicePaddingsMock.getWorkspaceTopPadding(anyInt())).thenReturn(topPadding) - whenever(staticdevicePaddingsMock.getWorkspaceBottomPadding(anyInt())) - .thenReturn(bottomPadding) - whenever(staticdevicePaddingsMock.maxEmptySpacePx).thenReturn(maxEmptySpace) this.isGestureMode = isGestureMode useTwoPanels = true @@ -305,11 +275,9 @@ abstract class DeviceProfileBaseTest { numFolderRows = 3 numFolderColumns = 3 - folderBorderSpaces = PointF(16f, 16f) - folderTopPadding = 24f - folderCellSize = PointF(80f, 94f) + folderStyle = R.style.FolderDefaultStyle - inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_4_4 + inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f) @@ -348,7 +316,7 @@ abstract class DeviceProfileBaseTest { false ) - devicePaddings = devicePaddingsMock + devicePaddingId = R.xml.paddings_handhelds } } diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java index 2846cae1e8..9da7e0f39b 100644 --- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java +++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java @@ -35,13 +35,13 @@ import com.android.launcher3.tapl.Widget; import com.android.launcher3.tapl.WidgetResizeFrame; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TaplTestsLauncher3; -import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; import com.android.launcher3.util.rule.ShellCommandRule; import com.android.launcher3.views.DoubleShadowBubbleTextView; import com.android.launcher3.widget.LauncherAppWidgetHostView; import org.junit.Assume; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,7 +49,6 @@ import org.junit.runner.RunWith; import java.util.Map; import java.util.concurrent.ExecutionException; - @SmallTest @RunWith(AndroidJUnit4.class) public class ReorderWidgets extends AbstractLauncherUiTest { @@ -116,7 +115,7 @@ public class ReorderWidgets extends AbstractLauncherUiTest { FavoriteItemsTransaction transaction = new FavoriteItemsTransaction(mTargetContext, this); mWorkspaceBuilder.buildFromBoard(testCase.mStart, transaction).commit(); - + waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading()); Widget widget = mLauncher.getWorkspace().getWidgetAtCell(mainWidgetCellPos.x, mainWidgetCellPos.y); assertNotNull(widget); @@ -146,28 +145,26 @@ public class ReorderWidgets extends AbstractLauncherUiTest { runTestCase(testCaseMap.get(iconGridDimensions)); } - @ScreenRecord // b/242323136 @Test - public void simpleReorder() throws ExecutionException, InterruptedException { + public void simpleReorder() throws ExecutionException, InterruptedException { runTestCaseMap(SimpleReorderCase.TEST_BY_GRID_SIZE, SimpleReorderCase.class.getSimpleName()); } - @ScreenRecord // b/242323136 + @Ignore @Test - public void pushTest() throws ExecutionException, InterruptedException { + public void pushTest() throws ExecutionException, InterruptedException { runTestCaseMap(PushReorderCase.TEST_BY_GRID_SIZE, PushReorderCase.class.getSimpleName()); } - @ScreenRecord // b/242323136 + @Ignore @Test - public void fullReorder() throws ExecutionException, InterruptedException { + public void fullReorder() throws ExecutionException, InterruptedException { runTestCaseMap(FullReorderCase.TEST_BY_GRID_SIZE, FullReorderCase.class.getSimpleName()); } - @ScreenRecord // b/242323136 @Test - public void moveOutReorder() throws ExecutionException, InterruptedException { + public void moveOutReorder() throws ExecutionException, InterruptedException { runTestCaseMap(MoveOutReorderCase.TEST_BY_GRID_SIZE, MoveOutReorderCase.class.getSimpleName()); } diff --git a/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java index a98882cc7f..d68d2ede61 100644 --- a/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java +++ b/tests/src/com/android/launcher3/celllayout/testcases/FullReorderCase.java @@ -81,8 +81,29 @@ public class FullReorderCase { MOVE_TO_4x4, END_BOARD_STR_4x4); + /** 4x4 Test + **/ + private static final String START_BOARD_STR_4x5 = "" + + "xxxx\n" + + "22mm\n" + + "iimm\n" + + "ii11\n" + + "ii11"; + private static final Point MOVE_TO_4x5 = new Point(0, 3); + private static final String END_BOARD_STR_4x5 = "" + + "xxxx\n" + + "22ii\n" + + "mmii\n" + + "mm11\n" + + "ii11"; + + private static final ReorderTestCase TEST_CASE_4x5 = new ReorderTestCase(START_BOARD_STR_4x5, + MOVE_TO_4x5, + END_BOARD_STR_4x5); + public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE = Map.of(new Point(5, 5), TEST_CASE_5x5, new Point(6, 5), TEST_CASE_6x5, - new Point(4, 4), TEST_CASE_4x4); + new Point(4, 4), TEST_CASE_4x4, + new Point(4, 5), TEST_CASE_4x5); } diff --git a/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java index a222d3d551..047d3422df 100644 --- a/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java +++ b/tests/src/com/android/launcher3/celllayout/testcases/MoveOutReorderCase.java @@ -63,25 +63,7 @@ public class MoveOutReorderCase { MOVE_TO_6x5, END_BOARD_STR_6x5); - /** 4x4 Test - **/ - private static final String START_BOARD_STR_4x4 = "" - + "xxxx\n" - + "34-m\n" - + "3511\n" - + "3211"; - private static final Point MOVE_TO_4x4 = new Point(1, 2); - private static final String END_BOARD_STR_4x4 = "" - + "xxxx\n" - + "345-\n" - + "3m11\n" - + "3211"; - private static final ReorderTestCase TEST_CASE_4x4 = new ReorderTestCase(START_BOARD_STR_4x4, - MOVE_TO_4x4, - END_BOARD_STR_4x4); - public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE = Map.of(new Point(5, 5), TEST_CASE_5x5, - new Point(6, 5), TEST_CASE_6x5, - new Point(4, 4), TEST_CASE_4x4); + new Point(6, 5), TEST_CASE_6x5); } diff --git a/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java b/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java index e16ff42a8b..38c9aee0fd 100644 --- a/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java +++ b/tests/src/com/android/launcher3/celllayout/testcases/PushReorderCase.java @@ -64,25 +64,7 @@ public class PushReorderCase { MOVE_TO_6x5, END_BOARD_STR_6x5); - /** 4x4 Test - **/ - private static final String START_BOARD_STR_4x4 = "" - + "xxxx\n" - + "222m\n" - + "-111\n" - + "----"; - private static final Point MOVE_TO_4x4 = new Point(2, 1); - private static final String END_BOARD_STR_4x4 = "" - + "xxxx\n" - + "--m-\n" - + "222-\n" - + "-111"; - private static final ReorderTestCase TEST_CASE_4x4 = new ReorderTestCase(START_BOARD_STR_4x4, - MOVE_TO_4x4, - END_BOARD_STR_4x4); - public static final Map<Point, ReorderTestCase> TEST_BY_GRID_SIZE = Map.of(new Point(5, 5), TEST_CASE_5x5, - new Point(6, 5), TEST_CASE_6x5, - new Point(4, 4), TEST_CASE_4x4); + new Point(6, 5), TEST_CASE_6x5); } diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java index 7d36740734..f55b244c24 100644 --- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java +++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java @@ -1,7 +1,5 @@ package com.android.launcher3.model; -import static com.android.launcher3.testing.shared.TestProtocol.INCORRECT_INFO_UPDATED; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; @@ -16,7 +14,6 @@ import android.graphics.Color; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; -import android.util.Log; import androidx.annotation.NonNull; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -29,7 +26,6 @@ import com.android.launcher3.icons.cache.CachingLogic; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.LauncherModelHelper; import org.junit.After; @@ -47,15 +43,12 @@ import java.util.HashSet; @RunWith(AndroidJUnit4.class) public class CacheDataUpdatedTaskTest { - private static final String TAG = "CacheDataUpdatedTaskTest"; - private static final String NEW_LABEL_PREFIX = "new-label-"; private LauncherModelHelper mModelHelper; @Before public void setup() throws Exception { - TestProtocol.sDebugTracing = true; mModelHelper = new LauncherModelHelper(); mModelHelper.initializeData("cache_data_updated_task_data"); @@ -98,7 +91,6 @@ public class CacheDataUpdatedTaskTest { @After public void tearDown() { mModelHelper.destroy(); - TestProtocol.sDebugTracing = false; } private CacheDataUpdatedTask newTask(int op, String... pkg) { @@ -122,7 +114,6 @@ public class CacheDataUpdatedTaskTest { // Verify that only app1 var updated in allAppsList assertFalse(mModelHelper.getAllAppsList().data.isEmpty()); for (AppInfo info : mModelHelper.getAllAppsList().data) { - Log.i(INCORRECT_INFO_UPDATED, "testCacheUpdate_update_apps: checking info=" + info); if (info.componentName.getPackageName().equals("app1")) { assertFalse(info.bitmap.isNullOrLowRes()); } else { diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt index 90d7b434df..76a186bd83 100644 --- a/tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.kt +++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt @@ -17,6 +17,7 @@ package com.android.launcher3.model import android.content.Context import android.content.Intent +import android.database.Cursor; import android.database.sqlite.SQLiteDatabase import android.graphics.Point import android.os.Process @@ -26,7 +27,7 @@ import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherFiles import com.android.launcher3.LauncherSettings.Favorites.* import com.android.launcher3.config.FeatureFlags -import com.android.launcher3.model.GridSizeMigrationTaskV2.DbReader +import com.android.launcher3.model.GridSizeMigrationUtil.DbReader import com.android.launcher3.pm.UserCache import com.android.launcher3.provider.LauncherDbUtils import com.android.launcher3.util.LauncherModelHelper @@ -37,10 +38,10 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -/** Unit tests for [GridSizeMigrationTaskV2] */ +/** Unit tests for [GridSizeMigrationUtil] */ @SmallTest @RunWith(AndroidJUnit4::class) -class GridSizeMigrationTaskV2Test { +class GridSizeMigrationUtilTest { private lateinit var modelHelper: LauncherModelHelper private lateinit var context: Context private lateinit var db: SQLiteDatabase @@ -122,15 +123,16 @@ class GridSizeMigrationTaskV2Test { idp.numRows = 4 val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) - val task = GridSizeMigrationTaskV2( - context, - db, - srcReader, - destReader, - idp.numDatabaseHotseatIcons, - Point(idp.numColumns, idp.numRows) + GridSizeMigrationUtil.migrate( + context, + db, + srcReader, + destReader, + idp.numDatabaseHotseatIcons, + Point(idp.numColumns, idp.numRows), + DeviceGridState(context), + DeviceGridState(idp) ) - task.migrate(DeviceGridState(context), DeviceGridState(idp)) // Check hotseat items var c = context.contentResolver.query( @@ -182,15 +184,232 @@ class GridSizeMigrationTaskV2Test { // Expected dest grid icons // _ _ _ _ // 5 6 7 8 - // 9 _ 10_ + // 9 _ _ _ // _ _ _ _ - assertThat(locMap.size.toLong()).isEqualTo(6) + assertThat(locMap.size.toLong()).isEqualTo(5) assertThat(locMap[testPackage5]).isEqualTo(Point(0, 1)) assertThat(locMap[testPackage6]).isEqualTo(Point(1, 1)) assertThat(locMap[testPackage7]).isEqualTo(Point(2, 1)) assertThat(locMap[testPackage8]).isEqualTo(Point(3, 1)) assertThat(locMap[testPackage9]).isEqualTo(Point(0, 2)) - assertThat(locMap[testPackage10]).isEqualTo(Point(2, 2)) + } + + /** + * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is + * not needed anymore + */ + @Test + @Throws(Exception::class) + fun testMigrationBackAndForth() { + // Hotseat items in grid A + // 1 2 _ 3 4 + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) + // Workspace items in grid A + // _ _ _ _ _ + // _ _ _ _ 5 + // _ _ 6 _ 7 + // _ _ 8 _ _ + // _ _ _ _ _ + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage5, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage6, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage7, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage8, 8, TMP_CONTENT_URI) + + // Hotseat items in grid B + // 2 _ _ _ + modelHelper.addItem(SHORTCUT, 0, HOTSEAT, 0, 0, testPackage2) + // Workspace items in grid B + // _ _ _ _ + // _ _ _ 10 + // _ _ _ _ + // _ _ _ _ + modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 3, testPackage10) + + idp.numDatabaseHotseatIcons = 4 + idp.numColumns = 4 + idp.numRows = 4 + val readerGridA = DbReader(db, TMP_TABLE, context, validPackages) + val readerGridB = DbReader(db, TABLE_NAME, context, validPackages) + // migrate from A -> B + GridSizeMigrationUtil.migrate( + context, + db, + readerGridA, + readerGridB, + idp.numDatabaseHotseatIcons, + Point(idp.numColumns, idp.numRows), + DeviceGridState(context), + DeviceGridState(idp) + ) + + // Check hotseat items in grid B + var c = context.contentResolver.query( + CONTENT_URI, + arrayOf(SCREEN, INTENT), + "container=$CONTAINER_HOTSEAT", + null, + SCREEN, + null + ) ?: throw IllegalStateException() + // Expected hotseat items in grid B + // 2 1 3 4 + verifyHotseat(c, idp, + mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()) + + // Check workspace items in grid B + c = context.contentResolver.query( + CONTENT_URI, + arrayOf(SCREEN, CELLX, CELLY, INTENT), + "container=$CONTAINER_DESKTOP", + null, + null, + null + ) ?: throw IllegalStateException() + var locMap = parseLocMap(context, c) + // Expected items in grid B + // _ _ _ _ + // 5 6 7 8 + // _ _ _ _ + // _ _ _ _ + assertThat(locMap.size.toLong()).isEqualTo(4) + assertThat(locMap[testPackage5]).isEqualTo(Triple(0, 0, 1)) + assertThat(locMap[testPackage6]).isEqualTo(Triple(0, 1, 1)) + assertThat(locMap[testPackage7]).isEqualTo(Triple(0, 2, 1)) + assertThat(locMap[testPackage8]).isEqualTo(Triple(0, 3, 1)) + + // add item in B + modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 2, testPackage9) + + // migrate from B -> A + GridSizeMigrationUtil.migrate( + context, + db, + readerGridB, + readerGridA, + 5, + Point(5, 5), + DeviceGridState(idp), + DeviceGridState(context) + ) + // Check hotseat items in grid A + c = context.contentResolver.query( + TMP_CONTENT_URI, + arrayOf(SCREEN, INTENT), + "container=$CONTAINER_HOTSEAT", + null, + SCREEN, + null + ) ?: throw IllegalStateException() + // Expected hotseat items in grid A + // 1 2 _ 3 4 + verifyHotseat(c, idp, mutableListOf( + testPackage1, testPackage2, null, testPackage3, testPackage4).toList()) + + // Check workspace items in grid A + c = context.contentResolver.query( + TMP_CONTENT_URI, + arrayOf(SCREEN, CELLX, CELLY, INTENT), + "container=$CONTAINER_DESKTOP", + null, + null, + null + ) ?: throw IllegalStateException() + locMap = parseLocMap(context, c) + // Expected workspace items in grid A + // _ _ _ _ _ + // _ _ _ _ 5 + // 9 _ 6 _ 7 + // _ _ 8 _ _ + // _ _ _ _ _ + assertThat(locMap.size.toLong()).isEqualTo(5) + // Verify items that existed in grid A remains in same position + assertThat(locMap[testPackage5]).isEqualTo(Triple(0, 4, 1)) + assertThat(locMap[testPackage6]).isEqualTo(Triple(0, 2, 2)) + assertThat(locMap[testPackage7]).isEqualTo(Triple(0, 4, 2)) + assertThat(locMap[testPackage8]).isEqualTo(Triple(0, 2, 3)) + // Verify items that didn't exist in grid A are added in new screen + assertThat(locMap[testPackage9]).isEqualTo(Triple(0, 0, 2)) + + // remove item from B + modelHelper.deleteItem(7, TMP_TABLE) + + // migrate from A -> B + GridSizeMigrationUtil.migrate( + context, + db, + readerGridA, + readerGridB, + idp.numDatabaseHotseatIcons, + Point(idp.numColumns, idp.numRows), + DeviceGridState(context), + DeviceGridState(idp) + ) + + // Check hotseat items in grid B + c = context.contentResolver.query( + CONTENT_URI, + arrayOf(SCREEN, INTENT), + "container=$CONTAINER_HOTSEAT", + null, + SCREEN, + null + ) ?: throw IllegalStateException() + // Expected hotseat items in grid B + // 2 1 3 4 + verifyHotseat(c, idp, + mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()) + + // Check workspace items in grid B + c = context.contentResolver.query( + CONTENT_URI, + arrayOf(SCREEN, CELLX, CELLY, INTENT), + "container=$CONTAINER_DESKTOP", + null, + null, + null + ) ?: throw IllegalStateException() + locMap = parseLocMap(context, c) + // Expected workspace items in grid B + // _ _ _ _ + // 5 6 _ 8 + // 9 _ _ _ + // _ _ _ _ + assertThat(locMap.size.toLong()).isEqualTo(4) + assertThat(locMap[testPackage5]).isEqualTo(Triple(0, 0, 1)) + assertThat(locMap[testPackage6]).isEqualTo(Triple(0, 1, 1)) + assertThat(locMap[testPackage8]).isEqualTo(Triple(0, 3, 1)) + assertThat(locMap[testPackage9]).isEqualTo(Triple(0, 0, 2)) + } + + private fun verifyHotseat(c: Cursor, idp: InvariantDeviceProfile, expected: List<String?>) { + assertThat(c.count).isEqualTo(idp.numDatabaseHotseatIcons) + val screenIndex = c.getColumnIndex(SCREEN) + val intentIndex = c.getColumnIndex(INTENT) + expected.forEachIndexed { idx, pkg -> + if (pkg == null) return@forEachIndexed + c.moveToNext() + assertThat(c.getInt(screenIndex).toLong()).isEqualTo(idx) + assertThat(c.getString(intentIndex)).contains(pkg) + } + c.close() + } + + private fun parseLocMap(context: Context, c: Cursor): Map<String, Triple<Int, Int, Int>> { + // Check workspace items + val intentIndex = c.getColumnIndex(INTENT) + val screenIndex = c.getColumnIndex(SCREEN) + val cellXIndex = c.getColumnIndex(CELLX) + val cellYIndex = c.getColumnIndex(CELLY) + val locMap = mutableMapOf<String, Triple<Int, Int, Int>>() + while (c.moveToNext()) { + locMap[Intent.parseUri(c.getString(intentIndex), 0).getPackage()] = + Triple(c.getInt(screenIndex), c.getInt(cellXIndex), c.getInt(cellYIndex)) + } + c.close() + return locMap.toMap() } @Test @@ -207,15 +426,16 @@ class GridSizeMigrationTaskV2Test { idp.numRows = 4 val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) - val task = GridSizeMigrationTaskV2( - context, - db, - srcReader, - destReader, - idp.numDatabaseHotseatIcons, - Point(idp.numColumns, idp.numRows) + GridSizeMigrationUtil.migrate( + context, + db, + srcReader, + destReader, + idp.numDatabaseHotseatIcons, + Point(idp.numColumns, idp.numRows), + DeviceGridState(context), + DeviceGridState(idp) ) - task.migrate(DeviceGridState(context), DeviceGridState(idp)) // Check hotseat items val c = context.contentResolver.query( @@ -262,15 +482,16 @@ class GridSizeMigrationTaskV2Test { idp.numRows = 4 val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) - val task = GridSizeMigrationTaskV2( - context, - db, - srcReader, - destReader, - idp.numDatabaseHotseatIcons, - Point(idp.numColumns, idp.numRows) + GridSizeMigrationUtil.migrate( + context, + db, + srcReader, + destReader, + idp.numDatabaseHotseatIcons, + Point(idp.numColumns, idp.numRows), + DeviceGridState(context), + DeviceGridState(idp) ) - task.migrate(DeviceGridState(context), DeviceGridState(idp)) // Check hotseat items val c = context.contentResolver.query( @@ -327,15 +548,16 @@ class GridSizeMigrationTaskV2Test { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) - val task = GridSizeMigrationTaskV2( - context, - db, - srcReader, - destReader, - idp.numDatabaseHotseatIcons, - Point(idp.numColumns, idp.numRows) + GridSizeMigrationUtil.migrate( + context, + db, + srcReader, + destReader, + idp.numDatabaseHotseatIcons, + Point(idp.numColumns, idp.numRows), + DeviceGridState(context), + DeviceGridState(idp) ) - task.migrate(DeviceGridState(context), DeviceGridState(idp)) // Get workspace items val c = context.contentResolver.query( @@ -387,15 +609,16 @@ class GridSizeMigrationTaskV2Test { idp.numRows = 5 val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) - val task = GridSizeMigrationTaskV2( - context, - db, - srcReader, - destReader, - idp.numDatabaseHotseatIcons, - Point(idp.numColumns, idp.numRows) + GridSizeMigrationUtil.migrate( + context, + db, + srcReader, + destReader, + idp.numDatabaseHotseatIcons, + Point(idp.numColumns, idp.numRows), + DeviceGridState(context), + DeviceGridState(idp) ) - task.migrate(DeviceGridState(context), DeviceGridState(idp)) // Get workspace items val c = context.contentResolver.query( @@ -448,15 +671,16 @@ class GridSizeMigrationTaskV2Test { idp.numRows = 4 val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) - val task = GridSizeMigrationTaskV2( - context, - db, - srcReader, - destReader, - idp.numDatabaseHotseatIcons, - Point(idp.numColumns, idp.numRows) + GridSizeMigrationUtil.migrate( + context, + db, + srcReader, + destReader, + idp.numDatabaseHotseatIcons, + Point(idp.numColumns, idp.numRows), + DeviceGridState(context), + DeviceGridState(idp) ) - task.migrate(DeviceGridState(context), DeviceGridState(idp)) // Get workspace items val c = context.contentResolver.query( diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt index 55520e8ade..c99ad7604a 100644 --- a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt +++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt @@ -63,13 +63,13 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { assertThat(dp.hotseatBarEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) - assertThat(dp.hotseatBorderSpace).isEqualTo(94) + assertThat(dp.hotseatBorderSpace).isEqualTo(72) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(121) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(121) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(110) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(110) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.hotseatQsbWidth).isEqualTo(1058) + assertThat(dp.hotseatQsbWidth).isEqualTo(1080) } /** @@ -84,13 +84,13 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { assertThat(dp.hotseatBarEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) - assertThat(dp.hotseatBorderSpace).isEqualTo(105) + assertThat(dp.hotseatBorderSpace).isEqualTo(104) assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(370) assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(370) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.hotseatQsbWidth).isEqualTo(1467) + assertThat(dp.hotseatQsbWidth).isEqualTo(1468) } /** @@ -130,13 +130,13 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { assertThat(dp.hotseatBarEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) - assertThat(dp.hotseatBorderSpace).isEqualTo(96) + assertThat(dp.hotseatBorderSpace).isEqualTo(91) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(643) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(643) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(640) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(640) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.hotseatQsbWidth).isEqualTo(1174) + assertThat(dp.hotseatQsbWidth).isEqualTo(1179) } /** @@ -152,12 +152,12 @@ class HotseatWidthCalculationTest : DeviceProfileBaseTest() { assertThat(dp.hotseatBarEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) - assertThat(dp.hotseatBorderSpace).isEqualTo(89) + assertThat(dp.hotseatBorderSpace).isEqualTo(75) - assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(589) - assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(589) + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(582) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(582) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.hotseatQsbWidth).isEqualTo(1081) + assertThat(dp.hotseatQsbWidth).isEqualTo(1095) } } diff --git a/tests/src/com/android/launcher3/search/StringMatcherUtilityTest.java b/tests/src/com/android/launcher3/search/StringMatcherUtilityTest.java index 413f404406..3b53255550 100644 --- a/tests/src/com/android/launcher3/search/StringMatcherUtilityTest.java +++ b/tests/src/com/android/launcher3/search/StringMatcherUtilityTest.java @@ -24,6 +24,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.search.StringMatcherUtility.StringMatcher; +import com.android.launcher3.search.StringMatcherUtility.StringMatcherSpace; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,11 +35,12 @@ import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) public class StringMatcherUtilityTest { - private static final StringMatcher MATCHER = - StringMatcher.getInstance(); + private static final StringMatcher MATCHER = StringMatcher.getInstance(); + private static final StringMatcherSpace MATCHER_SPACE = StringMatcherSpace.getInstance(); @Test public void testMatches() { + assertTrue(matches("white", "white cow", MATCHER)); assertTrue(matches("white ", "white cow", MATCHER)); assertTrue(matches("white c", "white cow", MATCHER)); assertTrue(matches("cow", "white cow", MATCHER)); @@ -93,4 +95,47 @@ public class StringMatcherUtilityTest { assertFalse(matches("ㄷ", "로드라이브", MATCHER)); assertFalse(matches("åç", "abc", MATCHER)); } + + @Test + public void testMatchesWithSpaceBreakOnly() { + assertTrue(matches("white", "white cow", MATCHER_SPACE)); + assertTrue(matches("white ", "white cow", MATCHER_SPACE)); + assertTrue(matches("white c", "white cow", MATCHER_SPACE)); + assertTrue(matches("cow", "white cow", MATCHER_SPACE)); + assertTrue(matches("cow", "whitecow cow", MATCHER_SPACE)); + + assertFalse(matches("cow", "whiteCow", MATCHER_SPACE)); + assertFalse(matches("cow", "whiteCOW", MATCHER_SPACE)); + assertFalse(matches("cow", "whitecowCOW", MATCHER_SPACE)); + assertFalse(matches("cow", "white2cow", MATCHER_SPACE)); + assertFalse(matches("cow", "whitecow", MATCHER_SPACE)); + assertFalse(matches("cow", "whitEcow", MATCHER_SPACE)); + assertFalse(matches("cow", "whitecowCow", MATCHER_SPACE)); + assertFalse(matches("cow", "whitecowcow", MATCHER_SPACE)); + assertFalse(matches("cow", "whit ecowcow", MATCHER_SPACE)); + + assertFalse(matches("dog", "cats&dogs", MATCHER_SPACE)); + assertFalse(matches("dog", "cats&Dogs", MATCHER_SPACE)); + assertFalse(matches("&", "cats&Dogs", MATCHER_SPACE)); + + assertFalse(matches("43", "2+43", MATCHER_SPACE)); + assertFalse(matches("3", "2+43", MATCHER_SPACE)); + + assertTrue(matches("q", "Q", MATCHER_SPACE)); + assertTrue(matches("q", " Q", MATCHER_SPACE)); + + // match lower case words + assertTrue(matches("e", "elephant", MATCHER_SPACE)); + assertTrue(matches("eL", "Elephant", MATCHER_SPACE)); + + assertTrue(matches("电", "电子邮件", MATCHER_SPACE)); + assertTrue(matches("电子", "电子邮件", MATCHER_SPACE)); + assertTrue(matches("子", "电子邮件", MATCHER_SPACE)); + assertTrue(matches("邮件", "电子邮件", MATCHER_SPACE)); + + assertFalse(matches("ba", "Bot", MATCHER_SPACE)); + assertFalse(matches("ba", "bot", MATCHER_SPACE)); + assertFalse(matches("phant", "elephant", MATCHER_SPACE)); + assertFalse(matches("elephants", "elephant", MATCHER_SPACE)); + } } diff --git a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java index 93fa705880..082e243694 100644 --- a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java +++ b/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java @@ -15,39 +15,273 @@ */ package com.android.launcher3.secondarydisplay; -import static androidx.test.core.app.ActivityScenario.launch; +import static android.content.Context.MODE_PRIVATE; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.view.MotionEvent.ACTION_DOWN; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Point; +import android.os.SystemClock; +import android.view.MotionEvent; +import android.widget.TextView; -import androidx.test.core.app.ActivityScenario; -import androidx.test.espresso.intent.Intents; import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.MediumTest; +import androidx.test.filters.LargeTest; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.Until; + +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.tapl.LauncherInstrumentation; +import com.android.launcher3.ui.AbstractLauncherUiTest; +import com.android.launcher3.util.LauncherModelHelper; import org.junit.After; -import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; /** - * Tests for {@link SecondaryDisplayLauncher} + * Tests for {@link SecondaryDisplayLauncher}. + * TODO (b/242776943): Remove anti-patterns & migrate prediction row tests to Quickstep directory */ -@MediumTest +@LargeTest @RunWith(AndroidJUnit4.class) -public class SecondaryDisplayLauncherTest { +public final class SecondaryDisplayLauncherTest extends AbstractLauncherUiTest { + private static final int WAIT_TIME_MS = 5000; + private static final int LONG_PRESS_DURATION_MS = 1000; + private static final int DRAG_TIME_MS = 160; + + private static final String PINNED_APPS_KEY = "pinned_apps"; - @Before - public void setUp() { - Intents.init(); + // Variables required to coordinate drag steps. + private Point mStartPoint; + private Point mEndPoint; + private long mDownTime; + + @Override + public void setUp() throws Exception { + super.setUp(); + setDragNDropFlag(true); } @After public void tearDown() { - Intents.release(); + mTargetContext.getSharedPreferences(PINNED_APPS_KEY, MODE_PRIVATE) + .edit().clear().commit(); + } + + @Test + @Ignore + public void initializeSecondaryDisplayLauncher_allAppsButtonVisible() { + assertThat(findObjectByResourceName("all_apps_button")).isNotNull(); + } + + @Test + @Ignore + public void allAppsButtonTap_opensAppDrawer() { + openAppDrawer(); + assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull(); + } + + @Test + @Ignore("Launcher3 without quickstep doesn't have a predictions row.") + public void appDrawerOpened_predictionRowAppDividerVisible() { + openAppDrawer(); + assertThat(findObjectByResourceName("apps_divider_view")).isNotNull(); + } + + @Test + @Ignore + public void dragNDropDisabled_pinIconAddsToWorkspace() { + setDragNDropFlag(false); + openAppDrawer(); + UiObject2 app = findDescendantByResourceName( + findObjectByResourceName("apps_list_view"), "icon"); + app.click(LONG_PRESS_DURATION_MS); + UiObject2 popupContainer = findObjectByResourceName("popup_container"); + assertThat(popupContainer).isNotNull(); + UiObject2 pinIcon = findDescendantByTextOrDesc(popupContainer, "Add to home screen"); + assertThat(pinIcon).isNotNull(); + pinIcon.click(); + String appName = app.getContentDescription(); + assertThat(findAppInWorkspace(appName)).isNotNull(); + } + + @Test + @Ignore + public void pressBackFromAllApps_popupMenuOpen_returnsToWorkspace() { + openAppDrawer(); + assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull(); + + findDescendantByResourceName(findObjectByResourceName("apps_list_view"), "icon") + .click(LONG_PRESS_DURATION_MS); + assertThat(findObjectByResourceName("popup_container")).isNotNull(); + + // First back press should close only popup menu. + mDevice.pressBack(); + assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull(); + assertThat(findObjectByResourceName("popup_container")).isNull(); + + // Second back press should close app drawer. + mDevice.pressBack(); + assertThat(findObjectByResourceName("popup_container")).isNull(); + assertThat(findObjectByResourceName("search_container_all_apps")).isNull(); + } + + @Test + @Ignore("Launcher3 without quickstep doesn't have a predictions row.") + public void dragNDropFromPredictionsRow_pinToGrid() { + openAppDrawer(); + assertThat(findObjectByResourceName("prediction_row")).isNotNull(); + String appName = startDragFromPredictionRow(); + moveAppToCenterOfScreen(); + dropApp(); + + // Ensure app was added. + assertThat(findAppInWorkspace(appName)).isNotNull(); + } + + @Test + @Ignore + public void dragNDropFromAppDrawer_pinToGrid() { + openAppDrawer(); + String draggedAppName = startDragFromAllApps(); + moveAppToCenterOfScreen(); + dropApp(); + + // Ensure app was added. + assertThat(findAppInWorkspace(draggedAppName)).isNotNull(); } @Test - public void testAllAppsListOpens() { - ActivityScenario<SecondaryDisplayLauncher> launcher = - launch(SecondaryDisplayLauncher.class); - launcher.onActivity(l -> l.showAppDrawer(true)); + @Ignore + public void tapRemoveButton_unpinApp() { + openAppDrawer(); + String draggedAppName = startDragFromAllApps(); + moveAppToCenterOfScreen(); + dropApp(); + removeAppByName(draggedAppName); + assertThat(findAppInWorkspace(draggedAppName)).isNull(); + } + + private void openAppDrawer() { + UiObject2 allAppsButton = findObjectByResourceName("all_apps_button"); + assertThat(allAppsButton).isNotNull(); + allAppsButton.click(); + } + + private String startDragFromAllApps() { + // Find app from app drawer. + UiObject2 allApps = findObjectByResourceName("apps_list_view"); + assertThat(allApps).isNotNull(); + UiObject2 icon = findDescendantByResourceName(allApps, "icon"); + assertThat(icon).isNotNull(); + String appName = icon.getContentDescription(); + + // Start drag action. + mDownTime = SystemClock.uptimeMillis(); + mStartPoint = icon.getVisibleCenter(); + mEndPoint = new Point(mStartPoint.x, mStartPoint.y); + mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint, + LauncherInstrumentation.GestureScope.INSIDE); + assertThat(findObjectByResourceName("popup_container")).isNotNull(); + return appName; + } + + private String startDragFromPredictionRow() { + // Find app from predictions. + UiObject2 predictionRow = findObjectByResourceName("prediction_row"); + assertThat(predictionRow).isNotNull(); + + UiObject2 icon = findDescendantByResourceName(predictionRow, "icon"); + assertThat(icon).isNotNull(); + + String appName = icon.getContentDescription(); + UiObject2 app = findDescendantByAppName(predictionRow, appName); + assertThat(app).isNotNull(); + + // Start drag action. + mDownTime = SystemClock.uptimeMillis(); + mStartPoint = icon.getVisibleCenter(); + mEndPoint = new Point(mStartPoint.x, mStartPoint.y); + mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint, + LauncherInstrumentation.GestureScope.INSIDE); + assertThat(findObjectByResourceName("popup_container")).isNotNull(); + return appName; + } + + private void moveAppToCenterOfScreen() { + mEndPoint.set(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() / 2); + mLauncher.movePointer(mDownTime, SystemClock.uptimeMillis(), DRAG_TIME_MS, true, + mStartPoint, mEndPoint, LauncherInstrumentation.GestureScope.INSIDE); + } + + private void dropApp() { + mLauncher.sendPointer(mDownTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, + mEndPoint, LauncherInstrumentation.GestureScope.INSIDE); + } + + private void removeAppByName(String appName) { + // Find app within home screen. + UiObject2 app = findDescendantByAppName(findObjectByResourceName("workspace_grid"), + appName); + if (app == null) return; + + // Open app's popup container. + app.click(LONG_PRESS_DURATION_MS); + UiObject2 popupContainer = findObjectByResourceName("popup_container"); + assertThat(popupContainer).isNotNull(); + + // Grab & click remove button. + UiObject2 removeButton = findDescendantByTextOrDesc(popupContainer, "Remove"); + assertThat(removeButton).isNotNull(); + removeButton.click(); + } + + private UiObject2 findAppInWorkspace(String appName) { + UiObject2 workspace = findObjectByResourceName("workspace_grid"); + return findDescendantByAppName(workspace, appName); + } + + private UiObject2 findObjectByResourceName(String resourceName) { + return mDevice.wait(Until.findObject(By.res(mTargetPackage, resourceName)), WAIT_TIME_MS); + } + + private UiObject2 findDescendantByResourceName(UiObject2 outerObject, + String resourceName) { + assertThat(outerObject).isNotNull(); + return outerObject.findObject(By.res(mTargetPackage, resourceName)); + } + + private UiObject2 findDescendantByAppName(UiObject2 outerObject, String appName) { + assertThat(outerObject).isNotNull(); + return outerObject.findObject(By.clazz(TextView.class).text(appName) + .pkg(mDevice.getLauncherPackageName())); + } + + private UiObject2 findDescendantByTextOrDesc(UiObject2 outerObject, String content) { + assertThat(outerObject).isNotNull(); + UiObject2 innerObject = outerObject.findObject(By.desc(content)); + if (innerObject == null) innerObject = outerObject.findObject(By.text(content)); + return innerObject; + } + + private void startSecondaryDisplayActivity() { + mTargetContext.startActivity(( + new Intent(mTargetContext, SecondaryDisplayLauncher.class).addFlags( + FLAG_ACTIVITY_NEW_TASK))); + } + + private void setDragNDropFlag(Boolean status) { + Context context = new LauncherModelHelper().sandboxContext; + context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit() + .putBoolean(FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.key, status) + .commit(); + FeatureFlags.initialize(context); + startSecondaryDisplayActivity(); } } diff --git a/tests/src/com/android/launcher3/testcomponent/AppWidgetWithDialog.java b/tests/src/com/android/launcher3/testcomponent/AppWidgetWithDialog.java new file mode 100644 index 0000000000..6d617fa240 --- /dev/null +++ b/tests/src/com/android/launcher3/testcomponent/AppWidgetWithDialog.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 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.launcher3.testcomponent; + +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.content.Context; +import android.content.Intent; +import android.widget.RemoteViews; + +/** + * A simple app widget with shows a dialog on clicking. + */ +public class AppWidgetWithDialog extends AppWidgetNoConfig { + + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + int layoutId = context.getResources().getIdentifier( + "test_layout_appwidget_blue", "layout", context.getPackageName()); + RemoteViews views = new RemoteViews(context.getPackageName(), layoutId); + + PendingIntent pi = PendingIntent.getActivity(context, 0, + new Intent(context, DialogTestActivity.class), PendingIntent.FLAG_IMMUTABLE); + views.setOnClickPendingIntent(android.R.id.content, pi); + AppWidgetManager.getInstance(context).updateAppWidget(appWidgetIds, views); + } +} diff --git a/tests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java b/tests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java index 9c6d10232e..d3ce67c81c 100644 --- a/tests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java +++ b/tests/src/com/android/launcher3/testcomponent/BaseTestingActivity.java @@ -24,7 +24,9 @@ import android.graphics.Color; import android.os.Bundle; import android.util.TypedValue; import android.view.View; +import android.view.WindowInsets; import android.widget.Button; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; @@ -81,6 +83,20 @@ public class BaseTestingActivity extends Activity implements View.OnClickListene mView.addView(button, lp); } + protected void addEditor(String initText, String hint, boolean requestIme) { + EditText editText = new EditText(this); + editText.setHint(hint); + editText.setText(initText); + + LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + lp.bottomMargin = mMargin; + mView.addView(editText, lp); + if (requestIme) { + editText.requestFocus(); + mView.getWindowInsetsController().show(WindowInsets.Type.ime()); + } + } + @Override protected void onResume() { super.onResume(); diff --git a/tests/src/com/android/launcher3/testcomponent/DialogTestActivity.java b/tests/src/com/android/launcher3/testcomponent/DialogTestActivity.java new file mode 100644 index 0000000000..9e5a2740f7 --- /dev/null +++ b/tests/src/com/android/launcher3/testcomponent/DialogTestActivity.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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.launcher3.testcomponent; + + +/** + * Extension of BaseTestingActivity with a Dialog theme + */ +public class DialogTestActivity extends BaseTestingActivity {} diff --git a/tests/src/com/android/launcher3/testcomponent/ImeTestActivity.java b/tests/src/com/android/launcher3/testcomponent/ImeTestActivity.java new file mode 100644 index 0000000000..43952d5508 --- /dev/null +++ b/tests/src/com/android/launcher3/testcomponent/ImeTestActivity.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 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.launcher3.testcomponent; + +import android.os.Bundle; + +public class ImeTestActivity extends OtherBaseTestingActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Requests to focus an editor and show IME for test. + addEditor("Focused editor for test", "Focused editor for test", true); + } +} diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 2d519d98da..70d122bc90 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -479,6 +479,16 @@ public abstract class AbstractLauncherUiTest { false /* newTask */); } + public static void startImeTestActivity() { + final String packageName = getAppPackageName(); + final Intent intent = getInstrumentation().getContext().getPackageManager(). + getLaunchIntentForPackage(packageName); + intent.setComponent(new ComponentName(packageName, + "com.android.launcher3.testcomponent.ImeTestActivity")); + startIntent(intent, By.pkg(packageName).text("ImeTestActivity"), + false /* newTask */); + } + private static void startIntent(Intent intent, BySelector selector, boolean newTask) { intent.addCategory(Intent.CATEGORY_LAUNCHER); if (newTask) { diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java index 07bfe4c971..e1a2c1bf4d 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -18,8 +18,6 @@ package com.android.launcher3.ui; import static androidx.test.InstrumentationRegistry.getInstrumentation; -import android.platform.test.annotations.IwTest; - import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; @@ -31,6 +29,7 @@ import static org.junit.Assume.assumeTrue; import android.content.Intent; import android.graphics.Point; +import android.platform.test.annotations.IwTest; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; @@ -196,6 +195,15 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test @PortraitLandscape + public void testAllAppsSwitchToWorkspace() { + assertNotNull("switchToWorkspace() returned null", + mLauncher.getWorkspace().switchToAllApps().switchToWorkspace()); + assertTrue("Launcher internal state is not Workspace", + isInState(() -> LauncherState.NORMAL)); + } + + @Test + @PortraitLandscape public void testAllAppsDeadzoneForTablet() throws Exception { assumeTrue(mLauncher.isTablet()); @@ -336,6 +344,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @IwTest(focusArea="launcher") @Test @PortraitLandscape + @ScreenRecord // b/256898879 public void testDragAppIcon() throws Throwable { // 1. Open all apps and wait for load complete. // 2. Drag icon to homescreen. @@ -437,6 +446,23 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test @PortraitLandscape + public void testDragAndCancelAppIcon() { + final HomeAppIcon homeAppIcon = createShortcutInCenterIfNotExist(GMAIL_APP_NAME); + Point positionBeforeDrag = + mLauncher.getWorkspace().getWorkspaceIconsPositions().get(GMAIL_APP_NAME); + assertNotNull("App not found in Workspace before dragging.", positionBeforeDrag); + + mLauncher.getWorkspace().dragAndCancelAppIcon(homeAppIcon); + + Point positionAfterDrag = + mLauncher.getWorkspace().getWorkspaceIconsPositions().get(GMAIL_APP_NAME); + assertNotNull("App not found in Workspace after dragging.", positionAfterDrag); + assertEquals("App not returned to same position in Workspace after drag & cancel", + positionBeforeDrag, positionAfterDrag); + } + + @Test + @PortraitLandscape public void testDeleteFromWorkspace() throws Exception { // test delete both built-in apps and user-installed app from workspace for (String appName : new String[]{"Gmail", "Play Store", APP_NAME}) { @@ -462,7 +488,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test @PortraitLandscape public void testUninstallFromWorkspace() throws Exception { - TestUtil.installDummyApp(); + installDummyAppAndWaitForUIUpdate(); try { verifyAppUninstalledFromAllApps( createShortcutInCenterIfNotExist(DUMMY_APP_NAME).uninstall(), DUMMY_APP_NAME); @@ -473,8 +499,9 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test @PortraitLandscape + @ScreenRecord // (b/256659409) public void testUninstallFromAllApps() throws Exception { - TestUtil.installDummyApp(); + installDummyAppAndWaitForUIUpdate(); try { Workspace workspace = mLauncher.getWorkspace(); final HomeAllApps allApps = workspace.switchToAllApps(); @@ -519,7 +546,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { Point[] gridPositions = getCornersAndCenterPositions(); createShortcutIfNotExist(STORE_APP_NAME, gridPositions[0]); createShortcutIfNotExist(MAPS_APP_NAME, gridPositions[1]); - TestUtil.installDummyApp(); + installDummyAppAndWaitForUIUpdate(); try { createShortcutIfNotExist(DUMMY_APP_NAME, gridPositions[2]); Map<String, Point> initialPositions = @@ -570,6 +597,17 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { mLauncher.getWorkspace().getHotseatAppIcon(APP_NAME)); } + private void installDummyAppAndWaitForUIUpdate() throws IOException { + TestUtil.installDummyApp(); + // Wait for model thread completion as it may be processing + // the install event from the SystemService + mLauncher.waitForModelQueueCleared(); + // Wait for Launcher UI thread completion, as it may be processing updating the UI in + // response to the model update. Not that `waitForLauncherInitialized` is just a proxy + // method, we can use any method which touches Launcher UI thread, + mLauncher.waitForLauncherInitialized(); + } + /** * @return List of workspace grid coordinates. Those are not pixels. See {@link * Workspace#getIconGridDimensions()} diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java index 302bd2fd59..c7628ccd63 100644 --- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java +++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java @@ -38,6 +38,7 @@ import com.android.launcher3.tapl.LauncherInstrumentation; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import java.util.Objects; @@ -118,6 +119,7 @@ public class WorkProfileTest extends AbstractLauncherUiTest { } @Test + @Ignore("b/243855320") public void toggleWorks() { assumeTrue(mWorkProfileSetupSuccessful); waitForWorkTabSetup(); diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java index 561f3ccbf2..0fccf7960b 100644 --- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java @@ -33,6 +33,7 @@ import com.android.launcher3.ui.TestViewHelpers; import com.android.launcher3.util.rule.ShellCommandRule; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,6 +55,8 @@ public class AddWidgetTest extends AbstractLauncherUiTest { clearHomescreen(); mDevice.pressHome(); + waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading()); + final LauncherAppWidgetProviderInfo widgetInfo = TestViewHelpers.findWidgetProvider(this, false /* hasConfigureScreen */); @@ -83,6 +86,7 @@ public class AddWidgetTest extends AbstractLauncherUiTest { * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it. * Custom shortcuts are replaced by deep shortcuts after api 25. */ + @Ignore @Test @PortraitLandscape public void testDragCustomShortcut() throws Throwable { diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java index fa39ce0604..0f861eb1f3 100644 --- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java @@ -190,7 +190,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest { waitForLauncherCondition("App widget options did not update", l -> appWidgetManager.getAppWidgetOptions(appWidgetId).getBoolean( WidgetManagerHelper.WIDGET_OPTION_RESTORE_COMPLETED)); - executeOnLauncher(l -> l.getAppWidgetHost().startListening()); + executeOnLauncher(l -> l.getAppWidgetHolder().startListening()); verifyWidgetPresent(info); assertNull(mLauncher.getWorkspace().tryGetPendingWidget(100)); } diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java index e66810cc3d..9dae00c29c 100644 --- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java +++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java @@ -32,8 +32,11 @@ import com.android.launcher3.BubbleTextView; import com.android.launcher3.icons.ThemedIconDrawable; import com.android.launcher3.tapl.HomeAllApps; import com.android.launcher3.tapl.HomeAppIcon; +import com.android.launcher3.tapl.HomeAppIconMenuItem; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TaplTestsLauncher3; +import com.android.launcher3.util.Executors; +import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; import org.junit.Test; @@ -48,7 +51,9 @@ import java.util.Queue; @LargeTest public class ThemeIconsTest extends AbstractLauncherUiTest { - private static final String APP_NAME = "ThemeIconTestActivity"; + private static final String APP_NAME = "IconThemedActivity"; + private static final String SHORTCUT_APP_NAME = "LauncherTestApp"; + private static final String SHORTCUT_NAME = "Shortcut 1"; @Test public void testIconWithoutTheme() throws Exception { @@ -60,9 +65,28 @@ public class ThemeIconsTest extends AbstractLauncherUiTest { try { HomeAppIcon icon = allApps.getAppIcon(APP_NAME); - executeOnLauncher(l -> verifyIconTheme(l.getAppsView(), false)); + executeOnLauncher(l -> verifyIconTheme(APP_NAME, l.getAppsView(), false)); icon.dragToWorkspace(false, false); - executeOnLauncher(l -> verifyIconTheme(l.getWorkspace(), false)); + executeOnLauncher(l -> verifyIconTheme(APP_NAME, l.getWorkspace(), false)); + } finally { + allApps.unfreeze(); + } + } + + @Test + public void testShortcutIconWithoutTheme() throws Exception { + setThemeEnabled(false); + TaplTestsLauncher3.initialize(this); + + HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps(); + allApps.freeze(); + + try { + HomeAppIcon icon = allApps.getAppIcon(SHORTCUT_APP_NAME); + HomeAppIconMenuItem shortcutItem = + (HomeAppIconMenuItem) icon.openDeepShortcutMenu().getMenuItem(SHORTCUT_NAME); + shortcutItem.dragToWorkspace(false, false); + executeOnLauncher(l -> verifyIconTheme(SHORTCUT_NAME, l.getWorkspace(), false)); } finally { allApps.unfreeze(); } @@ -78,15 +102,42 @@ public class ThemeIconsTest extends AbstractLauncherUiTest { try { HomeAppIcon icon = allApps.getAppIcon(APP_NAME); - executeOnLauncher(l -> verifyIconTheme(l.getAppsView(), false)); + executeOnLauncher(l -> verifyIconTheme(APP_NAME, l.getAppsView(), false)); icon.dragToWorkspace(false, false); - executeOnLauncher(l -> verifyIconTheme(l.getWorkspace(), true)); + executeOnLauncher(l -> verifyIconTheme(APP_NAME, l.getWorkspace(), true)); } finally { allApps.unfreeze(); } } - private void verifyIconTheme(ViewGroup parent, boolean isThemed) { + @Test + @ScreenRecord // b/260722220 + public void testShortcutIconWithTheme() throws Exception { + setThemeEnabled(true); + TaplTestsLauncher3.initialize(this); + + HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps(); + allApps.freeze(); + + try { + HomeAppIcon icon = allApps.getAppIcon(SHORTCUT_APP_NAME); + HomeAppIconMenuItem shortcutItem = + (HomeAppIconMenuItem) icon.openDeepShortcutMenu().getMenuItem(SHORTCUT_NAME); + shortcutItem.dragToWorkspace(false, false); + executeOnLauncher(l -> verifyIconTheme(SHORTCUT_NAME, l.getWorkspace(), true)); + } finally { + allApps.unfreeze(); + } + } + + private void verifyIconTheme(String title, ViewGroup parent, boolean isThemed) { + // Wait for Launcher model to be completed + try { + Executors.MODEL_EXECUTOR.submit(() -> { }).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + // Find the app icon Queue<View> viewQueue = new ArrayDeque<>(); viewQueue.add(parent); @@ -100,7 +151,7 @@ public class ThemeIconsTest extends AbstractLauncherUiTest { } } else if (view instanceof BubbleTextView) { BubbleTextView btv = (BubbleTextView) view; - if (APP_NAME.equals(btv.getText())) { + if (title.equals(btv.getText())) { icon = btv; break; } diff --git a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java index f646b504a9..6a938daf96 100644 --- a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java +++ b/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java @@ -31,6 +31,7 @@ import com.android.launcher3.tapl.Workspace; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TaplTestsLauncher3; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -51,6 +52,7 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { @Before public void setUp() throws Exception { super.setUp(); + mLauncher.useTest2WorkspaceLayoutOnReload(); TaplTestsLauncher3.initialize(this); assumeTrue(mLauncher.isTwoPanels()); @@ -63,6 +65,11 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { }); } + @After + public void tearDown() { + mLauncher.useDefaultWorkspaceLayoutOnReload(); + } + @Test @PortraitLandscape public void testDragIconToRightPanel() { @@ -339,4 +346,4 @@ public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest { + itemTitleSet.stream().collect(Collectors.joining(",")), itemTitleSet.isEmpty()); } -} +}
\ No newline at end of file diff --git a/tests/src/com/android/launcher3/util/ActivityContextWrapper.java b/tests/src/com/android/launcher3/util/ActivityContextWrapper.java index 2618a2e1f1..191d284939 100644 --- a/tests/src/com/android/launcher3/util/ActivityContextWrapper.java +++ b/tests/src/com/android/launcher3/util/ActivityContextWrapper.java @@ -20,15 +20,21 @@ import android.content.ContextWrapper; import android.view.ContextThemeWrapper; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; +import java.util.ArrayList; +import java.util.List; + /** * {@link ContextWrapper} with internal Launcher interface for testing */ public class ActivityContextWrapper extends ContextThemeWrapper implements ActivityContext { + private final List<OnDeviceProfileChangeListener> mDpChangeListeners = new ArrayList<>(); + private final DeviceProfile mProfile; private final MyDragLayer mMyDragLayer; @@ -44,6 +50,11 @@ public class ActivityContextWrapper extends ContextThemeWrapper implements Activ } @Override + public List<OnDeviceProfileChangeListener> getOnDeviceProfileChangeListeners() { + return mDpChangeListeners; + } + + @Override public DeviceProfile getDeviceProfile() { return mProfile; } diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java index e7e551fd0d..93bf31256d 100644 --- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -362,6 +362,12 @@ public class LauncherModelHelper { sandboxContext.getContentResolver().insert(contentUri, values); } + public void deleteItem(int itemId, @NonNull final String tableName) { + final Uri uri = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + tableName + "/" + itemId); + sandboxContext.getContentResolver().delete(uri, null, null); + } + public int[][][] createGrid(int[][][] typeArray) { return createGrid(typeArray, 1); } diff --git a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt b/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt index a4f189c6b3..bf3a092adb 100644 --- a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt +++ b/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt @@ -39,21 +39,21 @@ class MultiPropertyFactoryTest { } } - private val factory = MultiPropertyFactory("depth_property", receiveProperty) { + private val factory = MultiPropertyFactory(null, receiveProperty, 3) { x: Float, y: Float -> x + y } - private val p1 = factory.get(1) - private val p2 = factory.get(2) - private val p3 = factory.get(3) + private val p1 = factory.get(0) + private val p2 = factory.get(1) + private val p3 = factory.get(2) @Test fun set_sameIndexes_allApplied() { val v1 = 50f val v2 = 100f - p1.set(null, v1) - p1.set(null, v1) - p1.set(null, v2) + p1.value = v1 + p1.value = v1 + p1.value = v2 assertThat(received).containsExactly(v1, v1, v2) } @@ -63,9 +63,9 @@ class MultiPropertyFactoryTest { val v1 = 50f val v2 = 100f val v3 = 150f - p1.set(null, v1) - p2.set(null, v2) - p3.set(null, v3) + p1.value = v1 + p2.value = v2 + p3.value = v3 assertThat(received).containsExactly(v1, v1 + v2, v1 + v2 + v3) } diff --git a/tests/src/com/android/launcher3/util/TestUtil.java b/tests/src/com/android/launcher3/util/TestUtil.java index 67f3902095..d7c6c4fda9 100644 --- a/tests/src/com/android/launcher3/util/TestUtil.java +++ b/tests/src/com/android/launcher3/util/TestUtil.java @@ -17,8 +17,13 @@ package com.android.launcher3.util; import static androidx.test.InstrumentationRegistry.getContext; import static androidx.test.InstrumentationRegistry.getInstrumentation; +import static androidx.test.InstrumentationRegistry.getTargetContext; +import android.content.pm.LauncherApps; import android.content.res.Resources; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; import androidx.test.uiautomator.UiDevice; @@ -27,6 +32,7 @@ import org.junit.Assert; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.concurrent.CountDownLatch; public class TestUtil { public static final String DUMMY_PACKAGE = "com.example.android.aardwolf"; @@ -40,24 +46,77 @@ public class TestUtil { final String apkFilename = getInstrumentation().getTargetContext(). getFilesDir().getPath() + "/dummy_app.apk"; - final FileOutputStream out = new FileOutputStream(apkFilename); - byte[] buff = new byte[1024]; - int read; + try (PackageInstallCheck pic = new PackageInstallCheck()) { + final FileOutputStream out = new FileOutputStream(apkFilename); + byte[] buff = new byte[1024]; + int read; - while ((read = in.read(buff)) > 0) { - out.write(buff, 0, read); - } - in.close(); - out.close(); + while ((read = in.read(buff)) > 0) { + out.write(buff, 0, read); + } + in.close(); + out.close(); - final String result = UiDevice.getInstance(getInstrumentation()) - .executeShellCommand("pm install " + apkFilename); - Assert.assertTrue("Failed to install wellbeing test apk; make sure the device is rooted", - "Success".equals(result.replaceAll("\\s+", ""))); + final String result = UiDevice.getInstance(getInstrumentation()) + .executeShellCommand("pm install " + apkFilename); + Assert.assertTrue( + "Failed to install wellbeing test apk; make sure the device is rooted", + "Success".equals(result.replaceAll("\\s+", ""))); + pic.mAddWait.await(); + } catch (InterruptedException e) { + throw new IOException(e); + } } public static void uninstallDummyApp() throws IOException { UiDevice.getInstance(getInstrumentation()).executeShellCommand( "pm uninstall " + DUMMY_PACKAGE); } + + private static class PackageInstallCheck extends LauncherApps.Callback + implements AutoCloseable { + + final CountDownLatch mAddWait = new CountDownLatch(1); + final LauncherApps mLauncherApps; + + PackageInstallCheck() { + mLauncherApps = getTargetContext().getSystemService(LauncherApps.class); + mLauncherApps.registerCallback(this, new Handler(Looper.getMainLooper())); + } + + private void verifyPackage(String packageName) { + if (DUMMY_PACKAGE.equals(packageName)) { + mAddWait.countDown(); + } + } + + @Override + public void onPackageAdded(String packageName, UserHandle user) { + verifyPackage(packageName); + } + + @Override + public void onPackageChanged(String packageName, UserHandle user) { + verifyPackage(packageName); + } + + @Override + public void onPackageRemoved(String packageName, UserHandle user) { } + + @Override + public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) { + for (String packageName : packageNames) { + verifyPackage(packageName); + } + } + + @Override + public void onPackagesUnavailable(String[] packageNames, UserHandle user, + boolean replacing) { } + + @Override + public void close() { + mLauncherApps.unregisterCallback(this); + } + } } diff --git a/tests/src/com/android/launcher3/util/TouchUtilTest.kt b/tests/src/com/android/launcher3/util/TouchUtilTest.kt new file mode 100644 index 0000000000..d6c6e91e49 --- /dev/null +++ b/tests/src/com/android/launcher3/util/TouchUtilTest.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 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.launcher3.util + +import android.view.InputDevice +import android.view.MotionEvent +import androidx.test.filters.SmallTest +import com.google.common.truth.Truth.assertThat +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Test +import org.junit.runner.RunWith + +/** Unit tests for [TouchUtil] */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class TouchUtilTest { + + @Test + fun isMouseRightClickDownOrMove_onMouseRightButton_returnsTrue() { + val ev = MotionEvent.obtain(200, 300, MotionEvent.ACTION_MOVE, 1.0f, 0.0f, 0) + ev.source = InputDevice.SOURCE_MOUSE + ev.buttonState = MotionEvent.BUTTON_SECONDARY + + assertThat(TouchUtil.isMouseRightClickDownOrMove(ev)).isTrue() + } + + @Test + fun isMouseRightClickDownOrMove_onMouseLeftButton_returnsFalse() { + val ev = MotionEvent.obtain(200, 300, MotionEvent.ACTION_MOVE, 1.0f, 0.0f, 0) + ev.source = InputDevice.SOURCE_MOUSE + ev.buttonState = MotionEvent.BUTTON_PRIMARY + + assertThat(TouchUtil.isMouseRightClickDownOrMove(ev)).isFalse() + } + + @Test + fun isMouseRightClickDownOrMove_onMouseTertiaryButton_returnsFalse() { + val ev = MotionEvent.obtain(200, 300, MotionEvent.ACTION_MOVE, 1.0f, 0.0f, 0) + ev.source = InputDevice.SOURCE_MOUSE + ev.buttonState = MotionEvent.BUTTON_TERTIARY + + assertThat(TouchUtil.isMouseRightClickDownOrMove(ev)).isFalse() + } + + @Test + fun isMouseRightClickDownOrMove_onDpadRightButton_returnsFalse() { + val ev = MotionEvent.obtain(200, 300, MotionEvent.ACTION_MOVE, 1.0f, 0.0f, 0) + ev.source = InputDevice.SOURCE_DPAD + ev.buttonState = MotionEvent.BUTTON_SECONDARY + + assertThat(TouchUtil.isMouseRightClickDownOrMove(ev)).isFalse() + } +} diff --git a/tests/src/com/android/launcher3/util/WidgetUtils.java b/tests/src/com/android/launcher3/util/WidgetUtils.java index 6fc84914f8..b0df0558dd 100644 --- a/tests/src/com/android/launcher3/util/WidgetUtils.java +++ b/tests/src/com/android/launcher3/util/WidgetUtils.java @@ -20,7 +20,6 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID; -import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; @@ -32,8 +31,8 @@ import android.os.Process; import com.android.launcher3.LauncherSettings; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; -import com.android.launcher3.widget.LauncherAppWidgetHost; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; +import com.android.launcher3.widget.LauncherWidgetHolder; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.WidgetManagerHelper; @@ -71,14 +70,19 @@ public class WidgetUtils { pendingInfo.minSpanY = item.minSpanY; Bundle options = pendingInfo.getDefaultSizeOptions(targetContext); - AppWidgetHost host = new LauncherAppWidgetHost(targetContext); - int widgetId = host.allocateAppWidgetId(); - if (!new WidgetManagerHelper(targetContext) - .bindAppWidgetIdIfAllowed(widgetId, info, options)) { - host.deleteAppWidgetId(widgetId); - throw new IllegalArgumentException("Unable to bind widget id"); + LauncherWidgetHolder holder = LauncherWidgetHolder.newInstance(targetContext); + try { + int widgetId = holder.allocateAppWidgetId(); + if (!new WidgetManagerHelper(targetContext) + .bindAppWidgetIdIfAllowed(widgetId, info, options)) { + holder.deleteAppWidgetId(widgetId); + throw new IllegalArgumentException("Unable to bind widget id"); + } + item.appWidgetId = widgetId; + } finally { + // Necessary to destroy the holder to free up possible activity context + holder.destroy(); } - item.appWidgetId = widgetId; } return item; } diff --git a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java index 98eb32e818..10afe13d62 100644 --- a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java +++ b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java @@ -45,7 +45,8 @@ public class AddToHomeScreenPrompt { mLauncher.clickObject( mLauncher.waitForObjectInContainer( mWidgetCell.getParent().getParent().getParent().getParent(), - By.text(ADD_AUTOMATICALLY))); + By.text(ADD_AUTOMATICALLY)), + LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER); mLauncher.waitUntilLauncherObjectGone(getSelector()); } } diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index 4791846626..6f6428ad78 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -16,6 +16,9 @@ package com.android.launcher3.tapl; +import static com.android.launcher3.tapl.LauncherInstrumentation.DEFAULT_POLL_INTERVAL; +import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS; + import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; @@ -37,6 +40,9 @@ import java.util.stream.Collectors; * Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview. */ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { + // Defer updates flag used to defer all apps updates by a test's request. + private static final int DEFER_UPDATES_TEST = 1 << 1; + private static final int MAX_SCROLL_ATTEMPTS = 40; private final int mHeight; @@ -46,8 +52,7 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { super(launcher); final UiObject2 allAppsContainer = verifyActiveContainer(); mHeight = mLauncher.getVisibleBounds(allAppsContainer).height(); - final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer, - "apps_list_view"); + final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer); // Wait for the recycler to populate. mLauncher.waitForObjectInContainer(appListRecycler, By.clazz(TextView.class)); verifyNotFrozen("All apps freeze flags upon opening all apps"); @@ -78,6 +83,11 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { LauncherInstrumentation.log("hasClickableIcon: icon center is under search box"); return false; } + if (iconCenterInRecyclerTopPadding(appListRecycler, icon)) { + LauncherInstrumentation.log( + "hasClickableIcon: icon center is under the app list recycler's top padding."); + return false; + } if (iconBounds.bottom > displayBottom) { LauncherInstrumentation.log("hasClickableIcon: icon bottom below bottom offset"); return false; @@ -92,6 +102,13 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { iconCenter.x, iconCenter.y); } + private boolean iconCenterInRecyclerTopPadding(UiObject2 appListRecycler, UiObject2 icon) { + final Point iconCenter = icon.getVisibleCenter(); + + return iconCenter.y <= mLauncher.getVisibleBounds(appListRecycler).top + + getAppsListRecyclerTopPadding(); + } + /** * Finds an icon. If the icon doesn't exist, return null. * Scrolls the app list when needed to make sure the icon is visible. @@ -105,9 +122,7 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "getting app icon " + appName + " on all apps")) { final UiObject2 allAppsContainer = verifyActiveContainer(); - final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer, - "apps_list_view"); - final UiObject2 searchBox = hasSearchBox() ? getSearchBox(allAppsContainer) : null; + final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer); int deviceHeight = mLauncher.getRealDisplaySize().y; int bottomGestureStartOnScreen = mLauncher.getBottomGestureStartOnScreen(); @@ -128,10 +143,9 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { mLauncher.getVisibleBounds(icon).top < bottomGestureStartOnScreen) .collect(Collectors.toList()), - hasSearchBox() - ? mLauncher.getVisibleBounds(searchBox).bottom - - mLauncher.getVisibleBounds(allAppsContainer).top - : 0); + mLauncher.getVisibleBounds(appListRecycler).top + + getAppsListRecyclerTopPadding() + - mLauncher.getVisibleBounds(allAppsContainer).top); verifyActiveContainer(); final int newScroll = getAllAppsScroll(); mLauncher.assertTrue( @@ -180,16 +194,22 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { protected abstract boolean hasSearchBox(); + protected abstract int getAppsListRecyclerTopPadding(); + private void scrollBackToBeginning() { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to scroll back in all apps")) { LauncherInstrumentation.log("Scrolling to the beginning"); final UiObject2 allAppsContainer = verifyActiveContainer(); - final UiObject2 searchBox = hasSearchBox() ? getSearchBox(allAppsContainer) : null; + final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer); int attempts = 0; final Rect margins = new Rect( - 0, hasSearchBox() ? mLauncher.getVisibleBounds(searchBox).bottom + 1 : 0, 0, 5); + /* left= */ 0, + mLauncher.getVisibleBounds(appListRecycler).top + + getAppsListRecyclerTopPadding() + 1, + /* right= */ 0, + /* bottom= */ 5); for (int scroll = getAllAppsScroll(); scroll != 0; @@ -220,7 +240,11 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); } - private UiObject2 getSearchBox(UiObject2 allAppsContainer) { + private UiObject2 getAppListRecycler(UiObject2 allAppsContainer) { + return mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view"); + } + + protected UiObject2 getSearchBox(UiObject2 allAppsContainer) { return mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps"); } @@ -274,12 +298,16 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer { */ public void unfreeze() { mLauncher.getTestInfo(TestProtocol.REQUEST_UNFREEZE_APP_LIST); - verifyNotFrozen("All apps freeze flags upon unfreezing"); } private void verifyNotFrozen(String message) { + mLauncher.assertEquals(message, 0, getFreezeFlags() & DEFER_UPDATES_TEST); + mLauncher.assertTrue(message, mLauncher.waitAndGet(() -> getFreezeFlags() == 0, + WAIT_TIME_MS, DEFAULT_POLL_INTERVAL)); + } + + private int getFreezeFlags() { final Bundle testInfo = mLauncher.getTestInfo(TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS); - if (testInfo == null) return; - mLauncher.assertEquals(message, 0, testInfo.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD)); + return testInfo == null ? 0 : testInfo.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); } }
\ No newline at end of file diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java index 516402563d..f804e28ceb 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java +++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromTaskbar.java @@ -18,6 +18,8 @@ package com.android.launcher3.tapl; import androidx.annotation.NonNull; import androidx.test.uiautomator.UiObject2; +import com.android.launcher3.testing.shared.TestProtocol; + /** * Operations on AllApps opened from the Taskbar. */ @@ -48,4 +50,10 @@ public class AllAppsFromTaskbar extends AllApps { protected boolean hasSearchBox() { return false; } + + @Override + protected int getAppsListRecyclerTopPadding() { + return mLauncher.getTestInfo(TestProtocol.REQUEST_TASKBAR_ALL_APPS_TOP_PADDING) + .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); + } } diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java index eb8d055a35..5a96d95316 100644 --- a/tests/tapl/com/android/launcher3/tapl/Background.java +++ b/tests/tapl/com/android/launcher3/tapl/Background.java @@ -58,7 +58,7 @@ public abstract class Background extends LauncherInstrumentation.VisibleContaine "want to switch from background to overview")) { verifyActiveContainer(); goToOverviewUnchecked(); - return mLauncher.isFallbackOverview() + return mLauncher.is3PLauncher() ? new BaseOverview(mLauncher) : new Overview(mLauncher); } } @@ -206,21 +206,30 @@ public abstract class Background extends LauncherInstrumentation.VisibleContaine MotionEvent.ACTION_UP, end, gestureScope); } + /** + * Quick switching to the app with swiping to right. + */ @NonNull public LaunchedAppState quickSwitchToPreviousApp() { - boolean toRight = true; - quickSwitch(toRight); + quickSwitch(true /* toRight */); return new LaunchedAppState(mLauncher); } + /** + * Quick switching to the app with swiping to left. + */ @NonNull public LaunchedAppState quickSwitchToPreviousAppSwipeLeft() { - boolean toRight = false; - quickSwitch(toRight); + quickSwitch(false /* toRight */); return new LaunchedAppState(mLauncher); } - @NonNull + /** + * Making swipe gesture to quick-switch app tasks. + * + * @param toRight {@code true} means swiping right, {@code false} means swiping left. + * @throws {@link AssertionError} when failing to verify the visible UI in the container. + */ private void quickSwitch(boolean toRight) { try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); LauncherInstrumentation.Closable c = mLauncher.addContextLayer( diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index f47f7105fc..afeb8d782b 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -244,43 +244,39 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { * Returns if clear all button is visible. */ public boolean isClearAllVisible() { - return mLauncher.hasLauncherObject(mLauncher.getOverviewObjectSelector("clear_all")); + return verifyActiveContainer().hasObject( + mLauncher.getOverviewObjectSelector("clear_all")); } protected boolean isActionsViewVisible() { + if (!hasTasks() || isClearAllVisible()) { + return false; + } OverviewTask task = mLauncher.isTablet() ? getFocusedTaskForTablet() : getCurrentTask(); if (task == null) { return false; } + // In tablets, if focused task is not in center, overview actions aren't visible. + if (mLauncher.isTablet() + && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) { + return false; + } + // Overview actions aren't visible for split screen tasks. return !task.isTaskSplit(); } private void verifyActionsViewVisibility() { - if (!hasTasks() || !isActionsViewVisible()) { - return; - } try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to assert overview actions view visibility")) { - if (mLauncher.isTablet() && !isOverviewSnappedToFocusedTaskForTablet()) { - mLauncher.waitUntilOverviewObjectGone("action_buttons"); - } else { + if (isActionsViewVisible()) { mLauncher.waitForOverviewObject("action_buttons"); + } else { + mLauncher.waitUntilOverviewObjectGone("action_buttons"); } } } /** - * Returns if focused task is currently snapped task in tablet grid overview. - */ - private boolean isOverviewSnappedToFocusedTaskForTablet() { - OverviewTask focusedTask = getFocusedTaskForTablet(); - if (focusedTask == null) { - return false; - } - return Math.abs(focusedTask.getExactCenterX() - mLauncher.getExactScreenCenterX()) < 1; - } - - /** * Returns Overview focused task if it exists. * * @throws IllegalStateException if not run on a tablet device. diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java index 7123de44a9..50b03aa7df 100644 --- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java @@ -15,9 +15,17 @@ */ package com.android.launcher3.tapl; +import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL; + +import android.graphics.Rect; + import androidx.annotation.NonNull; import androidx.test.uiautomator.UiObject2; +import com.android.launcher3.testing.shared.TestProtocol; + +import java.util.Objects; + public class HomeAllApps extends AllApps { private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background"; @@ -25,6 +33,42 @@ public class HomeAllApps extends AllApps { super(launcher); } + /** + * Swipes down to Workspace. + * + * @return the Workspace object. + */ + @NonNull + public Workspace switchToWorkspace() { + try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); + LauncherInstrumentation.Closable c = + mLauncher.addContextLayer("want to switch from all apps to workspace")) { + UiObject2 allAppsContainer = verifyActiveContainer(); + + final Rect searchBoxBounds = Objects.requireNonNull( + mLauncher.getVisibleBounds(getSearchBox(allAppsContainer))); + final int startX = searchBoxBounds.centerX(); + final int startY = searchBoxBounds.bottom; + final int endY = mLauncher.getDevice().getDisplayHeight(); + LauncherInstrumentation.log( + "switchToWorkspace: startY = " + startY + ", endY = " + endY + + ", slop = " + mLauncher.getTouchSlop()); + + mLauncher.swipeToState( + startX, + startY, + startX, + endY, + 12 /* steps */, + NORMAL_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE); + + try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( + "swiped to workspace")) { + return mLauncher.getWorkspace(); + } + } + } + @Override protected LauncherInstrumentation.ContainerType getContainerType() { return LauncherInstrumentation.ContainerType.HOME_ALL_APPS; @@ -47,6 +91,12 @@ public class HomeAllApps extends AllApps { return true; } + @Override + protected int getAppsListRecyclerTopPadding() { + return mLauncher.getTestInfo(TestProtocol.REQUEST_ALL_APPS_TOP_PADDING) + .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); + } + /** * Taps outside bottom sheet to dismiss and return to workspace. Available on tablets only. * @param tapRight Tap on the right of bottom sheet if true, or left otherwise. diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java index a17651b640..4a3507ed69 100644 --- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java +++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java @@ -17,7 +17,9 @@ package com.android.launcher3.tapl; import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID; +import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT; import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING; +import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT; import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING; import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT; @@ -55,7 +57,7 @@ public final class LaunchedAppState extends Background { public Taskbar getTaskbar() { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to get the taskbar")) { - mLauncher.waitForLauncherObject(TASKBAR_RES_ID); + mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); return new Taskbar(mLauncher); } @@ -67,7 +69,17 @@ public final class LaunchedAppState extends Background { public void assertTaskbarHidden() { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "waiting for taskbar to be hidden")) { - mLauncher.waitUntilLauncherObjectGone(TASKBAR_RES_ID); + mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); + } + } + + /** + * Waits for the taskbar to be visible, or fails. + */ + public void assertTaskbarVisible() { + try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( + "waiting for taskbar to be visible")) { + mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); } } @@ -78,11 +90,12 @@ public final class LaunchedAppState extends Background { */ public Taskbar showTaskbar() { mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING); + mLauncher.getTestInfo(REQUEST_ENABLE_BLOCK_TIMEOUT); try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( "want to show the taskbar")) { - mLauncher.waitUntilLauncherObjectGone(TASKBAR_RES_ID); + mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); final long downTime = SystemClock.uptimeMillis(); final int unstashTargetY = mLauncher.getRealDisplaySize().y @@ -96,7 +109,7 @@ public final class LaunchedAppState extends Background { LauncherInstrumentation.log("showTaskbar: sent down"); try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) { - mLauncher.waitForLauncherObject(TASKBAR_RES_ID); + mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget, LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER); @@ -104,6 +117,7 @@ public final class LaunchedAppState extends Background { } } finally { mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING); + mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT); } } diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 3986df6508..ae9ba6787b 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -48,7 +48,6 @@ import android.text.TextUtils; import android.util.Log; import android.view.InputDevice; import android.view.MotionEvent; -import android.view.Surface; import android.view.ViewConfiguration; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; @@ -84,6 +83,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.concurrent.TimeoutException; +import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -138,6 +138,15 @@ public final class LauncherInstrumentation { OUTSIDE_WITH_KEYCODE, } + /** + * Represents a point in the code at which a callback can run. + */ + public enum CALLBACK_RUN_POINT { + CALLBACK_HOLD_BEFORE_DROP + } + + private Consumer<CALLBACK_RUN_POINT> mCallbackAtRunPoint = null; + // Base class for launcher containers. abstract static class VisibleContainer { protected final LauncherInstrumentation mLauncher; @@ -173,6 +182,7 @@ public final class LauncherInstrumentation { static final String TASKBAR_RES_ID = "taskbar_view"; private static final String SPLIT_PLACEHOLDER_RES_ID = "split_placeholder"; public static final int WAIT_TIME_MS = 30000; + static final long DEFAULT_POLL_INTERVAL = 1000; private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; private static final String ANDROID_PACKAGE = "android"; @@ -180,11 +190,13 @@ public final class LauncherInstrumentation { private final UiDevice mDevice; private final Instrumentation mInstrumentation; - private int mExpectedRotation = Surface.ROTATION_0; + private Integer mExpectedRotation = null; private final Uri mTestProviderUri; private final Deque<String> mDiagnosticContext = new LinkedList<>(); private Function<Long, String> mSystemHealthSupplier; + private boolean mIgnoreTaskbarVisibility = false; + private Consumer<ContainerType> mOnSettledStateAction; private LogEventChecker mEventChecker; @@ -296,8 +308,8 @@ public final class LauncherInstrumentation { final String testSuffix = ".test"; return testPackage.endsWith(testSuffix) && testPackage.length() > testSuffix.length() - && testPackage.substring(0, testPackage.length() - testSuffix.length()) - .equals(targetPackage); + && testPackage.substring(0, testPackage.length() - testSuffix.length()) + .equals(targetPackage); } public void enableCheckEventsForSuccessfulGestures() { @@ -381,6 +393,10 @@ public final class LauncherInstrumentation { getTestInfo(TestProtocol.REQUEST_ENABLE_ROTATION, Boolean.toString(on)); } + public void setEnableSuggestion(boolean enableSuggestion) { + getTestInfo(TestProtocol.REQUEST_ENABLE_SUGGESTION, Boolean.toString(enableSuggestion)); + } + public boolean hadNontestEvents() { return getTestInfo(TestProtocol.REQUEST_GET_HAD_NONTEST_EVENTS) .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD); @@ -545,7 +561,7 @@ public final class LauncherInstrumentation { private String getVisibleStateMessage() { if (hasLauncherObject(CONTEXT_MENU_RES_ID)) return "Context Menu"; if (hasLauncherObject(WIDGETS_RES_ID)) return "Widgets"; - if (hasLauncherObject(OVERVIEW_RES_ID)) return "Overview"; + if (hasSystemLauncherObject(OVERVIEW_RES_ID)) return "Overview"; if (hasLauncherObject(WORKSPACE_RES_ID)) return "Workspace"; if (hasLauncherObject(APPS_RES_ID)) return "AllApps"; return "LaunchedApp (" + getVisiblePackages() + ")"; @@ -680,7 +696,24 @@ public final class LauncherInstrumentation { } } - public void setExpectedRotation(int expectedRotation) { + /** + * Whether to ignore verifying the task bar visibility during instrumenting. + * + * @param ignoreTaskbarVisibility {@code true} will ignore the instrumentation implicitly + * verifying the task bar visibility with + * {@link VisibleContainer#verifyActiveContainer}. + * {@code false} otherwise. + */ + public void setIgnoreTaskbarVisibility(boolean ignoreTaskbarVisibility) { + mIgnoreTaskbarVisibility = ignoreTaskbarVisibility; + } + + /** + * Sets expected rotation. + * TAPL periodically checks that Launcher didn't suddenly change the rotation to unexpected one. + * Null parameter disables checks. The initial state is "no checks". + */ + public void setExpectedRotation(Integer expectedRotation) { mExpectedRotation = expectedRotation; } @@ -717,8 +750,10 @@ public final class LauncherInstrumentation { private UiObject2 verifyContainerType(ContainerType containerType) { waitForLauncherInitialized(); - assertEquals("Unexpected display rotation", - mExpectedRotation, mDevice.getDisplayRotation()); + if (mExpectedRotation != null) { + assertEquals("Unexpected display rotation", + mExpectedRotation, mDevice.getDisplayRotation()); + } final String error = getNavigationModeMismatchError(true); assertTrue(error, error == null); @@ -738,70 +773,97 @@ public final class LauncherInstrumentation { switch (containerType) { case WORKSPACE: { waitUntilLauncherObjectGone(APPS_RES_ID); - waitUntilLauncherObjectGone(OVERVIEW_RES_ID); waitUntilLauncherObjectGone(WIDGETS_RES_ID); - waitUntilLauncherObjectGone(TASKBAR_RES_ID); - waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID); + waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + + if (is3PLauncher() && isTablet()) { + waitForSystemLauncherObject(TASKBAR_RES_ID); + } else { + waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); + } return waitForLauncherObject(WORKSPACE_RES_ID); } case WIDGETS: { waitUntilLauncherObjectGone(WORKSPACE_RES_ID); waitUntilLauncherObjectGone(APPS_RES_ID); - waitUntilLauncherObjectGone(OVERVIEW_RES_ID); - waitUntilLauncherObjectGone(TASKBAR_RES_ID); - waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID); + waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + + if (is3PLauncher() && isTablet()) { + waitForSystemLauncherObject(TASKBAR_RES_ID); + } else { + waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); + } return waitForLauncherObject(WIDGETS_RES_ID); } - case TASKBAR_ALL_APPS: - case HOME_ALL_APPS: { + case TASKBAR_ALL_APPS: { waitUntilLauncherObjectGone(WORKSPACE_RES_ID); - waitUntilLauncherObjectGone(OVERVIEW_RES_ID); waitUntilLauncherObjectGone(WIDGETS_RES_ID); - waitUntilLauncherObjectGone(TASKBAR_RES_ID); - waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID); + waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); + waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); return waitForLauncherObject(APPS_RES_ID); } - case OVERVIEW: { - waitUntilLauncherObjectGone(APPS_RES_ID); + case HOME_ALL_APPS: { waitUntilLauncherObjectGone(WORKSPACE_RES_ID); waitUntilLauncherObjectGone(WIDGETS_RES_ID); - waitUntilLauncherObjectGone(TASKBAR_RES_ID); - waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID); + waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + + if (is3PLauncher() && isTablet()) { + waitForSystemLauncherObject(TASKBAR_RES_ID); + } else { + waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); + } - return waitForLauncherObject(OVERVIEW_RES_ID); + return waitForLauncherObject(APPS_RES_ID); } - case SPLIT_SCREEN_SELECT: { + case OVERVIEW: + case FALLBACK_OVERVIEW: { waitUntilLauncherObjectGone(APPS_RES_ID); waitUntilLauncherObjectGone(WORKSPACE_RES_ID); waitUntilLauncherObjectGone(WIDGETS_RES_ID); - waitUntilLauncherObjectGone(TASKBAR_RES_ID); + if (isTablet()) { + waitForSystemLauncherObject(TASKBAR_RES_ID); + } else { + waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); + } + waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); - waitForLauncherObject(SPLIT_PLACEHOLDER_RES_ID); - return waitForLauncherObject(OVERVIEW_RES_ID); + return waitForSystemLauncherObject(OVERVIEW_RES_ID); } - case FALLBACK_OVERVIEW: { + case SPLIT_SCREEN_SELECT: { waitUntilLauncherObjectGone(APPS_RES_ID); waitUntilLauncherObjectGone(WORKSPACE_RES_ID); waitUntilLauncherObjectGone(WIDGETS_RES_ID); - waitUntilLauncherObjectGone(TASKBAR_RES_ID); - waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + if (isTablet()) { + waitForSystemLauncherObject(TASKBAR_RES_ID); + } else { + waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); + } - return waitForFallbackLauncherObject(OVERVIEW_RES_ID); + waitForSystemLauncherObject(SPLIT_PLACEHOLDER_RES_ID); + return waitForSystemLauncherObject(OVERVIEW_RES_ID); } case LAUNCHED_APP: { waitUntilLauncherObjectGone(WORKSPACE_RES_ID); waitUntilLauncherObjectGone(APPS_RES_ID); - waitUntilLauncherObjectGone(OVERVIEW_RES_ID); waitUntilLauncherObjectGone(WIDGETS_RES_ID); - waitUntilLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID); + waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID); + + if (mIgnoreTaskbarVisibility) { + return null; + } - if (isTablet() && !isFallbackOverview()) { - waitForLauncherObject(TASKBAR_RES_ID); + if (isTablet()) { + waitForSystemLauncherObject(TASKBAR_RES_ID); } else { - waitUntilLauncherObjectGone(TASKBAR_RES_ID); + waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); } return null; } @@ -812,6 +874,10 @@ public final class LauncherInstrumentation { } } + public void waitForModelQueueCleared() { + getTestInfo(TestProtocol.REQUEST_MODEL_QUEUE_CLEARED); + } + public void waitForLauncherInitialized() { for (int i = 0; i < 100; ++i) { if (getTestInfo( @@ -932,14 +998,9 @@ public final class LauncherInstrumentation { checkForAnomaly(false, true); final Point displaySize = getRealDisplaySize(); - // The swipe up to home gesture starts from inside the launcher when the user is - // already home. Otherwise, the gesture can start inside the launcher process if the - // taskbar is visible. - boolean gestureStartFromLauncher = isTablet() - ? !isLauncher3() - || hasLauncherObject(WORKSPACE_RES_ID) - || hasLauncherObject(TASKBAR_RES_ID) - : isLauncherVisible(); + + boolean gestureStartFromLauncher = + isTablet() ? !isLauncher3() : isLauncherVisible(); // CLose floating views before going back to home. swipeUpToCloseFloatingView(gestureStartFromLauncher); @@ -972,7 +1033,7 @@ public final class LauncherInstrumentation { NORMAL_STATE_ORDINAL, !hasLauncherObject(WORKSPACE_RES_ID) && (hasLauncherObject(APPS_RES_ID) - || hasLauncherObject(OVERVIEW_RES_ID)), + || hasSystemLauncherObject(OVERVIEW_RES_ID)), action); } try (LauncherInstrumentation.Closable c1 = addContextLayer( @@ -1028,7 +1089,8 @@ public final class LauncherInstrumentation { boolean isLauncherContainerVisible() { final String[] containerResources = {WORKSPACE_RES_ID, OVERVIEW_RES_ID, APPS_RES_ID}; - return Arrays.stream(containerResources).anyMatch(r -> hasLauncherObject(r)); + return Arrays.stream(containerResources).anyMatch( + r -> r.equals(OVERVIEW_RES_ID) ? hasSystemLauncherObject(r) : hasLauncherObject(r)); } /** @@ -1111,6 +1173,14 @@ public final class LauncherInstrumentation { waitUntilGoneBySelector(getOverviewObjectSelector(resId)); } + void waitUntilSystemLauncherObjectGone(String resId) { + if (is3PLauncher()) { + waitUntilOverviewObjectGone(resId); + } else { + waitUntilLauncherObjectGone(resId); + } + } + void waitUntilLauncherObjectGone(BySelector selector) { waitUntilGoneBySelector(makeLauncherSelector(selector)); } @@ -1241,6 +1311,11 @@ public final class LauncherInstrumentation { return mDevice.hasObject(getLauncherObjectSelector(resId)); } + private boolean hasSystemLauncherObject(String resId) { + return mDevice.hasObject(is3PLauncher() ? getOverviewObjectSelector(resId) + : getLauncherObjectSelector(resId)); + } + boolean hasLauncherObject(BySelector selector) { return mDevice.hasObject(makeLauncherSelector(selector)); } @@ -1260,6 +1335,12 @@ public final class LauncherInstrumentation { } @NonNull + UiObject2 waitForSystemLauncherObject(String resName) { + return is3PLauncher() ? waitForOverviewObject(resName) + : waitForLauncherObject(resName); + } + + @NonNull UiObject2 waitForLauncherObject(BySelector selector) { return waitForObjectBySelector(makeLauncherSelector(selector)); } @@ -1270,11 +1351,6 @@ public final class LauncherInstrumentation { } @NonNull - UiObject2 waitForFallbackLauncherObject(String resName) { - return waitForObjectBySelector(getOverviewObjectSelector(resName)); - } - - @NonNull UiObject2 waitForAndroidObject(String resId) { final UiObject2 object = TestHelpers.wait( Until.findObject(By.res(ANDROID_PACKAGE, resId)), WAIT_TIME_MS); @@ -1311,7 +1387,7 @@ public final class LauncherInstrumentation { return mDevice.getLauncherPackageName(); } - boolean isFallbackOverview() { + boolean is3PLauncher() { return !getOverviewPackageName().equals(getLauncherPackageName()); } @@ -1390,19 +1466,22 @@ public final class LauncherInstrumentation { return getRealDisplaySize().x - getWindowInsets().right - 1; } - void clickObject(UiObject2 object) { - waitForObjectEnabled(object, "clickObject"); - if (!isLauncher3() && getNavigationModel() != NavigationModel.THREE_BUTTON) { - expectEvent(TestProtocol.SEQUENCE_TIS, LauncherInstrumentation.EVENT_TOUCH_DOWN_TIS); - expectEvent(TestProtocol.SEQUENCE_TIS, LauncherInstrumentation.EVENT_TOUCH_UP_TIS); - } - object.click(); + /** + * Click on the ui object right away without waiting for animation. + * + * [UiObject2.click] would wait for all animations finished before clicking. Not waiting for + * animations because in some scenarios there is a playing animations when the click is + * attempted. + */ + void clickObject(UiObject2 uiObject, GestureScope gestureScope) { + final long clickTime = SystemClock.uptimeMillis(); + final Point center = uiObject.getVisibleCenter(); + sendPointer(clickTime, clickTime, MotionEvent.ACTION_DOWN, center, gestureScope); + sendPointer(clickTime, clickTime, MotionEvent.ACTION_UP, center, gestureScope); } void clickLauncherObject(UiObject2 object) { - expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_TOUCH_DOWN); - expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_TOUCH_UP); - clickObject(object); + clickObject(object, GestureScope.INSIDE); } void scrollToLastVisibleRow( @@ -1772,6 +1851,14 @@ public final class LauncherInstrumentation { getTestInfo(TestProtocol.REQUEST_USE_TEST_WORKSPACE_LAYOUT); } + /** + * Reloads the workspace with a test layout that includes Maps/Play on workspace, and + * Dialer/Messaging/Chrome/Camera on hotseat. + */ + public void useTest2WorkspaceLayoutOnReload() { + getTestInfo(TestProtocol.REQUEST_USE_TEST2_WORKSPACE_LAYOUT); + } + /** Reloads the workspace with the default layout defined by the user's grid size selection. */ public void useDefaultWorkspaceLayoutOnReload() { getTestInfo(TestProtocol.REQUEST_USE_DEFAULT_WORKSPACE_LAYOUT); @@ -1782,6 +1869,20 @@ public final class LauncherInstrumentation { getTestInfo(TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED); } + /** Blocks the taskbar from automatically stashing based on time. */ + public void enableBlockTimeout(boolean enable) { + getTestInfo(enable + ? TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT + : TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT); + } + + /** Enables transient taskbar for testing purposes only. */ + public void enableTransientTaskbar(boolean enable) { + getTestInfo(enable + ? TestProtocol.REQUEST_ENABLE_TRANSIENT_TASKBAR + : TestProtocol.REQUEST_DISABLE_TRANSIENT_TASKBAR); + } + /** * Recreates the taskbar (outside of tests this is done for certain configuration changes). * The expected behavior is that the taskbar retains its current state after being recreated. @@ -1935,4 +2036,37 @@ public final class LauncherInstrumentation { LauncherInstrumentation.GestureScope.INSIDE); } } + + /** + * Sets the consumer to run callbacks at all run-points. + */ + public void setRunPointCallback(Consumer<CALLBACK_RUN_POINT> callback) { + mCallbackAtRunPoint = callback; + } + + /** + * Runs the callback at the specified point if it exists. + */ + void runCallbackIfActive(CALLBACK_RUN_POINT runPoint) { + if (mCallbackAtRunPoint != null) { + mCallbackAtRunPoint.accept(runPoint); + } + } + + /** + * Waits until a particular condition is true. Based on WaitMixin. + */ + boolean waitAndGet(BooleanSupplier condition, long timeout, long interval) { + long startTime = SystemClock.uptimeMillis(); + + boolean result = condition.getAsBoolean(); + for (long elapsedTime = 0; !result; elapsedTime = SystemClock.uptimeMillis() - startTime) { + if (elapsedTime >= timeout) { + break; + } + SystemClock.sleep(interval); + result = condition.getAsBoolean(); + } + return result; + } } diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java index ddeeac225a..80e4116406 100644 --- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java +++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java @@ -20,6 +20,8 @@ import android.widget.TextView; import androidx.test.uiautomator.By; import androidx.test.uiautomator.UiObject2; +import java.util.ArrayList; + /** * Operations on search result page opened from home screen qsb. */ @@ -27,6 +29,9 @@ public class SearchResultFromQsb { // The input resource id in the search box. private static final String INPUT_RES = "input"; private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background"; + + // This particular ID change should happen with caution + private static final String SEARCH_CONTAINER_RES_ID = "search_results_list_view"; private final LauncherInstrumentation mLauncher; SearchResultFromQsb(LauncherInstrumentation launcher) { @@ -49,6 +54,33 @@ public class SearchResultFromQsb { return new AllAppsAppIcon(mLauncher, icon); } + /** Find the web suggestion from search suggestion's title text */ + public void verifyWebSuggestIsPresent(String text) { + ArrayList<UiObject2> goldenGateResults = + new ArrayList<>(mLauncher.waitForObjectsInContainer( + mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID), + By.clazz(TextView.class))); + boolean found = false; + for(UiObject2 uiObject: goldenGateResults) { + String currentString = uiObject.getText(); + if (currentString.equals(text)) { + found = true; + } + } + if (!found) { + throw new IllegalStateException("Web suggestion title: " + text + " not found"); + } + } + + /** Find the total amount of views being displayed and return the size */ + public int getSearchResultItemSize() { + ArrayList<UiObject2> searchResultItems = + new ArrayList<>(mLauncher.waitForObjectsInContainer( + mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID), + By.clazz(TextView.class))); + return searchResultItems.size(); + } + /** * Taps outside bottom sheet to dismiss and return to workspace. Available on tablets only. * @param tapRight Tap on the right of bottom sheet if true, or left otherwise. diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java index 0f9d5f52c7..6ca7f4bf79 100644 --- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java +++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java @@ -52,7 +52,7 @@ public final class Taskbar { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to get a taskbar icon")) { return new TaskbarAppIcon(mLauncher, mLauncher.waitForObjectInContainer( - mLauncher.waitForLauncherObject(TASKBAR_RES_ID), + mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID), AppIcon.getAppIconSelector(appName, mLauncher))); } } @@ -68,7 +68,7 @@ public final class Taskbar { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to hide the taskbar"); LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) { - mLauncher.waitForLauncherObject(TASKBAR_RES_ID); + mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID); final long downTime = SystemClock.uptimeMillis(); Point stashTarget = new Point( @@ -79,7 +79,7 @@ public final class Taskbar { LauncherInstrumentation.log("hideTaskbar: sent down"); try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) { - mLauncher.waitUntilLauncherObjectGone("taskbar_view"); + mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID); mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, stashTarget, LauncherInstrumentation.GestureScope.INSIDE); } @@ -97,7 +97,8 @@ public final class Taskbar { LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) { mLauncher.clickLauncherObject(mLauncher.waitForObjectInContainer( - mLauncher.waitForLauncherObject(TASKBAR_RES_ID), getAllAppsButtonSelector())); + mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID), + getAllAppsButtonSelector())); return new AllAppsFromTaskbar(mLauncher); } @@ -108,7 +109,7 @@ public final class Taskbar { try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "want to get all taskbar icons")) { return mLauncher.waitForObjectsInContainer( - mLauncher.waitForLauncherObject(TASKBAR_RES_ID), + mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID), AppIcon.getAnyAppIconSelector()) .stream() .map(UiObject2::getText) diff --git a/tests/tapl/com/android/launcher3/tapl/Widget.java b/tests/tapl/com/android/launcher3/tapl/Widget.java index 29eb46cbd4..046308b595 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widget.java +++ b/tests/tapl/com/android/launcher3/tapl/Widget.java @@ -32,7 +32,7 @@ import java.util.regex.Pattern; */ public final class Widget extends Launchable implements WorkspaceDragSource { - private static final Pattern LONG_CLICK_EVENT = Pattern.compile("Widgets.onLongClick"); + static final Pattern LONG_CLICK_EVENT = Pattern.compile("Widgets.onLongClick"); Widget(LauncherInstrumentation launcher, UiObject2 icon) { super(launcher, icon); diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index 2c9fdb357e..2c82c50eca 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -18,6 +18,7 @@ package com.android.launcher3.tapl; import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED; +import static com.android.launcher3.tapl.LauncherInstrumentation.CALLBACK_RUN_POINT.CALLBACK_HOLD_BEFORE_DROP; import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL; import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL; @@ -302,6 +303,31 @@ public final class Workspace extends Home { } /** + * Drag the appIcon from the workspace and cancel by dragging icon to corner of screen where no + * drop point exists. + * + * @param homeAppIcon to be dragged. + */ + @NonNull + public Workspace dragAndCancelAppIcon(HomeAppIcon homeAppIcon) { + try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck(); + LauncherInstrumentation.Closable c = mLauncher.addContextLayer( + "dragging app icon across workspace")) { + dragIconToWorkspace( + mLauncher, + homeAppIcon, + () -> new Point(0, 0), + () -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), + null); + + try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( + "dragged the app across workspace")) { + return new Workspace(mLauncher); + } + } + } + + /** * Delete the appIcon from the workspace. * * @param homeAppIcon to be deleted. @@ -325,6 +351,7 @@ public final class Workspace extends Home { } } + /** * Uninstall the appIcon by dragging it to the 'uninstall' drop point of the drop_target_bar. * @@ -358,7 +385,7 @@ public final class Workspace extends Home { Until.hasObject(installerAlert), LauncherInstrumentation.WAIT_TIME_MS)); final UiObject2 ok = device.findObject(By.text("OK")); assertNotNull("OK button is not shown", ok); - launcher.clickObject(ok); + launcher.clickObject(ok, LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER); assertTrue("Uninstall alert is not dismissed after clicking OK", device.wait( Until.gone(installerAlert), LauncherInstrumentation.WAIT_TIME_MS)); @@ -493,6 +520,7 @@ public final class Workspace extends Home { launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating, downTime, SystemClock.uptimeMillis(), false, LauncherInstrumentation.GestureScope.INSIDE); + launcher.runCallbackIfActive(CALLBACK_HOLD_BEFORE_DROP); dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents); } } |