Merge "Add gesture navigation education animations for foldables" into udc-dev
diff --git a/quickstep/res/layout/taskbar_edu.xml b/quickstep/res/layout/taskbar_edu.xml
deleted file mode 100644
index d7daea3..0000000
--- a/quickstep/res/layout/taskbar_edu.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.launcher3.taskbar.TaskbarEduView xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:gravity="bottom"
- android:orientation="vertical"
- android:layout_marginHorizontal="108dp">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/edu_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/bg_rounded_corner_bottom_sheet"
- android:gravity="center_horizontal"
- android:paddingHorizontal="36dp"
- android:paddingTop="64dp">
-
- <com.android.launcher3.taskbar.TaskbarEduPagedView
- android:id="@+id/content"
- android:clipToPadding="false"
- android:layout_width="match_parent"
- android:layout_height="378dp"
- app:layout_constraintTop_toTopOf="parent"
- launcher:pageIndicator="@+id/content_page_indicator" />
-
- <Button
- android:id="@+id/edu_start_button"
- android:layout_width="wrap_content"
- android:layout_height="36dp"
- android:layout_marginBottom="18dp"
- android:layout_marginTop="32dp"
- app:layout_constraintTop_toBottomOf="@id/content"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- android:text="@string/taskbar_edu_close"
- style="@style/TaskbarEdu.Button.Close"
- android:textColor="?android:attr/textColorPrimary"/>
-
- <com.android.launcher3.pageindicators.PageIndicatorDots
- android:id="@+id/content_page_indicator"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintTop_toTopOf="@id/edu_start_button"
- app:layout_constraintBottom_toBottomOf="@id/edu_start_button"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- android:elevation="1dp" />
-
- <Button
- android:id="@+id/edu_end_button"
- android:layout_width="wrap_content"
- android:layout_height="0dp"
- app:layout_constraintTop_toTopOf="@id/edu_start_button"
- app:layout_constraintBottom_toBottomOf="@id/edu_start_button"
- app:layout_constraintEnd_toEndOf="parent"
- android:text="@string/taskbar_edu_next"
- style="@style/TaskbarEdu.Button.Next"
- android:textColor="?androidprv:attr/textColorOnAccent"/>
- </androidx.constraintlayout.widget.ConstraintLayout>
-</com.android.launcher3.taskbar.TaskbarEduView>
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_edu_features.xml b/quickstep/res/layout/taskbar_edu_features.xml
index 4137df7..5cd7aaf 100644
--- a/quickstep/res/layout/taskbar_edu_features.xml
+++ b/quickstep/res/layout/taskbar_edu_features.xml
@@ -106,7 +106,7 @@
<Button
android:id="@+id/done_button"
- style="@style/TaskbarEdu.Button.Next"
+ style="@style/TaskbarEdu.Button.Done"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:layout_marginTop="32dp"
diff --git a/quickstep/res/layout/taskbar_edu_pages_persistent.xml b/quickstep/res/layout/taskbar_edu_pages_persistent.xml
deleted file mode 100644
index 77ce31a..0000000
--- a/quickstep/res/layout/taskbar_edu_pages_persistent.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:orientation="vertical">
-
- <TextView
- style="@style/TextAppearance.TaskbarEdu.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/taskbar_edu_splitscreen" />
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@+id/animation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- app:lottie_rawRes="@raw/taskbar_edu_splitscreen_persistent" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:orientation="vertical">
-
- <TextView
- style="@style/TextAppearance.TaskbarEdu.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/taskbar_edu_suggestions" />
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@id/animation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- app:lottie_rawRes="@raw/taskbar_edu_suggestions_persistent" />
- </LinearLayout>
-</merge>
diff --git a/quickstep/res/layout/taskbar_edu_pages_transient.xml b/quickstep/res/layout/taskbar_edu_pages_transient.xml
deleted file mode 100644
index b68e723..0000000
--- a/quickstep/res/layout/taskbar_edu_pages_transient.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:orientation="vertical">
-
- <TextView
- style="@style/TextAppearance.TaskbarEdu.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/taskbar_edu_stashing" />
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@+id/animation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- app:lottie_rawRes="@raw/taskbar_edu_stashing_transient" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:orientation="vertical">
-
- <TextView
- style="@style/TextAppearance.TaskbarEdu.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/taskbar_edu_splitscreen" />
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@id/animation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- app:lottie_rawRes="@raw/taskbar_edu_splitscreen_transient" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:orientation="vertical">
-
- <TextView
- style="@style/TextAppearance.TaskbarEdu.Title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/taskbar_edu_suggestions" />
-
- <com.airbnb.lottie.LottieAnimationView
- android:id="@id/animation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- app:lottie_rawRes="@raw/taskbar_edu_suggestions_transient" />
- </LinearLayout>
-</merge>
\ No newline at end of file
diff --git a/quickstep/res/raw/taskbar_edu_stashing_transient.json b/quickstep/res/raw/taskbar_edu_stashing_transient.json
deleted file mode 100644
index 847a607..0000000
--- a/quickstep/res/raw/taskbar_edu_stashing_transient.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.9.0","fr":60,"ip":0,"op":94,"w":412,"h":300,"nm":"Taskbar_Transient_Step_1_LT","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_Transient_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"press 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":381,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":391,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":416,"s":[100]},{"t":426,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[259.25,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":406,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":416,"s":[40,40,100]},{"t":426,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":381,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":406,"s":[0,0],"h":1}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":381,"op":437,"st":176,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"press","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":301,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":336,"s":[100]},{"t":346,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248,134,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":326,"s":[50,50,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":336,"s":[40,40,100]},{"t":346,"s":[50,50,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.186},"t":301,"s":[-37,67],"to":[15,-7],"ti":[7,20]},{"t":326,"s":[0,0],"h":1}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Touch","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":301,"op":357,"st":96,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,194,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":15,"op":73,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"swipe up","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":25,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":15,"s":[-48.3,37.417,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":40,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.45,"y":0},"t":50,"s":[-15.3,91.417,0],"to":[0,0,0],"ti":[0,0,0]},{"t":70,"s":[-15.3,-62.583,0],"h":1}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":40,"s":[100,100,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[80,80,100]},{"t":70,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":52,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":62,"s":[56,98]},{"t":72,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":52,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.5,"y":0},"t":62,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":72,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":15,"op":73,"st":-10,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"screen_matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-81,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Pre-comp_TaskBar_Transient_LT","tt":1,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.7,"y":0},"t":50,"s":[204.5,244.501,0],"to":[0,-2.5,0],"ti":[0,2.5,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":94,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[204.5,229.501,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[204.5,237.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[204.5,237.501,0],"to":[0,-1.333,0],"ti":[0,1.333,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.3,"y":0.3},"t":466,"s":[204.5,229.501,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":474,"s":[204.5,229.501,0],"to":[-42.083,-12.917,0],"ti":[42.083,12.917,0]},{"t":554,"s":[-48,152.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[206,227.625,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":50,"s":[70,70,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":94,"s":[100,100,100]},{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":474,"s":[100,100,100]},{"t":554,"s":[370,370,100]}],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.9,"y":0},"t":46,"s":[205.5,241.5,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"t":76,"s":[205.5,231.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,0],[0,-1.381],[0,0],[1.381,0],[0,0],[0,1.381],[0,0]],"o":[[0,0],[1.381,0],[0,0],[0,1.381],[0,0],[-1.381,0],[0,0],[0,-1.381]],"v":[[-42,-2.5],[42,-2.5],[44.5,0],[44.5,0],[42,2.5],[-42,2.5],[-44.5,0],[-44.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":65,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Pre-comp_Toggle_LT","refId":"comp_2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":256,"s":[0]},{"i":{"x":[0.316],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":286,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":474,"s":[100]},{"t":554,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":235,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":249,"s":[0]},{"t":269,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":356,"s":[320,204.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":386,"s":[320,173.01]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":436,"s":[320,173.01]},{"t":466,"s":[320,204.01]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":12,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":356,"s":[-81,0],"to":[0,-2.542],"ti":[0,2.542]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":386,"s":[-81,-15.25],"to":[0,0],"ti":[0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":436,"s":[-81,-15.25],"to":[0,2.542],"ti":[0,-2.542]},{"t":466,"s":[-81,0]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":286,"op":11635,"st":235,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[132.562,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-154.438,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[0,-89.005],[0,89.005],[-13,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[-13,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[13.125,-89.005],[13.125,89.005],[0.125,102.005],[-147,102.005],[-160,89.005],[-160,-89.005],[-147,-102.005],[0.125,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-81,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":137,"s":[100]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.8],"y":[0]},"t":187,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":249,"s":[0]},{"t":259,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.549019607843,0.713725490196,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-81,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[279.438,150,0],"ix":2,"l":2},"a":{"a":0,"k":[-7.562,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.3,0.3,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":137,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.8,0.8,0.167],"y":[0,0,0]},"t":187,"s":[95,95,100]},{"i":{"x":[0.1,0.1,0.833],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.167],"y":[0,0,0]},"t":249,"s":[95,95,100]},{"t":269,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"i":{"x":0.1,"y":1},"o":{"x":0.3,"y":0},"t":249,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[13,102.005],[0,89.005],[0,-89.005],[13,-102.005],[147,-102.005]],"c":true}]},{"t":269,"s":[{"i":[[0,-7.18],[0,0],[7.18,0],[0,0],[0,7.18],[0,0],[-7.18,0],[0,0]],"o":[[0,0],[0,7.18],[0,0],[-7.18,0],[0,0],[0,-7.18],[0,0],[7.18,0]],"v":[[160,-89.005],[160,89.005],[147,102.005],[-0.125,102.005],[-13.125,89.005],[-13.125,-89.005],[-0.125,-102.005],[147,-102.005]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.98431372549,0.78431372549,0.274509803922,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-81,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":286,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[287,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[320,204.01],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":13,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-81,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":100,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[15.3,0],[0,0],[0,15.7],[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0]],"o":[[0,0],[-15.3,0],[0,0],[0,-15.7],[0,0],[15.2,0],[0,0],[0,15.5]],"v":[[178.2,150],[-178.2,150],[-206,121.5],[-206,-121.5],[-178.2,-150],[178.3,-150],[206,-121.5],[206,121.7]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]},{"id":"comp_1","nm":"Pre-comp_TaskBar_Transient_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[237.75,183,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"ip":102,"op":255,"st":90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"swipe up 2","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":100,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":110,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":100,"s":[-45.3,33.917,0],"to":[5.5,9,0],"ti":[-12,-36,0]},{"i":{"x":0.3,"y":0.3},"o":{"x":0.333,"y":0.333},"t":127,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[-12.3,87.917,0],"to":[0,0,0],"ti":[-99.967,45.186,0]},{"t":187,"s":[89.5,-76.7,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":127,"s":[100,100,100]},{"i":{"x":[0.1,0.1,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":137,"s":[80,80,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.333],"y":[0,0,0]},"t":167,"s":[80,80,100]},{"t":179,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":25,"nm":"Drop Shadow","np":8,"mn":"ADBE Drop Shadow","ix":1,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":63.75,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":8,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":30,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]},{"ty":25,"nm":"Drop Shadow 2","np":8,"mn":"ADBE Drop Shadow","ix":2,"en":1,"ef":[{"ty":2,"nm":"Shadow Color","mn":"ADBE Drop Shadow-0001","ix":1,"v":{"a":0,"k":[0,0,0,1],"ix":1}},{"ty":0,"nm":"Opacity","mn":"ADBE Drop Shadow-0002","ix":2,"v":{"a":0,"k":10.2,"ix":2}},{"ty":0,"nm":"Direction","mn":"ADBE Drop Shadow-0003","ix":3,"v":{"a":0,"k":180,"ix":3}},{"ty":0,"nm":"Distance","mn":"ADBE Drop Shadow-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Softness","mn":"ADBE Drop Shadow-0005","ix":5,"v":{"a":0,"k":40,"ix":5}},{"ty":7,"nm":"Shadow Only","mn":"ADBE Drop Shadow-0006","ix":6,"v":{"a":0,"k":0,"ix":6}}]}],"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":240,"s":[56,56]},{"i":{"x":[0.5,0.5],"y":[1,1]},"o":{"x":[0.5,0.5],"y":[0,0]},"t":262,"s":[56,98]},{"t":288,"s":[56,56]}],"ix":2},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[0,0],"to":[0,0],"ti":[0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.8,"y":0},"t":187,"s":[0,14],"to":[0,0],"ti":[0,0]},{"t":189,"s":[0,0]}],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":102,"op":234,"st":77,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey300","cl":"grey300","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83.044,0.454,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.454901960784,0.470588235294,0.486274509804,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"green circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":550,"s":[84.522,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":580,"s":[84.522,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"green circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".green400","cl":"green400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":553,"s":[84.522,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":583,"s":[84.522,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".green100","cl":"green100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[84.409,0.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"blue circle matte 2","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":544,"s":[55.772,0.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":574,"s":[55.772,-19.999,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"blue circle matte","parent":20,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":547,"s":[55.772,20.001,0],"to":[0,-3.333,0],"ti":[0,3.333,0]},{"t":577,"s":[55.772,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue100","cl":"blue100","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.772,0.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":177,"s":[0]},{"t":187,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":947,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":957,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":967,"s":[27.135,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":177,"op":11577,"st":177,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".yellow400","cl":"yellow400","parent":20,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":167,"s":[100]},{"t":177,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":137,"s":[27.135,0.001,0],"to":[0.728,-9.542,0],"ti":[-45.478,19.292,0]},{"t":187,"s":[78,-76.749,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.941176470588,0.596078431373,0.145098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey400","cl":"grey400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":944,"s":[27.135,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":954,"s":[27.135,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":964,"s":[27.135,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":137,"op":252,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".green400","cl":"green400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":941,"s":[-1.498,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":951,"s":[-1.498,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":961,"s":[-1.498,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".red400","cl":"red400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":938,"s":[-30.134,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":948,"s":[-30.134,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":958,"s":[-30.134,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".blue400","cl":"blue400","parent":20,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":935,"s":[-58.771,0.001,0],"to":[0,-0.625,0],"ti":[0,0,0]},{"i":{"x":0.3,"y":1},"o":{"x":0.7,"y":0},"t":945,"s":[-58.771,-3.749,0],"to":[0,0,0],"ti":[0,-0.625,0]},{"t":955,"s":[-58.771,0.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[204.5,227.001,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0.001,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-86.5,-15],[86.5,-15],[101.5,0],[101.5,0],[86.5,15],[-86.5,15],[-101.5,0],[-101.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":65,"op":11400,"st":0,"bm":0}]},{"id":"comp_2","nm":"Pre-comp_Toggle_LT","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue900","cl":"blue900","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":336,"s":[-12.5,0,0],"to":[3.75,0,0],"ti":[-3.75,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":356,"s":[10,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":416,"s":[10,0,0],"to":[-3.75,0,0],"ti":[3.75,0,0]},{"t":436,"s":[-12.5,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":336,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.8,"y":0},"t":356,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"i":{"x":0.3,"y":1},"o":{"x":0.167,"y":0},"t":416,"s":[{"i":[[-7.732,0],[0,0],[0,-7.732],[0,0],[7.732,0],[0,0],[0,7.732],[0,0]],"o":[[0,0],[7.732,0],[0,0],[0,7.732],[0,0],[-7.732,0],[0,0],[0,-7.732]],"v":[[0,-14],[0,-14],[14,0],[14,0],[0,14],[0,14],[-14,0],[-14,0]],"c":true}]},{"t":436,"s":[{"i":[[-6.627,0],[0,0],[0,-6.627],[0,0],[6.627,0],[0,0],[0,6.627],[0,0]],"o":[[0,0],[6.627,0],[0,0],[0,6.627],[0,0],[-6.627,0],[0,0],[0,-6.627]],"v":[[0,-12],[0,-12],[12,0],[12,0],[0,12],[0,12],[-12,0],[-12,0]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.090196078431,0.305882352941,0.650980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue200","cl":"blue200","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[254.5,133.75,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.837,0],[0,0],[0,-8.837],[0,0],[8.837,0],[0,0],[0,8.837],[0,0]],"o":[[0,0],[8.837,0],[0,0],[0,8.837],[0,0],[-8.837,0],[0,0],[0,-8.837]],"v":[[-10,-16],[10,-16],[26,0],[26,0],[10,16],[-10,16],[-26,0],[-26,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.682352941176,0.796078431373,0.980392156863,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100_T","cl":"blue100_T","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.784,0],[0,1.783],[1.783,0],[0,-1.783]],"o":[[1.783,0],[0,-1.783],[-1.784,0],[0,1.783]],"v":[[-43.755,-12.577],[-40.526,-15.806],[-43.755,-19.035],[-46.984,-15.806]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0.053]],"o":[[0,0.053],[0,0]],"v":[[-44.937,-23.822],[-44.937,-23.822]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.054]],"o":[[0,0.054],[0,0]],"v":[[-49.458,-21.078],[-49.458,-21.078]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.431,0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.216],[-0.054,-0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,-0.162],[0,0]],"o":[[0,0],[0,0],[0,0],[0.431,-0.162],[0,0],[0,0],[0,0],[0,0],[0,0],[0.054,-0.215],[0,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.377,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.377,0.323],[0,0],[0,0]],"v":[[-45.045,-8.215],[-42.515,-8.215],[-42.138,-10.529],[-41.654,-10.744],[-40.416,-11.444],[-39.986,-11.767],[-37.779,-10.906],[-36.487,-13.112],[-38.371,-14.565],[-38.317,-15.104],[-38.263,-15.803],[-38.317,-16.503],[-38.371,-17.041],[-36.487,-18.494],[-37.779,-20.701],[-39.986,-19.84],[-40.416,-20.163],[-41.654,-20.862],[-42.138,-21.078],[-42.461,-23.392],[-44.991,-23.392],[-45.314,-21.078],[-45.798,-20.862],[-47.036,-20.163],[-47.467,-19.84],[-49.673,-20.701],[-50.965,-18.494],[-49.081,-17.041],[-49.135,-16.503],[-49.189,-15.803],[-49.135,-15.104],[-49.081,-14.565],[-50.965,-13.112],[-49.673,-10.906],[-47.467,-11.767],[-47.036,-11.444],[-45.798,-10.744],[-45.368,-10.529]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.054,0]],"o":[[0.054,0],[0,0]],"v":[[-44.991,-7.784],[-44.991,-7.784]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.7,0],[0,0],[0.108,0.7],[0,0],[0.215,0.162],[0,0],[0.323,0.592],[0,0],[-0.484,0.376],[0,0],[0,0.161],[0,0.162],[0,0],[-0.376,0.593],[0,0],[-0.592,-0.215],[0,0],[-0.215,0.162],[0,0],[-0.7,0],[0,0],[-0.107,-0.7],[0,0],[-0.269,-0.162],[0,0],[-0.323,-0.592],[0,0],[0.484,-0.377],[0,0],[0,-0.162],[0,-0.161],[0,0],[0.323,-0.592],[0,0],[0.646,0.215],[0,0],[0.216,-0.162],[0,0]],"o":[[0,0],[-0.7,0],[0,0],[-0.269,-0.108],[0,0],[-0.646,0.215],[0,0],[-0.323,-0.592],[0,0],[0,-0.161],[0,-0.162],[0,0],[-0.538,-0.431],[0,0],[0.323,-0.592],[0,0],[0.215,-0.162],[0,0],[0.053,-0.646],[0,0],[0.699,0],[0,0],[0.269,0.108],[0,0],[0.646,-0.215],[0,0],[0.323,0.592],[0,0],[0,0.161],[0,0.161],[0,0],[0.538,0.431],[0,0],[-0.323,0.592],[0,0],[-0.215,0.161],[0,0],[0,0.538]],"v":[[-42.085,-6.385],[-45.475,-6.385],[-46.821,-7.569],[-47.09,-9.291],[-47.789,-9.722],[-49.458,-9.076],[-51.126,-9.668],[-52.795,-12.574],[-52.472,-14.296],[-51.072,-15.373],[-51.072,-15.803],[-51.072,-16.234],[-52.472,-17.31],[-52.795,-19.033],[-51.126,-21.939],[-49.512,-22.531],[-47.843,-21.831],[-47.144,-22.262],[-46.874,-24.038],[-45.529,-25.168],[-42.138,-25.168],[-40.793,-23.984],[-40.524,-22.262],[-39.77,-21.831],[-38.102,-22.477],[-36.433,-21.885],[-34.765,-18.979],[-35.088,-17.256],[-36.487,-16.18],[-36.487,-15.749],[-36.487,-15.319],[-35.088,-14.243],[-34.765,-12.52],[-36.487,-9.56],[-38.156,-8.968],[-39.824,-9.614],[-40.524,-9.183],[-40.793,-7.407]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-43.792,-15.776],"ix":2},"a":{"a":0,"k":[-43.792,-15.776],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-8.284,0],[0,0],[0,-8.284],[0,0],[8.284,0],[0,0],[0,8.284],[0,0]],"o":[[0,0],[8.284,0],[0,0],[0,8.284],[0,0],[-8.284,0],[0,0],[0,-8.284]],"v":[[-54,-33],[60,-33],[75,-18],[75,-13],[60,2],[-54,2],[-69,-13],[-69,-18]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254901961,0.462745098039,0.898039215686,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Taskbar_Transient_LT","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":11400,"st":0,"bm":0}],"markers":[{"tm":94,"cm":"","dr":0},{"tm":249,"cm":"","dr":0},{"tm":474,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 09ea534..2c17ce8 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -241,10 +241,6 @@
<!-- ******* Taskbar Edu ******* -->
<!-- Accessibility title for the Taskbar education window. [CHAR_LIMIT=NONE] -->
<string name="taskbar_edu_a11y_title">Taskbar education</string>
- <!-- Accessibility text spoken when the Taskbar education panel appears [CHAR_LIMIT=NONE] -->
- <string name="taskbar_edu_opened">Taskbar education appeared</string>
- <!-- Accessibility text spoken when the Taskbar education panel disappears [CHAR_LIMIT=NONE] -->
- <string name="taskbar_edu_closed">Taskbar education closed</string>
<!-- Text in dialog that lets a user know how they can use the Taskbar to use multiple apps at once on their device. [CHAR_LIMIT=60] -->
<string name="taskbar_edu_splitscreen">Drag an app to the side to use 2 apps at once</string>
<!-- Text in dialog that lets a user know how they can show the Taskbar on their device. [CHAR_LIMIT=60] -->
@@ -255,10 +251,6 @@
<string name="taskbar_edu_settings_persistent">Turn on gesture navigation in Settings to auto-hide the Taskbar</string>
<!-- Title in dialog that shows a user what they can do with the Taskbar. [CHAR_LIMIT=60] -->
<string name="taskbar_edu_features">Do more with the Taskbar</string>
- <!-- Text on button to go to the next screen of a tutorial [CHAR_LIMIT=16] -->
- <string name="taskbar_edu_next">Next</string>
- <!-- Text on button to go to the previous screen of a tutorial [CHAR_LIMIT=16] -->
- <string name="taskbar_edu_previous">Back</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/res/values/styles.xml b/quickstep/res/values/styles.xml
index 8eea37f..f9f2175 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -195,30 +195,13 @@
<item name="iconDisplay">taskbar</item>
</style>
- <style name="TaskbarEdu.Button.Close" parent="@android:style/Widget.Material.Button">
- <item name="android:background">@drawable/button_taskbar_edu_bordered</item>
- <item name="android:stateListAnimator">@null</item>
- <item name="android:textSize">16sp</item>
- <item name="android:padding">4dp</item>
- </style>
-
- <style name="TaskbarEdu.Button.Next" parent="@android:style/Widget.Material.Button">
+ <style name="TaskbarEdu.Button.Done" parent="@android:style/Widget.Material.Button">
<item name="android:background">@drawable/button_taskbar_edu_colored</item>
<item name="android:stateListAnimator">@null</item>
<item name="android:textSize">16sp</item>
<item name="android:padding">4dp</item>
</style>
- <style name="TextAppearance.TaskbarEdu.Title"
- parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" >
- <item name="android:layout_marginHorizontal">16dp</item>
- <item name="android:gravity">center_horizontal</item>
- <item name="android:fontFamily">google-sans</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:textSize">24sp</item>
- <item name="android:lines">2</item>
- </style>
-
<style name="TextAppearance.TaskbarEduTooltip.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
<item name="android:gravity">center_horizontal</item>
<item name="android:fontFamily">google-sans</item>
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 2e1318b..bc97df1 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -48,11 +48,15 @@
import android.util.Log;
import android.util.StatsEvent;
+import androidx.annotation.AnyThread;
+import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
@@ -62,6 +66,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.PersistedItemArray;
import com.android.quickstep.logging.SettingsChangeLogger;
@@ -111,45 +116,80 @@
mStatsManager = context.getSystemService(StatsManager.class);
}
+ @CallSuper
@Override
- public void loadHotseatItems(UserManagerState ums,
- Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
- // TODO: Implement caching and preloading
- super.loadHotseatItems(ums, pinnedShortcuts);
-
- WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
- mIDP.numDatabaseHotseatIcons, mHotseatState.containerId);
- FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId,
- mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get));
- mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems);
+ public void loadAndBindWorkspaceItems(@NonNull UserManagerState ums,
+ @NonNull BgDataModel.Callbacks[] callbacks,
+ @NonNull Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
+ loadAndBindItems(ums, pinnedShortcuts, callbacks, mIDP.numDatabaseHotseatIcons,
+ mHotseatState);
}
+ @CallSuper
@Override
- public void loadAllAppsItems(UserManagerState ums,
- Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
- // TODO: Implement caching and preloading
- super.loadAllAppsItems(ums, pinnedShortcuts);
-
- WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
- mIDP.numDatabaseAllAppsColumns, mAllAppsState.containerId);
- FixedContainerItems allAppsPredictionItems = new FixedContainerItems(
- mAllAppsState.containerId, mAllAppsState.storage.read(mApp.getContext(),
- allAppsFactory, ums.allUsers::get));
- mDataModel.extraItems.put(mAllAppsState.containerId, allAppsPredictionItems);
+ public void loadAndBindAllAppsItems(@NonNull UserManagerState ums,
+ @NonNull BgDataModel.Callbacks[] callbacks,
+ @NonNull Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
+ loadAndBindItems(ums, pinnedShortcuts, callbacks, mIDP.numDatabaseAllAppsColumns,
+ mAllAppsState);
}
- @Override
- public void loadWidgetsRecommendationItems() {
+ @WorkerThread
+ private void loadAndBindItems(@NonNull UserManagerState ums,
+ @NonNull Map<ShortcutKey, ShortcutInfo> pinnedShortcuts,
+ @NonNull BgDataModel.Callbacks[] callbacks,
+ int numColumns, @NonNull PredictorState state) {
// TODO: Implement caching and preloading
- super.loadWidgetsRecommendationItems();
+
+ WorkspaceItemFactory factory =
+ new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, numColumns, state.containerId);
+ FixedContainerItems fci = new FixedContainerItems(state.containerId,
+ state.storage.read(mApp.getContext(), factory, ums.allUsers::get));
+ if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ bindPredictionItems(callbacks, fci);
+ }
+ mDataModel.extraItems.put(state.containerId, fci);
+ }
+
+ @CallSuper
+ @Override
+ public void loadAndBindOtherItems(@NonNull BgDataModel.Callbacks[] callbacks) {
+ FixedContainerItems widgetPredictionFCI = new FixedContainerItems(
+ mWidgetsRecommendationState.containerId, new ArrayList<>());
// Widgets prediction isn't used frequently. And thus, it is not persisted on disk.
- mDataModel.extraItems.put(mWidgetsRecommendationState.containerId,
- new FixedContainerItems(mWidgetsRecommendationState.containerId,
- new ArrayList<>()));
+ mDataModel.extraItems.put(mWidgetsRecommendationState.containerId, widgetPredictionFCI);
+
+ bindPredictionItems(callbacks, widgetPredictionFCI);
+ loadStringCache(mDataModel.stringCache);
+ }
+
+ @AnyThread
+ private void bindPredictionItems(@NonNull BgDataModel.Callbacks[] callbacks,
+ @NonNull FixedContainerItems fci) {
+ Executors.MAIN_EXECUTOR.execute(() -> {
+ for (BgDataModel.Callbacks c : callbacks) {
+ c.bindExtraContainerItems(fci);
+ }
+ });
}
@Override
+ @WorkerThread
+ public void bindAllModelExtras(@NonNull BgDataModel.Callbacks[] callbacks) {
+ Iterable<FixedContainerItems> containerItems;
+ synchronized (mDataModel.extraItems) {
+ containerItems = mDataModel.extraItems.clone();
+ }
+ Executors.MAIN_EXECUTOR.execute(() -> {
+ for (BgDataModel.Callbacks c : callbacks) {
+ for (FixedContainerItems fci : containerItems) {
+ c.bindExtraContainerItems(fci);
+ }
+ }
+ });
+ }
+
public void markActive() {
super.markActive();
mActive = true;
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 3a985c4..b74964c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_EDU_TOOLTIP;
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_RESUMED;
@@ -252,13 +251,6 @@
return;
}
- // Transient and persistent bottom sheet.
- if (!ENABLE_TASKBAR_EDU_TOOLTIP.get()) {
- mLauncher.getOnboardingPrefs().markChecked(OnboardingPrefs.TASKBAR_EDU_SEEN);
- mControllers.taskbarEduController.showEdu();
- return;
- }
-
// Persistent features EDU tooltip.
if (!DisplayController.isTransientTaskbar(mLauncher)) {
mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
@@ -277,11 +269,6 @@
return false;
}
- // Transient and persistent bottom sheet.
- if (!ENABLE_TASKBAR_EDU_TOOLTIP.get()) {
- return !mLauncher.getOnboardingPrefs().getBoolean(OnboardingPrefs.TASKBAR_EDU_SEEN);
- }
-
// Persistent features EDU tooltip.
if (!DisplayController.isTransientTaskbar(mLauncher)) {
return !mLauncher.getOnboardingPrefs().hasReachedMaxCount(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index b61e9fc..5c53b5f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -224,7 +224,6 @@
new TaskbarKeyguardController(this),
new StashedHandleViewController(this, stashedHandleView),
new TaskbarStashController(this),
- new TaskbarEduController(this),
new TaskbarAutohideSuspendController(this),
new TaskbarPopupController(this),
new TaskbarForceVisibleImmersiveController(this),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index a71e5db..8efb9b0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -48,7 +48,6 @@
public final TaskbarKeyguardController taskbarKeyguardController;
public final StashedHandleViewController stashedHandleViewController;
public final TaskbarStashController taskbarStashController;
- public final TaskbarEduController taskbarEduController;
public final TaskbarAutohideSuspendController taskbarAutohideSuspendController;
public final TaskbarPopupController taskbarPopupController;
public final TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController;
@@ -95,7 +94,6 @@
TaskbarKeyguardController taskbarKeyguardController,
StashedHandleViewController stashedHandleViewController,
TaskbarStashController taskbarStashController,
- TaskbarEduController taskbarEduController,
TaskbarAutohideSuspendController taskbarAutoHideSuspendController,
TaskbarPopupController taskbarPopupController,
TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController,
@@ -120,7 +118,6 @@
this.taskbarKeyguardController = taskbarKeyguardController;
this.stashedHandleViewController = stashedHandleViewController;
this.taskbarStashController = taskbarStashController;
- this.taskbarEduController = taskbarEduController;
this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController;
this.taskbarPopupController = taskbarPopupController;
this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController;
@@ -155,7 +152,6 @@
taskbarSpringOnStashController.init(this);
stashedHandleViewController.init(this);
taskbarStashController.init(this, sharedState.setupUIVisible, mSharedState);
- taskbarEduController.init(this);
taskbarPopupController.init(this);
taskbarForceVisibleImmersiveController.init(this);
taskbarOverlayController.init(this);
@@ -172,7 +168,7 @@
taskbarDragController, navButtonController, navbarButtonsViewController,
taskbarDragLayerController, taskbarScrimViewController, taskbarViewController,
taskbarUnfoldAnimationController, taskbarKeyguardController,
- stashedHandleViewController, taskbarStashController, taskbarEduController,
+ stashedHandleViewController, taskbarStashController,
taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
voiceInteractionWindowController, taskbarTranslationController,
taskbarEduTooltipController, keyboardQuickSwitchController
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
deleted file mode 100644
index d1b8644..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
-import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
-import com.android.launcher3.util.DisplayController;
-
-import com.airbnb.lottie.LottieAnimationView;
-
-import java.io.PrintWriter;
-
-/** Handles the Taskbar Education flow. */
-public class TaskbarEduController implements TaskbarControllers.LoggableTaskbarController {
-
- private final TaskbarActivityContext mActivity;
-
- // Initialized in init.
- TaskbarControllers mControllers;
-
- private TaskbarEduView mTaskbarEduView;
- private TaskbarEduPagedView mPagedView;
-
- public TaskbarEduController(TaskbarActivityContext activity) {
- mActivity = activity;
- }
-
- public void init(TaskbarControllers controllers) {
- mControllers = controllers;
- }
-
- void showEdu() {
- TaskbarOverlayController overlayController = mControllers.taskbarOverlayController;
- TaskbarOverlayContext overlayContext = overlayController.requestWindow();
- LayoutInflater layoutInflater = overlayContext.getLayoutInflater();
-
- mTaskbarEduView = (TaskbarEduView) layoutInflater.inflate(
- R.layout.taskbar_edu, overlayContext.getDragLayer(), false);
- mPagedView = mTaskbarEduView.findViewById(R.id.content);
- layoutInflater.inflate(
- DisplayController.isTransientTaskbar(overlayContext)
- ? R.layout.taskbar_edu_pages_transient
- : R.layout.taskbar_edu_pages_persistent,
- mPagedView,
- true);
-
- // Provide enough room for taskbar.
- View startButton = mTaskbarEduView.findViewById(R.id.edu_start_button);
- ViewGroup.MarginLayoutParams layoutParams =
- (ViewGroup.MarginLayoutParams) startButton.getLayoutParams();
- DeviceProfile dp = overlayContext.getDeviceProfile();
- layoutParams.bottomMargin += dp.taskbarHeight + dp.taskbarBottomMargin;
-
- mTaskbarEduView.init(new TaskbarEduCallbacks());
-
- mControllers.navbarButtonsViewController.setSlideInViewVisible(true);
- mTaskbarEduView.setOnCloseBeginListener(
- () -> mControllers.navbarButtonsViewController.setSlideInViewVisible(false));
- mTaskbarEduView.addOnCloseListener(() -> mTaskbarEduView = null);
- mTaskbarEduView.show();
- }
-
- @Override
- public void dumpLogs(String prefix, PrintWriter pw) {
- pw.println(prefix + "TaskbarEduController:");
- pw.println(prefix + "\tisShowingEdu=" + (mTaskbarEduView != null));
- }
-
- /**
- * Callbacks for {@link TaskbarEduView} to interact with its controller.
- */
- class TaskbarEduCallbacks {
- void onPageChanged(int prevPage, int currentPage, int pageCount) {
- // Reset previous pages' animation.
- LottieAnimationView prevAnimation = mPagedView.getChildAt(prevPage)
- .findViewById(R.id.animation);
- prevAnimation.cancelAnimation();
- prevAnimation.setFrame(0);
-
- mPagedView.getChildAt(currentPage)
- .<LottieAnimationView>findViewById(R.id.animation)
- .playAnimation();
-
- if (currentPage == 0) {
- mTaskbarEduView.updateStartButton(R.string.taskbar_edu_close,
- v -> mTaskbarEduView.close(true /* animate */));
- } else {
- mTaskbarEduView.updateStartButton(R.string.taskbar_edu_previous,
- v -> mTaskbarEduView.snapToPage(currentPage - 1));
- }
- if (currentPage == pageCount - 1) {
- mTaskbarEduView.updateEndButton(R.string.taskbar_edu_done,
- v -> mTaskbarEduView.close(true /* animate */));
- } else {
- mTaskbarEduView.updateEndButton(R.string.taskbar_edu_next,
- v -> mTaskbarEduView.snapToPage(currentPage + 1));
- }
- }
-
- int getIconLayoutBoundsWidth() {
- return mControllers.taskbarViewController.getIconLayoutWidth();
- }
-
- int getOpenDuration() {
- return mControllers.taskbarOverlayController.getOpenDuration();
- }
-
- int getCloseDuration() {
- return mControllers.taskbarOverlayController.getCloseDuration();
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java
deleted file mode 100644
index 6cd6512..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.taskbar;
-
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
-import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_EDUCATION_DIALOG;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.PagedView;
-import com.android.launcher3.R;
-import com.android.launcher3.pageindicators.PageIndicatorDots;
-import com.android.launcher3.taskbar.TaskbarEduController.TaskbarEduCallbacks;
-import com.android.launcher3.views.ActivityContext;
-
-/** Horizontal carousel of tutorial screens for Taskbar Edu. */
-public class TaskbarEduPagedView extends PagedView<PageIndicatorDots> {
-
- private TaskbarEduView mTaskbarEduView;
- private TaskbarEduCallbacks mControllerCallbacks;
-
- public TaskbarEduPagedView(Context context, AttributeSet attrs) {
- super(context, attrs);
- setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
- }
-
- void setTaskbarEduView(TaskbarEduView taskbarEduView) {
- mTaskbarEduView = taskbarEduView;
- mPageIndicator = taskbarEduView.findViewById(R.id.content_page_indicator);
- initParentViews(taskbarEduView);
- }
-
- void setControllerCallbacks(TaskbarEduCallbacks controllerCallbacks) {
- mControllerCallbacks = controllerCallbacks;
- mControllerCallbacks.onPageChanged(getCurrentPage(), getCurrentPage(), getPageCount());
- }
-
- @Override
- protected int getChildGap(int fromIndex, int toIndex) {
- return mTaskbarEduView.getPaddingLeft() + mTaskbarEduView.getPaddingRight();
- }
-
- @Override
- protected void onScrollChanged(int l, int t, int oldl, int oldt) {
- super.onScrollChanged(l, t, oldl, oldt);
- if (mMaxScroll > 0) {
- mPageIndicator.setScroll(l, mMaxScroll);
- }
- }
-
- @Override
- protected void notifyPageSwitchListener(int prevPage) {
- super.notifyPageSwitchListener(prevPage);
- mControllerCallbacks.onPageChanged(prevPage, getCurrentPage(), getPageCount());
- }
-
- @Override
- protected boolean canScroll(float absVScroll, float absHScroll) {
- return AbstractFloatingView.getTopOpenViewWithType(
- ActivityContext.lookupContext(getContext()),
- TYPE_ALL & ~TYPE_TASKBAR_EDUCATION_DIALOG) == null;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index 22ed284..4373a88 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -31,7 +31,6 @@
import com.airbnb.lottie.model.KeyPath
import com.android.launcher3.R
import com.android.launcher3.Utilities
-import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_EDU_TOOLTIP
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import com.android.launcher3.util.DisplayController
@@ -59,7 +58,7 @@
LoggableTaskbarController {
private val isTooltipEnabled: Boolean
- get() = !Utilities.isRunningInTestHarness() && ENABLE_TASKBAR_EDU_TOOLTIP.get()
+ get() = !Utilities.isRunningInTestHarness()
private val isOpen: Boolean
get() = tooltip?.isOpen ?: false
val isBeforeTooltipFeaturesStep: Boolean
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
deleted file mode 100644
index 5702b6b..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
-
-import android.animation.PropertyValuesHolder;
-import android.content.Context;
-import android.graphics.Rect;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.View;
-import android.view.animation.Interpolator;
-import android.widget.Button;
-
-import com.android.launcher3.Insettable;
-import com.android.launcher3.R;
-import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
-import com.android.launcher3.views.AbstractSlideInView;
-
-/** Education view about the Taskbar. */
-public class TaskbarEduView extends AbstractSlideInView<TaskbarOverlayContext>
- implements Insettable {
-
- private final Rect mInsets = new Rect();
-
- // Initialized in init.
- private TaskbarEduController.TaskbarEduCallbacks mTaskbarEduCallbacks;
-
- private Button mStartButton;
- private Button mEndButton;
- private TaskbarEduPagedView mPagedView;
-
- public TaskbarEduView(Context context, AttributeSet attr) {
- this(context, attr, 0);
- }
-
- public TaskbarEduView(Context context, AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- protected void init(TaskbarEduController.TaskbarEduCallbacks callbacks) {
- if (mPagedView != null) {
- mPagedView.setControllerCallbacks(callbacks);
- }
- mTaskbarEduCallbacks = callbacks;
- }
-
- @Override
- protected void handleClose(boolean animate) {
- handleClose(animate, mTaskbarEduCallbacks.getCloseDuration());
- }
-
- @Override
- protected Interpolator getIdleInterpolator() {
- return EMPHASIZED;
- }
-
- @Override
- protected boolean isOfType(int type) {
- return (type & TYPE_TASKBAR_EDUCATION_DIALOG) != 0;
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mContent = findViewById(R.id.edu_view);
- mStartButton = findViewById(R.id.edu_start_button);
- mEndButton = findViewById(R.id.edu_end_button);
- mPagedView = findViewById(R.id.content);
- mPagedView.setTaskbarEduView(this);
- }
-
- @Override
- public void setInsets(Rect insets) {
- mInsets.set(insets);
- mContent.setPadding(mContent.getPaddingStart(),
- mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
- }
-
- @Override
- protected void attachToContainer() {
- if (mColorScrim != null) {
- getPopupContainer().addView(mColorScrim, 0);
- }
- getPopupContainer().addView(this, 1);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING, 0);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- int contentWidth = Math.min(getContentAreaWidth(), getMeasuredWidth());
- contentWidth = Math.max(contentWidth, mTaskbarEduCallbacks.getIconLayoutBoundsWidth());
- int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(contentWidth, MeasureSpec.EXACTLY);
-
- mContent.measure(contentAreaWidthSpec, MeasureSpec.UNSPECIFIED);
- }
-
- private int getContentAreaWidth() {
- return mTaskbarEduCallbacks.getIconLayoutBoundsWidth()
- + getResources().getDimensionPixelSize(R.dimen.taskbar_edu_horizontal_margin) * 2;
- }
-
- /** Show the Education flow. */
- public void show() {
- attachToContainer();
- animateOpen();
- }
-
- @Override
- protected Pair<View, String> getAccessibilityTarget() {
- return Pair.create(mContent, mIsOpen ? getContext().getString(R.string.taskbar_edu_opened)
- : getContext().getString(R.string.taskbar_edu_closed));
- }
-
- @Override
- protected int getScrimColor(Context context) {
- return context.getResources().getColor(R.color.widgets_picker_scrim);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- int width = r - l;
- int height = b - t;
-
- // Lay out the content as center bottom aligned.
- int contentWidth = mContent.getMeasuredWidth();
- int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left;
- mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
- contentLeft + contentWidth, height);
-
- setTranslationShift(mTranslationShift);
- }
-
- private void animateOpen() {
- if (mIsOpen || mOpenCloseAnimator.isRunning()) {
- return;
- }
- mIsOpen = true;
- mOpenCloseAnimator.setValues(
- PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
- mOpenCloseAnimator.setInterpolator(EMPHASIZED);
- mOpenCloseAnimator.setDuration(mTaskbarEduCallbacks.getOpenDuration()).start();
- }
-
- void snapToPage(int page) {
- mPagedView.snapToPage(page);
- }
-
- void updateStartButton(int textResId, OnClickListener onClickListener) {
- mStartButton.setText(textResId);
- mStartButton.setOnClickListener(onClickListener);
- }
-
- void updateEndButton(int textResId, OnClickListener onClickListener) {
- mEndButton.setText(textResId);
- mEndButton.setOnClickListener(onClickListener);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 58cb558..c9e7df4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -642,8 +642,14 @@
long resetDuration = mControllers.taskbarStashController.isInApp()
? duration
: duration / 2;
- if (mControllers.taskbarTranslationController.shouldResetBackToZero(resetDuration)
- && (isAnimatingToLauncher() || mLauncherState == LauncherState.NORMAL)) {
+ boolean shouldReset =
+ mControllers.taskbarTranslationController.shouldResetBackToZero(resetDuration);
+ boolean goingToLauncher = isAnimatingToLauncher();
+ boolean isNormalState = mLauncherState == LauncherState.NORMAL;
+ // Taskbar should always reset when animating to launcher in normal state to ensure there
+ // is no jump during the handoff to the hotseat.
+ if ((goingToLauncher && isNormalState)
+ || (shouldReset && (goingToLauncher || isNormalState))) {
animatorSet.play(mControllers.taskbarTranslationController
.createAnimToResetTranslation(resetDuration));
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
index b318100..36e78fb 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -155,7 +155,6 @@
} else if (KEY_VIEWS_UPDATE.equals(key)) {
// For views update, remove all previous updates, except the provider
pendingUpdate.remoteViews = (RemoteViews) data;
- pendingUpdate.changedViews.clear();
} else if (KEY_VIEW_DATA_CHANGED.equals(key)) {
pendingUpdate.changedViews.add((Integer) data);
}
@@ -197,7 +196,7 @@
@Override
public void addProviderChangeListener(
@NonNull LauncherWidgetHolder.ProviderChangedListener listener) {
- mProviderChangedListeners.add(listener);
+ MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.add(listener));
}
/**
@@ -207,7 +206,7 @@
@Override
public void removeProviderChangeListener(
LauncherWidgetHolder.ProviderChangedListener listener) {
- mProviderChangedListeners.remove(listener);
+ MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.remove(listener));
}
/**
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 73f05c2..512d47e 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -621,14 +621,15 @@
}
}
- public void startIntents(PendingIntent pendingIntent1, Bundle options1,
- PendingIntent pendingIntent2, Bundle options2,
- @SplitConfigurationOptions.StagePosition int splitPosition,
+ public void startIntents(PendingIntent pendingIntent1, @Nullable ShortcutInfo shortcutInfo1,
+ Bundle options1, PendingIntent pendingIntent2, @Nullable ShortcutInfo shortcutInfo2,
+ Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
if (mSystemUiProxy != null) {
try {
- mSplitScreen.startIntents(pendingIntent1, options1, pendingIntent2, options2,
- splitPosition, splitRatio, remoteTransition, instanceId);
+ mSplitScreen.startIntents(pendingIntent1, shortcutInfo1, options1, pendingIntent2,
+ shortcutInfo2, options2, splitPosition, splitRatio, remoteTransition,
+ instanceId);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntents");
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 11e1fbd..d44d7f6 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -309,9 +309,10 @@
shellInstanceId);
} else {
mSystemUiProxy.startIntents(getPendingIntent(intent1, mInitialUser),
- options1.toBundle(), getPendingIntent(intent2, mSecondUser),
- null /* options2 */, stagePosition, splitRatio, remoteTransition,
- shellInstanceId);
+ getShortcutInfo(intent1, mInitialUser), options1.toBundle(),
+ getPendingIntent(intent2, mSecondUser),
+ getShortcutInfo(intent2, mSecondUser), null /* options2 */,
+ stagePosition, splitRatio, remoteTransition, shellInstanceId);
}
} else {
final RemoteSplitLaunchAnimationRunner animationRunner =
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 172cb46..3bf4ad3 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -40,7 +40,6 @@
@Mock lateinit var taskbarKeyguardController: TaskbarKeyguardController
@Mock lateinit var stashedHandleViewController: StashedHandleViewController
@Mock lateinit var taskbarStashController: TaskbarStashController
- @Mock lateinit var taskbarEduController: TaskbarEduController
@Mock lateinit var taskbarAutohideSuspendController: TaskbarAutohideSuspendController
@Mock lateinit var taskbarPopupController: TaskbarPopupController
@Mock
@@ -81,7 +80,6 @@
taskbarKeyguardController,
stashedHandleViewController,
taskbarStashController,
- taskbarEduController,
taskbarAutohideSuspendController,
taskbarPopupController,
taskbarForceVisibleImmersiveController,
diff --git a/res/raw/downgrade_schema.json b/res/raw/downgrade_schema.json
index b8d0c6f..9929916 100644
--- a/res/raw/downgrade_schema.json
+++ b/res/raw/downgrade_schema.json
@@ -2,8 +2,11 @@
// Note: Comments are not supported in JSON schema, but android parser is lenient.
// Maximum DB version supported by this schema
- "version" : 31,
-
+ "version" : 32,
+ "downgrade_to_31" : [
+ "ALTER TABLE favorites ADD COLUMN iconPackage TEXT;",
+ "ALTER TABLE favorites ADD COLUMN iconResource TEXT;"
+ ],
"downgrade_to_30" : [],
"downgrade_to_29" : [],
"downgrade_to_28" : [
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7552b22..aebc1d0 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -192,9 +192,6 @@
<string name="permdesc_write_settings">Allows the app to change the settings and
shortcuts in home.</string>
- <!-- Toast shown on clicking a direct call shortcut. [CHAR_LIMIT=80] -->
- <string name="msg_no_phone_permission"><xliff:g id="app_name" example="Launcher3">%1$s</xliff:g> is not allowed to make phone calls</string>
-
<!-- Widgets: -->
<skip />
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 3bda94b..0988769 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -19,7 +19,6 @@
import static android.animation.ValueAnimator.areAnimatorsEnabled;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
-import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING;
import static com.android.launcher3.dragndrop.DraggableView.DRAGGABLE_ICON;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_BOUNCE_OFFSET;
@@ -557,9 +556,7 @@
public void setSpringLoadedProgress(float progress) {
if (Float.compare(progress, mSpringLoadedProgress) != 0) {
mSpringLoadedProgress = progress;
- if (!SHOW_HOME_GARDENING.get()) {
- updateBgAlpha();
- }
+ updateBgAlpha();
setGridAlpha(progress);
}
}
@@ -584,9 +581,7 @@
public void setScrollProgress(float progress) {
if (Float.compare(Math.abs(progress), mScrollProgress) != 0) {
mScrollProgress = Math.abs(progress);
- if (!SHOW_HOME_GARDENING.get()) {
- updateBgAlpha();
- }
+ updateBgAlpha();
}
}
@@ -625,7 +620,7 @@
}
}
- if (mVisualizeDropLocation && !SHOW_HOME_GARDENING.get()) {
+ if (mVisualizeDropLocation) {
for (int i = 0; i < mDragOutlines.length; i++) {
final float alpha = mDragOutlineAlphas[i];
if (alpha <= 0) continue;
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index 5225731..98ecf3a 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT;
import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility;
-import static com.android.launcher3.config.FeatureFlags.HOME_GARDENING_WORKSPACE_BUTTONS;
import android.animation.TimeInterpolator;
import android.content.Context;
@@ -119,13 +118,7 @@
lp.rightMargin = (grid.widthPx - lp.width) / 2;
}
lp.height = grid.dropTargetBarSizePx;
- // TODO: Add tablet support for DropTargetBar when HOME_GARDENING_WORKSPACE_BUTTONS flag
- // is on
- if (HOME_GARDENING_WORKSPACE_BUTTONS.get()) {
- lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- } else {
- lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
- }
+ lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
DeviceProfile dp = mLauncher.getDeviceProfile();
int horizontalPadding = dp.dropTargetHorizontalPaddingPx;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4f7380a..59f56ff 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -82,7 +82,6 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
@@ -92,7 +91,6 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Parcelable;
-import android.os.Process;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.Trace;
@@ -115,7 +113,6 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
-import android.widget.Toast;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
@@ -160,7 +157,6 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.model.ModelUtils;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.WidgetsModel;
@@ -192,7 +188,6 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.OnboardingPrefs;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.RunnableList;
@@ -263,8 +258,6 @@
public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
- private static final int REQUEST_PERMISSION_CALL_PHONE = 14;
-
private static final float BOUNCE_ANIMATION_TENSION = 1.3f;
/**
@@ -975,33 +968,6 @@
handleActivityResult(requestCode, resultCode, data);
}
- @Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions,
- int[] grantResults) {
- PendingRequestArgs pendingArgs = mPendingRequestArgs;
- if (requestCode == REQUEST_PERMISSION_CALL_PHONE && pendingArgs != null
- && pendingArgs.getRequestCode() == REQUEST_PERMISSION_CALL_PHONE) {
- setWaitingForResult(null);
-
- View v = null;
- CellPos cellPos = getCellPosMapper().mapModelToPresenter(pendingArgs);
- CellLayout layout = getCellLayout(pendingArgs.container, cellPos.screenId);
- if (layout != null) {
- v = layout.getChildAt(cellPos.cellX, cellPos.cellY);
- }
- Intent intent = pendingArgs.getPendingIntent();
-
- if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- startActivitySafely(v, intent, null);
- } else {
- // TODO: Show a snack bar with link to settings
- Toast.makeText(this, getString(R.string.msg_no_phone_permission,
- getString(R.string.derived_app_name)), Toast.LENGTH_SHORT).show();
- }
- }
- }
-
/**
* Check to see if a given screen id exists. If not, create it at the end, return the new id.
*
@@ -1417,21 +1383,9 @@
WorkspaceItemInfo info = PinRequestHelper.createWorkspaceItemFromPinItemRequest(
this, PinRequestHelper.getPinItemRequest(data), 0);
-
if (info == null) {
- // Legacy shortcuts are only supported for primary profile.
- info = Process.myUserHandle().equals(args.user)
- ? ModelUtils.fromLegacyShortcutIntent(this, data) : null;
-
- if (info == null) {
- Log.e(TAG, "Unable to parse a valid custom shortcut result");
- return;
- } else if (!new PackageManagerHelper(this).hasPermissionForActivity(
- info.intent, args.getPendingIntent().getComponent().getPackageName())) {
- // The app is trying to add a shortcut without sufficient permissions
- Log.e(TAG, "Ignoring malicious intent " + info.intent.toUri(0));
- return;
- }
+ Log.e(TAG, "Unable to parse a valid shortcut result");
+ return;
}
if (container < 0) {
@@ -2151,27 +2105,6 @@
}
}
- @TargetApi(Build.VERSION_CODES.M)
- @Override
- public boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
- // Due to legacy reasons, direct call shortcuts require Launchers to have the
- // corresponding permission. Show the appropriate permission prompt if that
- // is the case.
- if (intent.getComponent() == null
- && Intent.ACTION_CALL.equals(intent.getAction())
- && checkSelfPermission(android.Manifest.permission.CALL_PHONE) !=
- PackageManager.PERMISSION_GRANTED) {
-
- setWaitingForResult(PendingRequestArgs
- .forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
- requestPermissions(new String[]{android.Manifest.permission.CALL_PHONE},
- REQUEST_PERMISSION_CALL_PHONE);
- return true;
- } else {
- return false;
- }
- }
-
@Override
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
if (!hasBeenResumed()) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index ad95f7e..06ac44a 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -421,6 +421,9 @@
launcherBinder.bindAllApps();
launcherBinder.bindDeepShortcuts();
launcherBinder.bindWidgets();
+ if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ mModelDelegate.bindAllModelExtras(callbacksList);
+ }
return true;
} else {
stopLoader();
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index d1fa764..f4892b2 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
-import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
import android.annotation.TargetApi;
@@ -30,83 +29,55 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.Intent;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
-import android.database.sqlite.SQLiteStatement;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Process;
-import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.BaseColumns;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logging.FileLog;
-import com.android.launcher3.model.DbDowngradeHelper;
-import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.model.DatabaseHelper;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.util.IOUtils;
import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.IntSet;
-import com.android.launcher3.util.NoLocaleSQLiteHelper;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Partner;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.LauncherWidgetHolder;
import org.xmlpull.v1.XmlPullParser;
-import java.io.File;
import java.io.FileDescriptor;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
-import java.net.URISyntaxException;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
import java.util.function.Supplier;
-import java.util.stream.Collectors;
public class LauncherProvider extends ContentProvider {
private static final String TAG = "LauncherProvider";
- private static final boolean LOGD = false;
-
- private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json";
-
- /**
- * Represents the schema of the database. Changes in scheme need not be backwards compatible.
- * When increasing the scheme version, ensure that downgrade_schema.json is updated
- */
- public static final int SCHEMA_VERSION = 31;
public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".settings";
- public static final String KEY_LAYOUT_PROVIDER_AUTHORITY = "KEY_LAYOUT_PROVIDER_AUTHORITY";
private static final int TEST_WORKSPACE_LAYOUT_RES_XML = R.xml.default_test_workspace;
private static final int TEST2_WORKSPACE_LAYOUT_RES_XML = R.xml.default_test2_workspace;
private static final int TAPL_WORKSPACE_LAYOUT_RES_XML = R.xml.default_tapl_test_workspace;
- static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
+ public static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
protected DatabaseHelper mOpenHelper;
protected String mProviderAuthority;
@@ -193,18 +164,6 @@
return result;
}
- @Thunk static int dbInsertAndCheck(DatabaseHelper helper,
- SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
- if (values == null) {
- throw new RuntimeException("Error: attempting to insert null values");
- }
- if (!values.containsKey(LauncherSettings.Favorites._ID)) {
- throw new RuntimeException("Error: attempting to add item without specifying an id");
- }
- helper.checkId(values);
- return (int) db.insert(table, nullColumnHack, values);
- }
-
private void reloadLauncherIfExternal() {
if (Binder.getCallingPid() != Process.myPid()) {
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
@@ -228,7 +187,7 @@
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
addModifiedTime(initialValues);
- final int rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
+ final int rowId = mOpenHelper.dbInsertAndCheck(db, args.table, initialValues);
if (rowId < 0) return null;
onAddOrDeleteOp(db);
@@ -287,7 +246,7 @@
int numValues = values.length;
for (int i = 0; i < numValues; i++) {
addModifiedTime(values[i]);
- if (dbInsertAndCheck(mOpenHelper, db, args.table, null, values[i]) < 0) {
+ if (mOpenHelper.dbInsertAndCheck(db, args.table, values[i]) < 0) {
return 0;
}
}
@@ -616,499 +575,6 @@
mOpenHelper, getContext().getResources(), defaultLayout);
}
- /**
- * The class is subclassed in tests to create an in-memory db.
- */
- public static class DatabaseHelper extends NoLocaleSQLiteHelper implements
- LayoutParserCallback {
- private final Context mContext;
- private final boolean mForMigration;
- private int mMaxItemId = -1;
- private boolean mHotseatRestoreTableExists;
-
- static DatabaseHelper createDatabaseHelper(Context context, boolean forMigration) {
- return createDatabaseHelper(context, null, forMigration);
- }
-
- static DatabaseHelper createDatabaseHelper(Context context, String dbName,
- boolean forMigration) {
- if (dbName == null) {
- dbName = InvariantDeviceProfile.INSTANCE.get(context).dbFile;
- }
- DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName, forMigration);
- // Table creation sometimes fails silently, which leads to a crash loop.
- // This way, we will try to create a table every time after crash, so the device
- // would eventually be able to recover.
- if (!tableExists(databaseHelper.getReadableDatabase(), Favorites.TABLE_NAME)) {
- Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate");
- // This operation is a no-op if the table already exists.
- databaseHelper.addFavoritesTable(databaseHelper.getWritableDatabase(), true);
- }
- databaseHelper.mHotseatRestoreTableExists = tableExists(
- databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
-
- databaseHelper.initIds();
- return databaseHelper;
- }
-
- /**
- * Constructor used in tests and for restore.
- */
- public DatabaseHelper(Context context, String dbName, boolean forMigration) {
- super(context, dbName, SCHEMA_VERSION);
- mContext = context;
- mForMigration = forMigration;
- }
-
- protected void initIds() {
- // In the case where neither onCreate nor onUpgrade gets called, we read the maxId from
- // the DB here
- if (mMaxItemId == -1) {
- mMaxItemId = initializeMaxItemId(getWritableDatabase());
- }
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- if (LOGD) Log.d(TAG, "creating new launcher database");
-
- mMaxItemId = 1;
-
- addFavoritesTable(db, false);
-
- // Fresh and clean launcher DB.
- mMaxItemId = initializeMaxItemId(db);
- if (!mForMigration) {
- onEmptyDbCreated();
- }
- }
-
- protected void onAddOrDeleteOp(SQLiteDatabase db) {
- if (mHotseatRestoreTableExists) {
- dropTable(db, Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
- mHotseatRestoreTableExists = false;
- }
- }
-
- /**
- * Re-composite given key in respect to database. If the current db is
- * {@link LauncherFiles#LAUNCHER_DB}, return the key as-is. Otherwise append the db name to
- * given key. e.g. consider key="EMPTY_DATABASE_CREATED", dbName="minimal.db", the returning
- * string will be "EMPTY_DATABASE_CREATED@minimal.db".
- */
- String getKey(final String key) {
- if (TextUtils.equals(getDatabaseName(), LauncherFiles.LAUNCHER_DB)) {
- return key;
- }
- return key + "@" + getDatabaseName();
- }
-
- /**
- * Overriden in tests.
- */
- protected void onEmptyDbCreated() {
- // Set the flag for empty DB
- LauncherPrefs.getPrefs(mContext).edit().putBoolean(getKey(EMPTY_DATABASE_CREATED), true)
- .commit();
- }
-
- public long getSerialNumberForUser(UserHandle user) {
- return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user);
- }
-
- public long getDefaultUserSerial() {
- return getSerialNumberForUser(Process.myUserHandle());
- }
-
- private void addFavoritesTable(SQLiteDatabase db, boolean optional) {
- Favorites.addTableToDb(db, getDefaultUserSerial(), optional);
- }
-
- @Override
- public void onOpen(SQLiteDatabase db) {
- super.onOpen(db);
-
- File schemaFile = mContext.getFileStreamPath(DOWNGRADE_SCHEMA_FILE);
- if (!schemaFile.exists()) {
- handleOneTimeDataUpgrade(db);
- }
- DbDowngradeHelper.updateSchemaFile(schemaFile, SCHEMA_VERSION, mContext);
- }
-
- /**
- * One-time data updated before support of onDowngrade was added. This update is backwards
- * compatible and can safely be run multiple times.
- * Note: No new logic should be added here after release, as the new logic might not get
- * executed on an existing device.
- * TODO: Move this to db upgrade path, once the downgrade path is released.
- */
- protected void handleOneTimeDataUpgrade(SQLiteDatabase db) {
- // Remove "profile extra"
- UserCache um = UserCache.INSTANCE.get(mContext);
- for (UserHandle user : um.getUserProfiles()) {
- long serial = um.getSerialNumberForUser(user);
- String sql = "update favorites set intent = replace(intent, "
- + "';l.profile=" + serial + ";', ';') where itemType = 0;";
- db.execSQL(sql);
- }
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion);
- switch (oldVersion) {
- // The version cannot be lower that 12, as Launcher3 never supported a lower
- // version of the DB.
- case 12:
- // No-op
- case 13: {
- try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- // Insert new column for holding widget provider name
- db.execSQL("ALTER TABLE favorites " +
- "ADD COLUMN appWidgetProvider TEXT;");
- t.commit();
- } catch (SQLException ex) {
- Log.e(TAG, ex.getMessage(), ex);
- // Old version remains, which means we wipe old data
- break;
- }
- }
- case 14: {
- if (!addIntegerColumn(db, Favorites.MODIFIED, 0)) {
- // Old version remains, which means we wipe old data
- break;
- }
- }
- case 15: {
- if (!addIntegerColumn(db, Favorites.RESTORED, 0)) {
- // Old version remains, which means we wipe old data
- break;
- }
- }
- case 16:
- // No-op
- case 17:
- // No-op
- case 18:
- // No-op
- case 19: {
- // Add userId column
- if (!addIntegerColumn(db, Favorites.PROFILE_ID, getDefaultUserSerial())) {
- // Old version remains, which means we wipe old data
- break;
- }
- }
- case 20:
- if (!updateFolderItemsRank(db, true)) {
- break;
- }
- case 21:
- // No-op
- case 22: {
- if (!addIntegerColumn(db, Favorites.OPTIONS, 0)) {
- // Old version remains, which means we wipe old data
- break;
- }
- }
- case 23:
- // No-op
- case 24:
- // No-op
- case 25:
- convertShortcutsToLauncherActivities(db);
- case 26:
- // QSB was moved to the grid. Ignore overlapping items
- case 27: {
- // Update the favorites table so that the screen ids are ordered based on
- // workspace page rank.
- IntArray finalScreens = LauncherDbUtils.queryIntArray(false, db,
- "workspaceScreens", BaseColumns._ID, null, null, "screenRank");
- int[] original = finalScreens.toArray();
- Arrays.sort(original);
- String updatemap = "";
- for (int i = 0; i < original.length; i++) {
- if (finalScreens.get(i) != original[i]) {
- updatemap += String.format(Locale.ENGLISH, " WHEN %1$s=%2$d THEN %3$d",
- Favorites.SCREEN, finalScreens.get(i), original[i]);
- }
- }
- if (!TextUtils.isEmpty(updatemap)) {
- String query = String.format(Locale.ENGLISH,
- "UPDATE %1$s SET %2$s=CASE %3$s ELSE %2$s END WHERE %4$s = %5$d",
- Favorites.TABLE_NAME, Favorites.SCREEN, updatemap,
- Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP);
- db.execSQL(query);
- }
- dropTable(db, "workspaceScreens");
- }
- case 28: {
- boolean columnAdded = addIntegerColumn(
- db, Favorites.APPWIDGET_SOURCE, Favorites.CONTAINER_UNKNOWN);
- if (!columnAdded) {
- // Old version remains, which means we wipe old data
- break;
- }
- }
- case 29: {
- // Remove widget panel related leftover workspace items
- db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
- Favorites.SCREEN, IntArray.wrap(-777, -778)), null);
- }
- case 30: {
- if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
- // Clean up first row in screen 0 as it might contain junk data.
- Log.d(TAG, "Cleaning up first row");
- db.delete(Favorites.TABLE_NAME,
- String.format(Locale.ENGLISH,
- "%1$s = %2$d AND %3$s = %4$d AND %5$s = %6$d",
- Favorites.SCREEN, 0,
- Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP,
- Favorites.CELLY, 0), null);
- }
- return;
- }
- case 31: {
- // DB Upgraded successfully
- return;
- }
- }
-
- // DB was not upgraded
- Log.w(TAG, "Destroying all old data.");
- createEmptyDB(db);
- }
-
- @Override
- public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- try {
- DbDowngradeHelper.parse(mContext.getFileStreamPath(DOWNGRADE_SCHEMA_FILE))
- .onDowngrade(db, oldVersion, newVersion);
- } catch (Exception e) {
- Log.d(TAG, "Unable to downgrade from: " + oldVersion + " to " + newVersion +
- ". Wiping databse.", e);
- createEmptyDB(db);
- }
- }
-
- /**
- * Clears all the data for a fresh start.
- */
- public void createEmptyDB(SQLiteDatabase db) {
- try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- dropTable(db, Favorites.TABLE_NAME);
- dropTable(db, "workspaceScreens");
- onCreate(db);
- t.commit();
- }
- }
-
- /**
- * Removes widgets which are registered to the Launcher's host, but are not present
- * in our model.
- */
- public void removeGhostWidgets(SQLiteDatabase db) {
- // Get all existing widget ids.
- final LauncherWidgetHolder holder = newLauncherWidgetHolder();
- try {
- final int[] allWidgets;
- try {
- // Although the method was defined in O, it has existed since the beginning of
- // time, so it might work on older platforms as well.
- allWidgets = holder.getAppWidgetIds();
- } catch (IncompatibleClassChangeError e) {
- Log.e(TAG, "getAppWidgetIds not supported", e);
- return;
- }
- final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db,
- Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
- "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null));
- boolean isAnyWidgetRemoved = false;
- for (int widgetId : allWidgets) {
- if (!validWidgets.contains(widgetId)) {
- try {
- FileLog.d(TAG, "Deleting invalid widget " + widgetId);
- holder.deleteAppWidgetId(widgetId);
- isAnyWidgetRemoved = true;
- } catch (RuntimeException e) {
- // Ignore
- }
- }
- }
- if (isAnyWidgetRemoved) {
- final String allWidgetsIds = Arrays.stream(allWidgets).mapToObj(String::valueOf)
- .collect(Collectors.joining(",", "[", "]"));
- final String validWidgetsIds = Arrays.stream(
- validWidgets.getArray().toArray()).mapToObj(String::valueOf)
- .collect(Collectors.joining(",", "[", "]"));
- FileLog.d(TAG, "One or more widgets was removed. db_path=" + db.getPath()
- + " allWidgetsIds=" + allWidgetsIds
- + ", validWidgetsIds=" + validWidgetsIds);
- }
- } finally {
- holder.destroy();
- }
- }
-
- /**
- * Replaces all shortcuts of type {@link Favorites#ITEM_TYPE_SHORTCUT} which have a valid
- * launcher activity target with {@link Favorites#ITEM_TYPE_APPLICATION}.
- */
- @Thunk void convertShortcutsToLauncherActivities(SQLiteDatabase db) {
- try (SQLiteTransaction t = new SQLiteTransaction(db);
- // Only consider the primary user as other users can't have a shortcut.
- Cursor c = db.query(Favorites.TABLE_NAME,
- new String[] { Favorites._ID, Favorites.INTENT},
- "itemType=" + Favorites.ITEM_TYPE_SHORTCUT +
- " AND profileId=" + getDefaultUserSerial(),
- null, null, null, null);
- SQLiteStatement updateStmt = db.compileStatement("UPDATE favorites SET itemType="
- + Favorites.ITEM_TYPE_APPLICATION + " WHERE _id=?")
- ) {
- final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
- final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT);
-
- while (c.moveToNext()) {
- String intentDescription = c.getString(intentIndex);
- Intent intent;
- try {
- intent = Intent.parseUri(intentDescription, 0);
- } catch (URISyntaxException e) {
- Log.e(TAG, "Unable to parse intent", e);
- continue;
- }
-
- if (!PackageManagerHelper.isLauncherAppTarget(intent)) {
- continue;
- }
-
- int id = c.getInt(idIndex);
- updateStmt.bindLong(1, id);
- updateStmt.executeUpdateDelete();
- }
- t.commit();
- } catch (SQLException ex) {
- Log.w(TAG, "Error deduping shortcuts", ex);
- }
- }
-
- @Thunk boolean updateFolderItemsRank(SQLiteDatabase db, boolean addRankColumn) {
- try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- if (addRankColumn) {
- // Insert new column for holding rank
- db.execSQL("ALTER TABLE favorites ADD COLUMN rank INTEGER NOT NULL DEFAULT 0;");
- }
-
- // Get a map for folder ID to folder width
- Cursor c = db.rawQuery("SELECT container, MAX(cellX) FROM favorites"
- + " WHERE container IN (SELECT _id FROM favorites WHERE itemType = ?)"
- + " GROUP BY container;",
- new String[] {Integer.toString(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)});
-
- while (c.moveToNext()) {
- db.execSQL("UPDATE favorites SET rank=cellX+(cellY*?) WHERE "
- + "container=? AND cellX IS NOT NULL AND cellY IS NOT NULL;",
- new Object[] {c.getLong(1) + 1, c.getLong(0)});
- }
-
- c.close();
- t.commit();
- } catch (SQLException ex) {
- // Old version remains, which means we wipe old data
- Log.e(TAG, ex.getMessage(), ex);
- return false;
- }
- return true;
- }
-
- private boolean addIntegerColumn(SQLiteDatabase db, String columnName, long defaultValue) {
- try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- db.execSQL("ALTER TABLE favorites ADD COLUMN "
- + columnName + " INTEGER NOT NULL DEFAULT " + defaultValue + ";");
- t.commit();
- } catch (SQLException ex) {
- Log.e(TAG, ex.getMessage(), ex);
- return false;
- }
- return true;
- }
-
- // Generates a new ID to use for an object in your database. This method should be only
- // called from the main UI thread. As an exception, we do call it when we call the
- // constructor from the worker thread; however, this doesn't extend until after the
- // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
- // after that point
- @Override
- public int generateNewItemId() {
- if (mMaxItemId < 0) {
- throw new RuntimeException("Error: max item id was not initialized");
- }
- mMaxItemId += 1;
- return mMaxItemId;
- }
-
- /**
- * @return A new {@link LauncherWidgetHolder} based on the current context
- */
- @NonNull
- public LauncherWidgetHolder newLauncherWidgetHolder() {
- return LauncherWidgetHolder.newInstance(mContext);
- }
-
- @Override
- public int insertAndCheck(SQLiteDatabase db, ContentValues values) {
- return dbInsertAndCheck(this, db, Favorites.TABLE_NAME, null, values);
- }
-
- public void checkId(ContentValues values) {
- int id = values.getAsInteger(Favorites._ID);
- mMaxItemId = Math.max(id, mMaxItemId);
- }
-
- private int initializeMaxItemId(SQLiteDatabase db) {
- return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s", Favorites._ID, Favorites.TABLE_NAME);
- }
-
- // Returns a new ID to use for an workspace screen in your database that is greater than all
- // existing screen IDs.
- private int getNewScreenId() {
- return getMaxId(getWritableDatabase(),
- "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
- Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
- Favorites.CONTAINER_DESKTOP) + 1;
- }
-
- @Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
- // TODO: Use multiple loaders with fall-back and transaction.
- int count = loader.loadLayout(db, new IntArray());
-
- // Ensure that the max ids are initialized
- mMaxItemId = initializeMaxItemId(db);
- return count;
- }
- }
-
- /**
- * @return the max _id in the provided table.
- */
- @Thunk static int getMaxId(SQLiteDatabase db, String query, Object... args) {
- int max = 0;
- try (SQLiteStatement prog = db.compileStatement(
- String.format(Locale.ENGLISH, query, args))) {
- max = (int) DatabaseUtils.longForQuery(prog, null);
- if (max < 0) {
- throw new RuntimeException("Error: could not query max id");
- }
- } catch (IllegalArgumentException exception) {
- String message = exception.getMessage();
- if (message.contains("re-open") && message.contains("already-closed")) {
- // Don't crash trying to end a transaction an an already closed DB. See b/173162852.
- } else {
- throw exception;
- }
- }
- return max;
- }
-
static class SqlArguments {
public final String table;
public final String where;
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 1cd2a30..1bbb09a 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -131,18 +131,6 @@
public static final int ITEM_TYPE_SEARCH_ACTION = 9;
/**
- * The icon package name in Intent.ShortcutIconResource
- * <P>Type: TEXT</P>
- */
- public static final String ICON_PACKAGE = "iconPackage";
-
- /**
- * The icon resource name in Intent.ShortcutIconResource
- * <P>Type: TEXT</P>
- */
- public static final String ICON_RESOURCE = "iconResource";
-
- /**
* The custom icon bitmap.
* <P>Type: BLOB</P>
*/
@@ -357,8 +345,6 @@
"spanY INTEGER," +
"itemType INTEGER," +
"appWidgetId INTEGER NOT NULL DEFAULT -1," +
- "iconPackage TEXT," +
- "iconResource TEXT," +
"icon BLOB," +
"appWidgetProvider TEXT," +
"modified INTEGER NOT NULL DEFAULT 0," +
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index fd78739..6e6f1ac 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -952,10 +952,6 @@
return mScreenOrder;
}
- protected View getFirstPagePinnedItem() {
- return mFirstPagePinnedItem;
- }
-
/**
* Returns the screen ID of a page that is shown together with the given page screen ID when the
* two panel UI is enabled.
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 62e7ef3..55ab7f1 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -29,14 +29,11 @@
import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.LauncherState.WORKSPACE_PAGE_INDICATOR;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
-import static com.android.launcher3.config.FeatureFlags.HOME_GARDENING_WORKSPACE_BUTTONS;
-import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING;
import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
@@ -160,30 +157,6 @@
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, hotseatFadeInterpolator);
- if (SHOW_HOME_GARDENING.get()) {
- propertySetter.setViewAlpha(
- mWorkspace.getFirstPagePinnedItem(),
- state == SPRING_LOADED ? FIRST_PAGE_PINNED_WIDGET_DISABLED_ALPHA : 1,
- workspaceFadeInterpolator);
- propertySetter.addEndListener(success -> {
- if (success) {
- mWorkspace.getFirstPagePinnedItem().setClickable(state != SPRING_LOADED);
- }
- });
- }
-
- if (HOME_GARDENING_WORKSPACE_BUTTONS.get()) {
- propertySetter.setViewAlpha(
- mLauncher.getHotseat().getQsb(),
- state == SPRING_LOADED ? 0 : 1,
- workspaceFadeInterpolator);
- propertySetter.addEndListener(success -> {
- if (success) {
- mLauncher.getHotseat().getQsb().setClickable(state != SPRING_LOADED);
- }
- });
- }
-
// Update the accessibility flags for hotseat based on launcher state.
hotseat.setImportantForAccessibility(
state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)
diff --git a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
index 3863dc1..b911928 100644
--- a/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
+++ b/src/com/android/launcher3/anim/KeyboardInsetAnimationCallback.java
@@ -27,7 +27,16 @@
import java.util.List;
/**
- * Callback that animates views above the IME
+ * Callback that animates views above the IME.
+ * <p>
+ * The expected stages of a keyboard transition are:
+ * <p>
+ * <ul>
+ * <li>PREPARING: Keyboard insets haven't changed yet, but are about to.</li>
+ * <li>STARTED: Keyboard insets have temporarily changed to the end state, but not drawn.</li>
+ * <li>PROGRESSING: At least one frame of the animation has been drawn.</li>
+ * <li>FINISHED: Keyboard has reached its end state, and animation is complete.</li>
+ * </ul>
*/
@RequiresApi(api = Build.VERSION_CODES.R)
public class KeyboardInsetAnimationCallback extends WindowInsetsAnimation.Callback {
@@ -46,6 +55,18 @@
mInitialTranslation = mView.getTranslationY();
}
+ @Override
+ public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation,
+ WindowInsetsAnimation.Bounds bounds) {
+ // Final insets have temporarily been applied, so store the current translation as final.
+ mTerminalTranslation = mView.getTranslationY();
+ // Reset the translation in case the view is drawn before onProgress gets called.
+ mView.setTranslationY(mInitialTranslation);
+ if (mView instanceof KeyboardInsetListener) {
+ ((KeyboardInsetListener) mView).onTranslationStart();
+ }
+ return super.onStart(animation, bounds);
+ }
@Override
public WindowInsets onProgress(WindowInsets windowInsets, List<WindowInsetsAnimation> list) {
@@ -73,18 +94,7 @@
}
@Override
- public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation,
- WindowInsetsAnimation.Bounds bounds) {
- mTerminalTranslation = mView.getTranslationY();
- if (mView instanceof KeyboardInsetListener) {
- ((KeyboardInsetListener) mView).onTranslationStart();
- }
- return super.onStart(animation, bounds);
- }
-
- @Override
public void onEnd(WindowInsetsAnimation animation) {
- mView.setTranslationY(mTerminalTranslation);
if (mView instanceof KeyboardInsetListener) {
((KeyboardInsetListener) mView).onTranslationEnd();
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index b8893b6..c0ea6eb 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -269,13 +269,6 @@
public static final BooleanFlag ENABLE_SEARCH_UNINSTALLED_APPS = getReleaseFlag(270395269,
"ENABLE_SEARCH_UNINSTALLED_APPS", DISABLED, "Search uninstalled app results.");
- public static final BooleanFlag SHOW_HOME_GARDENING = getDebugFlag(270395183,
- "SHOW_HOME_GARDENING", DISABLED, "Show the new home gardening mode");
-
- public static final BooleanFlag HOME_GARDENING_WORKSPACE_BUTTONS = getDebugFlag(270395133,
- "HOME_GARDENING_WORKSPACE_BUTTONS", DISABLED,
- "Change workspace edit buttons to reflect home gardening");
-
public static final BooleanFlag ENABLE_DOWNLOAD_APP_UX_V2 = getReleaseFlag(270395134,
"ENABLE_DOWNLOAD_APP_UX_V2", ENABLED, "Updates the download app UX"
+ " to have better visuals");
@@ -331,10 +324,6 @@
"ENABLE_FORCED_MONO_ICON", DISABLED,
"Enable the ability to generate monochromatic icons, if it is not provided by the app");
- public static final BooleanFlag ENABLE_TASKBAR_EDU_TOOLTIP = getDebugFlag(270396268,
- "ENABLE_TASKBAR_EDU_TOOLTIP", ENABLED,
- "Enable the tooltip version of the Taskbar education flow.");
-
public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680,
"ENABLE_MULTI_INSTANCE", DISABLED,
"Enables creation and filtering of multiple task instances in overview");
@@ -349,6 +338,11 @@
"load the current workspace screen visible to the user before the rest rather than "
+ "loading all of them at once.");
+ public static final BooleanFlag CHANGE_MODEL_DELEGATE_LOADING_ORDER = getDebugFlag(251502424,
+ "CHANGE_MODEL_DELEGATE_LOADING_ORDER", DISABLED,
+ "changes the timing of the loading and binding of delegate items during "
+ + "data preparation for loading the home screen");
+
public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(270397206,
"ENABLE_GRID_ONLY_OVERVIEW", DISABLED,
"Enable a grid-only overview without a focused task.");
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 0767e69..372e9bf 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -229,8 +229,8 @@
query += " or " + LauncherSettings.Favorites.SCREEN + " = "
+ Workspace.SECOND_SCREEN_ID;
}
- loadWorkspace(new ArrayList<>(), LauncherSettings.Favorites.PREVIEW_CONTENT_URI,
- query);
+ loadWorkspaceForPreviewSurfaceRenderer(new ArrayList<>(),
+ LauncherSettings.Favorites.PREVIEW_CONTENT_URI, query);
final SparseArray<Size> spanInfo =
getLoadedLauncherWidgetInfo(previewContext.getBaseContext());
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 91ace27..358992e 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -63,7 +63,7 @@
protected final BgDataModel mBgDataModel;
private final AllAppsList mBgAllAppsList;
- private final Callbacks[] mCallbacksList;
+ final Callbacks[] mCallbacksList;
private int mMyBindingId;
@@ -293,8 +293,10 @@
// Load items on the current page.
bindWorkspaceItems(currentWorkspaceItems, mUiExecutor);
bindAppWidgets(currentAppWidgets, mUiExecutor);
- mExtraItems.forEach(item ->
- executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
+ if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ mExtraItems.forEach(item ->
+ executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
+ }
RunnableList pendingTasks = new RunnableList();
Executor pendingExecutor = pendingTasks::add;
@@ -382,14 +384,22 @@
// Save a copy of all the bg-thread collections
ArrayList<ItemInfo> workspaceItems;
ArrayList<LauncherAppWidgetInfo> appWidgets;
+ ArrayList<FixedContainerItems> fciList = new ArrayList<>();
synchronized (mBgDataModel) {
workspaceItems = new ArrayList<>(mBgDataModel.workspaceItems);
appWidgets = new ArrayList<>(mBgDataModel.appWidgets);
+ if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ mBgDataModel.extraItems.forEach(fciList::add);
+ }
}
workspaceItems.forEach(it -> mBoundItemIds.add(it.id));
appWidgets.forEach(it -> mBoundItemIds.add(it.id));
+ if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ fciList.forEach(item ->
+ executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
+ }
sortWorkspaceItemsSpatially(mApp.getInvariantDeviceProfile(), workspaceItems);
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
new file mode 100644
index 0000000..1840b75
--- /dev/null
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
+import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteStatement;
+import android.os.Process;
+import android.os.UserHandle;
+import android.provider.BaseColumns;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.AutoInstallsLayout;
+import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherFiles;
+import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.LauncherProvider;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.provider.LauncherDbUtils;
+import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.NoLocaleSQLiteHelper;
+import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.LauncherWidgetHolder;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+/**
+ * SqLite database for launcher home-screen model
+ * The class is subclassed in tests to create an in-memory db.
+ */
+public class DatabaseHelper extends NoLocaleSQLiteHelper implements
+ LayoutParserCallback {
+
+ /**
+ * Represents the schema of the database. Changes in scheme need not be backwards compatible.
+ * When increasing the scheme version, ensure that downgrade_schema.json is updated
+ */
+ public static final int SCHEMA_VERSION = 32;
+ private static final String TAG = "DatabaseHelper";
+ private static final boolean LOGD = false;
+
+ private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json";
+
+ private final Context mContext;
+ private final boolean mForMigration;
+ private int mMaxItemId = -1;
+ public boolean mHotseatRestoreTableExists;
+
+ public static DatabaseHelper createDatabaseHelper(Context context, boolean forMigration) {
+ return createDatabaseHelper(context, null, forMigration);
+ }
+
+ public static DatabaseHelper createDatabaseHelper(Context context, String dbName,
+ boolean forMigration) {
+ if (dbName == null) {
+ dbName = InvariantDeviceProfile.INSTANCE.get(context).dbFile;
+ }
+ DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName, forMigration);
+ // Table creation sometimes fails silently, which leads to a crash loop.
+ // This way, we will try to create a table every time after crash, so the device
+ // would eventually be able to recover.
+ if (!tableExists(databaseHelper.getReadableDatabase(), Favorites.TABLE_NAME)) {
+ Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate");
+ // This operation is a no-op if the table already exists.
+ databaseHelper.addFavoritesTable(databaseHelper.getWritableDatabase(), true);
+ }
+ databaseHelper.mHotseatRestoreTableExists = tableExists(
+ databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
+
+ databaseHelper.initIds();
+ return databaseHelper;
+ }
+
+ /**
+ * Constructor used in tests and for restore.
+ */
+ public DatabaseHelper(Context context, String dbName, boolean forMigration) {
+ super(context, dbName, SCHEMA_VERSION);
+ mContext = context;
+ mForMigration = forMigration;
+ }
+
+ protected void initIds() {
+ // In the case where neither onCreate nor onUpgrade gets called, we read the maxId from
+ // the DB here
+ if (mMaxItemId == -1) {
+ mMaxItemId = initializeMaxItemId(getWritableDatabase());
+ }
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ if (LOGD) Log.d(TAG, "creating new launcher database");
+
+ mMaxItemId = 1;
+
+ addFavoritesTable(db, false);
+
+ // Fresh and clean launcher DB.
+ mMaxItemId = initializeMaxItemId(db);
+ if (!mForMigration) {
+ onEmptyDbCreated();
+ }
+ }
+
+ public void onAddOrDeleteOp(SQLiteDatabase db) {
+ if (mHotseatRestoreTableExists) {
+ dropTable(db, Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
+ mHotseatRestoreTableExists = false;
+ }
+ }
+
+ /**
+ * Re-composite given key in respect to database. If the current db is
+ * {@link LauncherFiles#LAUNCHER_DB}, return the key as-is. Otherwise append the db name to
+ * given key. e.g. consider key="EMPTY_DATABASE_CREATED", dbName="minimal.db", the returning
+ * string will be "EMPTY_DATABASE_CREATED@minimal.db".
+ */
+ public String getKey(final String key) {
+ if (TextUtils.equals(getDatabaseName(), LauncherFiles.LAUNCHER_DB)) {
+ return key;
+ }
+ return key + "@" + getDatabaseName();
+ }
+
+ /**
+ * Overridden in tests.
+ */
+ protected void onEmptyDbCreated() {
+ // Set the flag for empty DB
+ LauncherPrefs.getPrefs(mContext).edit().putBoolean(getKey(
+ LauncherProvider.EMPTY_DATABASE_CREATED), true)
+ .commit();
+ }
+
+ public long getSerialNumberForUser(UserHandle user) {
+ return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user);
+ }
+
+ public long getDefaultUserSerial() {
+ return getSerialNumberForUser(Process.myUserHandle());
+ }
+
+ private void addFavoritesTable(SQLiteDatabase db, boolean optional) {
+ Favorites.addTableToDb(db, getDefaultUserSerial(), optional);
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) {
+ super.onOpen(db);
+
+ File schemaFile = mContext.getFileStreamPath(DOWNGRADE_SCHEMA_FILE);
+ if (!schemaFile.exists()) {
+ handleOneTimeDataUpgrade(db);
+ }
+ DbDowngradeHelper.updateSchemaFile(schemaFile, SCHEMA_VERSION, mContext);
+ }
+
+ /**
+ * One-time data updated before support of onDowngrade was added. This update is backwards
+ * compatible and can safely be run multiple times.
+ * Note: No new logic should be added here after release, as the new logic might not get
+ * executed on an existing device.
+ * TODO: Move this to db upgrade path, once the downgrade path is released.
+ */
+ protected void handleOneTimeDataUpgrade(SQLiteDatabase db) {
+ // Remove "profile extra"
+ UserCache um = UserCache.INSTANCE.get(mContext);
+ for (UserHandle user : um.getUserProfiles()) {
+ long serial = um.getSerialNumberForUser(user);
+ String sql = "update favorites set intent = replace(intent, "
+ + "';l.profile=" + serial + ";', ';') where itemType = 0;";
+ db.execSQL(sql);
+ }
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ if (LOGD) {
+ Log.d(TAG, "onUpgrade triggered: " + oldVersion);
+ }
+ switch (oldVersion) {
+ // The version cannot be lower that 12, as Launcher3 never supported a lower
+ // version of the DB.
+ case 12:
+ // No-op
+ case 13: {
+ try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+ // Insert new column for holding widget provider name
+ db.execSQL("ALTER TABLE favorites ADD COLUMN appWidgetProvider TEXT;");
+ t.commit();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ // Old version remains, which means we wipe old data
+ break;
+ }
+ }
+ case 14: {
+ if (!addIntegerColumn(db, Favorites.MODIFIED, 0)) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
+ }
+ case 15: {
+ if (!addIntegerColumn(db, Favorites.RESTORED, 0)) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
+ }
+ case 16:
+ // No-op
+ case 17:
+ // No-op
+ case 18:
+ // No-op
+ case 19: {
+ // Add userId column
+ if (!addIntegerColumn(db, Favorites.PROFILE_ID, getDefaultUserSerial())) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
+ }
+ case 20:
+ if (!updateFolderItemsRank(db, true)) {
+ break;
+ }
+ case 21:
+ // No-op
+ case 22: {
+ if (!addIntegerColumn(db, Favorites.OPTIONS, 0)) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
+ }
+ case 23:
+ // No-op
+ case 24:
+ // No-op
+ case 25:
+ convertShortcutsToLauncherActivities(db);
+ case 26:
+ // QSB was moved to the grid. Ignore overlapping items
+ case 27: {
+ // Update the favorites table so that the screen ids are ordered based on
+ // workspace page rank.
+ IntArray finalScreens = LauncherDbUtils.queryIntArray(false, db,
+ "workspaceScreens", BaseColumns._ID, null, null, "screenRank");
+ int[] original = finalScreens.toArray();
+ Arrays.sort(original);
+ String updatemap = "";
+ for (int i = 0; i < original.length; i++) {
+ if (finalScreens.get(i) != original[i]) {
+ updatemap += String.format(Locale.ENGLISH, " WHEN %1$s=%2$d THEN %3$d",
+ Favorites.SCREEN, finalScreens.get(i), original[i]);
+ }
+ }
+ if (!TextUtils.isEmpty(updatemap)) {
+ String query = String.format(Locale.ENGLISH,
+ "UPDATE %1$s SET %2$s=CASE %3$s ELSE %2$s END WHERE %4$s = %5$d",
+ Favorites.TABLE_NAME, Favorites.SCREEN, updatemap,
+ Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP);
+ db.execSQL(query);
+ }
+ dropTable(db, "workspaceScreens");
+ }
+ case 28: {
+ boolean columnAdded = addIntegerColumn(
+ db, Favorites.APPWIDGET_SOURCE, Favorites.CONTAINER_UNKNOWN);
+ if (!columnAdded) {
+ // Old version remains, which means we wipe old data
+ break;
+ }
+ }
+ case 29: {
+ // Remove widget panel related leftover workspace items
+ db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
+ Favorites.SCREEN, IntArray.wrap(-777, -778)), null);
+ }
+ case 30: {
+ if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
+ // Clean up first row in screen 0 as it might contain junk data.
+ Log.d(TAG, "Cleaning up first row");
+ db.delete(Favorites.TABLE_NAME,
+ String.format(Locale.ENGLISH,
+ "%1$s = %2$d AND %3$s = %4$d AND %5$s = %6$d",
+ Favorites.SCREEN, 0,
+ Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP,
+ Favorites.CELLY, 0), null);
+ }
+ return;
+ }
+ case 31: {
+ LauncherDbUtils.migrateLegacyShortcuts(mContext, db);
+ }
+ // Fall through
+ case 32: {
+ // DB Upgraded successfully
+ return;
+ }
+ }
+
+ // DB was not upgraded
+ Log.w(TAG, "Destroying all old data.");
+ createEmptyDB(db);
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ try {
+ DbDowngradeHelper.parse(mContext.getFileStreamPath(DOWNGRADE_SCHEMA_FILE))
+ .onDowngrade(db, oldVersion, newVersion);
+ } catch (Exception e) {
+ Log.d(TAG, "Unable to downgrade from: " + oldVersion + " to " + newVersion
+ + ". Wiping database.", e);
+ createEmptyDB(db);
+ }
+ }
+
+ /**
+ * Clears all the data for a fresh start.
+ */
+ public void createEmptyDB(SQLiteDatabase db) {
+ try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+ dropTable(db, Favorites.TABLE_NAME);
+ dropTable(db, "workspaceScreens");
+ onCreate(db);
+ t.commit();
+ }
+ }
+
+ /**
+ * Removes widgets which are registered to the Launcher's host, but are not present
+ * in our model.
+ */
+ public void removeGhostWidgets(SQLiteDatabase db) {
+ // Get all existing widget ids.
+ final LauncherWidgetHolder holder = newLauncherWidgetHolder();
+ try {
+ final int[] allWidgets;
+ try {
+ // Although the method was defined in O, it has existed since the beginning of
+ // time, so it might work on older platforms as well.
+ allWidgets = holder.getAppWidgetIds();
+ } catch (IncompatibleClassChangeError e) {
+ Log.e(TAG, "getAppWidgetIds not supported", e);
+ return;
+ }
+ final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db,
+ Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
+ "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null));
+ boolean isAnyWidgetRemoved = false;
+ for (int widgetId : allWidgets) {
+ if (!validWidgets.contains(widgetId)) {
+ try {
+ FileLog.d(TAG, "Deleting invalid widget " + widgetId);
+ holder.deleteAppWidgetId(widgetId);
+ isAnyWidgetRemoved = true;
+ } catch (RuntimeException e) {
+ // Ignore
+ }
+ }
+ }
+ if (isAnyWidgetRemoved) {
+ final String allWidgetsIds = Arrays.stream(allWidgets).mapToObj(String::valueOf)
+ .collect(Collectors.joining(",", "[", "]"));
+ final String validWidgetsIds = Arrays.stream(
+ validWidgets.getArray().toArray()).mapToObj(String::valueOf)
+ .collect(Collectors.joining(",", "[", "]"));
+ FileLog.d(TAG,
+ "One or more widgets was removed. db_path=" + db.getPath()
+ + " allWidgetsIds=" + allWidgetsIds
+ + ", validWidgetsIds=" + validWidgetsIds);
+ }
+ } finally {
+ holder.destroy();
+ }
+ }
+
+ /**
+ * Replaces all shortcuts of type {@link Favorites#ITEM_TYPE_SHORTCUT} which have a valid
+ * launcher activity target with {@link Favorites#ITEM_TYPE_APPLICATION}.
+ */
+ @Thunk
+ void convertShortcutsToLauncherActivities(SQLiteDatabase db) {
+ try (SQLiteTransaction t = new SQLiteTransaction(db);
+ // Only consider the primary user as other users can't have a shortcut.
+ Cursor c = db.query(Favorites.TABLE_NAME,
+ new String[]{Favorites._ID, Favorites.INTENT},
+ "itemType=" + Favorites.ITEM_TYPE_SHORTCUT
+ + " AND profileId=" + getDefaultUserSerial(),
+ null, null, null, null);
+ SQLiteStatement updateStmt = db.compileStatement("UPDATE favorites SET itemType="
+ + Favorites.ITEM_TYPE_APPLICATION + " WHERE _id=?")
+ ) {
+ final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
+ final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT);
+
+ while (c.moveToNext()) {
+ String intentDescription = c.getString(intentIndex);
+ Intent intent;
+ try {
+ intent = Intent.parseUri(intentDescription, 0);
+ } catch (URISyntaxException e) {
+ Log.e(TAG, "Unable to parse intent", e);
+ continue;
+ }
+
+ if (!PackageManagerHelper.isLauncherAppTarget(intent)) {
+ continue;
+ }
+
+ int id = c.getInt(idIndex);
+ updateStmt.bindLong(1, id);
+ updateStmt.executeUpdateDelete();
+ }
+ t.commit();
+ } catch (SQLException ex) {
+ Log.w(TAG, "Error deduping shortcuts", ex);
+ }
+ }
+
+ @Thunk
+ boolean updateFolderItemsRank(SQLiteDatabase db, boolean addRankColumn) {
+ try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+ if (addRankColumn) {
+ // Insert new column for holding rank
+ db.execSQL("ALTER TABLE favorites ADD COLUMN rank INTEGER NOT NULL DEFAULT 0;");
+ }
+
+ // Get a map for folder ID to folder width
+ Cursor c = db.rawQuery("SELECT container, MAX(cellX) FROM favorites"
+ + " WHERE container IN (SELECT _id FROM favorites WHERE itemType = ?)"
+ + " GROUP BY container;",
+ new String[]{Integer.toString(Favorites.ITEM_TYPE_FOLDER)});
+
+ while (c.moveToNext()) {
+ db.execSQL("UPDATE favorites SET rank=cellX+(cellY*?) WHERE "
+ + "container=? AND cellX IS NOT NULL AND cellY IS NOT NULL;",
+ new Object[]{c.getLong(1) + 1, c.getLong(0)});
+ }
+
+ c.close();
+ t.commit();
+ } catch (SQLException ex) {
+ // Old version remains, which means we wipe old data
+ Log.e(TAG, ex.getMessage(), ex);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean addIntegerColumn(SQLiteDatabase db, String columnName, long defaultValue) {
+ try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+ db.execSQL("ALTER TABLE favorites ADD COLUMN "
+ + columnName + " INTEGER NOT NULL DEFAULT " + defaultValue + ";");
+ t.commit();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ return false;
+ }
+ return true;
+ }
+
+ // Generates a new ID to use for an object in your database. This method should be only
+ // called from the main UI thread. As an exception, we do call it when we call the
+ // constructor from the worker thread; however, this doesn't extend until after the
+ // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
+ // after that point
+ @Override
+ public int generateNewItemId() {
+ if (mMaxItemId < 0) {
+ throw new RuntimeException("Error: max item id was not initialized");
+ }
+ mMaxItemId += 1;
+ return mMaxItemId;
+ }
+
+ /**
+ * @return A new {@link LauncherWidgetHolder} based on the current context
+ */
+ @NonNull
+ public LauncherWidgetHolder newLauncherWidgetHolder() {
+ return LauncherWidgetHolder.newInstance(mContext);
+ }
+
+ @Override
+ public int insertAndCheck(SQLiteDatabase db, ContentValues values) {
+ return dbInsertAndCheck(db, Favorites.TABLE_NAME, values);
+ }
+
+ public int dbInsertAndCheck(SQLiteDatabase db, String table, ContentValues values) {
+ if (values == null) {
+ throw new RuntimeException("Error: attempting to insert null values");
+ }
+ if (!values.containsKey(LauncherSettings.Favorites._ID)) {
+ throw new RuntimeException("Error: attempting to add item without specifying an id");
+ }
+ checkId(values);
+ return (int) db.insert(table, null, values);
+ }
+
+ public void checkId(ContentValues values) {
+ int id = values.getAsInteger(Favorites._ID);
+ mMaxItemId = Math.max(id, mMaxItemId);
+ }
+
+ private int initializeMaxItemId(SQLiteDatabase db) {
+ return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s", Favorites._ID,
+ Favorites.TABLE_NAME);
+ }
+
+ /**
+ * Returns a new ID to use for a workspace screen in your database that is greater than all
+ * existing screen IDs
+ */
+ public int getNewScreenId() {
+ return getMaxId(getWritableDatabase(),
+ "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
+ Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
+ Favorites.CONTAINER_DESKTOP) + 1;
+ }
+
+ public int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
+ // TODO: Use multiple loaders with fall-back and transaction.
+ int count = loader.loadLayout(db, new IntArray());
+
+ // Ensure that the max ids are initialized
+ mMaxItemId = initializeMaxItemId(db);
+ return count;
+ }
+
+ /**
+ * @return the max _id in the provided table.
+ */
+ private static int getMaxId(SQLiteDatabase db, String query, Object... args) {
+ int max = 0;
+ try (SQLiteStatement prog = db.compileStatement(
+ String.format(Locale.ENGLISH, query, args))) {
+ max = (int) DatabaseUtils.longForQuery(prog, null);
+ if (max < 0) {
+ throw new RuntimeException("Error: could not query max id");
+ }
+ } catch (IllegalArgumentException exception) {
+ String message = exception.getMessage();
+ if (message.contains("re-open") && message.contains("already-closed")) {
+ // Don't crash trying to end a transaction an an already closed DB. See b/173162852.
+ } else {
+ throw exception;
+ }
+ }
+ return max;
+ }
+}
diff --git a/src/com/android/launcher3/model/DbDowngradeHelper.java b/src/com/android/launcher3/model/DbDowngradeHelper.java
index e5c44d1..006a9b7 100644
--- a/src/com/android/launcher3/model/DbDowngradeHelper.java
+++ b/src/com/android/launcher3/model/DbDowngradeHelper.java
@@ -72,8 +72,18 @@
}
}
+ /**
+ * Creates a helper from the provided file
+ */
public static DbDowngradeHelper parse(File file) throws JSONException, IOException {
- JSONObject obj = new JSONObject(new String(IOUtils.toByteArray(file)));
+ return parse(IOUtils.toByteArray(file));
+ }
+
+ /**
+ * Creates a helper from the provided bytes
+ */
+ public static DbDowngradeHelper parse(byte[] fileData) throws JSONException {
+ JSONObject obj = new JSONObject(new String(fileData));
DbDowngradeHelper helper = new DbDowngradeHelper(obj.getInt(KEY_VERSION));
for (int version = helper.version - 1; version > 0; version--) {
if (obj.has(KEY_DOWNGRADE_TO + version)) {
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 855a69d..c237f5b 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -75,8 +75,6 @@
private final IntArray mRestoredRows = new IntArray();
private final IntSparseArrayMap<GridOccupancy> mOccupied = new IntSparseArrayMap<>();
- private final int mIconPackageIndex;
- private final int mIconResourceIndex;
private final int mIconIndex;
public final int mTitleIndex;
@@ -122,8 +120,6 @@
// Init column indices
mIconIndex = getColumnIndexOrThrow(Favorites.ICON);
- mIconPackageIndex = getColumnIndexOrThrow(Favorites.ICON_PACKAGE);
- mIconResourceIndex = getColumnIndexOrThrow(Favorites.ICON_RESOURCE);
mTitleIndex = getColumnIndexOrThrow(Favorites.TITLE);
mIdIndex = getColumnIndexOrThrow(Favorites._ID);
@@ -200,23 +196,25 @@
public IconRequestInfo<WorkspaceItemInfo> createIconRequestInfo(
WorkspaceItemInfo wai, boolean useLowResIcon) {
- String packageName = itemType == Favorites.ITEM_TYPE_SHORTCUT
- ? getString(mIconPackageIndex) : null;
- String resourceName = itemType == Favorites.ITEM_TYPE_SHORTCUT
- ? getString(mIconResourceIndex) : null;
byte[] iconBlob = itemType == Favorites.ITEM_TYPE_SHORTCUT
|| itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
|| restoreFlag != 0
- ? getBlob(mIconIndex) : null;
+ ? getIconBlob() : null;
- return new IconRequestInfo<>(
- wai, mActivityInfo, packageName, resourceName, iconBlob, useLowResIcon);
+ return new IconRequestInfo<>(wai, mActivityInfo, iconBlob, useLowResIcon);
+ }
+
+ /**
+ * Returns the icon data for at the current position
+ */
+ public byte[] getIconBlob() {
+ return getBlob(mIconIndex);
}
/**
* Returns the title or empty string
*/
- private String getTitle() {
+ public String getTitle() {
return Utilities.trim(getString(mTitleIndex));
}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 38a112e..481cc6e 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -138,6 +138,7 @@
private final UserManagerState mUserManagerState = new UserManagerState();
protected final Map<ComponentKey, AppWidgetProviderInfo> mWidgetProvidersMap = new ArrayMap<>();
+ private Map<ShortcutKey, ShortcutInfo> mShortcutKeyToPinnedShortcuts;
private boolean mStopped;
@@ -211,6 +212,14 @@
}
logASplit(timingLogger, "loadWorkspace");
+ if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ verifyNotStopped();
+ mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState,
+ mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
+ mModelDelegate.markActive();
+ logASplit(timingLogger, "workspaceDelegateItems");
+ }
+
// Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
// sanitizeData should not be invoked if the workspace is loaded from a db different
// from the main db as defined in the invariant device profile.
@@ -246,6 +255,11 @@
}
logASplit(timingLogger, "loadAllApps");
+ if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ mModelDelegate.loadAndBindAllAppsItems(mUserManagerState,
+ mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
+ logASplit(timingLogger, "allAppsDelegateItems");
+ }
verifyNotStopped();
mLauncherBinder.bindAllApps();
logASplit(timingLogger, "bindAllApps");
@@ -296,6 +310,12 @@
logASplit(timingLogger, "bindWidgets");
verifyNotStopped();
+ if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList);
+ logASplit(timingLogger, "otherDelegateItems");
+ verifyNotStopped();
+ }
+
updateHandler.updateIcons(allWidgetsList,
new ComponentWithIconCachingLogic(mApp.getContext(), true),
mApp.getModel()::onWidgetLabelsUpdated);
@@ -334,9 +354,14 @@
null /* selection */, memoryLogger);
}
- protected void loadWorkspace(
+ protected void loadWorkspaceForPreviewSurfaceRenderer(
List<ShortcutInfo> allDeepShortcuts, Uri contentUri, String selection) {
loadWorkspace(allDeepShortcuts, contentUri, selection, null);
+ if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState,
+ mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
+ mModelDelegate.markActive();
+ }
}
protected void loadWorkspace(
@@ -376,7 +401,7 @@
final PackageUserKey tempPackageKey = new PackageUserKey(null, null);
mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
- Map<ShortcutKey, ShortcutInfo> shortcutKeyToPinnedShortcuts = new HashMap<>();
+ mShortcutKeyToPinnedShortcuts = new HashMap<>();
final LoaderCursor c = new LoaderCursor(
contentResolver.query(contentUri, null, selection, null, null), contentUri,
mApp, mUserManagerState);
@@ -397,7 +422,7 @@
.query(ShortcutRequest.PINNED);
if (pinnedShortcuts.wasSuccess()) {
for (ShortcutInfo shortcut : pinnedShortcuts) {
- shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
+ mShortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
shortcut);
}
} else {
@@ -414,7 +439,7 @@
while (!mStopped && c.moveToNext()) {
processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady,
- tempPackageKey, widgetHelper, pmHelper, shortcutKeyToPinnedShortcuts,
+ tempPackageKey, widgetHelper, pmHelper,
iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts);
}
tryLoadWorkspaceIconsInBulk(iconRequestInfos);
@@ -422,14 +447,14 @@
IOUtils.closeSilently(c);
}
- // Load delegate items
- mModelDelegate.loadHotseatItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
- mModelDelegate.loadAllAppsItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
- mModelDelegate.loadWidgetsRecommendationItems();
- mModelDelegate.markActive();
-
- // Load string cache
- mModelDelegate.loadStringCache(mBgDataModel.stringCache);
+ if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
+ mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState,
+ mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
+ mModelDelegate.loadAndBindAllAppsItems(mUserManagerState,
+ mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
+ mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList);
+ mModelDelegate.markActive();
+ }
// Break early if we've stopped loading
if (mStopped) {
@@ -474,7 +499,6 @@
PackageUserKey tempPackageKey,
WidgetManagerHelper widgetHelper,
PackageManagerHelper pmHelper,
- Map<ShortcutKey, ShortcutInfo> shortcutKeyToPinnedShortcuts,
List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos,
LongSparseArray<Boolean> unlockedUsers,
boolean isSafeMode,
@@ -603,7 +627,7 @@
} else if (c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
if (unlockedUsers.get(c.serialNumber)) {
- ShortcutInfo pinnedShortcut = shortcutKeyToPinnedShortcuts.get(key);
+ ShortcutInfo pinnedShortcut = mShortcutKeyToPinnedShortcuts.get(key);
if (pinnedShortcut == null) {
// The shortcut is no longer valid.
c.markDeleted("Pinned shortcut not found");
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 0639a6c..7e7bfb3 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.pm.ShortcutInfo;
+import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import com.android.launcher3.LauncherAppState;
@@ -68,9 +69,7 @@
this.mContext = context;
}
- /**
- * Called periodically to validate and update any data
- */
+ /** Called periodically to validate and update any data */
@WorkerThread
public void validateData() {
if (hasShortcutsPermission(mApp.getContext())
@@ -79,36 +78,32 @@
}
}
- /**
- * Load hot seat items if any in the data model
- */
+ /** Load workspace items (for example, those in the hot seat) if any in the data model */
@WorkerThread
- public void loadHotseatItems(UserManagerState ums,
- Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+ public void loadAndBindWorkspaceItems(@NonNull UserManagerState ums,
+ @NonNull BgDataModel.Callbacks[] callbacks,
+ @NonNull Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
- /**
- * Load all apps items if any in the data model
- */
+ /** Load all apps items if any in the data model */
@WorkerThread
- public void loadAllAppsItems(UserManagerState ums,
- Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+ public void loadAndBindAllAppsItems(@NonNull UserManagerState ums,
+ @NonNull BgDataModel.Callbacks[] callbacks,
+ @NonNull Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
- /**
- * Load widget recommendation items if any in the data model
- */
+ /** Load other items like widget recommendations if any in the data model */
@WorkerThread
- public void loadWidgetsRecommendationItems() { }
+ public void loadAndBindOtherItems(@NonNull BgDataModel.Callbacks[] callbacks) { }
- /**
- * Marks the ModelDelegate as active
- */
+ /** binds everything not bound by launcherBinder */
+ @WorkerThread
+ public void bindAllModelExtras(@NonNull BgDataModel.Callbacks[] callbacks) { }
+
+ /** Marks the ModelDelegate as active */
public void markActive() { }
- /**
- * Load String cache
- */
+ /** Load String cache */
@WorkerThread
- public void loadStringCache(StringCache cache) {
+ public void loadStringCache(@NonNull StringCache cache) {
cache.loadStrings(mContext);
}
diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java
index c21fc38..48fb537 100644
--- a/src/com/android/launcher3/model/ModelUtils.java
+++ b/src/com/android/launcher3/model/ModelUtils.java
@@ -15,18 +15,10 @@
*/
package com.android.launcher3.model;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.Process;
import android.util.Log;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -99,60 +91,4 @@
IntStream.range(0, len).filter(i -> !seen.contains(i)).forEach(result::add);
return result;
}
-
-
- /**
- * Creates a workspace item info for the legacy shortcut intent
- */
- @SuppressWarnings("deprecation")
- public static WorkspaceItemInfo fromLegacyShortcutIntent(Context context, Intent data) {
- if (!isValidExtraType(data, Intent.EXTRA_SHORTCUT_INTENT, Intent.class)
- || !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
- Intent.ShortcutIconResource.class))
- || !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON, Bitmap.class))) {
-
- Log.e(TAG, "Invalid install shortcut intent");
- return null;
- }
-
- Intent launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
- String label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
- if (launchIntent == null || label == null) {
- Log.e(TAG, "Invalid install shortcut intent");
- return null;
- }
-
- final WorkspaceItemInfo info = new WorkspaceItemInfo();
- info.user = Process.myUserHandle();
-
- BitmapInfo iconInfo = null;
- try (LauncherIcons li = LauncherIcons.obtain(context)) {
- Bitmap bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
- if (bitmap != null) {
- iconInfo = li.createIconBitmap(bitmap);
- } else {
- info.iconResource = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
- if (info.iconResource != null) {
- iconInfo = li.createIconBitmap(info.iconResource);
- }
- }
- }
-
- if (iconInfo == null) {
- Log.e(TAG, "Invalid icon by the app");
- return null;
- }
- info.bitmap = iconInfo;
- info.contentDescription = info.title = Utilities.trim(label);
- info.intent = launchIntent;
- return info;
- }
-
- /**
- * @return true if the extra is either null or is of type {@param type}
- */
- private static boolean isValidExtraType(Intent intent, String key, Class type) {
- Object extra = intent.getParcelableExtra(key);
- return extra == null || type.isInstance(extra);
- }
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 3d9d81f..1ab64df 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -36,9 +36,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -204,18 +202,6 @@
boolean infoUpdated = false;
boolean shortcutUpdated = false;
- // Update shortcuts which use iconResource.
- if ((si.iconResource != null)
- && packageSet.contains(si.iconResource.packageName)) {
- LauncherIcons li = LauncherIcons.obtain(context);
- BitmapInfo iconInfo = li.createIconBitmap(si.iconResource);
- li.recycle();
- if (iconInfo != null) {
- si.bitmap = iconInfo;
- infoUpdated = true;
- }
- }
-
ComponentName cn = si.getTargetComponent();
if (cn != null && matcher.test(si)) {
String packageName = cn.getPackageName();
diff --git a/src/com/android/launcher3/model/data/IconRequestInfo.java b/src/com/android/launcher3/model/data/IconRequestInfo.java
index fbf01e5..e77e527 100644
--- a/src/com/android/launcher3/model/data/IconRequestInfo.java
+++ b/src/com/android/launcher3/model/data/IconRequestInfo.java
@@ -18,16 +18,12 @@
import static android.graphics.BitmapFactory.decodeByteArray;
import android.content.Context;
-import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
-import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.LauncherIcons;
/**
@@ -42,8 +38,6 @@
@NonNull public final T itemInfo;
@Nullable public final LauncherActivityInfo launcherActivityInfo;
- @Nullable public final String packageName;
- @Nullable public final String resourceName;
@Nullable public final byte[] iconBlob;
public final boolean useLowResIcon;
@@ -54,8 +48,6 @@
this(
itemInfo,
launcherActivityInfo,
- /* packageName= */ null,
- /* resourceName= */ null,
/* iconBlob= */ null,
useLowResIcon);
}
@@ -63,14 +55,10 @@
public IconRequestInfo(
@NonNull T itemInfo,
@Nullable LauncherActivityInfo launcherActivityInfo,
- @Nullable String packageName,
- @Nullable String resourceName,
@Nullable byte[] iconBlob,
boolean useLowResIcon) {
this.itemInfo = itemInfo;
this.launcherActivityInfo = launcherActivityInfo;
- this.packageName = packageName;
- this.resourceName = resourceName;
this.iconBlob = iconBlob;
this.useLowResIcon = useLowResIcon;
}
@@ -87,31 +75,16 @@
try (LauncherIcons li = LauncherIcons.obtain(context)) {
WorkspaceItemInfo info = (WorkspaceItemInfo) itemInfo;
- if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
- if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
- info.iconResource = new Intent.ShortcutIconResource();
- info.iconResource.packageName = packageName;
- info.iconResource.resourceName = resourceName;
- BitmapInfo iconInfo = li.createIconBitmap(info.iconResource);
- if (iconInfo != null) {
- info.bitmap = iconInfo;
- return true;
- }
- }
- }
-
// Failed to load from resource, try loading from DB.
- try {
- if (iconBlob == null) {
- return false;
- }
- info.bitmap = li.createIconBitmap(decodeByteArray(
- iconBlob, 0, iconBlob.length));
- return true;
- } catch (Exception e) {
- Log.e(TAG, "Failed to decode byte array for info " + info, e);
+ if (iconBlob == null) {
return false;
}
+ info.bitmap = li.createIconBitmap(decodeByteArray(
+ iconBlob, 0, iconBlob.length));
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to decode byte array for info " + itemInfo, e);
+ return false;
}
}
}
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 59ef320..01606d4 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -79,12 +79,6 @@
public Intent intent;
/**
- * If isShortcut=true and customIcon=false, this contains a reference to the
- * shortcut icon as an application's resource.
- */
- public Intent.ShortcutIconResource iconResource;
-
- /**
* A message to display when the user tries to start a disabled shortcut.
* This is currently only used for deep shortcuts.
*/
@@ -109,7 +103,6 @@
super(info);
title = info.title;
intent = new Intent(info.intent);
- iconResource = info.iconResource;
status = info.status;
personKeys = info.personKeys.clone();
}
@@ -141,10 +134,6 @@
if (!usingLowResIcon()) {
writer.putIcon(bitmap, user);
}
- if (iconResource != null) {
- writer.put(Favorites.ICON_PACKAGE, iconResource.packageName)
- .put(Favorites.ICON_RESOURCE, iconResource.resourceName);
- }
}
@Override
diff --git a/src/com/android/launcher3/pm/PinRequestHelper.java b/src/com/android/launcher3/pm/PinRequestHelper.java
index 179061f..667136a 100644
--- a/src/com/android/launcher3/pm/PinRequestHelper.java
+++ b/src/com/android/launcher3/pm/PinRequestHelper.java
@@ -24,8 +24,10 @@
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.PinItemRequest;
import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
import android.os.Build;
import android.os.Parcelable;
+import android.os.SystemClock;
import androidx.annotation.Nullable;
@@ -63,17 +65,10 @@
}
} else {
// Block the worker thread until the accept() is called.
- MODEL_EXECUTOR.execute(new Runnable() {
- @Override
- public void run() {
- try {
- Thread.sleep(acceptDelay);
- } catch (InterruptedException e) {
- // Ignore
- }
- if (request.isValid()) {
- request.accept();
- }
+ MODEL_EXECUTOR.execute(() -> {
+ SystemClock.sleep(acceptDelay);
+ if (request.isValid()) {
+ request.accept();
}
});
}
@@ -95,4 +90,13 @@
Parcelable extra = intent.getParcelableExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST);
return extra instanceof PinItemRequest ? (PinItemRequest) extra : null;
}
+
+ /**
+ * Returns a PinItemRequest corresponding to the provided ShortcutInfo
+ */
+ public static PinItemRequest createRequestForShortcut(Context context, ShortcutInfo info) {
+ return context.getSystemService(LauncherApps.class)
+ .getPinItemRequest(context.getSystemService(ShortcutManager.class)
+ .createShortcutResultIntent(info));
+ }
}
diff --git a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
index 14e67b2..b24ee34 100644
--- a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
@@ -151,8 +151,6 @@
public static List<ShortcutConfigActivityInfo> queryList(
Context context, @Nullable PackageUserKey packageUser) {
List<ShortcutConfigActivityInfo> result = new ArrayList<>();
- UserHandle myUser = Process.myUserHandle();
-
final List<UserHandle> users;
final String packageName;
if (packageUser == null) {
@@ -164,11 +162,9 @@
}
LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
for (UserHandle user : users) {
- boolean ignoreTargetSdk = myUser.equals(user);
for (LauncherActivityInfo activityInfo :
launcherApps.getShortcutConfigActivityList(packageName, user)) {
- if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion
- >= Build.VERSION_CODES.O) {
+ if (activityInfo.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
result.add(new ShortcutConfigActivityInfoVO(activityInfo));
}
}
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index b510378..48969fc 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -16,15 +16,34 @@
package com.android.launcher3.provider;
+import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE;
+
+import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
import android.os.Binder;
+import android.os.PersistableBundle;
import android.os.Process;
+import android.os.UserManager;
+import android.text.TextUtils;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.model.LoaderCursor;
+import com.android.launcher3.model.UserManagerState;
+import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
/**
* A set of utility methods for Launcher DB used for DB updates and migration.
@@ -73,6 +92,78 @@
}
/**
+ * Migrates the legacy shortcuts to deep shortcuts pinned under Launcher.
+ * Removes any invalid shortcut or any shortcut which requires some permission to launch
+ */
+ public static void migrateLegacyShortcuts(Context context, SQLiteDatabase db) {
+ Cursor c = db.query(
+ Favorites.TABLE_NAME, null, "itemType = 1", null, null, null, null);
+ UserManagerState ums = new UserManagerState();
+ ums.init(UserCache.INSTANCE.get(context),
+ context.getSystemService(UserManager.class));
+ LoaderCursor lc = new LoaderCursor(c, null, LauncherAppState.getInstance(context), ums);
+ IntSet deletedShortcuts = new IntSet();
+
+ while (lc.moveToNext()) {
+ if (lc.user != Process.myUserHandle()) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+ Intent intent = lc.parseIntent();
+ if (intent == null) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+
+ // Make sure the target intent can be launched without any permissions. Otherwise remove
+ // the shortcut
+ ResolveInfo ri = context.getPackageManager().resolveActivity(intent, 0);
+ if (ri == null || !TextUtils.isEmpty(ri.activityInfo.permission)) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+ PersistableBundle extras = new PersistableBundle();
+ extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, ri.activityInfo.packageName);
+ ShortcutInfo.Builder infoBuilder = new ShortcutInfo.Builder(
+ context, "migrated_shortcut-" + lc.id)
+ .setIntent(intent)
+ .setExtras(extras)
+ .setShortLabel(lc.getTitle());
+
+ Bitmap bitmap = null;
+ byte[] iconData = lc.getIconBlob();
+ if (iconData != null) {
+ bitmap = BitmapFactory.decodeByteArray(iconData, 0, iconData.length);
+ }
+ if (bitmap != null) {
+ infoBuilder.setIcon(Icon.createWithBitmap(bitmap));
+ }
+
+ ShortcutInfo info = infoBuilder.build();
+ if (!PinRequestHelper.createRequestForShortcut(context, info).accept()) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+ ContentValues update = new ContentValues();
+ update.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_DEEP_SHORTCUT);
+ update.put(Favorites.INTENT,
+ ShortcutKey.makeIntent(info.getId(), context.getPackageName()).toUri(0));
+ db.update(Favorites.TABLE_NAME, update, "_id = ?",
+ new String[] {Integer.toString(lc.id)});
+ }
+ lc.close();
+ if (!deletedShortcuts.isEmpty()) {
+ db.delete(Favorites.TABLE_NAME,
+ Utilities.createDbSelectionQuery(Favorites._ID, deletedShortcuts.getArray()),
+ null);
+ }
+
+ // Drop the unused columns
+ db.execSQL("ALTER TABLE " + Favorites.TABLE_NAME + " DROP COLUMN iconPackage;");
+ db.execSQL("ALTER TABLE " + Favorites.TABLE_NAME + " DROP COLUMN iconResource;");
+ }
+
+ /**
* Utility class to simplify managing sqlite transactions
*/
public static class SQLiteTransaction extends Binder implements AutoCloseable {
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 6450c8e..c4eb14f 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -44,10 +44,10 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.LauncherProvider.DatabaseHelper;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.model.DatabaseHelper;
import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.model.GridBackupTable;
import com.android.launcher3.model.data.AppInfo;
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index f5d511c..3286afb 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.states;
-import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import android.content.Context;
@@ -45,11 +44,6 @@
@Override
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
-
- if (SHOW_HOME_GARDENING.get()) {
- return super.getWorkspaceScaleAndTranslation(launcher);
- }
-
DeviceProfile grid = launcher.getDeviceProfile();
Workspace<?> ws = launcher.getWorkspace();
if (ws.getChildCount() == 0) {
@@ -68,9 +62,6 @@
@Override
protected float getDepthUnchecked(Context context) {
- if (SHOW_HOME_GARDENING.get()) {
- return 0;
- }
return 0.5f;
}
@@ -81,10 +72,6 @@
@Override
public float getWorkspaceBackgroundAlpha(Launcher launcher) {
- if (SHOW_HOME_GARDENING.get()) {
- return 0;
- }
-
return 0.2f;
}
}
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index c146216..6573691 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -41,7 +41,6 @@
public static final String SEARCH_KEYBOARD_EDU_SEEN = "launcher.search_edu_seen";
public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
public static final String SEARCH_ONBOARDING_COUNT = "launcher.search_onboarding_count";
- public static final String TASKBAR_EDU_SEEN = "launcher.taskbar_edu_seen2";
public static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
public static final String QSB_SEARCH_ONBOARDING_CARD_DISMISSED = "launcher.qsb_edu_dismiss";
public static final String TASKBAR_EDU_TOOLTIP_STEP = "launcher.taskbar_edu_tooltip_step";
@@ -52,7 +51,7 @@
HOTSEAT_LONGPRESS_TIP_SEEN },
"Search Education", new String[] { SEARCH_KEYBOARD_EDU_SEEN, SEARCH_SNACKBAR_COUNT,
SEARCH_ONBOARDING_COUNT, QSB_SEARCH_ONBOARDING_CARD_DISMISSED},
- "Taskbar Education", new String[] { TASKBAR_EDU_SEEN, TASKBAR_EDU_TOOLTIP_STEP },
+ "Taskbar Education", new String[] { TASKBAR_EDU_TOOLTIP_STEP },
"All Apps Visited Count", new String[] {ALL_APPS_VISITED_COUNT}
);
@@ -63,7 +62,6 @@
HOME_BOUNCE_SEEN,
HOTSEAT_LONGPRESS_TIP_SEEN,
SEARCH_KEYBOARD_EDU_SEEN,
- TASKBAR_EDU_SEEN,
QSB_SEARCH_ONBOARDING_CARD_DISMISSED
})
@Retention(RetentionPolicy.SOURCE)
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index a6a2751..1d6bc25 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -16,7 +16,6 @@
package com.android.launcher3.util;
-import android.app.AppOpsManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -30,7 +29,6 @@
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -139,48 +137,6 @@
return (info.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
}
- /**
- * Returns true if {@param srcPackage} has the permission required to start the activity from
- * {@param intent}. If {@param srcPackage} is null, then the activity should not need
- * any permissions
- */
- public boolean hasPermissionForActivity(Intent intent, String srcPackage) {
- ResolveInfo target = mPm.resolveActivity(intent, 0);
- if (target == null) {
- // Not a valid target
- return false;
- }
- if (TextUtils.isEmpty(target.activityInfo.permission)) {
- // No permission is needed
- return true;
- }
- if (TextUtils.isEmpty(srcPackage)) {
- // The activity requires some permission but there is no source.
- return false;
- }
-
- // Source does not have sufficient permissions.
- if(mPm.checkPermission(target.activityInfo.permission, srcPackage) !=
- PackageManager.PERMISSION_GRANTED) {
- return false;
- }
-
- // On M and above also check AppOpsManager for compatibility mode permissions.
- if (TextUtils.isEmpty(AppOpsManager.permissionToOp(target.activityInfo.permission))) {
- // There is no app-op for this permission, which could have been disabled.
- return true;
- }
-
- // There is no direct way to check if the app-op is allowed for a particular app. Since
- // app-op is only enabled for apps running in compatibility mode, simply block such apps.
-
- try {
- return mPm.getApplicationInfo(srcPackage, 0).targetSdkVersion >= Build.VERSION_CODES.M;
- } catch (NameNotFoundException e) { }
-
- return false;
- }
-
public Intent getMarketIntent(String packageName) {
return new Intent(Intent.ACTION_VIEW)
.setData(new Uri.Builder()
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index a6744fb..79d4df0 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -437,9 +437,7 @@
StrictMode.setVmPolicy(oldPolicy);
}
} catch (SecurityException e) {
- if (!onErrorStartingShortcut(intent, info)) {
- throw e;
- }
+ throw e;
}
}
@@ -459,16 +457,6 @@
}
}
- /**
- * Invoked when a shortcut fails to launch.
- * @param intent Shortcut intent that failed to start.
- * @param info Shortcut information.
- * @return {@code true} if the error is handled by this callback.
- */
- default boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
- return false;
- }
-
default CellPosMapper getCellPosMapper() {
return CellPosMapper.DEFAULT;
}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index c3f26fa..4d38464 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -198,7 +198,9 @@
int widthUsed;
if (deviceProfile.isTablet) {
int margin = deviceProfile.allAppsLeftRightMargin;
- if (deviceProfile.isLandscape && LARGE_SCREEN_WIDGET_PICKER.get()) {
+ if (deviceProfile.isLandscape
+ && LARGE_SCREEN_WIDGET_PICKER.get()
+ && !deviceProfile.isTwoPanels) {
margin = getResources().getDimensionPixelSize(
R.dimen.widget_picker_landscape_tablet_left_right_margin);
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 5e165df..49f3fe9 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -183,7 +183,7 @@
super(context, attrs, defStyleAttr);
mDeviceProfile = Launcher.getLauncher(context).getDeviceProfile();
mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
- mOrientation = Launcher.getLauncher(context).getOrientation();
+ mOrientation = context.getResources().getConfiguration().orientation;
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
mAdapters.put(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
@@ -799,7 +799,8 @@
// Checks the orientation of the screen
if (LARGE_SCREEN_WIDGET_PICKER.get()
&& mOrientation != newConfig.orientation
- && mDeviceProfile.isTablet) {
+ && mDeviceProfile.isTablet
+ && !mDeviceProfile.isTwoPanels) {
mOrientation = newConfig.orientation;
handleClose(false);
show(Launcher.getLauncher(getContext()), false);
diff --git a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
index d849c8f..0a1a9ba 100644
--- a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
+++ b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java
@@ -37,8 +37,6 @@
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.launcher3.LauncherProvider;
-import com.android.launcher3.LauncherProvider.DatabaseHelper;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
@@ -74,7 +72,7 @@
mSchemaFile.delete();
assertFalse(mSchemaFile.exists());
DbDowngradeHelper.updateSchemaFile(mSchemaFile, 0, mContext);
- assertEquals(LauncherProvider.SCHEMA_VERSION, DbDowngradeHelper.parse(mSchemaFile).version);
+ assertEquals(DatabaseHelper.SCHEMA_VERSION, DbDowngradeHelper.parse(mSchemaFile).version);
}
@Test
@@ -111,6 +109,21 @@
}
@Test
+ public void testDowngrade_success_v31() throws Exception {
+ setupTestDb();
+
+ try (SQLiteOpenHelper helper = new MyDatabaseHelper()) {
+ assertFalse(hasFavoritesColumn(helper.getWritableDatabase(), "iconPackage"));
+ assertFalse(hasFavoritesColumn(helper.getWritableDatabase(), "iconResource"));
+ }
+
+ try (TestOpenHelper helper = new TestOpenHelper(24)) {
+ assertTrue(hasFavoritesColumn(helper.getWritableDatabase(), "iconPackage"));
+ assertTrue(hasFavoritesColumn(helper.getWritableDatabase(), "iconResource"));
+ }
+ }
+
+ @Test
public void testDowngrade_success_v24() throws Exception {
setupTestDb();
@@ -123,34 +136,18 @@
public void testDowngrade_success_v22() throws Exception {
setupTestDb();
- SQLiteOpenHelper helper = new TestOpenHelper(22);
- assertEquals(22, helper.getWritableDatabase().getVersion());
-
- // Check column does not exist
- try (Cursor c = helper.getWritableDatabase().query(Favorites.TABLE_NAME,
- null, null, null, null, null, null)) {
- assertEquals(-1, c.getColumnIndex(Favorites.OPTIONS));
-
- // Check data is present
- assertEquals(10, c.getCount());
+ try (SQLiteOpenHelper helper = new TestOpenHelper(22)) {
+ assertEquals(22, helper.getWritableDatabase().getVersion());
+ assertFalse(hasFavoritesColumn(helper.getWritableDatabase(), Favorites.OPTIONS));
+ assertEquals(10, getFavoriteDataCount(helper.getWritableDatabase()));
}
- helper.close();
- helper = new DatabaseHelper(mContext, DB_FILE, false) {
- @Override
- public void onOpen(SQLiteDatabase db) { }
- };
- assertEquals(LauncherProvider.SCHEMA_VERSION, helper.getWritableDatabase().getVersion());
-
- try (Cursor c = helper.getWritableDatabase().query(Favorites.TABLE_NAME,
- null, null, null, null, null, null)) {
- // Check column exists
- assertNotSame(-1, c.getColumnIndex(Favorites.OPTIONS));
-
- // Check data is present
- assertEquals(10, c.getCount());
+ try (SQLiteOpenHelper helper = new MyDatabaseHelper()) {
+ assertEquals(DatabaseHelper.SCHEMA_VERSION,
+ helper.getWritableDatabase().getVersion());
+ assertTrue(hasFavoritesColumn(helper.getWritableDatabase(), Favorites.OPTIONS));
+ assertEquals(10, getFavoriteDataCount(helper.getWritableDatabase()));
}
- helper.close();
}
@Test(expected = DowngradeFailException.class)
@@ -165,12 +162,9 @@
mSchemaFile.delete();
mDbFile.delete();
- DbDowngradeHelper.updateSchemaFile(mSchemaFile, LauncherProvider.SCHEMA_VERSION, mContext);
+ DbDowngradeHelper.updateSchemaFile(mSchemaFile, DatabaseHelper.SCHEMA_VERSION, mContext);
- DatabaseHelper dbHelper = new DatabaseHelper(mContext, DB_FILE, false) {
- @Override
- public void onOpen(SQLiteDatabase db) { }
- };
+ DatabaseHelper dbHelper = new MyDatabaseHelper();
// Insert mock data
for (int i = 0; i < 10; i++) {
ContentValues values = new ContentValues();
@@ -212,4 +206,26 @@
super(e);
}
}
+
+ private static boolean hasFavoritesColumn(SQLiteDatabase db, String columnName) {
+ try (Cursor c = db.query(Favorites.TABLE_NAME, null, null, null, null, null, null)) {
+ return c.getColumnIndex(columnName) >= 0;
+ }
+ }
+
+ public static int getFavoriteDataCount(SQLiteDatabase db) {
+ try (Cursor c = db.query(Favorites.TABLE_NAME, null, null, null, null, null, null)) {
+ return c.getCount();
+ }
+ }
+
+ private class MyDatabaseHelper extends DatabaseHelper {
+
+ MyDatabaseHelper() {
+ super(mContext, DB_FILE, false);
+ }
+
+ @Override
+ public void onOpen(SQLiteDatabase db) { }
+ }
}
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 7ab86ad..d192be4 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -27,8 +27,6 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
import static com.android.launcher3.LauncherSettings.Favorites.ICON;
-import static com.android.launcher3.LauncherSettings.Favorites.ICON_PACKAGE;
-import static com.android.launcher3.LauncherSettings.Favorites.ICON_RESOURCE;
import static com.android.launcher3.LauncherSettings.Favorites.INTENT;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
@@ -97,11 +95,10 @@
mApp = LauncherAppState.getInstance(mContext);
mCursor = new MatrixCursor(new String[] {
- ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE,
- _ID, CONTAINER, ITEM_TYPE, PROFILE_ID,
- SCREEN, CELLX, CELLY, RESTORED, INTENT,
- APPWIDGET_ID, APPWIDGET_PROVIDER, SPANX,
- SPANY, RANK, OPTIONS, APPWIDGET_SOURCE
+ ICON, TITLE, _ID, CONTAINER, ITEM_TYPE,
+ PROFILE_ID, SCREEN, CELLX, CELLY, RESTORED,
+ INTENT, APPWIDGET_ID, APPWIDGET_PROVIDER,
+ SPANX, SPANY, RANK, OPTIONS, APPWIDGET_SOURCE
});
UserManagerState ums = new UserManagerState();
diff --git a/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java b/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java
new file mode 100644
index 0000000..2b6f9ff
--- /dev/null
+++ b/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.provider;
+
+import static android.content.pm.LauncherApps.EXTRA_PIN_ITEM_REQUEST;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.LauncherSettings.Favorites.INTENT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.os.Process;
+
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.R;
+import com.android.launcher3.model.DatabaseHelper;
+import com.android.launcher3.model.DbDowngradeHelper;
+import com.android.launcher3.settings.SettingsActivity;
+import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.IOUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.io.InputStream;
+
+/**
+ * Test for {@link LauncherDbUtils}.
+ */
+public class LauncherDbUtilsTest {
+
+ private Context mContext;
+ private ArgumentCaptor<ShortcutInfo> mInfoArgumentCaptor;
+ private boolean mPinningAllowed = true;
+
+ @Before
+ public void setup() {
+ PinItemRequest req = mock(PinItemRequest.class);
+ doAnswer(i -> mPinningAllowed).when(req).accept();
+
+ mInfoArgumentCaptor = ArgumentCaptor.forClass(ShortcutInfo.class);
+ ShortcutManager sm = mock(ShortcutManager.class);
+ when(sm.createShortcutResultIntent(mInfoArgumentCaptor.capture()))
+ .thenReturn(new Intent().putExtra(EXTRA_PIN_ITEM_REQUEST, req));
+
+ mContext = new ContextWrapper(getInstrumentation().getTargetContext()) {
+
+ @Override
+ public Object getSystemService(String name) {
+ return SHORTCUT_SERVICE.equals(name) ? sm : super.getSystemService(name);
+ }
+ };
+ }
+
+ @Test
+ public void migrateLegacyShortcuts_invalidIntent() throws Exception {
+ SQLiteDatabase db = setupLegacyShortcut(null);
+ assertEquals(1, getFavoriteDataCount(db));
+
+ LauncherDbUtils.migrateLegacyShortcuts(mContext, db);
+
+ assertEquals(0, getFavoriteDataCount(db));
+ }
+
+ @Test
+ public void migrateLegacyShortcuts_protectedIntent() throws Exception {
+ Intent intent = new Intent(Intent.ACTION_CALL)
+ .setData(Uri.parse("tel:0000000000"));
+ SQLiteDatabase db = setupLegacyShortcut(intent);
+ assertEquals(1, getFavoriteDataCount(db));
+
+ LauncherDbUtils.migrateLegacyShortcuts(mContext, db);
+
+ assertEquals(0, getFavoriteDataCount(db));
+ }
+
+ @Test
+ public void migrateLegacyShortcuts_pinningDisabled() throws Exception {
+ mPinningAllowed = false;
+ Intent intent = new Intent(mContext, SettingsActivity.class);
+ SQLiteDatabase db = setupLegacyShortcut(intent);
+ assertEquals(1, getFavoriteDataCount(db));
+
+ LauncherDbUtils.migrateLegacyShortcuts(mContext, db);
+
+ assertEquals(0, getFavoriteDataCount(db));
+ }
+
+ @Test
+ public void migrateLegacyShortcuts_success() throws Exception {
+ Intent intent = new Intent(mContext, SettingsActivity.class);
+ SQLiteDatabase db = setupLegacyShortcut(intent);
+ assertEquals(1, getFavoriteDataCount(db));
+
+ LauncherDbUtils.migrateLegacyShortcuts(mContext, db);
+
+ assertEquals(1, getFavoriteDataCount(db));
+ ShortcutInfo info = mInfoArgumentCaptor.getValue();
+ assertNotNull(info);
+ assertEquals("Hello", info.getTitle());
+ try (Cursor c = db.query(Favorites.TABLE_NAME, null, null, null, null, null, null)) {
+ c.moveToNext();
+ assertEquals(Favorites.ITEM_TYPE_DEEP_SHORTCUT, c.getInt(c.getColumnIndex(ITEM_TYPE)));
+
+ ShortcutKey key = ShortcutKey.fromIntent(
+ Intent.parseUri(c.getString(c.getColumnIndex(INTENT)), 0),
+ Process.myUserHandle());
+
+ assertEquals(info.getId(), key.getId());
+ assertEquals(info.getPackage(), key.getPackageName());
+ }
+ }
+
+ private SQLiteDatabase setupLegacyShortcut(Intent intent) throws Exception {
+ SQLiteDatabase db = new MyDatabaseHelper().getWritableDatabase();
+ try (InputStream in = mContext.getResources().openRawResource(R.raw.downgrade_schema)) {
+ DbDowngradeHelper.parse(IOUtils.toByteArray(in)).onDowngrade(db, db.getVersion(), 31);
+ }
+
+ ContentValues cv = new ContentValues();
+ cv.put("itemType", 1);
+ cv.put("title", "Hello");
+ cv.put("intent", intent == null ? null : intent.toUri(0));
+ db.insert(Favorites.TABLE_NAME, null, cv);
+ return db;
+ }
+
+ public static int getFavoriteDataCount(SQLiteDatabase db) {
+ try (Cursor c = db.query(Favorites.TABLE_NAME, null, null, null, null, null, null)) {
+ return c.getCount();
+ }
+ }
+
+ private class MyDatabaseHelper extends DatabaseHelper {
+
+ MyDatabaseHelper() {
+ super(mContext, null, false);
+ }
+
+ @Override
+ protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { }
+
+ protected void onEmptyDbCreated() { }
+ }
+}
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 9c8de1c..aa091b6 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -26,8 +26,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.LauncherProvider.DatabaseHelper;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.model.DatabaseHelper;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
index 545b645..fdfeb7d 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -61,6 +61,7 @@
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.model.DatabaseHelper;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 1582e49..9905603 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1012,8 +1012,6 @@
if (hasLauncherObject(WORKSPACE_RES_ID)) {
log(action = "already at home");
} else {
- log("Hierarchy before swiping up to home:");
- dumpViewHierarchy();
action = "swiping up to home";
swipeToState(