Merge "Increase the delay in between gesture tutorials" into 24D1-dev
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 462d947..a9a8495 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -188,21 +188,33 @@
}
flag {
- name: "grid_migration_fix"
+ name: "enable_grid_migration_fix"
namespace: "launcher"
description: "Keep items in place when migrating to a bigger grid"
bug: "325286145"
+ is_fixed_read_only: true
metadata {
purpose: PURPOSE_BUGFIX
}
}
flag {
- name: "narrow_grid_restore"
+ name: "enable_narrow_grid_restore"
namespace: "launcher"
description: "Using only the most recent workspace when restoring to avoid confusion."
+ is_fixed_read_only: true
bug: "325285743"
metadata {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_handle_delayed_gesture_callbacks"
+ namespace: "launcher"
+ description: "Enables additional handling for delayed mid-gesture callbacks"
+ bug: "285636175"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/quickstep/res/layout/taskbar_all_apps_button.xml b/quickstep/res/layout/taskbar_all_apps_button.xml
index c50db2e..94596cb 100644
--- a/quickstep/res/layout/taskbar_all_apps_button.xml
+++ b/quickstep/res/layout/taskbar_all_apps_button.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<?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.
@@ -15,10 +14,9 @@
-->
<!-- 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"
+<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/BaseIcon.Workspace.Taskbar"
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:contentDescription="@string/all_apps_button_label" />
diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml
index 0a92fa9..330f85f 100644
--- a/quickstep/res/layout/taskbar_divider.xml
+++ b/quickstep/res/layout/taskbar_divider.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,9 +12,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.views.IconButtonView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/BaseIcon.Workspace.Taskbar"
android:layout_width="@dimen/taskbar_icon_min_touch_size"
android:layout_height="@dimen/taskbar_icon_min_touch_size"
- android:contentDescription="@string/taskbar_divider_a11y_title"
- android:backgroundTint="@android:color/transparent" />
\ No newline at end of file
+ android:backgroundTint="@android:color/transparent"
+ android:contentDescription="@string/taskbar_divider_a11y_title" />
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_edu_search.xml b/quickstep/res/layout/taskbar_edu_search.xml
new file mode 100644
index 0000000..ca84f35
--- /dev/null
+++ b/quickstep/res/layout/taskbar_edu_search.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextAppearance.TaskbarEduTooltip.Title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/taskbar_search_edu_title"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/search_edu_animation" />
+
+ <com.airbnb.lottie.LottieAnimationView
+ android:id="@+id/search_edu_animation"
+ android:layout_width="@dimen/taskbar_edu_swipe_lottie_width"
+ android:layout_height="@dimen/taskbar_edu_swipe_lottie_height"
+ android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
+ app:layout_constraintBottom_toTopOf="@id/search_edu_text"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/title"
+ app:lottie_rawRes="@raw/taskbar_edu_search"
+ app:lottie_autoPlay="true"
+ app:lottie_loop="true" />
+
+ <TextView
+ android:id="@+id/search_edu_text"
+ style="@style/TextAppearance.TaskbarEduTooltip.Subtext"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:textSize="@dimen/taskbar_edu_search_subtitle_text_size"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/search_edu_animation"
+ app:layout_constraintBottom_toBottomOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/raw/taskbar_edu_search.json b/quickstep/res/raw/taskbar_edu_search.json
new file mode 100644
index 0000000..0dcccd6
--- /dev/null
+++ b/quickstep/res/raw/taskbar_edu_search.json
@@ -0,0 +1 @@
+{"v":"5.12.1","fr":60,"ip":0,"op":431,"w":348,"h":218,"nm":"Omni_EDU_05_matted","ddd":0,"assets":[{"id":"comp_0","nm":"Omni_EDU_05","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".black","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-140,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,-48,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":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":174,"s":[0,0]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":192,"s":[17,17]},{"i":{"x":[0.999,0.999],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":237,"s":[17,17]},{"t":249,"s":[0,0]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0,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,-48],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"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":174,"op":249,"st":40,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"c2s null","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":193,"s":[-56.933,-189.286,0],"to":[-0.023,-0.021,0],"ti":[0.092,0.088,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":194,"s":[-57.069,-189.414,0],"to":[-0.092,-0.088,0],"ti":[0.189,0.184,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":195,"s":[-57.488,-189.813,0],"to":[-0.189,-0.184,0],"ti":[0.29,0.293,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":196,"s":[-58.204,-190.519,0],"to":[-0.29,-0.293,0],"ti":[0.392,0.419,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":197,"s":[-59.226,-191.574,0],"to":[-0.392,-0.419,0],"ti":[0.492,0.566,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":198,"s":[-60.555,-193.035,0],"to":[-0.492,-0.566,0],"ti":[0.582,0.741,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":199,"s":[-62.177,-194.971,0],"to":[-0.582,-0.741,0],"ti":[0.641,0.957,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":200,"s":[-64.048,-197.48,0],"to":[-0.641,-0.957,0],"ti":[0.644,1.22,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":201,"s":[-66.021,-200.712,0],"to":[-0.644,-1.22,0],"ti":[0.59,1.52,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":202,"s":[-67.912,-204.803,0],"to":[-0.59,-1.52,0],"ti":[0.478,1.841,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":203,"s":[-69.561,-209.83,0],"to":[-0.478,-1.841,0],"ti":[0.309,2.174,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":204,"s":[-70.781,-215.849,0],"to":[-0.309,-2.174,0],"ti":[0.095,2.509,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":205,"s":[-71.414,-222.876,0],"to":[-0.095,-2.509,0],"ti":[-0.149,2.838,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":206,"s":[-71.348,-230.903,0],"to":[0.149,-2.838,0],"ti":[-0.493,3.137,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":207,"s":[-70.519,-239.902,0],"to":[0.493,-3.137,0],"ti":[-0.971,3.37,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":208,"s":[-68.392,-249.724,0],"to":[0.971,-3.37,0],"ti":[-1.521,3.501,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":209,"s":[-64.693,-260.12,0],"to":[1.521,-3.501,0],"ti":[-2.183,3.438,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":210,"s":[-59.267,-270.731,0],"to":[2.183,-3.438,0],"ti":[-3.014,2.996,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":211,"s":[-51.596,-280.747,0],"to":[3.014,-2.996,0],"ti":[-3.718,2.327,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":212,"s":[-41.184,-288.709,0],"to":[3.718,-2.327,0],"ti":[-4.093,1.634,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":213,"s":[-29.289,-294.708,0],"to":[4.093,-1.634,0],"ti":[-4.243,0.814,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":214,"s":[-16.628,-298.511,0],"to":[4.243,-0.814,0],"ti":[-4.168,-0.028,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":215,"s":[-3.828,-299.591,0],"to":[4.168,0.028,0],"ti":[-3.907,-0.628,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":216,"s":[8.377,-298.344,0],"to":[3.907,0.628,0],"ti":[-3.551,-1.009,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":217,"s":[19.614,-295.822,0],"to":[3.551,1.009,0],"ti":[-3.138,-1.314,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":218,"s":[29.681,-292.288,0],"to":[3.138,1.314,0],"ti":[-2.68,-1.566,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":219,"s":[38.443,-287.941,0],"to":[2.68,1.566,0],"ti":[-2.137,-1.816,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":220,"s":[45.761,-282.889,0],"to":[2.137,1.816,0],"ti":[-1.616,-1.954,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":221,"s":[51.267,-277.046,0],"to":[1.616,1.954,0],"ti":[-1.251,-1.903,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":222,"s":[55.456,-271.165,0],"to":[1.251,1.903,0],"ti":[-0.99,-1.774,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":223,"s":[58.77,-265.626,0],"to":[0.99,1.774,0],"ti":[-0.752,-1.637,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":224,"s":[61.394,-260.52,0],"to":[0.752,1.637,0],"ti":[-0.54,-1.496,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":225,"s":[63.282,-255.805,0],"to":[0.54,1.496,0],"ti":[-0.388,-1.34,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":226,"s":[64.634,-251.545,0],"to":[0.388,1.34,0],"ti":[-0.278,-1.183,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":227,"s":[65.61,-247.762,0],"to":[0.278,1.183,0],"ti":[-0.195,-1.031,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":228,"s":[66.303,-244.447,0],"to":[0.195,1.031,0],"ti":[-0.13,-0.885,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":229,"s":[66.778,-241.579,0],"to":[0.13,0.885,0],"ti":[-0.081,-0.748,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":230,"s":[67.085,-239.135,0],"to":[0.081,0.748,0],"ti":[-0.045,-0.619,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":231,"s":[67.265,-237.089,0],"to":[0.045,0.619,0],"ti":[-0.02,-0.498,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":232,"s":[67.354,-235.418,0],"to":[0.02,0.498,0],"ti":[-0.004,-0.385,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":233,"s":[67.382,-234.099,0],"to":[0.004,0.385,0],"ti":[0.004,-0.279,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":234,"s":[67.377,-233.109,0],"to":[-0.004,0.279,0],"ti":[0.006,-0.18,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":235,"s":[67.358,-232.425,0],"to":[-0.006,0.18,0],"ti":[0.004,-0.087,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":236,"s":[67.341,-232.028,0],"to":[-0.004,0.087,0],"ti":[0.001,-0.021,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":237,"s":[67.335,-231.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":248,"s":[67.335,-231.9,0],"to":[-0.008,0.042,0],"ti":[0.033,-0.177,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":249,"s":[67.289,-231.647,0],"to":[-0.033,0.177,0],"ti":[0.079,-0.372,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":250,"s":[67.135,-230.84,0],"to":[-0.079,0.372,0],"ti":[0.155,-0.591,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":251,"s":[66.815,-229.413,0],"to":[-0.155,0.591,0],"ti":[0.268,-0.834,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":252,"s":[66.203,-227.297,0],"to":[-0.268,0.834,0],"ti":[0.413,-1.109,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":253,"s":[65.206,-224.409,0],"to":[-0.413,1.109,0],"ti":[0.247,-0.628,0]},{"t":254,"s":[63.723,-220.641,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":193,"op":264,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":90,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.149,"y":0.701},"o":{"x":0.4,"y":0.002},"t":248,"s":[-8.212,-253.668,0],"to":[0,0,0],"ti":[0,0,0]},{"t":263,"s":[0,-227,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.149,"y":0.701},"o":{"x":0.4,"y":0.002},"t":248,"s":[{"i":[[3.564,-2.549],[3.809,-1.264],[12.238,3.984],[8.325,10.606],[-0.214,12.436],[-2.655,8.03],[-10.533,8.871],[-9.434,2.582],[-8.48,-3.643],[-9.227,-13.6],[-1.802,-9.359],[2.171,-9.596]],"o":[[-3.564,2.549],[-12.609,4.183],[-12.52,-4.076],[-7.722,-9.838],[0.146,-8.454],[4.364,-13.197],[5.142,-4.331],[9.891,-2.707],[11.828,5.081],[4.099,6.042],[2.254,11.707],[-3.907,17.266]],"v":[[53.514,60.456],[41.519,66.798],[2.462,64.221],[-33.286,39.729],[-45.626,-0.393],[-41.723,-21.691],[-18.543,-58.238],[5.442,-69.196],[39.994,-68.523],[68.082,-43.976],[77.052,-19.838],[77.406,14.145]],"c":true}]},{"t":263,"s":[{"i":[[7.701,-4.092],[8.127,0],[7.226,4.357],[4.092,7.701],[0,8.127],[-4.357,7.226],[-7.701,4.092],[-8.127,0],[-7.226,-4.357],[-4.092,-7.701],[0,-8.127],[4.357,-7.226]],"o":[[-6.709,3.565],[-9.053,0],[-7.447,-4.489],[-3.565,-6.709],[0,-9.053],[4.489,-7.447],[6.709,-3.565],[9.053,0],[7.447,4.489],[3.565,6.709],[0,9.053],[-4.489,7.447]],"v":[[22.492,42.415],[0,48],[-24.747,41.137],[-42.415,22.492],[-48,0],[-41.137,-24.747],[-22.492,-42.415],[0,-48],[24.747,-41.137],[42.415,-22.492],[48,0],[41.137,24.747]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":78.63,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector 303","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":193,"s":[0]},{"t":237,"s":[63],"h":1},{"i":{"x":[0.149],"y":[0.701]},"o":{"x":[0.4],"y":[0.002]},"t":248,"s":[63]},{"t":263,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 2","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":193,"op":263,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":277,"s":[0]},{"t":289,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[2.625,-203,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[2.625,-221,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.5,1.3],[0,0],[0,0],[0,0],[-0.65,1.45],[-0.25,1.6],[0,0],[2.65,-2.25],[3.6,0],[2.9,2.85],[0,4.05],[-2.85,2.85],[-4.1,0],[-1.1,-0.3],[-1,-0.5],[0,0],[1.7,0.5],[1.8,0],[3.75,-3.75],[0,-5.3],[-3.75,-3.75],[-5.4,0],[-2,0.7]],"o":[[0,0],[0,0],[0,0],[1.05,-1.35],[0.7,-1.5],[0,0],[-0.7,3.35],[-2.6,2.2],[-4.1,0],[-2.85,-2.9],[0,-4.05],[2.9,-2.9],[1.2,0],[1.1,0.25],[0,0],[-1.45,-0.85],[-1.65,-0.5],[-5.35,0],[-3.75,3.75],[0,5.3],[3.75,3.75],[2.25,0],[2,-0.75]],"v":[[1.35,9.863],[21.075,29.587],[24.375,26.288],[4.575,6.637],[7.125,2.438],[8.55,-2.213],[3.975,-2.213],[-1.05,6.188],[-10.35,9.488],[-20.85,5.212],[-25.125,-5.213],[-20.85,-15.562],[-10.35,-19.913],[-6.9,-19.462],[-3.75,-18.337],[-0.45,-21.637],[-5.175,-23.663],[-10.35,-24.413],[-24,-18.788],[-29.625,-5.213],[-24,8.363],[-10.275,13.988],[-3.9,12.938]],"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":[[-3.05,-3.05],[0,-4.4],[-3.05,3.05],[-4.4,0],[3.05,3.05],[0,4.4],[3.05,-3.05],[4.4,0]],"o":[[3.05,3.05],[0,-4.4],[3.05,-3.05],[-4.4,0],[-3.05,-3.05],[0,4.4],[-3.05,3.05],[4.4,0]],"v":[[9.3,-9.262],[13.875,1.913],[18.45,-9.262],[29.625,-13.837],[18.45,-18.413],[13.875,-29.587],[9.3,-18.413],[-1.875,-13.837]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","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":"icon","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":60,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[-100,-161,0]}],"ix":2,"l":2},"a":{"a":0,"k":[11,11,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,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[{"i":[[0,0],[7.26,-4.415],[4.064,-7.787],[0,-8]],"o":[[-9.118,0],[-7.478,4.547],[-3.462,6.633],[0,0]],"v":[[11,-37],[-13.903,-30.043],[-31.581,-11.176],[-37,11]],"c":false}]},{"t":290,"s":[{"i":[[0,0],[0,0],[0,-7.732],[0,0]],"o":[[0,0],[-7.732,0],[0,0],[0,0]],"v":[[11,-11],[3,-11],[-11,3],[-11,11]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,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":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Handle Top Left","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":63,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[100,-161,0]}],"ix":2,"l":2},"a":{"a":0,"k":[11,11,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,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[{"i":[[0,0],[7.26,-4.415],[4.064,-7.787],[0,-8]],"o":[[-9.118,0],[-7.478,4.547],[-3.462,6.633],[0,0]],"v":[[11,-37],[-13.903,-30.043],[-31.581,-11.176],[-37,11]],"c":false}]},{"t":290,"s":[{"i":[[0,0],[0,0],[0,-7.732],[0,0]],"o":[[0,0],[-7.732,0],[0,0],[0,0]],"v":[[11,-11],[3,-11],[-11,3],[-11,11]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,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":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Handle Top Left","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":63,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[100,-279,0]}],"ix":2,"l":2},"a":{"a":0,"k":[11,11,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,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[{"i":[[0,0],[7.26,-4.415],[4.064,-7.787],[0,-8]],"o":[[-9.118,0],[-7.478,4.547],[-3.462,6.633],[0,0]],"v":[[11,-37],[-13.903,-30.043],[-31.581,-11.176],[-37,11]],"c":false}]},{"t":290,"s":[{"i":[[0,0],[0,0],[0,-7.732],[0,0]],"o":[[0,0],[-7.732,0],[0,0],[0,0]],"v":[[11,-11],[3,-11],[-11,3],[-11,11]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,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":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Handle Top Left","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":63,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[-100,-279,0]}],"ix":2,"l":2},"a":{"a":0,"k":[11,11,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,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[{"i":[[0,0],[7.26,-4.415],[4.064,-7.787],[0,-8]],"o":[[-9.118,0],[-7.478,4.547],[-3.462,6.633],[0,0]],"v":[[11,-37],[-13.903,-30.043],[-31.581,-11.176],[-37,11]],"c":false}]},{"t":290,"s":[{"i":[[0,0],[0,0],[0,-7.732],[0,0]],"o":[[0,0],[-7.732,0],[0,0],[0,0]],"v":[[11,-11],[3,-11],[-11,3],[-11,11]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,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":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Handle Top Left","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":63,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"Search","parent":12,"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,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-166,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[0,-109,0]}],"ix":2,"l":2},"a":{"a":0,"k":[83,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":166,"h":45,"ip":135,"op":319,"st":135,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":0,"nm":"Flower","parent":12,"refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.5,-209,0],"ix":2,"l":2},"a":{"a":0,"k":[109,115,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":219,"h":231,"ip":122,"op":431,"st":122,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue50","cl":"blue50","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":266,"s":[0]},{"t":278,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[0,-220,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,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":263,"s":[92,92]},{"t":299,"s":[240,158]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":263,"s":[46]},{"t":299,"s":[12]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.941176470588,0.996078431373,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"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":263,"op":431,"st":60,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":3,"nm":"pan up","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.15,"y":1},"o":{"x":0.653,"y":0},"t":99,"s":[174,109,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.15,"y":0.15},"o":{"x":0.546,"y":0.546},"t":169,"s":[174,327,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.15,"y":1},"o":{"x":0.653,"y":0},"t":357,"s":[174,327,0],"to":[0,0,0],"ti":[0,0,0]},{"t":427,"s":[174,109,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Void","np":19,"mn":"Pseudo/250958","ix":1,"en":1,"ef":[{"ty":0,"nm":"Width","mn":"Pseudo/250958-0001","ix":1,"v":{"a":0,"k":100,"ix":1}},{"ty":0,"nm":"Height","mn":"Pseudo/250958-0002","ix":2,"v":{"a":0,"k":100,"ix":2}},{"ty":0,"nm":"Offset X","mn":"Pseudo/250958-0003","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":0,"nm":"Offset Y","mn":"Pseudo/250958-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Roundness","mn":"Pseudo/250958-0005","ix":5,"v":{"a":0,"k":0,"ix":5}},{"ty":6,"nm":"About","mn":"Pseudo/250958-0006","ix":6,"v":0},{"ty":6,"nm":"Plague of null layers.","mn":"Pseudo/250958-0007","ix":7,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0008","ix":8,"v":0},{"ty":6,"nm":"Following projects","mn":"Pseudo/250958-0009","ix":9,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0010","ix":10,"v":0},{"ty":6,"nm":"through time.","mn":"Pseudo/250958-0011","ix":11,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0012","ix":12,"v":0},{"ty":6,"nm":"Be free of the past.","mn":"Pseudo/250958-0013","ix":13,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0014","ix":14,"v":0},{"ty":6,"nm":"Copyright 2023 Battle Axe Inc","mn":"Pseudo/250958-0015","ix":15,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0016","ix":16,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0017","ix":17,"v":0}]}],"ip":0,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"long Press Over - Outward","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":95,"s":[100]},{"t":113,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,38,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0.7]},"t":83,"s":[116,116]},{"t":113,"s":[136,136]}],"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.40000000596,0.615686297417,0.964705884457,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":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Long Pres Over","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":83,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"long Press Over","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":86,"s":[100]},{"t":95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,38,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.999,0.999],"y":[1,1]},"o":{"x":[0.001,0.001],"y":[0,0]},"t":33,"s":[40,40]},{"i":{"x":[0.8,0.8],"y":[0.15,0.15]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":83,"s":[120,120]},{"t":101,"s":[40,40]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.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":"Long Pres Over","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":0,"nm":"Action Key","parent":12,"refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-11.539,38,0],"ix":2,"l":2},"a":{"a":0,"k":[53.5,53.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":107,"h":107,"ip":0,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"long Press Under","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[100]},{"t":95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,38,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":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":30,"s":[96,96]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":66,"s":[120,120]},{"i":{"x":[0.999,0.999],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":83,"s":[120,120]},{"t":101,"s":[106,106]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Long Press Under","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".grey800","cl":"grey800","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,38,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":[348,142],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.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":"Grey800","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":18,"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":[174,109,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":[348,218],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.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":0,"op":431,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"SearchPill","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"superG","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[0]},{"t":17,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[-3.898,0.128,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-4.239,0.128,0],"t":1,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-5.311,0.128,0],"t":2,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-7.286,0.128,0],"t":3,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-10.519,0.128,0],"t":4,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-15.81,0.128,0],"t":5,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.898,0.128,0],"t":6,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-37.431,0.128,0],"t":7,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-43.055,0.128,0],"t":8,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-46.404,0.128,0],"t":9,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-48.712,0.128,0],"t":10,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-50.434,0.128,0],"t":11,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-51.781,0.128,0],"t":12,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.869,0.128,0],"t":13,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.768,0.128,0],"t":14,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.522,0.128,0],"t":15,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.162,0.128,0],"t":16,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.71,0.128,0],"t":17,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.182,0.128,0],"t":18,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.591,0.128,0],"t":19,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.947,0.128,0],"t":20,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.257,0.128,0],"t":21,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.526,0.128,0],"t":22,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.761,0.128,0],"t":23,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.965,0.128,0],"t":24,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.142,0.128,0],"t":25,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.295,0.128,0],"t":26,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.425,0.128,0],"t":27,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.537,0.128,0],"t":28,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.63,0.128,0],"t":29,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.707,0.128,0],"t":30,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.769,0.128,0],"t":31,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.818,0.128,0],"t":32,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.854,0.128,0],"t":33,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.853,0.128,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.679,0.128,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.301,0.128,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.701,0.128,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.039,0.128,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.46,0.128,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.983,0.128,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.588,0.128,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.255,0.128,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.97,0.128,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.723,0.128,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.507,0.128,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.316,0.128,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.147,0.128,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.996,0.128,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.861,0.128,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.74,0.128,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.631,0.128,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.534,0.128,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.446,0.128,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.367,0.128,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.297,0.128,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.234,0.128,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.178,0.128,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.128,0.128,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.084,0.128,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.046,0.128,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.012,0.128,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.96,0.128,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.913,0.128,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[24.102,22.628,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.788,0],[0.959,-2.878],[0,0],[-4.737,0],[-2.091,-1.959]],"o":[[-1.262,-1.202],[-3.161,0],[0,0],[1.99,-3.959],[3.272,0],[0,0]],"v":[[6.004,1.712],[1.358,-0.106],[-5.439,4.903],[-9.458,1.783],[1.358,-4.903],[9.458,-1.742]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917647063732,0.262745112181,0.207843139768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[23.001,15.411],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"g-red","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,-0.808],[-0.252,-0.727],[0,0],[0,1.959],[-0.828,1.636],[0,0],[0,0]],"o":[[0,0.808],[0,0],[-0.828,-1.636],[0,-1.959],[0,0],[0,0],[-0.242,0.727]],"v":[[2.277,0],[2.661,2.313],[-1.358,5.434],[-2.661,0],[-1.358,-5.434],[2.661,-5.434],[2.661,-2.313]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.976470589638,0.670588254929,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":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[14.901,22.628],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"g-yellow","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,0],[3.272,0],[1.99,3.959],[0,0],[0,0],[-3.161,0],[-1.091,0.727]],"o":[[-2,1.848],[-4.737,0],[0,0],[0,0],[0.959,2.878],[1.636,0],[0,0]],"v":[[9.413,1.964],[1.404,4.903],[-9.413,-1.783],[-9.413,-4.903],[-5.393,-4.903],[1.404,0.106],[5.514,-1.066]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.203921571374,0.658823549747,0.32549020648,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[22.955,29.844],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"g-green","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,0],[0,-0.798],[2.283,-2.111],[0,0],[0,0],[-0.293,1.495],[0,0],[0,0]],"o":[[0.121,0.737],[0,3.686],[0,0],[0,0],[1.273,-0.858],[0,0],[0,0],[0,0]],"v":[[5.61,-5.6],[5.802,-3.308],[2.207,5.6],[-1.692,5.6],[-1.692,2.57],[0.732,-1.045],[-5.802,-1.045],[-5.802,-5.6]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258823543787,0.521568655968,0.956862747669,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[30.161,26.208],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"g-blue","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"mic","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[0]},{"t":17,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[2.7,0.705,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.041,0.705,0],"t":1,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.113,0.705,0],"t":2,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[6.088,0.705,0],"t":3,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[9.321,0.705,0],"t":4,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[14.611,0.705,0],"t":5,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[24.7,0.705,0],"t":6,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.233,0.705,0],"t":7,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.857,0.705,0],"t":8,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[45.206,0.705,0],"t":9,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[47.514,0.705,0],"t":10,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.235,0.705,0],"t":11,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.583,0.705,0],"t":12,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.671,0.705,0],"t":13,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.569,0.705,0],"t":14,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.323,0.705,0],"t":15,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.963,0.705,0],"t":16,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.511,0.705,0],"t":17,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.984,0.705,0],"t":18,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.393,0.705,0],"t":19,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.749,0.705,0],"t":20,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.058,0.705,0],"t":21,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.328,0.705,0],"t":22,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.563,0.705,0],"t":23,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.767,0.705,0],"t":24,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.944,0.705,0],"t":25,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.096,0.705,0],"t":26,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.227,0.705,0],"t":27,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.338,0.705,0],"t":28,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.431,0.705,0],"t":29,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.509,0.705,0],"t":30,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.571,0.705,0],"t":31,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.62,0.705,0],"t":32,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.656,0.705,0],"t":33,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.655,0.705,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.48,0.705,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.103,0.705,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.503,0.705,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.841,0.705,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.262,0.705,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.785,0.705,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.39,0.705,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.057,0.705,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.772,0.705,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.525,0.705,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.309,0.705,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.118,0.705,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.949,0.705,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.798,0.705,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.663,0.705,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.542,0.705,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.433,0.705,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.335,0.705,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.248,0.705,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.169,0.705,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.098,0.705,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.035,0.705,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.979,0.705,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.929,0.705,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.886,0.705,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.847,0.705,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.814,0.705,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.786,0.705,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.742,0.705,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[140.7,23.205,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.688,0],[0,0],[0.012,3.389],[0,0],[4.735,0],[1.554,1.554]],"o":[[1.113,1.113],[0,0],[3.377,0],[0,0],[0,4.723],[-2.361,0],[0,0]],"v":[[-5.573,0.049],[-1.242,1.848],[-1.242,1.848],[4.851,-4.282],[7.298,-4.282],[-1.242,4.282],[-7.298,1.774]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917647063732,0.262745112181,0.207843139768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[141.954,27.475],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mic-red","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,2.361],[0,0],[0,0],[-1.101,-1.113],[0,0]],"o":[[0,0],[0,0],[0,1.688],[0,0],[-1.554,-1.554]],"v":[[-2.117,-3.028],[0.33,-3.028],[0.33,-3.028],[2.117,1.303],[0.392,3.028]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.976470589638,0.670588254929,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":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[134.264,26.233],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mic-yellow","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,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[1.224,-1.884],[-1.224,-1.884],[-1.224,1.884],[1.224,1.884]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.203921571374,0.658823549747,0.32549020648,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[140.712,33.556],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mic-green","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,0],[2.031,0],[0,0],[0,2.031],[0,0],[-2.031,0],[0,-2.031]],"o":[[0,2.031],[0,0],[-2.031,0],[0,0],[0,-2.031],[2.031,0],[0,0]],"v":[[3.658,4.282],[0,7.953],[0,7.953],[-3.671,4.282],[-3.671,-4.282],[0,-7.953],[3.671,-4.282]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258823543787,0.521568655968,0.956862747669,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[140.712,18.923],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mic-blue","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":12,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[83,22.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":1,"k":[{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":0,"s":[56,45]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":6,"s":[100,45]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[166,45]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":128,"s":[166,45]},{"t":164,"s":[154,45]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":87,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","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":"Grey 800","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0}]},{"id":"comp_2","nm":"Flower","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".grey700","cl":"grey700","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[109.453,193.777,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[36.517,1.481],[-36.517,1.481]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Union 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[5.448,5.448],"ix":2},"p":{"a":0,"k":[-12.903,0.471],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[5.448,5.448],"ix":2},"p":{"a":0,"k":[9.094,0.471],"ix":3},"nm":"Ellipse Path 2","mn":"ADBE Vector Shape - Ellipse","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[5.448,5.448],"ix":2},"p":{"a":0,"k":[2.554,0.471],"ix":3},"nm":"Ellipse Path 3","mn":"ADBE Vector Shape - Ellipse","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[6.588,6.588],"ix":2},"p":{"a":0,"k":[-8.927,-0.099],"ix":3},"nm":"Ellipse Path 4","mn":"ADBE Vector Shape - Ellipse","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[6.588,6.588],"ix":2},"p":{"a":0,"k":[5.118,-0.099],"ix":3},"nm":"Ellipse Path 5","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-0.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Union","np":7,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"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":[64.952,63.598,0],"ix":2,"l":2},"a":{"a":0,"k":[24.952,23.598,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.753,0],[0,1.753],[1.753,0],[0,-1.753]],"o":[[1.753,0],[0,-1.753],[-1.753,0],[0,1.753]],"v":[[0,3.174],[3.174,0],[0,-3.174],[-3.174,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[21.137,19.31],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"flower 1","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":[[-1.753,0],[0,1.753],[1.753,0],[0,-1.753]],"o":[[1.753,0],[0,-1.753],[-1.753,0],[0,1.753]],"v":[[0,3.174],[3.174,0],[0,-3.174],[-3.174,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[28.767,23.097],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"flower 2","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":[[-1.753,0],[0,1.753],[1.753,0],[0,-1.753]],"o":[[1.753,0],[0,-1.753],[-1.753,0],[0,1.753]],"v":[[0,3.174],[3.174,0],[0,-3.174],[-3.174,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[21.75,27.886],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"flower 3","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector 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}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[63.114,63.125,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.392,1.281],[2.395,-2.283],[1.893,0.223],[0.557,-3.174],[1.726,-0.891],[-1.504,-2.896],[0.835,-1.671],[-2.951,-1.504],[-0.278,-1.782],[-3.341,0.446],[-1.392,-1.281],[-2.395,2.283],[-1.893,-0.278],[-0.557,3.174],[-1.726,0.891],[1.504,2.896],[-0.835,1.671],[2.951,1.504],[0.334,1.838],[3.341,-0.446]],"o":[[-2.45,-2.283],[-1.392,1.337],[-3.341,-0.501],[-0.334,1.838],[-2.951,1.504],[0.835,1.671],[-1.504,2.896],[1.671,0.835],[0.557,3.174],[1.949,-0.278],[2.45,2.283],[1.392,-1.281],[3.341,0.501],[0.334,-1.838],[2.951,-1.504],[-0.835,-1.671],[1.504,-2.896],[-1.726,-0.891],[-0.557,-3.174],[-1.949,0.278]],"v":[[4.316,-21.412],[-4.372,-21.412],[-9.551,-19.741],[-16.567,-14.841],[-19.797,-10.553],[-22.47,-2.59],[-22.47,2.701],[-19.797,10.664],[-16.623,14.897],[-9.606,19.797],[-4.372,21.412],[4.316,21.412],[9.551,19.797],[16.567,14.897],[19.797,10.609],[22.47,2.645],[22.47,-2.645],[19.797,-10.609],[16.567,-14.897],[9.551,-19.797]],"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":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[97.335,135.554,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[10.748,5.402]],"o":[[0,0],[-0.891,-40.374],[0,0]],"v":[[16.706,59.315],[16.706,7.288],[-16.706,-59.315]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":3,"nm":"â–½ Right Flower","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.155,88.602,0],"ix":2,"l":2},"a":{"a":0,"k":[31.228,40.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".black","cl":"black","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[45.33,17.598,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":[[-2.184,0],[0,2.184],[2.184,0],[0,-2.184]],"o":[[2.184,0],[0,-2.184],[-2.184,0],[0,2.184]],"v":[[0,3.954],[3.954,0],[0,-3.954],[-3.954,0]],"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":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".red400","cl":"red400","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[45.024,17.515,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.167,2.283],[4.678,-6.014],[2.283,-0.223],[-5.959,-4.733],[-0.167,-2.283],[-4.678,6.014],[-2.283,0.223],[5.959,4.733]],"o":[[-0.613,-7.574],[-1.448,1.782],[-7.629,0.668],[1.838,1.448],[0.613,7.574],[1.392,-1.838],[7.629,-0.668],[-1.838,-1.448]],"v":[[11.054,-9.829],[-3.87,-14.284],[-9.718,-11.11],[-14.228,3.926],[-11.054,9.829],[3.87,14.284],[9.718,11.11],[14.228,-3.926]],"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":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".green400","cl":"green400","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[22.485,51.377,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":[[9.244,-14.2],[-4.678,11.138],[7.407,2.729]],"o":[[7.741,4.121],[1.002,-2.951],[-5.457,-1.448]],"v":[[-14.689,4.256],[14.269,2.642],[7.586,-8.663]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".green400","cl":"green400","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[16.651,52.32,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-10.414,5.68]],"o":[[1.726,-32.355],[0,0]],"v":[[-16.651,28.763],[16.651,-28.763]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.004,158.386,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-17.306]],"o":[[34.304,21.05],[0,0]],"v":[[-23.31,-36.483],[23.31,36.483]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.116,132.289,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.847,-0.501],[1.281,-3.62],[-0.78,-2.172],[-3.341,-0.891],[-3.898,2.951],[-2.339,4.01],[1.114,0.501]],"o":[[-4.177,0.39],[-0.668,1.893],[1.169,3.341],[4.733,0.668],[3.731,-2.84],[-1.114,-0.501],[-5.29,-2.228]],"v":[[-5.506,-9.773],[-14.416,-3.09],[-14.361,3.147],[-7.065,9.607],[5.91,6.655],[14.931,-4.315],[11.59,-5.819]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.652,111.9,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.179,3.007],[0.724,0.167],[2.228,-1.392],[-0.446,-4.622],[-4.288,-3.341],[0,-0.056],[-0.724,4.901]],"o":[[-0.668,-0.39],[-2.562,-0.613],[-4.065,2.617],[0.557,5.513],[0.501,0.39],[2.172,-4.511],[0.78,-5.235]],"v":[[4.896,-14.778],[2.836,-15.613],[-4.849,-14.221],[-9.917,-1.97],[-1.731,11.284],[5.23,15.851],[9.685,1.483]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[133.059,138.554,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[3.731,-15.203]],"o":[[-27.844,11.695],[0,0]],"v":[[19.018,-18.878],[-19.018,18.878]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[164.078,125.618,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":[[-6.404,-1.726],[-2.673,2.45],[-0.334,2.005],[0.446,1.392],[4.455,0.613],[1.671,-0.835],[0.223,-0.446],[-0.39,-0.501]],"o":[[3.397,0.891],[1.281,-1.169],[0.278,-1.448],[-1.392,-4.511],[-3.564,-0.501],[-0.446,0.223],[-0.223,0.501],[3.787,5.235]],"v":[[1.642,9.094],[11.777,7.256],[14.339,2.467],[14.061,-1.876],[4.705,-9.506],[-12.057,-5.942],[-14.452,-4.661],[-13.505,-2.879]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0}]},{"id":"comp_3","nm":"Action Key","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"action icon","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[67.56,56.18,0],"ix":2,"l":2},"a":{"a":0,"k":[67.56,56.18,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.379],[3.379,0],[0,-3.379],[-3.379,0]],"o":[[0,-3.379],[-3.379,0],[0,3.379],[3.379,0]],"v":[[6.144,0],[0,-6.144],[-6.144,0],[0,6.144]],"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,6.789],[-6.789,0],[0,-6.789],[6.789,0]],"o":[[0,-6.789],[6.789,0],[0,6.789],[-6.789,0]],"v":[[-12.288,0],[0,-12.288],[12.288,0],[0,12.288]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tr","p":{"a":0,"k":[-3.185,-3.229],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-1.101,1.239],[-1.26,-1.207],[0,0],[1.215,-1.215],[1.205,1.15],[0,0]],"o":[[1.159,-1.304],[0,0],[1.241,1.189],[-1.177,1.177],[0,0],[-1.199,-1.144]],"v":[[1.548,2.22],[5.978,2.043],[14.529,10.239],[14.575,14.619],[10.291,14.669],[1.723,6.491]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100.469,100.469],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Union","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[84.621,73.217],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mag","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24.577,24.577],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[81.029,35.842],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"top R","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24.577,24.577],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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 3","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[47.241,69.628],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"bottom L","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24.577,24.577],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"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":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[47.241,35.841],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"top L","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Action (not dynamic)","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[53.25,53.25,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":[106.5,106.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":32,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Action (not dynamic)","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109,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":[348,218],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Omni_EDU_05","tt":1,"tp":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109,0],"ix":2,"l":2},"a":{"a":0,"k":[174,109,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":348,"h":218,"ip":0,"op":431,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}
\ No newline at end of file
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index e45d9fd..8b483b5 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -26,6 +26,7 @@
<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>
+ <string name="taskbar_edu_tooltip_controller_class" translatable="false">com.android.launcher3.taskbar.TaskbarEduTooltipController</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 c8fb402..cdb257a 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -400,6 +400,7 @@
<dimen name="taskbar_edu_features_tooltip_width_with_one_feature">412dp</dimen>
<dimen name="taskbar_edu_features_tooltip_width_with_two_features">428dp</dimen>
<dimen name="taskbar_edu_features_tooltip_width_with_three_features">624dp</dimen>
+ <dimen name="taskbar_edu_search_subtitle_text_size">12sp</dimen>
<!--- Taskbar Pinning -->
<dimen name="taskbar_pinning_popup_menu_width">300dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 75a4fc8..d358426 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -273,6 +273,10 @@
<string name="taskbar_edu_pinning_title">Always show the Taskbar</string>
<!-- Text in dialog that shows a user how to pin the Taskbar. [CHAR_LIMIT 150] -->
<string name="taskbar_edu_pinning_standalone">To always show the Taskbar on the bottom of your screen, touch & hold the divider</string>
+ <!-- Title in dialog that shows a user how to invoke the Search feature. [CHAR_LIMIT 150] -->
+ <string name="taskbar_search_edu_title">Touch & hold the action key to search what\'s on your screen</string>
+ <!-- Message showed to user to disclose privacy information they need to accept in order to access the app. [CHAR LIMIT=200]-->
+ <string name="taskbar_edu_search_disclosure">This product uses the selected part of your screen to search. Google\'s <xliff:g example="https://policies.google.com/privacy/embedded" id="begin_privacy_link"><a href=\"%1$s\"></xliff:g>Privacy Policy<xliff:g id="end_privacy_link"></a></xliff:g> and <xliff:g example="https://policies.google.com/terms" id="begin_tos_link"><a href=\"%2$s\"></xliff:g>Terms of Service<xliff:g id="end_tos_link"></a></xliff:g> apply.</string>
<!-- Text on button to exit a tutorial [CHAR_LIMIT=16] -->
<string name="taskbar_edu_close">Close</string>
<!-- Text on button to finish a tutorial [CHAR_LIMIT=16] -->
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 58c616f..312e705 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -299,6 +299,8 @@
*/
public void showEduOnAppLaunch() {
if (!shouldShowEduOnAppLaunch()) {
+ // Called in case the edu finishes and search edu is still pending
+ mControllers.taskbarEduTooltipController.maybeShowSearchEdu();
return;
}
@@ -419,6 +421,13 @@
}
@Override
+ protected boolean canToggleHomeAllApps() {
+ return mLauncher.isResumed()
+ && !mTaskbarLauncherStateController.isInOverview()
+ && !mLauncher.areFreeformTasksVisible();
+ }
+
+ @Override
public RecentsView getRecentsView() {
return mLauncher.getOverviewPanel();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 8bc9ce0..bc71cae 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -36,14 +36,12 @@
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.TaskbarDragLayerController.TASKBAR_REAPPEAR_DELAY_MS;
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
@@ -81,7 +79,6 @@
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
-import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.config.FeatureFlags;
@@ -302,7 +299,7 @@
isDesktopMode
? new DesktopTaskbarRecentAppsController(this)
: TaskbarRecentAppsController.DEFAULT,
- new TaskbarEduTooltipController(this),
+ TaskbarEduTooltipController.newInstance(this),
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this),
bubbleControllersOptional);
@@ -1419,23 +1416,6 @@
});
}
- public void hideTaskbarWhenFolding() {
- AnimatedFloat alphaAnim = mControllers.taskbarDragLayerController.getTaskbarAlpha();
- alphaAnim.cancelAnimation();
- alphaAnim.updateValue(0);
- ObjectAnimator animator = alphaAnim.animateToValue(1).setDuration(0);
- animator.setStartDelay(TASKBAR_REAPPEAR_DELAY_MS);
- animator.start();
- }
-
- public void cancelHideTaskbarWhenFolding() {
- mControllers.taskbarDragLayerController.getTaskbarAlpha().cancelAnimation();
- }
-
- public void resetHideTaskbarWhenUnfolding() {
- mControllers.taskbarDragLayerController.getTaskbarAlpha().updateValue(1);
- }
-
protected boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
@@ -1572,4 +1552,8 @@
public void closeKeyboardQuickSwitchView() {
mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
}
+
+ boolean canToggleHomeAllApps() {
+ return mControllers.uiController.canToggleHomeAllApps();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index e48c20d..ff890fb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -44,12 +44,6 @@
private static final boolean DEBUG = SystemProperties.getBoolean(
"persist.debug.draw_taskbar_debug_ui", false);
- // Delay to reset the task bar alpha back to 1 after fading it for transition from unfold to
- // fold. Normally this is not needed since the new task bar is recreated after fading, but in
- // case something goes wrong this provides a fallback mechanism to make sure the task bar is
- // visible after the transition finishes.
- public static final long TASKBAR_REAPPEAR_DELAY_MS = 2000;
-
private final TaskbarActivityContext mActivity;
private final TaskbarDragLayer mTaskbarDragLayer;
private final int mFolderMargin;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index 7eed955..d43055d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -15,7 +15,13 @@
*/
package com.android.launcher3.taskbar
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
import android.os.Bundle
+import android.text.SpannableString
+import android.text.method.LinkMovementMethod
+import android.text.style.URLSpan
import android.view.Gravity
import android.view.View
import android.view.View.GONE
@@ -24,10 +30,13 @@
import android.view.ViewGroup.MarginLayoutParams
import android.view.accessibility.AccessibilityEvent
import android.view.accessibility.AccessibilityNodeInfo
+import android.widget.TextView
import androidx.annotation.IntDef
import androidx.annotation.LayoutRes
+import androidx.core.text.HtmlCompat
import androidx.core.view.updateLayoutParams
import com.airbnb.lottie.LottieAnimationView
+import com.android.launcher3.LauncherPrefs
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
@@ -35,6 +44,9 @@
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
+import com.android.launcher3.util.OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN
+import com.android.launcher3.util.ResourceBasedOverride
+import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.BaseDragLayer
import com.android.quickstep.util.LottieAnimationColorUtils
import java.io.PrintWriter
@@ -52,6 +64,10 @@
* This value should match the maximum count for [TASKBAR_EDU_TOOLTIP_STEP].
*/
const val TOOLTIP_STEP_NONE = 3
+/** The base URL for the Privacy Policy that will later be localized. */
+private const val PRIVACY_POLICY_BASE_URL = "https://policies.google.com/privacy/embedded?hl="
+/** The base URL for the Terms of Service that will later be localized. */
+private const val TOS_BASE_URL = "https://policies.google.com/terms?hl="
/** Current step in the tooltip EDU flow. */
@Retention(AnnotationRetention.SOURCE)
@@ -59,9 +75,11 @@
annotation class TaskbarEduTooltipStep
/** Controls stepping through the Taskbar tooltip EDU. */
-class TaskbarEduTooltipController(val activityContext: TaskbarActivityContext) :
- LoggableTaskbarController {
+open class TaskbarEduTooltipController(context: Context) :
+ ResourceBasedOverride, LoggableTaskbarController {
+ protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
+ open val shouldShowSearchEdu = false
private val isTooltipEnabled: Boolean
get() = !Utilities.isRunningInTestHarness() && !activityContext.isPhoneMode
private val isOpen: Boolean
@@ -70,6 +88,15 @@
get() = isTooltipEnabled && tooltipStep <= TOOLTIP_STEP_FEATURES
private lateinit var controllers: TaskbarControllers
+ // Keep track of whether the user has seen the Search Edu
+ private var userHasSeenSearchEdu: Boolean
+ get() {
+ return TASKBAR_SEARCH_EDU_SEEN.get(activityContext)
+ }
+ private set(seen) {
+ LauncherPrefs.get(activityContext).put(TASKBAR_SEARCH_EDU_SEEN, seen)
+ }
+
@TaskbarEduTooltipStep
var tooltipStep: Int
get() {
@@ -83,6 +110,8 @@
fun init(controllers: TaskbarControllers) {
this.controllers = controllers
+ // We want to show the Search Edu right after pinning the taskbar, so we post it here
+ activityContext.dragLayer.post { maybeShowSearchEdu() }
}
/** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
@@ -112,6 +141,7 @@
fun maybeShowFeaturesEdu() {
if (!isTooltipEnabled || tooltipStep > TOOLTIP_STEP_FEATURES) {
maybeShowPinningEdu()
+ maybeShowSearchEdu()
return
}
@@ -207,6 +237,96 @@
}
}
+ /**
+ * Shows standalone Search EDU tooltip if this EDU has not been seen.
+ *
+ * We show this standalone edu for users to learn to how to trigger Search from the pinned
+ * taskbar
+ */
+ fun maybeShowSearchEdu() {
+ if (
+ !enableTaskbarPinning() ||
+ !DisplayController.isPinnedTaskbar(activityContext) ||
+ !isTooltipEnabled ||
+ !shouldShowSearchEdu ||
+ userHasSeenSearchEdu
+ ) {
+ return
+ }
+ userHasSeenSearchEdu = true
+ inflateTooltip(R.layout.taskbar_edu_search)
+ tooltip?.run {
+ requireViewById<LottieAnimationView>(R.id.search_edu_animation).supportLightTheme()
+ val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
+ showDisclosureText(eduSubtitle)
+ updateLayoutParams<BaseDragLayer.LayoutParams> {
+ if (DisplayController.isTransientTaskbar(activityContext)) {
+ bottomMargin += activityContext.deviceProfile.taskbarHeight
+ }
+ // Unlike other tooltips, we want to align with the all apps button rather than
+ // center.
+ gravity = Gravity.BOTTOM
+ marginStart = 0
+ width =
+ resources.getDimensionPixelSize(
+ R.dimen.taskbar_edu_features_tooltip_width_with_one_feature
+ )
+ }
+
+ // Calculate the amount the tooltip must be shifted by to align with the action key
+ val allAppsButtonView = controllers.taskbarViewController.allAppsButtonView
+ if (allAppsButtonView != null) {
+ val allAppsIconLocation = allAppsButtonView.x + allAppsButtonView.width / 2
+ x = allAppsIconLocation - layoutParams.width / 2
+ }
+
+ show()
+ }
+ }
+
+ /**
+ * Set up the provided TextView to display legal disclosures. The method takes locale into
+ * account to show the appropriate links to regional disclosures.
+ */
+ private fun TaskbarEduTooltip.showDisclosureText(
+ textView: TextView,
+ stringId: Int = R.string.taskbar_edu_search_disclosure,
+ ) {
+ val locale = resources.configuration.locales[0]
+ val text =
+ SpannableString(
+ HtmlCompat.fromHtml(
+ resources.getString(
+ stringId,
+ PRIVACY_POLICY_BASE_URL + locale.language,
+ TOS_BASE_URL + locale.language,
+ ),
+ HtmlCompat.FROM_HTML_MODE_COMPACT,
+ )
+ )
+ // Directly process URLSpan clicks
+ text.getSpans(0, text.length, URLSpan::class.java).forEach { urlSpan ->
+ val url: URLSpan =
+ object : URLSpan(urlSpan.url) {
+ override fun onClick(widget: View) {
+ val uri = Uri.parse(urlSpan.url)
+ val context = widget.context
+ val intent =
+ Intent(Intent.ACTION_VIEW, uri).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ context.startActivity(intent)
+ }
+ }
+
+ val spanStart = text.getSpanStart(urlSpan)
+ val spanEnd = text.getSpanEnd(urlSpan)
+ val spanFlags = text.getSpanFlags(urlSpan)
+ text.removeSpan(urlSpan)
+ text.setSpan(url, spanStart, spanEnd, spanFlags)
+ }
+ textView.text = text
+ textView.movementMethod = LinkMovementMethod.getInstance()
+ }
+
/** Closes the current [tooltip]. */
fun hide() = tooltip?.close(true)
@@ -280,6 +400,17 @@
pw?.println("$prefix\tisOpen=$isOpen")
pw?.println("$prefix\ttooltipStep=$tooltipStep")
}
+
+ companion object {
+ @JvmStatic
+ fun newInstance(context: Context): TaskbarEduTooltipController {
+ return ResourceBasedOverride.Overrides.getObject(
+ TaskbarEduTooltipController::class.java,
+ context,
+ R.string.taskbar_edu_tooltip_controller_class
+ )
+ }
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index ff33ca9..8072492 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -23,14 +23,12 @@
import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
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_TASKBAR_PINNING;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
-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.FlagDebugUtils.formatFlagChange;
import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR;
@@ -44,7 +42,6 @@
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
-import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Handler;
@@ -69,6 +66,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SimpleBroadcastReceiver;
+import com.android.quickstep.AllAppsActionManager;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
@@ -111,7 +109,6 @@
private final Context mContext;
private final @Nullable Context mNavigationBarPanelContext;
- private final DeviceStateManager mDeviceStateManager;
private WindowManager mWindowManager;
private FrameLayout mTaskbarRootLayout;
private boolean mAddedWindow;
@@ -158,6 +155,8 @@
private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
new SimpleBroadcastReceiver(this::showTaskbarFromBroadcast);
+ private final AllAppsActionManager mAllAppsActionManager;
+
private final Runnable mActivityOnDestroyCallback = new Runnable() {
@Override
public void run() {
@@ -178,8 +177,7 @@
}
};
- private final UnfoldTransitionProgressProvider.TransitionProgressListener
- mUnfoldTransitionProgressListener =
+ UnfoldTransitionProgressProvider.TransitionProgressListener mUnfoldTransitionProgressListener =
new UnfoldTransitionProgressProvider.TransitionProgressListener() {
@Override
public void onTransitionStarted() {
@@ -208,16 +206,15 @@
}
};
- private final DeviceStateManager.FoldStateListener mFoldStateListener;
- private Boolean mFolded;
-
@SuppressLint("WrongConstant")
- public TaskbarManager(TouchInteractionService service) {
+ public TaskbarManager(
+ TouchInteractionService service, AllAppsActionManager allAppsActionManager) {
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = service.createWindowContext(display,
ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL,
null);
+ mAllAppsActionManager = allAppsActionManager;
mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
? service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
: null;
@@ -236,29 +233,6 @@
}
};
}
- // Temporary solution to mitigate the visual jump from folding the device. Currently, the
- // screen turns on much earlier than we receive the onConfigurationChanged callback or
- // receiving the correct device profile. While the ideal the solution is to align turning
- // the screen on after onConfigurationChanged (by either delaying turning on the screen or
- // figuring out what is causing the delay in getting onConfigurationChanged callback), one
- // easy temporary mitigation is to dimming the bar so that the visual jump isn't as glaring.
- mFoldStateListener = new DeviceStateManager.FoldStateListener(mContext, folded -> {
- boolean firstTime = mFolded == null;
- if (mTaskbarActivityContext == null) {
- return;
- }
- if (!firstTime && mFolded.booleanValue() != folded) {
- mTaskbarActivityContext.cancelHideTaskbarWhenFolding();
- }
- mFolded = folded;
- if (folded && !firstTime) {
- mTaskbarActivityContext.hideTaskbarWhenFolding();
- } else {
- mTaskbarActivityContext.resetHideTaskbarWhenUnfolding();
- }
- });
- mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
- mDeviceStateManager.registerCallback(MAIN_EXECUTOR, mFoldStateListener);
mNavButtonController = new TaskbarNavButtonController(service,
SystemUiProxy.INSTANCE.get(mContext), new Handler(),
AssistUtils.newInstance(mContext));
@@ -291,10 +265,10 @@
recreateTaskbar();
} else {
// Config change might be handled without re-creating the taskbar
- if (dp != null && !isTaskbarPresent(dp)) {
+ if (dp != null && !isTaskbarEnabled(dp)) {
destroyExistingTaskbar();
} else {
- if (dp != null && isTaskbarPresent(dp)) {
+ if (dp != null && isTaskbarEnabled(dp)) {
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// Re-initialize for screen size change? Should this be done
// by looking at screen-size change flag in configDiff in the
@@ -349,7 +323,7 @@
}
DeviceProfile dp = mUserUnlocked ?
LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
- if (dp == null || !isTaskbarPresent(dp)) {
+ if (dp == null || !isTaskbarEnabled(dp)) {
removeTaskbarRootViewFromWindow();
}
}
@@ -369,20 +343,11 @@
* @param homeAllAppsIntent Intent used if Taskbar is not enabled or Launcher is resumed.
*/
public void toggleAllApps(Intent homeAllAppsIntent) {
- if (mTaskbarActivityContext == null) {
+ if (mTaskbarActivityContext == null || mTaskbarActivityContext.canToggleHomeAllApps()) {
mContext.startActivity(homeAllAppsIntent);
- return;
+ } else {
+ mTaskbarActivityContext.toggleAllAppsSearch();
}
-
- if (mActivity != null
- && mActivity.isResumed()
- && !mActivity.isInState(OVERVIEW)
- && !(mActivity instanceof QuickstepLauncher l && l.areFreeformTasksVisible())) {
- mContext.startActivity(homeAllAppsIntent);
- return;
- }
-
- mTaskbarActivityContext.toggleAllAppsSearch();
}
/**
@@ -477,9 +442,12 @@
DeviceProfile dp = mUserUnlocked ?
LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
+ // All Apps action is unrelated to navbar unification, so we only need to check DP.
+ final boolean isLargeScreenTaskbar = dp != null && dp.isTaskbarPresent;
+ mAllAppsActionManager.setTaskbarPresent(isLargeScreenTaskbar);
destroyExistingTaskbar();
- boolean isTaskbarEnabled = dp != null && isTaskbarPresent(dp);
+ boolean isTaskbarEnabled = dp != null && isTaskbarEnabled(dp);
debugWhyTaskbarNotDestroyed("recreateTaskbar: isTaskbarEnabled=" + isTaskbarEnabled
+ " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
+ " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
@@ -499,6 +467,7 @@
}
mSharedState.startTaskbarVariantIsTransient =
DisplayController.isTransientTaskbar(mTaskbarActivityContext);
+ mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar;
mTaskbarActivityContext.init(mSharedState);
if (mActivity != null) {
@@ -544,7 +513,7 @@
}
}
- private static boolean isTaskbarPresent(DeviceProfile deviceProfile) {
+ private static boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
return ENABLE_TASKBAR_NAVBAR_UNIFICATION || deviceProfile.isTaskbarPresent;
}
@@ -621,7 +590,6 @@
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
mContext.unregisterComponentCallbacks(mComponentCallbacks);
mContext.unregisterReceiver(mShutdownReceiver);
- mDeviceStateManager.unregisterCallback(mFoldStateListener);
}
public @Nullable TaskbarActivityContext getCurrentActivityContext() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 689a1ec..7e74c27 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -598,7 +598,8 @@
? stashTranslation : 0)
.setDuration(duration));
mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
- hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration));
+ (hasAnyFlag(FLAG_STASHED_IN_APP_IME) && isStashed) ? 0 : 1).setDuration(
+ duration));
mAnimator.addListener(AnimatorListeners.forEndCallback(() -> {
mAnimator = null;
mIsStashed = isStashed;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index c74fd83..cb0fa40 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -197,6 +197,11 @@
return false;
}
+ /** Returns {@code true} if Home All Apps available instead of Taskbar All Apps. */
+ protected boolean canToggleHomeAllApps() {
+ return false;
+ }
+
@CallSuper
protected void dumpLogs(String prefix, PrintWriter pw) {
pw.println(String.format(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 67b41c6..81bade3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -32,6 +32,7 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
+import android.view.DisplayCutout;
import android.view.InputDevice;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -134,7 +135,7 @@
int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
int actualIconSize = mActivityContext.getDeviceProfile().taskbarIconSize;
- if (enableTaskbarPinning()) {
+ if (enableTaskbarPinning() && !mActivityContext.isThreeButtonNav()) {
DeviceProfile deviceProfile = mActivityContext.getTransientTaskbarDeviceProfile();
actualIconSize = deviceProfile.taskbarIconSize;
}
@@ -472,6 +473,29 @@
iconEnd = centerAlignIconEnd + offset;
}
+ // Currently, we support only one device with display cutout and we only are concern about
+ // it when the bottom rect is present and non empty
+ DisplayCutout displayCutout = getDisplay().getCutout();
+ if (displayCutout != null && !displayCutout.getBoundingRectBottom().isEmpty()) {
+ Rect cutoutBottomRect = displayCutout.getBoundingRectBottom();
+ // when cutout present at the bottom of screen align taskbar icons to cutout offset
+ // if taskbar icon overlaps with cutout
+ int taskbarIconLeftBound = iconEnd - spaceNeeded;
+ int taskbarIconRightBound = iconEnd;
+
+ boolean doesTaskbarIconsOverlapWithCutout =
+ taskbarIconLeftBound <= cutoutBottomRect.centerX()
+ && cutoutBottomRect.centerX() <= taskbarIconRightBound;
+
+ if (doesTaskbarIconsOverlapWithCutout) {
+ if (!layoutRtl) {
+ iconEnd = spaceNeeded + cutoutBottomRect.width();
+ } else {
+ iconEnd = right - cutoutBottomRect.width();
+ }
+ }
+ }
+
sTmpRect.set(mIconLayoutBounds);
// Layout the children
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 1f7f0a7..5d0eac3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -337,11 +337,6 @@
private void updateTaskbarIconTranslationXForPinning() {
View[] iconViews = mTaskbarView.getIconViews();
float scale = mTaskbarIconTranslationXForPinning.value;
- float taskbarCenterX =
- mTaskbarView.getLeft() + (mTaskbarView.getRight() - mTaskbarView.getLeft()) / 2.0f;
-
- float finalMarginScale = mapRange(scale, 0f, mTransientIconSize - mPersistentIconSize);
-
float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
mTaskbarView.getAllAppsButtonTranslationXOffset(true));
float persistentTaskbarAllAppsOffset = mActivity.getResources().getDimension(
@@ -354,6 +349,17 @@
allAppIconTranslateRange *= -1;
}
+ if (mActivity.isThreeButtonNav()) {
+ ((IconButtonView) mTaskbarView.getAllAppsButtonView())
+ .setTranslationXForTaskbarAllAppsIcon(allAppIconTranslateRange);
+ return;
+ }
+
+ float taskbarCenterX =
+ mTaskbarView.getLeft() + (mTaskbarView.getRight() - mTaskbarView.getLeft()) / 2.0f;
+
+ float finalMarginScale = mapRange(scale, 0f, mTransientIconSize - mPersistentIconSize);
+
float halfIconCount = iconViews.length / 2.0f;
for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) {
View iconView = iconViews[iconIndex];
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
index 5c57a01..a385502 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
@@ -28,35 +28,39 @@
import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.systemui.shared.rotation.RotationButton
-/**
- * Layoutter for rendering task bar in large screen, both in 3-button and gesture nav mode.
- */
+/** Layoutter for rendering task bar in large screen, both in 3-button and gesture nav mode. */
class TaskbarNavLayoutter(
- resources: Resources,
- navBarContainer: LinearLayout,
- endContextualContainer: ViewGroup,
- startContextualContainer: ViewGroup,
- imeSwitcher: ImageView?,
- rotationButton: RotationButton?,
- a11yButton: ImageView?,
- space: Space?
+ resources: Resources,
+ navBarContainer: LinearLayout,
+ endContextualContainer: ViewGroup,
+ startContextualContainer: ViewGroup,
+ imeSwitcher: ImageView?,
+ rotationButton: RotationButton?,
+ a11yButton: ImageView?,
+ space: Space?
) :
AbstractNavButtonLayoutter(
- resources,
- navBarContainer,
- endContextualContainer,
- startContextualContainer,
- imeSwitcher,
- rotationButton,
- a11yButton,
- space
+ resources,
+ navBarContainer,
+ endContextualContainer,
+ startContextualContainer,
+ imeSwitcher,
+ rotationButton,
+ a11yButton,
+ space
) {
override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
// Add spacing after the end of the last nav button
- var navMarginEnd = resources
- .getDimension(context.deviceProfile.inv.inlineNavButtonsEndSpacing)
- .toInt()
+ var navMarginEnd =
+ resources.getDimension(context.deviceProfile.inv.inlineNavButtonsEndSpacing).toInt()
+
+ val cutout = context.display.cutout
+ val bottomRect = cutout?.boundingRectBottom
+ if (bottomRect != null && !bottomRect.isEmpty) {
+ navMarginEnd = bottomRect.width()
+ }
+
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
@@ -65,8 +69,11 @@
navMarginEnd += resources.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing) / 2
}
- val navButtonParams = FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ val navButtonParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
navButtonParams.apply {
gravity = Gravity.END or Gravity.CENTER_VERTICAL
marginEnd = navMarginEnd
diff --git a/quickstep/src/com/android/quickstep/AllAppsActionManager.kt b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
new file mode 100644
index 0000000..fd2ed3a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS
+import android.app.PendingIntent
+import android.app.RemoteAction
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.view.accessibility.AccessibilityManager
+import com.android.launcher3.R
+import java.util.concurrent.Executor
+
+/**
+ * Registers a [RemoteAction] for toggling All Apps if needed.
+ *
+ * We need this action when either [isHomeAndOverviewSame] or [isTaskbarPresent] is `true`. When
+ * home and overview are the same, we can control Launcher's or Taskbar's All Apps tray. If they are
+ * not the same, but Taskbar is present, we can only control Taskbar's tray.
+ */
+class AllAppsActionManager(
+ private val context: Context,
+ private val bgExecutor: Executor,
+ private val createAllAppsPendingIntent: () -> PendingIntent,
+) {
+
+ /** `true` if home and overview are the same Activity. */
+ var isHomeAndOverviewSame = false
+ set(value) {
+ field = value
+ updateSystemAction()
+ }
+
+ /** `true` if Taskbar is enabled. */
+ var isTaskbarPresent = false
+ set(value) {
+ field = value
+ updateSystemAction()
+ }
+
+ /** `true` if the action should be registered. */
+ var isActionRegistered = false
+ private set
+
+ private fun updateSystemAction() {
+ val shouldRegisterAction = isHomeAndOverviewSame || isTaskbarPresent
+ if (isActionRegistered == shouldRegisterAction) return
+ isActionRegistered = shouldRegisterAction
+
+ bgExecutor.execute {
+ val accessibilityManager =
+ context.getSystemService(AccessibilityManager::class.java) ?: return@execute
+ if (shouldRegisterAction) {
+ accessibilityManager.registerSystemAction(
+ RemoteAction(
+ Icon.createWithResource(context, R.drawable.ic_apps),
+ context.getString(R.string.all_apps_label),
+ context.getString(R.string.all_apps_label),
+ createAllAppsPendingIntent(),
+ ),
+ GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
+ )
+ } else {
+ accessibilityManager.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS)
+ }
+ }
+ }
+
+ fun onDestroy() {
+ context
+ .getSystemService(AccessibilityManager::class.java)
+ ?.unregisterSystemAction(
+ GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
+ )
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index d02909c..63833c2 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -516,13 +516,14 @@
return mSwipeUpStartTimeMs;
}
- public void dump(PrintWriter pw) {
- pw.println("GestureState:");
- pw.println(" gestureID=" + mGestureId);
- pw.println(" runningTask=" + mRunningTask);
- pw.println(" endTarget=" + mEndTarget);
- pw.println(" lastAppearedTaskTargetId=" + Arrays.toString(mLastAppearedTaskTargets));
- pw.println(" lastStartedTaskId=" + Arrays.toString(mLastStartedTaskId));
- pw.println(" isRecentsAnimationRunning=" + isRecentsAnimationRunning());
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "GestureState:");
+ pw.println(prefix + "\tgestureID=" + mGestureId);
+ pw.println(prefix + "\trunningTask=" + mRunningTask);
+ pw.println(prefix + "\tendTarget=" + mEndTarget);
+ pw.println(prefix + "\tlastAppearedTaskTargetId="
+ + Arrays.toString(mLastAppearedTaskTargets));
+ pw.println(prefix + "\tlastStartedTaskId=" + Arrays.toString(mLastStartedTaskId));
+ pw.println(prefix + "\tisRecentsAnimationRunning=" + isRecentsAnimationRunning());
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 5d26ec0..da7a98f 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -39,6 +39,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -219,6 +220,13 @@
}
}
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "RecentsAnimationCallbacks:");
+
+ pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
+ pw.println(prefix + "\tmCancelled=" + mCancelled);
+ }
+
/**
* Listener for the recents animation callbacks.
*/
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 06a442b..1b05e28 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -41,6 +41,7 @@
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import java.io.PrintWriter;
import java.util.function.Consumer;
/**
@@ -267,4 +268,14 @@
public boolean getFinishTargetIsLauncher() {
return mFinishTargetIsLauncher;
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "RecentsAnimationController:");
+
+ pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
+ pw.println(prefix + "\tmUseLauncherSysBarFlags=" + mUseLauncherSysBarFlags);
+ pw.println(prefix + "\tmSplitScreenMinimized=" + mSplitScreenMinimized);
+ pw.println(prefix + "\tmFinishRequested=" + mFinishRequested);
+ pw.println(prefix + "\tmFinishTargetIsLauncher=" + mFinishTargetIsLauncher);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 556dd7e..b10fba4 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -24,6 +24,8 @@
import android.os.Bundle;
import android.view.RemoteAnimationTarget;
+import java.io.PrintWriter;
+
/**
* Extension of {@link RemoteAnimationTargets} with additional information about swipe
* up animation
@@ -62,4 +64,14 @@
}
return false;
}
+
+ @Override
+ public void dump(String prefix, PrintWriter pw) {
+ super.dump(prefix, pw);
+ prefix += '\t';
+ pw.println(prefix + "RecentsAnimationTargets:");
+
+ pw.println(prefix + "\thomeContentInsets=" + homeContentInsets);
+ pw.println(prefix + "\tminimizedHomeBounds=" + minimizedHomeBounds);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
index e0c7403..57edd82 100644
--- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
@@ -22,6 +22,7 @@
import android.os.Bundle;
import android.view.RemoteAnimationTarget;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -149,6 +150,14 @@
}
}
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "RemoteAnimationTargets:");
+
+ pw.println(prefix + "\ttargetMode=" + targetMode);
+ pw.println(prefix + "\thasRecents=" + hasRecents);
+ pw.println(prefix + "\tmReleased=" + mReleased);
+ }
+
/**
* Interface for intercepting surface release method
*/
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 4e62d60..53275a8 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -17,6 +17,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
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.NavigationMode.NO_BUTTON;
@@ -49,6 +50,7 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import java.io.PrintWriter;
import java.util.HashMap;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
@@ -67,6 +69,7 @@
private Context mCtx;
private boolean mRecentsAnimationStartPending = false;
+ private boolean mShouldIgnoreMotionEvents = false;
private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
@Override
@@ -102,8 +105,16 @@
.startRecentsActivity(intent, 0, null, null, null));
}
- public boolean isRecentsAnimationStartPending() {
- return mRecentsAnimationStartPending;
+ boolean shouldIgnoreMotionEvents() {
+ return mShouldIgnoreMotionEvents;
+ }
+
+ void notifyNewGestureStart() {
+ // If mRecentsAnimationStartPending is true at the beginning of a gesture, block all motion
+ // events for this new gesture so that this new gesture does not interfere with the
+ // previously-requested recents animation. Otherwise, clean up mShouldIgnoreMotionEvents.
+ // NOTE: this can lead to misleading logs
+ mShouldIgnoreMotionEvents = mRecentsAnimationStartPending;
}
/**
@@ -144,7 +155,12 @@
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
- mRecentsAnimationStartPending = false;
+ if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+ ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+ "TaskAnimationManager.startRecentsAnimation(onRecentsAnimationStart): ")
+ .append("Setting mRecentsAnimationStartPending = false"));
+ mRecentsAnimationStartPending = false;
+ }
if (mCallbacks == null) {
// It's possible for the recents animation to have finished and be cleaned up
// by the time we process the start callback, and in that case, just we can skip
@@ -185,13 +201,25 @@
@Override
public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
- mRecentsAnimationStartPending = false;
+ if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+ ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+ "TaskAnimationManager.startRecentsAnimation")
+ .append("(onRecentsAnimationCanceled): ")
+ .append("Setting mRecentsAnimationStartPending = false"));
+ mRecentsAnimationStartPending = false;
+ }
cleanUpRecentsAnimation(newCallbacks);
}
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
- mRecentsAnimationStartPending = false;
+ if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+ ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+ "TaskAnimationManager.startRecentsAnimation")
+ .append("(onRecentsAnimationFinished): ")
+ .append("Setting mRecentsAnimationStartPending = false"));
+ mRecentsAnimationStartPending = false;
+ }
cleanUpRecentsAnimation(newCallbacks);
}
@@ -301,13 +329,29 @@
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.getNoCreate()
.startRecentsActivity(intent, options, mCallbacks);
+ if (enableHandleDelayedGestureCallbacks()) {
+ ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+ "TaskAnimationManager.startRecentsAnimation(shell transition path): ")
+ .append("Setting mRecentsAnimationStartPending = ")
+ .append(mRecentsAnimationStartPending));
+ }
} else {
UI_HELPER_EXECUTOR.execute(
() -> ActivityManagerWrapper.getInstance().startRecentsActivity(
intent,
eventTime,
mCallbacks,
- result -> mRecentsAnimationStartPending = result,
+ result -> {
+ if (enableHandleDelayedGestureCallbacks()) {
+ ActiveGestureLog.INSTANCE.addLog(
+ new ActiveGestureLog.CompoundString(
+ "TaskAnimationManager.startRecentsAnimation")
+ .append("(legacy path): Setting ")
+ .append("mRecentsAnimationStartPending = ")
+ .append(result));
+ }
+ mRecentsAnimationStartPending = result;
+ },
MAIN_EXECUTOR.getHandler()));
}
gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
@@ -437,7 +481,24 @@
return mCallbacks;
}
- public void dump() {
- // TODO
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + "TaskAnimationManager:");
+
+ if (enableHandleDelayedGestureCallbacks()) {
+ pw.println(prefix + "\tmRecentsAnimationStartPending=" + mRecentsAnimationStartPending);
+ pw.println(prefix + "\tmShouldIgnoreUpcomingGestures=" + mShouldIgnoreMotionEvents);
+ }
+ if (mController != null) {
+ mController.dump(prefix + '\t', pw);
+ }
+ if (mCallbacks != null) {
+ mCallbacks.dump(prefix + '\t', pw);
+ }
+ if (mTargets != null) {
+ mTargets.dump(prefix + '\t', pw);
+ }
+ if (mLastGestureState != null) {
+ mLastGestureState.dump(prefix + '\t', pw);
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 719c4f7..8cd733b 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -24,6 +24,7 @@
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
import static com.android.launcher3.Flags.useActivityOverlay;
import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE;
import static com.android.launcher3.LauncherPrefs.backedUpItem;
@@ -31,6 +32,7 @@
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
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.OnboardingPrefs.HOME_BOUNCE_SEEN;
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
@@ -40,6 +42,7 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_MOVE;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP;
+import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENTS_ANIMATION_START_PENDING;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
@@ -59,14 +62,12 @@
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
import android.app.PendingIntent;
-import android.app.RemoteAction;
import android.app.Service;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Region;
-import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
@@ -77,7 +78,6 @@
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
-import android.view.accessibility.AccessibilityManager;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -88,7 +88,6 @@
import com.android.launcher3.ConstantItem;
import com.android.launcher3.EncryptionType;
import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.provider.RestoreDbTask;
@@ -101,7 +100,6 @@
import com.android.launcher3.uioverrides.flags.FlagsFactory;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.ScreenOnTracker;
@@ -488,6 +486,7 @@
private TaskbarManager mTaskbarManager;
private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
+ private AllAppsActionManager mAllAppsActionManager;
@Override
public void onCreate() {
@@ -497,7 +496,9 @@
mMainChoreographer = Choreographer.getInstance();
mAM = ActivityManagerWrapper.getInstance();
mDeviceState = new RecentsAnimationDeviceState(this, true);
- mTaskbarManager = new TaskbarManager(this);
+ mAllAppsActionManager = new AllAppsActionManager(
+ this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
+ mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager);
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
BootAwarePreloader.start(this);
@@ -590,16 +591,7 @@
}
private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
- Executors.UI_HELPER_EXECUTOR.execute(() -> {
- AccessibilityManager am = getSystemService(AccessibilityManager.class);
-
- if (isHomeAndOverviewSame) {
- am.registerSystemAction(
- createAllAppsAction(), GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
- } else {
- am.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
- }
- });
+ mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame);
StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface()
.getCreatedActivity();
@@ -609,13 +601,12 @@
mTISBinder.onOverviewTargetChange();
}
- private RemoteAction createAllAppsAction() {
+ private PendingIntent createAllAppsPendingIntent() {
final Intent homeIntent = new Intent(mOverviewComponentObserver.getHomeIntent())
.setAction(INTENT_ACTION_ALL_APPS_TOGGLE);
- final PendingIntent actionPendingIntent;
if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
- actionPendingIntent = new PendingIntent(new IIntentSender.Stub() {
+ return new PendingIntent(new IIntentSender.Stub() {
@Override
public void send(int code, Intent intent, String resolvedType,
IBinder allowlistToken, IIntentReceiver finishedReceiver,
@@ -624,18 +615,12 @@
}
});
} else {
- actionPendingIntent = PendingIntent.getActivity(
+ return PendingIntent.getActivity(
this,
GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
homeIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
-
- return new RemoteAction(
- Icon.createWithResource(this, R.drawable.ic_apps),
- getString(R.string.all_apps_label),
- getString(R.string.all_apps_label),
- actionPendingIntent);
}
@UiThread
@@ -678,8 +663,7 @@
mDeviceState.destroy();
SystemUiProxy.INSTANCE.get(this).clearProxy();
- getSystemService(AccessibilityManager.class)
- .unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
+ mAllAppsActionManager.onDestroy();
mTaskbarManager.destroy();
sConnected = false;
@@ -734,16 +718,22 @@
boolean isHoverActionWithoutConsumer = enableCursorHoverStates()
&& isHoverActionWithoutConsumer(event);
- // TODO(b/285636175): Uncomment this once WM can properly guarantee all animation callbacks
-// if (mTaskAnimationManager.isRecentsAnimationStartPending()
-// && (action == ACTION_DOWN || isHoverActionWithoutConsumer)) {
-// ActiveGestureLog.INSTANCE.addLog(
-// new CompoundString("TIS.onInputEvent: ")
-// .append("Cannot process input event: a recents animation has been ")
-// .append("requested, but hasn't started."),
-// RECENTS_ANIMATION_START_PENDING);
-// return;
-// }
+ if (enableHandleDelayedGestureCallbacks()) {
+ if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
+ mTaskAnimationManager.notifyNewGestureStart();
+ }
+ if (mTaskAnimationManager.shouldIgnoreMotionEvents()) {
+ if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
+ ActiveGestureLog.INSTANCE.addLog(
+ new CompoundString("TIS.onMotionEvent: A new gesture has been ")
+ .append("started, but a previously-requested recents ")
+ .append("animation hasn't started. Ignoring all following ")
+ .append("motion events."),
+ RECENTS_ANIMATION_START_PENDING);
+ }
+ return;
+ }
+ }
SafeCloseable traceToken = TraceHelper.INSTANCE.allowIpcs("TIS.onInputEvent");
@@ -1449,28 +1439,31 @@
mOverviewCommandHelper.dump(pw);
}
if (mGestureState != null) {
- mGestureState.dump(pw);
+ mGestureState.dump("", pw);
}
pw.println("Input state:");
- pw.println(" mInputMonitorCompat=" + mInputMonitorCompat);
- pw.println(" mInputEventReceiver=" + mInputEventReceiver);
+ pw.println("\tmInputMonitorCompat=" + mInputMonitorCompat);
+ pw.println("\tmInputEventReceiver=" + mInputEventReceiver);
DisplayController.INSTANCE.get(this).dump(pw);
pw.println("TouchState:");
BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
: mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
boolean resumed = mOverviewComponentObserver != null
&& mOverviewComponentObserver.getActivityInterface().isResumed();
- pw.println(" createdOverviewActivity=" + createdOverviewActivity);
- pw.println(" resumed=" + resumed);
- pw.println(" mConsumer=" + mConsumer.getName());
+ pw.println("\tcreatedOverviewActivity=" + createdOverviewActivity);
+ pw.println("\tresumed=" + resumed);
+ pw.println("\tmConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
RecentsModel.INSTANCE.get(this).dump("", pw);
+ if (mTaskAnimationManager != null) {
+ mTaskAnimationManager.dump("", pw);
+ }
if (createdOverviewActivity != null) {
createdOverviewActivity.getDeviceProfile().dump(this, "", pw);
}
mTaskbarManager.dumpLogs("", pw);
pw.println("AssistStateManager:");
- AssistStateManager.INSTANCE.get(this).dump(" ", pw);
+ AssistStateManager.INSTANCE.get(this).dump("\t", pw);
SystemUiProxy.INSTANCE.get(this).dump(pw);
}
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
index e3772bd..cfa6b98 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
@@ -277,7 +277,8 @@
errorDetected |= printErrorIfTrue(
true,
prefix,
- /* errorMessage= */ "new gesture attempted while a requested recents"
+ /* errorMessage= */ (eventEntry.getDuplicateCount() + 1)
+ + " gesture(s) attempted while a requested recents"
+ " animation is still pending.",
writer);
break;
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 1e05a69..c54862a 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -216,6 +216,10 @@
return gestureEvent;
}
+ public int getDuplicateCount() {
+ return duplicateCount;
+ }
+
private void update(
@NonNull CompoundString compoundString,
ActiveGestureErrorDetector.GestureEvent gestureEvent) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 0fc16ba..4fd0f3c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2759,18 +2759,20 @@
* Returns true if we should add a stub taskView for the running task id
*/
protected boolean shouldAddStubTaskView(Task[] runningTasks) {
- if (runningTasks.length > 1) {
- TaskView primaryTaskView = getTaskViewByTaskId(runningTasks[0].key.id);
- TaskView secondaryTaskView = getTaskViewByTaskId(runningTasks[1].key.id);
- int leftTopTaskViewId =
- (primaryTaskView == null) ? -1 : primaryTaskView.getTaskViewId();
- int rightBottomTaskViewId =
- (secondaryTaskView == null) ? -1 : secondaryTaskView.getTaskViewId();
- // Add a new stub view if both taskIds don't match any taskViews
- return leftTopTaskViewId != rightBottomTaskViewId || leftTopTaskViewId == -1;
+ TaskView taskView = getTaskViewByTaskId(runningTasks[0].key.id);
+ if (taskView == null) {
+ // No TaskView found, add a stub task.
+ return true;
}
- Task runningTaskInfo = runningTasks[0];
- return runningTaskInfo != null && getTaskViewByTaskId(runningTaskInfo.key.id) == null;
+
+ if (runningTasks.length > 1) {
+ // Ensure all taskIds matches the TaskView, otherwise add a stub task.
+ return Arrays.stream(runningTasks).anyMatch(
+ runningTask -> !taskView.containsTaskId(runningTask.key.id));
+ } else {
+ // Ensure the TaskView only contains a single taskId, otherwise add a stub task.
+ return taskView.containsMultipleTasks();
+ }
}
/**
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
new file mode 100644
index 0000000..73b35e8
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.app.PendingIntent
+import android.content.IIntentSender
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import com.android.launcher3.util.TestUtil
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit.SECONDS
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TIMEOUT = 5L
+
+@RunWith(AndroidJUnit4::class)
+class AllAppsActionManagerTest {
+ private val callbackSemaphore = Semaphore(0)
+ private val bgExecutor = UI_HELPER_EXECUTOR
+
+ private val allAppsActionManager =
+ AllAppsActionManager(
+ InstrumentationRegistry.getInstrumentation().targetContext,
+ bgExecutor,
+ ) {
+ callbackSemaphore.release()
+ PendingIntent(IIntentSender.Default())
+ }
+
+ @Test
+ fun taskbarPresent_actionRegistered() {
+ allAppsActionManager.isTaskbarPresent = true
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+ assertThat(allAppsActionManager.isActionRegistered).isTrue()
+ }
+
+ @Test
+ fun homeAndOverviewSame_actionRegistered() {
+ allAppsActionManager.isHomeAndOverviewSame = true
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+ assertThat(allAppsActionManager.isActionRegistered).isTrue()
+ }
+
+ @Test
+ fun toggleTaskbar_destroyedAfterActionRegistered_actionUnregistered() {
+ allAppsActionManager.isTaskbarPresent = true
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+
+ allAppsActionManager.isTaskbarPresent = false
+ TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to unregister.
+ assertThat(allAppsActionManager.isActionRegistered).isFalse()
+ }
+
+ @Test
+ fun toggleTaskbar_destroyedBeforeActionRegistered_pendingActionUnregistered() {
+ allAppsActionManager.isTaskbarPresent = true
+ allAppsActionManager.isTaskbarPresent = false
+
+ TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to unregister.
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+ assertThat(allAppsActionManager.isActionRegistered).isFalse()
+ }
+
+ @Test
+ fun changeHome_sameAsOverviewBeforeActionUnregistered_actionRegisteredAgain() {
+ allAppsActionManager.isHomeAndOverviewSame = true // Initialize to same.
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+
+ allAppsActionManager.isHomeAndOverviewSame = false
+ allAppsActionManager.isHomeAndOverviewSame = true
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+ assertThat(allAppsActionManager.isActionRegistered).isTrue()
+ }
+}
diff --git a/res/values/config.xml b/res/values/config.xml
index 21d6024..c774a8c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -107,6 +107,8 @@
<!-- Menu id for feature flags -->
<item type="id" name="menu_apply_flags" />
+ <string name="taskbar_edu_tooltip_controller_class" translatable="false"></string>
+
<!-- Default packages -->
<string name="wallpaper_picker_package" translatable="false"></string>
<string name="local_colors_extraction_class" translatable="false"></string>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 4ca20d6..43d1213 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -237,7 +237,7 @@
defaultIconSize = getResources().getDimensionPixelSize(
R.dimen.search_row_small_icon_size);
} else if (mDisplay == DISPLAY_TASKBAR) {
- defaultIconSize = mDeviceProfile.iconSizePx;
+ defaultIconSize = mDeviceProfile.taskbarIconSize;
} else {
// widget_selection or shortcut_popup
defaultIconSize = mDeviceProfile.iconSizePx;
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 6a7c3a3..2fd5ebd 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -72,6 +72,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.stream.Collectors;
public class InvariantDeviceProfile {
@@ -357,6 +358,15 @@
return displayOption.grid.name;
}
+ /**
+ * @deprecated This is a temporary solution because on the backup and restore case we modify the
+ * IDP, this resets it. b/332974074
+ */
+ @Deprecated
+ public void reset(Context context) {
+ initGrid(context, getCurrentGridName(context));
+ }
+
@VisibleForTesting
public static String getDefaultGridName(Context context) {
return new InvariantDeviceProfile().initGrid(context, null);
@@ -576,6 +586,45 @@
}
/**
+ * Returns the GridOption associated to the given file name or null if the fileName is not
+ * supported.
+ * Ej, launcher.db -> "normal grid", launcher_4_by_4.db -> "practical grid"
+ */
+ public GridOption getGridOptionFromFileName(Context context, String fileName) {
+ return parseAllGridOptions(context).stream()
+ .filter(gridOption -> Objects.equals(gridOption.dbFile, fileName))
+ .findFirst()
+ .orElse(null);
+ }
+
+ /**
+ * Returns the name of the given size on the current device or empty string if the size is not
+ * supported. Ej. 4x4 -> normal, 5x4 -> practical, etc.
+ * (Note: the name of the grid can be different for the same grid size depending of
+ * the values of the InvariantDeviceProfile)
+ *
+ */
+ public String getGridNameFromSize(Context context, Point size) {
+ return parseAllGridOptions(context).stream()
+ .filter(gridOption -> gridOption.numColumns == size.x
+ && gridOption.numRows == size.y)
+ .map(gridOption -> gridOption.name)
+ .findFirst()
+ .orElse("");
+ }
+
+ /**
+ * Returns the grid option for the given gridName on the current device (Note: the gridOption
+ * be different for the same gridName depending on the values of the InvariantDeviceProfile).
+ */
+ public GridOption getGridOptionFromName(Context context, String gridName) {
+ return parseAllGridOptions(context).stream()
+ .filter(gridOption -> Objects.equals(gridOption.name, gridName))
+ .findFirst()
+ .orElse(null);
+ }
+
+ /**
* @return all the grid options that can be shown on the device
*/
public List<GridOption> parseAllGridOptions(Context context) {
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
index f24d1d2..8c68eb8 100644
--- a/src/com/android/launcher3/model/DeviceGridState.java
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -53,6 +53,13 @@
private final @DeviceType int mDeviceType;
private final String mDbFile;
+ public DeviceGridState(int columns, int row, int numHotseat, int deviceType, String dbFile) {
+ mGridSizeString = String.format(Locale.ENGLISH, "%d,%d", columns, row);
+ mNumHotseat = numHotseat;
+ mDeviceType = deviceType;
+ mDbFile = dbFile;
+ }
+
public DeviceGridState(InvariantDeviceProfile idp) {
mGridSizeString = String.format(Locale.ENGLISH, "%d,%d", idp.numColumns, idp.numRows);
mNumHotseat = idp.numDatabaseHotseatIcons;
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index af66431..15190c7 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -38,7 +38,9 @@
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings;
@@ -94,6 +96,15 @@
return needsToMigrate;
}
+ @VisibleForTesting
+ public static List<DbEntry> readAllEntries(SQLiteDatabase db, String tableName,
+ Context context) {
+ DbReader dbReader = new DbReader(db, tableName, context, getValidPackages(context));
+ List<DbEntry> result = dbReader.loadAllWorkspaceEntries();
+ result.addAll(dbReader.loadHotseatEntries());
+ return result;
+ }
+
/**
* When migrating the grid, we copy the table
* {@link LauncherSettings.Favorites#TABLE_NAME} from {@code source} into
@@ -105,15 +116,23 @@
*/
public static boolean migrateGridIfNeeded(
@NonNull Context context,
- @NonNull InvariantDeviceProfile idp,
+ @NonNull DeviceGridState srcDeviceState,
+ @NonNull DeviceGridState destDeviceState,
@NonNull DatabaseHelper target,
@NonNull SQLiteDatabase source) {
-
- DeviceGridState srcDeviceState = new DeviceGridState(context);
- DeviceGridState destDeviceState = new DeviceGridState(idp);
if (!needsToMigrate(srcDeviceState, destDeviceState)) {
return true;
}
+
+ if (Flags.enableGridMigrationFix()
+ && srcDeviceState.getColumns().equals(destDeviceState.getColumns())
+ && srcDeviceState.getRows() < destDeviceState.getRows()) {
+ // Only use this strategy when comparing the previous grid to the new grid and the
+ // columns are the same and the destination has more rows
+ copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
+ destDeviceState.writeToPrefs(context);
+ return true;
+ }
copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context);
HashSet<String> validPackages = getValidPackages(context);
@@ -656,7 +675,7 @@
}
}
- protected static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
+ public static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
private String mIntent;
private String mProvider;
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 64771bd..7e1d40d 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -312,8 +312,12 @@
mOpenHelper = (mContext instanceof SandboxContext) ? oldHelper
: createDatabaseHelper(true /* forMigration */);
try {
- return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, idp, mOpenHelper,
- oldHelper.getWritableDatabase());
+ // This is the current grid we have, given by the mContext
+ DeviceGridState srcDeviceState = new DeviceGridState(mContext);
+ // This is the state we want to migrate to that is given by the idp
+ DeviceGridState destDeviceState = new DeviceGridState(idp);
+ return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, srcDeviceState,
+ destDeviceState, mOpenHelper, oldHelper.getWritableDatabase());
} catch (Exception e) {
FileLog.e(TAG, "Failed to migrate grid", e);
return false;
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 22bc13b..e6ce337 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -50,8 +50,10 @@
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
+import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherFiles;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
@@ -73,9 +75,11 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.LogConfig;
+import java.io.File;
import java.io.InvalidObjectException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -121,7 +125,66 @@
// executed again.
LauncherPrefs.get(context).removeSync(RESTORE_DEVICE);
- idp.reinitializeAfterRestore(context);
+ if (Flags.enableNarrowGridRestore()) {
+ String oldPhoneFileName = idp.dbFile;
+ List<String> previousDbs = existingDbs();
+ removeOldDBs(context, oldPhoneFileName);
+ // The idp before this contains data about the old phone, after this it becomes the idp
+ // of the current phone.
+ idp.reset(context);
+ trySettingPreviousGidAsCurrent(context, idp, oldPhoneFileName, previousDbs);
+ } else {
+ idp.reinitializeAfterRestore(context);
+ }
+ }
+
+
+ /**
+ * Try setting the gird used in the previous phone to the new one. If the current device doesn't
+ * support the previous grid option it will not be set.
+ */
+ private static void trySettingPreviousGidAsCurrent(Context context, InvariantDeviceProfile idp,
+ String oldPhoneDbFileName, List<String> previousDbs) {
+ InvariantDeviceProfile.GridOption oldPhoneGridOption = idp.getGridOptionFromFileName(
+ context, oldPhoneDbFileName);
+ // The grid option could be null if current phone doesn't support the previous db.
+ if (oldPhoneGridOption != null) {
+ /* If the user only used the default db on the previous phone and the new default db is
+ * bigger than or equal to the previous one, then keep the new default db */
+ if (previousDbs.size() == 1 && oldPhoneGridOption.numColumns <= idp.numColumns
+ && oldPhoneGridOption.numRows <= idp.numRows) {
+ /* Keep the user in default grid */
+ return;
+ }
+ /*
+ * Here we are setting the previous db as the current one.
+ */
+ idp.setCurrentGrid(context, oldPhoneGridOption.name);
+ }
+ }
+
+ /**
+ * Returns a list of paths of the existing launcher dbs.
+ */
+ private static List<String> existingDbs() {
+ // At this point idp.dbFile contains the name of the dbFile from the previous phone
+ return LauncherFiles.GRID_DB_FILES.stream()
+ .filter(dbName -> new File(dbName).exists())
+ .toList();
+ }
+
+ /**
+ * Only keep the last database used on the previous device.
+ */
+ private static void removeOldDBs(Context context, String oldPhoneDbFileName) {
+ // At this point idp.dbFile contains the name of the dbFile from the previous phone
+ LauncherFiles.GRID_DB_FILES.stream()
+ .filter(dbName -> !dbName.equals(oldPhoneDbFileName))
+ .forEach(dbName -> {
+ if (context.getDatabasePath(dbName).delete()) {
+ FileLog.d(TAG, "Removed old grid db file: " + dbName);
+ }
+ });
}
private static boolean performRestore(Context context, ModelDbController controller) {
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.kt b/src/com/android/launcher3/util/OnboardingPrefs.kt
index 4528cba..ac6e97c 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.kt
+++ b/src/com/android/launcher3/util/OnboardingPrefs.kt
@@ -75,4 +75,6 @@
@JvmField
val HOTSEAT_LONGPRESS_TIP_SEEN = backedUpItem("launcher.hotseat_longpress_tip_seen", false)
+
+ @JvmField val TASKBAR_SEARCH_EDU_SEEN = backedUpItem("launcher.taskbar_search_edu_seen", false)
}
diff --git a/tests/assets/databases/BackupAndRestore/launcher.db b/tests/assets/databases/BackupAndRestore/launcher.db
new file mode 100644
index 0000000..126d166
--- /dev/null
+++ b/tests/assets/databases/BackupAndRestore/launcher.db
Binary files differ
diff --git a/tests/assets/databases/BackupAndRestore/launcher_3_by_3.db b/tests/assets/databases/BackupAndRestore/launcher_3_by_3.db
new file mode 100644
index 0000000..6d8cd73
--- /dev/null
+++ b/tests/assets/databases/BackupAndRestore/launcher_3_by_3.db
Binary files differ
diff --git a/tests/assets/databases/BackupAndRestore/launcher_4_by_4.db b/tests/assets/databases/BackupAndRestore/launcher_4_by_4.db
new file mode 100644
index 0000000..00061dd
--- /dev/null
+++ b/tests/assets/databases/BackupAndRestore/launcher_4_by_4.db
Binary files differ
diff --git a/tests/assets/databases/BackupAndRestore/launcher_4_by_5.db b/tests/assets/databases/BackupAndRestore/launcher_4_by_5.db
new file mode 100644
index 0000000..e2e65aa
--- /dev/null
+++ b/tests/assets/databases/BackupAndRestore/launcher_4_by_5.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db b/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db
new file mode 100644
index 0000000..8bea3ce
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to3x3.db b/tests/assets/databases/GridMigrationTest/result5x5to3x3.db
new file mode 100644
index 0000000..686056d
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/result5x5to3x3.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to4x7.db b/tests/assets/databases/GridMigrationTest/result5x5to4x7.db
new file mode 100644
index 0000000..cd105c5
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/result5x5to4x7.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to5x8.db b/tests/assets/databases/GridMigrationTest/result5x5to5x8.db
new file mode 100644
index 0000000..4b46969
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/result5x5to5x8.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/test_launcher.db b/tests/assets/databases/GridMigrationTest/test_launcher.db
new file mode 100644
index 0000000..c680e95
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/test_launcher.db
Binary files differ
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt b/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt
new file mode 100644
index 0000000..9ac976f
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util.rule
+
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherPrefs
+import java.io.File
+import java.nio.file.Paths
+import kotlin.io.path.pathString
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Removes all launcher's DBs from the device and copies the dbs in
+ * assets/databases/BackupAndRestore to the device. It also set's the needed LauncherPrefs variables
+ * needed to kickstart a backup and restore.
+ */
+class BackAndRestoreRule : TestRule {
+
+ private val phoneContext = getInstrumentation().targetContext
+
+ private fun dbBackUp() = File(phoneContext.dataDir.path, "/databasesBackUp")
+
+ private fun dbDirectory() = File(phoneContext.dataDir.path, "/databases")
+
+ private fun isWorkspaceDatabase(rawFileName: String): Boolean {
+ val fileName = Paths.get(rawFileName).fileName.pathString
+ return fileName.startsWith("launcher") && fileName.endsWith(".db")
+ }
+
+ fun getDatabaseFiles() = dbDirectory().listFiles().filter { isWorkspaceDatabase(it.name) }
+
+ /**
+ * Setting RESTORE_DEVICE would trigger a restore next time the Launcher starts, and we remove
+ * the widgets and apps ids to prevent issues when loading the database.
+ */
+ private fun setRestoreConstants() {
+ LauncherPrefs.get(phoneContext)
+ .put(LauncherPrefs.RESTORE_DEVICE.to(InvariantDeviceProfile.TYPE_MULTI_DISPLAY))
+ LauncherPrefs.get(phoneContext)
+ .remove(LauncherPrefs.OLD_APP_WIDGET_IDS, LauncherPrefs.APP_WIDGET_IDS)
+ }
+
+ private fun uploadDatabase(dbName: String) {
+ val file = File(File(getInstrumentation().targetContext.dataDir, "/databases"), dbName)
+ file.writeBytes(
+ getInstrumentation()
+ .context
+ .assets
+ .open("databases/BackupAndRestore/$dbName")
+ .readBytes()
+ )
+ file.setWritable(true, false)
+ }
+
+ private fun uploadDbs() {
+ uploadDatabase("launcher.db")
+ uploadDatabase("launcher_4_by_4.db")
+ uploadDatabase("launcher_4_by_5.db")
+ uploadDatabase("launcher_3_by_3.db")
+ }
+
+ private fun savePreviousState() {
+ dbBackUp().deleteRecursively()
+ if (!dbDirectory().renameTo(dbBackUp())) {
+ throw Exception("Unable to move databases to backup directory")
+ }
+ dbDirectory().mkdir()
+ if (!dbDirectory().exists()) {
+ throw Exception("Databases directory doesn't exist")
+ }
+ }
+
+ private fun restorePreviousState() {
+ dbDirectory().deleteRecursively()
+ if (!dbBackUp().renameTo(dbDirectory())) {
+ throw Exception("Unable to restore backup directory to databases directory")
+ }
+ dbBackUp().delete()
+ }
+
+ fun before() {
+ savePreviousState()
+ setRestoreConstants()
+ uploadDbs()
+ }
+
+ fun after() {
+ restorePreviousState()
+ }
+
+ override fun apply(base: Statement?, description: Description?): Statement =
+ object : Statement() {
+ override fun evaluate() {
+ before()
+ try {
+ base?.evaluate()
+ } finally {
+ after()
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
new file mode 100644
index 0000000..479b201
--- /dev/null
+++ b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.backuprestore
+
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.Flags
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.model.ModelDbController
+import com.android.launcher3.util.Executors.MODEL_EXECUTOR
+import com.android.launcher3.util.TestUtil
+import com.android.launcher3.util.rule.BackAndRestoreRule
+import com.android.launcher3.util.rule.setFlags
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Makes sure to test {@code RestoreDbTask#removeOldDBs}, we need to remove all the dbs that are not
+ * the last one used when we restore the device.
+ */
+@RunWith(AndroidJUnit4::class)
+@MediumTest
+class BackupAndRestoreDBSelectionTest {
+
+ @JvmField @Rule var backAndRestoreRule = BackAndRestoreRule()
+
+ @JvmField
+ @Rule
+ val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
+ @Before
+ fun setUp() {
+ setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_NARROW_GRID_RESTORE)
+ }
+
+ @Test
+ fun oldDatabasesNotPresentAfterRestore() {
+ val dbController = ModelDbController(getInstrumentation().targetContext)
+ dbController.tryMigrateDB(null)
+ TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
+ assert(backAndRestoreRule.getDatabaseFiles().size == 1) {
+ "There should only be one database after restoring, the last one used. Actual databases ${backAndRestoreRule.getDatabaseFiles()}"
+ }
+ assert(
+ !LauncherPrefs.get(getInstrumentation().targetContext)
+ .has(LauncherPrefs.RESTORE_DEVICE)
+ ) {
+ "RESTORE_DEVICE shouldn't be present after a backup and restore."
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java b/tests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
index 62f2259..e5ad888 100644
--- a/tests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
+++ b/tests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
@@ -199,6 +199,19 @@
return 'z';
}
+ /**
+ * Check if the given area is empty.
+ */
+ public boolean isEmpty(int x, int y, int spanX, int spanY) {
+ for (int xi = x; xi < x + spanX; xi++) {
+ for (int yi = y; yi < y + spanY; yi++) {
+ if (mWidget[xi][yi] == CellType.IGNORE) continue;
+ if (mWidget[xi][yi] != CellType.EMPTY) return false;
+ }
+ }
+ return true;
+ }
+
public void addWidget(int x, int y, int spanX, int spanY, char type) {
Rect rect = new Rect(x, y + spanY - 1, x + spanX - 1, y);
removeOverlappingItems(rect);
diff --git a/tests/src/com/android/launcher3/model/GridMigrationTest.kt b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
new file mode 100644
index 0000000..15222a4
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.Flags
+import com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE
+import com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.util.rule.TestToPhoneFileCopier
+import com.android.launcher3.util.rule.setFlags
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private val phoneContext = InstrumentationRegistry.getInstrumentation().targetContext
+
+data class EntryData(val x: Int, val y: Int, val spanX: Int, val spanY: Int, val rank: Int)
+
+/**
+ * Holds the data needed to run a test in GridMigrationTest, usually we would have a src
+ * GridMigrationData and a dst GridMigrationData meaning the data after a migration has occurred.
+ * This class holds a gridState, which is the size of the grid like 5x5 (among other things). a
+ * dbHelper which contains the readable database and writable database used to migrate the
+ * databases.
+ *
+ * You can also get all the entries defined in the dbHelper database.
+ */
+class GridMigrationData(dbFileName: String?, val gridState: DeviceGridState) {
+
+ val dbHelper: DatabaseHelper =
+ DatabaseHelper(
+ phoneContext,
+ dbFileName,
+ { UserCache.INSTANCE.get(phoneContext).getSerialNumberForUser(it) },
+ {}
+ )
+
+ fun readEntries(): List<GridSizeMigrationUtil.DbEntry> =
+ GridSizeMigrationUtil.readAllEntries(dbHelper.readableDatabase, TABLE_NAME, phoneContext)
+}
+
+/**
+ * Test the migration of a database from one size to another. It reads a database from the test
+ * assets, uploads it into the phone and migrates the database to a database in memory which is
+ * later compared against a database in the test assets to make sure they are identical.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GridMigrationTest {
+ private val DB_FILE = "test_launcher.db"
+
+ @JvmField
+ @Rule
+ val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
+ // Copying the src db for all tests.
+ @JvmField
+ @Rule
+ val fileCopier =
+ TestToPhoneFileCopier(
+ src = "databases/GridMigrationTest/$DB_FILE",
+ dest = "databases/$DB_FILE",
+ removeOnFinish = true
+ )
+
+ @Before
+ fun setup() {
+ setFlagsRule.setFlags(false, Flags.FLAG_ENABLE_GRID_MIGRATION_FIX)
+ }
+
+ private fun migrate(src: GridMigrationData, dst: GridMigrationData) {
+ GridSizeMigrationUtil.migrateGridIfNeeded(
+ phoneContext,
+ src.gridState,
+ dst.gridState,
+ dst.dbHelper,
+ src.dbHelper.readableDatabase
+ )
+ }
+
+ /**
+ * Makes sure that none of the items overlaps on the result, i.e. no widget or icons share the
+ * same space in the db.
+ */
+ private fun validateDb(data: GridMigrationData) {
+ // The array size is just a big enough number to fit all the number of workspaces
+ val boards = Array(100) { CellLayoutBoard(data.gridState.columns, data.gridState.rows) }
+ data.readEntries().forEach {
+ val cellLayoutBoard = boards[it.screenId]
+ assert(cellLayoutBoard.isEmpty(it.cellX, it.cellY, it.spanX, it.spanY)) {
+ "Db has overlapping items"
+ }
+ cellLayoutBoard.addWidget(it.cellX, it.cellY, it.spanX, it.spanY)
+ }
+ }
+
+ private fun compare(dst: GridMigrationData, target: GridMigrationData) {
+ val sort = compareBy<GridSizeMigrationUtil.DbEntry>({ it.cellX }, { it.cellY })
+ val mapF = { it: GridSizeMigrationUtil.DbEntry ->
+ EntryData(it.cellX, it.cellY, it.spanX, it.spanY, it.rank)
+ }
+ val entriesDst = dst.readEntries().sortedWith(sort).map(mapF)
+ val entriesTarget = target.readEntries().sortedWith(sort).map(mapF)
+
+ assert(entriesDst == entriesTarget) {
+ "The elements on the dst database is not the same as in the target"
+ }
+ }
+
+ /**
+ * Migrate src into dst and compare to target. This method validates 3 things:
+ * 1. dst has the same number of items as src after the migration, meaning, none of the items
+ * were removed during the migration.
+ * 2. dst is valid, meaning that none of the items overlap with each other.
+ * 3. dst is equal to target to ensure we don't unintentionally change the migration logic.
+ */
+ private fun runTest(src: GridMigrationData, dst: GridMigrationData, target: GridMigrationData) {
+ migrate(src, dst)
+ assert(src.readEntries().size == dst.readEntries().size) {
+ "Source db and destination db do not contain the same number of elements"
+ }
+ validateDb(dst)
+ compare(dst, target)
+ }
+
+ @JvmField
+ @Rule
+ val result5x5to3x3 =
+ TestToPhoneFileCopier(
+ src = "databases/GridMigrationTest/result5x5to3x3.db",
+ dest = "databases/result5x5to3x3.db",
+ removeOnFinish = true
+ )
+
+ @Test
+ fun `5x5 to 3x3`() =
+ runTest(
+ src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+ dst =
+ GridMigrationData(
+ null, // in memory db, to download a new db change null for the filename of the
+ // db name to store it. Do not use existing names.
+ DeviceGridState(3, 3, 3, TYPE_PHONE, "")
+ ),
+ target =
+ GridMigrationData("result5x5to3x3.db", DeviceGridState(3, 3, 3, TYPE_PHONE, ""))
+ )
+
+ @JvmField
+ @Rule
+ val result5x5to4x7 =
+ TestToPhoneFileCopier(
+ src = "databases/GridMigrationTest/result5x5to4x7.db",
+ dest = "databases/result5x5to4x7.db",
+ removeOnFinish = true
+ )
+
+ @Test
+ fun `5x5 to 4x7`() =
+ runTest(
+ src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+ dst =
+ GridMigrationData(
+ null, // in memory db, to download a new db change null for the filename of the
+ // db name to store it. Do not use existing names.
+ DeviceGridState(4, 7, 4, TYPE_PHONE, "")
+ ),
+ target =
+ GridMigrationData("result5x5to4x7.db", DeviceGridState(4, 7, 4, TYPE_PHONE, ""))
+ )
+
+ @JvmField
+ @Rule
+ val result5x5to5x8 =
+ TestToPhoneFileCopier(
+ src = "databases/GridMigrationTest/result5x5to5x8.db",
+ dest = "databases/result5x5to5x8.db",
+ removeOnFinish = true
+ )
+
+ @Test
+ fun `5x5 to 5x8`() =
+ runTest(
+ src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+ dst =
+ GridMigrationData(
+ null, // in memory db, to download a new db change null for the filename of the
+ // db name to store it. Do not use existing names.
+ DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+ ),
+ target =
+ GridMigrationData("result5x5to5x8.db", DeviceGridState(5, 8, 5, TYPE_PHONE, ""))
+ )
+
+ @JvmField
+ @Rule
+ val flaggedResult5x5to5x8 =
+ TestToPhoneFileCopier(
+ src = "databases/GridMigrationTest/flagged_result5x5to5x8.db",
+ dest = "databases/flagged_result5x5to5x8.db",
+ removeOnFinish = true
+ )
+
+ @Test
+ fun `flagged 5x5 to 5x8`() {
+ setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_GRID_MIGRATION_FIX)
+ runTest(
+ src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+ dst =
+ GridMigrationData(
+ null, // in memory db, to download a new db change null for the filename of the
+ // db name to store it. Do not use existing names.
+ DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+ ),
+ target =
+ GridMigrationData(
+ "flagged_result5x5to5x8.db",
+ DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+ )
+ )
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt b/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt
new file mode 100644
index 0000000..d3516d1
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util.rule
+
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.File
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/** Copy a file from the tests assets folder to the phone. */
+class TestToPhoneFileCopier(
+ val src: String,
+ dest: String,
+ private val removeOnFinish: Boolean = false
+) : TestRule {
+
+ private val dstFile =
+ File(InstrumentationRegistry.getInstrumentation().targetContext.dataDir, dest)
+
+ fun getDst() = dstFile.absolutePath
+
+ fun before() =
+ dstFile.writeBytes(
+ InstrumentationRegistry.getInstrumentation().context.assets.open(src).readBytes()
+ )
+
+ fun after() {
+ if (removeOnFinish) {
+ dstFile.delete()
+ }
+ }
+
+ override fun apply(base: Statement, description: Description): Statement =
+ object : Statement() {
+ override fun evaluate() {
+ before()
+ try {
+ base.evaluate()
+ } finally {
+ after()
+ }
+ }
+ }
+}