Merge "TalkBack doesn't announce when a task has being closed." into sc-v2-dev
diff --git a/Android.bp b/Android.bp
index 60ef5b1..bab994a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -258,6 +258,10 @@
"go/res",
"go/quickstep/res",
],
+ // Note the ordering here is important when it comes to resource
+ // overriding. We want the most specific resource overrides defined
+ // in QuickstepResLib to take precendece, so it should be the final
+ // dependency. See b/205278434 for how this can go wrong.
static_libs: [
"Launcher3CommonDepsLib",
"QuickstepResLib",
@@ -283,11 +287,15 @@
libs: [
"framework-statsd",
],
+ // Note the ordering here is important when it comes to resource
+ // overriding. We want the most specific resource overrides defined
+ // in QuickstepResLib to take precendece, so it should be the final
+ // dependency. See b/208647810 for how this can go wrong.
static_libs: [
- "QuickstepResLib",
"SystemUI-statsd",
"SystemUISharedLib",
"Launcher3CommonDepsLib",
+ "QuickstepResLib",
],
manifest: "quickstep/AndroidManifest.xml",
platform_apis: true,
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index d1bf152..c559988 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -60,6 +60,7 @@
PredictedHotseatContainer predicted_hotseat_container = 10;
TaskSwitcherContainer task_switcher_container = 11;
TaskBarContainer task_bar_container = 12;
+ WallpapersContainer wallpapers_container = 13;
ExtendedContainers extended_containers = 20;
}
}
@@ -247,6 +248,12 @@
}
}
+// Represents wallpapers container for quick switching.
+message WallpapersContainer {
+ // Number of wallpapers in the container.
+ optional int32 cardinality = 1;
+}
+
// Represents state of EditText field before update.
enum FromState {
// Default value.
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 0f92274..352cd3e 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -28,6 +28,7 @@
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS"/>
<uses-permission android:name="android.permission.REMOVE_TASKS"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
<uses-permission android:name="android.permission.STATUS_BAR"/>
<uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
@@ -35,6 +36,7 @@
<uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
<uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY"/>
<uses-permission android:name="android.permission.MONITOR_INPUT"/>
+ <uses-permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"/>
<uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
diff --git a/quickstep/res/drawable/ic_screenshot.xml b/quickstep/res/drawable/ic_screenshot.xml
index d97eae1..9ee6c44 100644
--- a/quickstep/res/drawable/ic_screenshot.xml
+++ b/quickstep/res/drawable/ic_screenshot.xml
@@ -13,11 +13,20 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
<path
- android:fillColor="#FF000000"
- android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,21L7,21v-1h10v1zM17,18L7,18L7,6h10v12zM17,4L7,4L7,3h10v1zM9.5,8.5L12,8.5L12,7L8,7v4h1.5zM12,17h4v-4h-1.5v2.5L12,15.5z"/>
-</vector>
+ android:pathData="M5.8334,1.666H8.3334V3.3327H5.8334V6.666H4.1667V3.3327C4.1667,2.4122 4.9129,1.666 5.8334,1.666Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M4.1667,13.3327V16.666C4.1667,17.5865 4.9129,18.3327 5.8334,18.3327H8.3334V16.666H5.8334V13.3327H4.1667Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M14.1667,13.3327V16.666H11.6667V18.3327H14.1667C15.0872,18.3327 15.8334,17.5865 15.8334,16.666V13.3327H14.1667Z"
+ android:fillColor="#000000"/>
+ <path
+ android:pathData="M15.8334,6.666V3.3327C15.8334,2.4122 15.0872,1.666 14.1667,1.666H11.6667V3.3327H14.1667V6.666H15.8334Z"
+ android:fillColor="#000000"/>
+</vector>
\ No newline at end of file
diff --git a/quickstep/res/drawable/taskbar_icon_click_feedback_roundrect.xml b/quickstep/res/drawable/taskbar_icon_click_feedback_roundrect.xml
index d6160de..534f241 100644
--- a/quickstep/res/drawable/taskbar_icon_click_feedback_roundrect.xml
+++ b/quickstep/res/drawable/taskbar_icon_click_feedback_roundrect.xml
@@ -16,7 +16,7 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/taskbar_icon_selection_ripple">
+ android:color="@color/taskbar_nav_icon_selection_ripple">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index dd8afc2..0fda0bf 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -38,6 +38,20 @@
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_screenshot"
android:text="@string/action_screenshot"
+ android:theme="@style/ThemeControlHighlightWorkspaceColor" />
+
+ <Space
+ android:id="@+id/action_split_space"
+ android:layout_width="@dimen/overview_actions_button_spacing"
+ android:layout_height="1dp"
+ android:visibility="gone" />
+
+ <Button
+ android:id="@+id/action_split"
+ style="@style/OverviewActionButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/action_split"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
@@ -46,23 +60,6 @@
android:layout_height="1dp"
android:layout_weight="1" />
- <Button
- android:id="@+id/action_split"
- style="@style/OverviewActionButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:drawableStart="@drawable/ic_split_screen"
- android:text="@string/action_split"
- android:theme="@style/ThemeControlHighlightWorkspaceColor"
- android:visibility="gone" />
-
- <Space
- android:id="@+id/action_split_space"
- android:layout_width="0dp"
- android:layout_height="1dp"
- android:layout_weight="1"
- android:visibility="gone" />
-
<Space
android:id="@+id/oav_three_button_space"
android:layout_width="0dp"
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index f303f31..01d675f 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -25,13 +25,6 @@
android:clipToPadding="false"
android:visibility="invisible" />
- <com.android.quickstep.views.SplitPlaceholderView
- android:id="@+id/split_placeholder"
- android:layout_width="match_parent"
- android:layout_height="@dimen/split_placeholder_size"
- android:background="@android:color/darker_gray"
- android:visibility="gone" />
-
<include
android:id="@+id/overview_actions_view"
layout="@layout/overview_actions_container" />
diff --git a/quickstep/res/layout/taskbar_nav_button.xml b/quickstep/res/layout/taskbar_nav_button.xml
index 4ffb8d8..aea4885 100644
--- a/quickstep/res/layout/taskbar_nav_button.xml
+++ b/quickstep/res/layout/taskbar_nav_button.xml
@@ -15,7 +15,10 @@
-->
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="@dimen/taskbar_nav_buttons_size"
android:layout_height="@dimen/taskbar_nav_buttons_size"
android:background="@drawable/taskbar_icon_click_feedback_roundrect"
- android:scaleType="center"/>
\ No newline at end of file
+ android:scaleType="center"
+ android:tint="@color/taskbar_nav_icon_light_color"
+ tools:ignore="UseAppTint" />
\ No newline at end of file
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 1185c03..792116f 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Draai skerm"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taakbalkopvoeding het verskyn"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taakbalkopvoeding is toegemaak"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gebruik die taakbalk om tussen programme te wissel"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Sleep na die kant om twee programme gelyktydig te gebruik"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Raak en hou om die taakbalk te versteek"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Volgende"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Terug"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 73347df..76ff87a 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"ማያ ገጹን አዙር"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"የተግባር አሞሌ ትምህርት ይታያል"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"የተግባር አሞሌ ትምህርት ተዘግቷል"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"መተግበሪያዎችን ለመቀየር የተግባር አሞሌውን ይጠቀሙ"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"በአንድ ጊዜ ሁለት መተግበሪያዎችን ለመጠቀም ወደ ጎን ይጎትቱ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"የተግባር አሞሌውን ለመደበቅ ነክተው ይያዙት"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ቀጣይ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ተመለስ"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 553c22f..a853e27 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"تدوير الشاشة"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ظهرت لوحة تعليم استخدام شريط المهام."</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"تم إغلاق لوحة تعليم استخدام شريط المهام."</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"يمكنك استخدام شريط المهام للتبديل بين التطبيقات."</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"اسحبه إلى جانب الشاشة لاستخدام تطبيقين في آنٍ واحد."</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"انقر مع الاستمرار لإخفاء شريط المهام."</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"الشاشة التالية"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"رجوع"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 1651e4f..9bfbbc1 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"স্ক্ৰীনখন ঘূৰাওক"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো প্ৰদর্শিত হৈছে"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো বন্ধ হৈছে"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"এপ্ সলনি কৰিবলৈ টাস্কবাৰডাল ব্যৱহাৰ কৰক"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"এবাৰতে দুটা এপ্ ব্যৱহাৰ কৰিবলৈ কাষলৈ টানি আনি এৰক"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"টাস্কবাৰডাল লুকুৱাবলৈ স্পৰ্শ কৰি ধৰি ৰাখক"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"পৰৱৰ্তী"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"উভতি যাওক"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 0f302c4..b1e4fb0 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranı fırladın"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tapşırıq panelindəki təlim bölməsi görünür"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tapşırıq panelindəki təlim bölməsi bağlanıb"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Tətbiqləri keçirmək üçün tapşırıq panelindən istifadə edin"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Eyni anda iki tətbiqi istifadə etmək üçün yan tərəfə çəkin"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tapşırıq panelini toxunub saxlamaqla gizlədin"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Sonra"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Geri"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 0d96cb9..a5d8870 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotirajte ekran"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukativno okno iz trake zadataka se pojavilo"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukativno okno iz trake zadataka je zatvoreno"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Koristite traku zadataka da biste menjali aplikacije"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Prevucite na stranu da koristite dve aplikacije odjednom"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i zadržite za skrivanje trake zadataka"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Dalje"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Nazad"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 44778be..5cecdd1 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Павярнуць экран"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"З\'явілася панэль навучання на панэлі задач"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Панэль навучання на панэлі задач закрыта"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Выкарыстоўвайце панэль задач для пераключэння праграм"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Перацягніце ўбок, каб адначасова скарыстаць дзве праграмы"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Націсніце і ўтрымлівайце, каб схаваць панэль задач"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Далей"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 5991ce7..8be99dc 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Завъртане на екрана"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Показва се урокът за лентата на задачите"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Урокът за лентата на задачите бе затворен"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Използвайте лентата на задачите за превключване между прил."</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Плъзнете встрани, за да използвате едновременно 2 приложения"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Докоснете и задръжте, за да скриете лентата на задачите"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Напред"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 1027853..553b062 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"স্ক্রিন ঘোরান"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"টাস্কবার এডুকেশন দেখানো হয়েছে"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"টাস্কবার এডুকেশন বন্ধ করা আছে"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"অ্যাপ পাল্টানোর জন্য টাস্কবার ব্যবহার করুন"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"একসাথে দুটি অ্যাপ ব্যবহার করতে পাশে টেনে আনুন"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"টাস্কবার লুকানোর জন্য টাচ করে ধরে থাকুন"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"পরবর্তী"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ফিরুন"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 6aee9f9..7870538 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotiranje ekrana"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukacija o programskoj traci je prikazana"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukacija o programskoj traci je zatvorena"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Koristite programsku traku da promijenite aplikacije"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Prevucite u stranu da istovremeno koristite dvije aplikacije"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i držite da sakrijete programsku traku"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Naprijed"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Nazad"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index a52025c..eb5728c 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Gira la pantalla"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Ha aparegut el tauler educatiu de la barra de tasques"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"S\'ha tancat el tauler educatiu de la barra de tasques"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Utilitza la barra de tasques per canviar d\'aplicació"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arrossega al costat per utilitzar dues aplicacions alhora"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén premut per amagar la barra de tasques"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Següent"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Enrere"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 95f39cc..a885503 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Otočit obrazovku"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila se výuka k hlavnímu panelu"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnímu panelu byla zavřena"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Aplikace lze přepínat pomocí hlavního panelu"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Po přetažení na stranu lze používat dvě aplikace současně"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Hlavní panel můžete skrýt podržením"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Další"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Zpět"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index eb5b8ee..0c2b720 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Roter skærm"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Vejledningen om proceslinjen blev åbnet"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Vejledningen om proceslinjen blev lukket"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Skift mellem apps ved hjælp af proceslinjen"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Træk til siden for at bruge to apps samtidig"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Du kan skjule proceslinjen ved at holde fingeren nede"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Næste"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Tilbage"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index f8c1783..f2bfd27 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Bildschirm drehen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Anleitung für Taskleiste eingeblendet"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Anleitung für Taskleiste geschlossen"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Über die Taskleiste zwischen Apps wechseln"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Zur Seite ziehen, um zwei Apps gleichzeitig zu verwenden"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Gedrückt halten, um die Taskleiste auszublenden"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Weiter"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Zurück"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 233a1ba..707ef69 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Περιστροφή οθόνης"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Η εκπαίδευση για τη γραμμή εργασιών εμφανίστηκε"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Η εκπαίδευση για τη γραμμή εργασιών έκλεισε"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Χρήση της γραμμής εργασιών για εναλλαγή εφαρμογών"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Σύρετε στο πλάι για ταυτόχρονη χρήση δύο εφαρμογών"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Αγγίξτε παρατεταμένα για απόκρυψη της γραμμής εργασιών."</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Επόμενο"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Πίσω"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index f4607c7..e1f1e27 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index f4607c7..e1f1e27 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index f4607c7..e1f1e27 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index f4607c7..e1f1e27 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 92574fe..f2b4cd2 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use the taskbar to switch apps"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Drag to the side to use two apps at once"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Back"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 6aa7a2f..7b62c2d 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar pantalla"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Se abrió la barra de herramientas Educación"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Se cerró la barra de herramientas Educación"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Usa la barra de tareas para cambiar de app"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arrastra a un lado para usar dos apps a la vez"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén presionado para ocultar la barra de tareas"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Siguiente"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 7c711a5..93f66c8 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar la pantalla"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Ha aparecido una nota sobre la barra de tareas"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Nota sobre la barra de tareas cerrada"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Usa la barra de tareas para cambiar de aplicación"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arrastra hacia un lado para usar dos aplicaciones a la vez"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén pulsada la barra de tareas para ocultarla"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Siguiente"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 6f93fb1..5734825 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Pöörake ekraani"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tegumiriba juhised kuvati"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tegumiriba juhised on suletud"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Kasutage rakenduste vahetamiseks tegumiriba"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Kahe rakenduse korraga kasutamiseks lohistage külje poole"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tegumiriba peitmiseks puudutage pikalt"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Järgmine"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Tagasi"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 5e4d423..84ec586 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Biratu pantaila"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Agertu egin da zereginen barraren tutoriala"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Itxi egin da zereginen barraren tutoriala"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Erabili zereginen barra aplikazioz aldatzeko"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Bi aplikazio batera erabiltzeko, arrastatu hatza albo batera"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Zereginen barra ezkutatzeko, eduki ezazu sakatuta"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Hurrengoa"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atzera"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index c6174a1..ad87c8f 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"چرخاندن صفحه"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"پانل آموزشی نوار وظیفه نمایان شد"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"پانل آموزشی نوار وظیفه بسته شد"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"برای جابهجایی بین برنامهها، از نوار وظیفه استفاده کنید"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"برای استفاده همزمان از دو برنامه، آن را به کنار بکشید"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"برای پنهان کردن نوار وظیفه، لمس کنید و نگه دارید"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"بعدی"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"برگشت"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 151ad5c..01cdbf1 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Käännä näyttö"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tehtäväpalkin ohje näkyvissä"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tehtäväpalkin ohje suljettu"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Vaihda sovellusta tehtäväpalkin kautta"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Vetämällä sivuun voit käyttää kahta sovellusta samaan aikaan"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Piilota tehtäväpalkki koskettamalla pitkään"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Seuraava"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Takaisin"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 474b86f..65bb0f5 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"La barre des tâches éducatives s\'est affichée"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"La barre des tâches éducatives est fermée"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Utilisez la barre des tâches pour changer les applications"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Glissez sur le côté pour utiliser 2 applications à la fois"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Maintenez le doigt sur la barre des tâches pour la masquer"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Suivant"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Retour"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index ee16bca..10f1152 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Infos sur la barre des tâches affichées"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Infos sur la barre des tâches fermées"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Utilisez la barre des tâches pour changer d\'application"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Faites glisser sur côté pour utiliser deux applis à la fois"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Appuyez de manière prolongée pour masquer barre des tâches"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Suivant"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Retour"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index aac2076..e983361 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Xira a pantalla"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Panel de información de barra de tarefas aberto"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Panel de información de barra de tarefas pechado"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Usa a barra de ferramentas para cambiar de aplicación"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Para usar dúas aplicacións á vez, arrastra cara ao lado"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén premida a barra de tarefas para ocultala"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index e943eff..7861011 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"સ્ક્રીન ફેરવો"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ટાસ્કબારનું શિક્ષણ આપતી પૅનલ દેખાય છે"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ટાસ્કબારનું શિક્ષણ આપતી પૅનલ બંધ થઈ છે"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ઍપ સ્વિચ કરવા માટે, ટાસ્કબારનો ઉપયોગ કરો"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"એક જ સમયે બે ઍપનો ઉપયોગ કરવા માટે, ખેંચીને બાજુ પર લઈ જાઓ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ટાસ્કબાર છુપાવવા, તેને ટચ કરીને થોડીવાર દબાવી રાખો"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"આગળ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"પાછળ"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index fc4b27a..4802dbb 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रीन घुमाएं"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार ट्यूटोरियल दिखाया गया"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबार ट्यूटोरियल बंद किया गया"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ऐप्लिकेशन स्विच करने के लिए, टास्कबार का इस्तेमाल करें"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"एक साथ दो ऐप्लिकेशन इस्तेमाल करने के लिए, उन्हें किनारे की ओर खींचें और छोड़ें"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार को छिपाने के लिए, उसे दबाकर रखें"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"आगे बढ़ें"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"वापस जाएं"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 78dd559..bb5d3dc 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Zakretanje zaslona"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Upute za programsku traku su se pojavile"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Upute za programsku traku su zatvorene"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Upotrijebite program. traku da biste promijenili aplikaciju"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Povucite u stranu da biste istovremeno koristili dvije aplikacije"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i zadržite da biste sakrili programsku traku"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Dalje"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Natrag"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index c7f68a8..e6aa5cf 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Képernyő elforgatása"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Az eszköztár használatát ismertető panel megjelent"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Az eszköztár használatát ismertető panel bezárult"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Az eszköztárral válthat az alkalmazások között"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Húzza oldalra, ha egyszerre két appot szeretne használni"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Nyomva tartással elrejthető az eszköztár"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Tovább"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Vissza"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index c10db3e..5cf779a 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Պտտել էկրանը"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Խնդրագոտու «Կրթություն» վահանակը բացվեց"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Խնդրագոտու «Կրթություն» վահանակը փակվեց"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Օգտագործեք խնդրագոտին՝ մի հավելվածից մյուսին անցնելու համար"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Քաշեք մի կողմ՝ միաժամանակ երկու հավելված օգտագործելու համար"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Հպեք և պահեք՝ խնդրագոտին թաքցնելու համար"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Առաջ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Հետ"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 97ddd9d..d48383e 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Putar layar"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukasi taskbar ditampilkan"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukasi taskbar ditutup"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gunakan taskbar untuk beralih aplikasi"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Tarik ke samping untuk menggunakan dua aplikasi sekaligus"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Sentuh lama untuk menyembunyikan taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Berikutnya"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Kembali"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index e9bc164..15ee8ab 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Snúa skjánum"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Leiðsögn verkefnastiku sýnileg"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Leiðsögn verkefnastiku lokað"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Notaðu verkefnastikuna til að skipta á milli forrita"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Dragðu til hliðar til að nota tvö forrit í einu"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Haltu inni til að fela verkefnastikuna"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Áfram"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Til baka"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 8550d1e..493fdfb 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Ruota lo schermo"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Riquadro Formazione barra delle applicazioni visualizzato"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Riquadro Formazione barra delle applicazioni chiuso"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Usa la barra delle applicazioni per cambiare app"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Trascina di lato per usare due app contemporaneamente"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tocca e tieni premuto per nascondere barra applicazioni"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Avanti"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Indietro"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index e208dd1..15398f7 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"סיבוב המסך"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"חלונית ההסברים על שורת המשימות מופיעה"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"חלונית ההסברים על שורת המשימות נסגרה"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"כדי לעבור בין אפליקציות, משתמשים בשורת המשימות"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"כדי להשתמש בשתי אפליקציות בו-זמנית, צריך לגרור לצד"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"כדי להסתיר את שורת המשימות, לוחצים לחיצה ארוכה"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"הבא"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"חזרה"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index b1f0280..8b0780f 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"画面を回転"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"タスクバーの説明を開きました"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"タスクバーの説明を閉じました"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"アプリを切り替えるには、タスクバーを使用します"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"2 個のアプリを同時に使用するには、横にドラッグします"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"タスクバーを長押しすると非表示になります"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"次へ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"戻る"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 5a1cc6d..c094d6c 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"ეკრანის შეტრიალება"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ამოცანების ზოლის სასწავლო არე გამოჩნდა"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ამოცანების ზოლის სასწავლო არე დაიხურა"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"აპების გადასართავად გამოიყენეთ ამოცანათა ზოლი"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"გადაათრიეთ კიდეზე ორი აპის ერთდოულად გამოსაყენებლად"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ხანგრძლივად შეეხეთ ამოცანების ზოლის დასამალად"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"შემდეგი"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"უკან"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 390daa1..77e4f6a 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Экранды бұру"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапсырмалар тақтасы бойынша нұсқаулық ашылды."</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Тапсырмалар тақтасы бойынша нұсқаулық жабылды."</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Қолданбаларды ауыстыру үшін тапсырма тақтасын пайдаланыңыз."</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Екі қолданбаны бір уақытта пайдалану үшін шетке сүйреңіз."</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Тапсырмалар тақтасын жасыру үшін басып тұрыңыз."</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Келесі"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Артқа"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index b2702db..a9f41d1 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"បង្វិលអេក្រង់"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ការបង្រៀនអំពីរបារកិច្ចការបានបង្ហាញ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ការបង្រៀនអំពីរបារកិច្ចការត្រូវបានបិទ"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ប្រើរបារកិច្ចការ ដើម្បីប្ដូរកម្មវិធី"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"អូសទៅចំហៀង ដើម្បីប្រើកម្មវិធីពីរក្នុងពេលតែមួយ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ចុចឱ្យជាប់ ដើម្បីលាក់របារកិច្ចការ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"បន្ទាប់"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ថយក្រោយ"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 6c27841..33f6565 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"ಸ್ಕ್ರೀನ್ ತಿರುಗಿಸಿ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ ಕಾಣಿಸಿಕೊಂಡಿದೆ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ ಮುಚ್ಚಿದೆ"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟಾಸ್ಕ್ ಬಾರ್ ಬಳಸಿ"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ಏಕಕಾಲದಲ್ಲಿ ಎರಡು ಆ್ಯಪ್ಗಳನ್ನು ಬಳಸಲು, ಬದಿಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ಟಾಸ್ಕ್ಬಾರ್ ಅನ್ನು ಮರೆಮಾಡಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ಮುಂದೆ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ಹಿಂದೆ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index e31112e..6e658ae 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"화면 회전"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"작업 표시줄 튜토리얼 패널 표시됨"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"작업 표시줄 튜토리얼 패널 닫힘"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"작업 표시줄을 사용하여 앱 전환"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"옆으로 드래그하여 한 번에 앱 두 개 사용"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"작업 표시줄을 숨기려면 길게 터치하세요."</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"다음"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"뒤로"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index ae00943..ac22e8d 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Экранды буруу"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапшырмалар тактасынын окутуу панели көрсөтүлдү"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Тапшырмалар тактасынын окутуу панели жабылды"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Тапшырмалар тактасы аркылуу башка колдонмого которула аласыз"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Эки колдонмону бир убакта пайдалануу үчүн капталга сүрүңүз"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Тапшырмалар тактасын жашыруу үчүн коё бербей басып туруңуз"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Кийинки"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Артка"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index e2eef9d..3b726fd 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"ໝຸນໜ້າຈໍ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ສະແດງການສຶກສາແຖບໜ້າວຽກແລ້ວ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ປິດການສຶກສາແຖບໜ້າວຽກແລ້ວ"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ໃຊ້ແຖບໜ້າວຽກເພື່ອສະຫຼັບແອັບ"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ລາກໄປທາງຂ້າງເພື່ອໃຊ້ສອງແອັບພ້ອມກັນ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ແຕະຄ້າງໄວ້ເພື່ອເຊື່ອງແຖບໜ້າວຽກ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ຕໍ່ໄປ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ກັບຄືນ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 8c27487..5ceaff1 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Pasukti ekraną"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Užduočių juostos patarimai rodomi"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Užduočių juostos patarimai uždaryti"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Naudokite užduočių juostą, kad gal. perjungti programas"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Nuvilkite į šoną, kad gal. vienu metu naudoti dvi programas"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Palieskite ir palaikykite, kad paslėptumėte užduočių juostą"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Kitas"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atgal"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index be70bf5..96e0a4e 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Pagriezt ekrānu"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tika atvērta uzdevumjoslas apmācība"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tika aizvērta uzdevumjoslas apmācība"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Izmantojiet uzdevumjoslu, lai pārslēgtu lietotnes."</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Velciet uz malu, lai izmantotu divas lietotnes vienlaikus."</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pieskarieties un turiet, lai paslēptu uzdevumjoslu."</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Tālāk"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Atpakaļ"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 2806746..b94d06e 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте го екранот"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Се појави лентата за задачи за образование"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Затворена е лентата за задачи за образование"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Префрлувајте се меѓу апликации преку лентата за задачи"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Повлечете кон страната за да користите две апликации одеднаш"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Допрете и задржете за да се сокрие лентата за задачи"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Следна"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 1794aec..aca3b5b 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"സ്ക്രീൻ റൊട്ടേറ്റ് ചെയ്യുക"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ടാസ്ക്ക്ബാർ വിവര പാനൽ ദൃശ്യമായി"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ടാസ്ക്ക്ബാർ വിവര പാനൽ അടച്ചു"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ആപ്പുകൾ മാറാൻ ടാസ്ക്ക്ബാർ ഉപയോഗിക്കുക"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"രണ്ട് ആപ്പുകൾ ഒരുമിച്ച് ഉപയോഗിക്കാൻ അരികിലേക്ക് വലിച്ചിടുക"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ടാസ്ക്ക്ബാർ മറയ്ക്കാൻ സ്പർശിച്ച് പിടിക്കുക"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"അടുത്തത്"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"മടങ്ങുക"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index c8d614b..117bc0e 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Дэлгэцийг эргүүлэх"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Боловсролын ажлын талбар гарч ирсэн"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Боловсролын ажлын талбарыг хаасан"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Аппуудыг сэлгэхийн тулд талбарыг ашиглана уу"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Хоёр аппыг зэрэг ашиглахын тулд хажуу тал руу чирнэ үү"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Ажлын талбарыг нуухын тулд хүрээд удаан дарна уу"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Дараах"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Буцах"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 7540a5d..3e4adf7 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रीन फिरवा"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबारशी संबंधित माहिती देणारे पॅनल उघडले आहे"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबारशी संबंधित माहिती देणारे पॅनल बंद केले आहे"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ॲप्स स्विच करण्यासाठी टास्कबार वापरा"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"दोन ॲप्स एकत्र वापरण्यासाठी, त्यांना बाजूला नेऊन ड्रॅग करा"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार लपवण्यासाठी स्पर्श करा आणि धरून ठेवा"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"पुढे"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"मागे जा"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 9ea6e22..8ad1c37 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Putar skrin"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Pendidikan bar tugas muncul"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Pendidikan bar tugas ditutup"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gunakan bar tugas untuk menukar apl"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Seret ke tepi untuk menggunakan dua apl serentak"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Sentuh & tahan untuk menyembunyikan bar tugas"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Seterusnya"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Kembali"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index a8ccfb0..e528b58 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"ဖန်သားပြင်လှည့်ရန်"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ပညာရေး လုပ်ဆောင်စရာဘား ပြထားသည်"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ပညာရေး လုပ်ဆောင်စရာဘား ပိတ်ထားသည်"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"အက်ပ်များပြောင်းရန် လုပ်ဆောင်စရာဘားကို သုံးပါ"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"အက်ပ်နှစ်ခု တစ်ပြိုင်တည်းသုံးရန် တစ်ဖက်သို့ ဖိဆွဲပါ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"လုပ်ဆောင်စရာဘားကို ဖျောက်ရန် ထိပြီးဖိထားနိုင်သည်"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ရှေ့သို့"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"နောက်သို့"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index fe3e2e4..537289d 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotér skjermen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Opplæringen for oppgavelinjen vises"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Opplæringen for oppgavelinjen er lukket"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Bruk oppgavelinjen for å bytte app"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Dra til siden for å bruke to apper samtidig"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Trykk og hold for å skjule oppgavelinjen"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Neste"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Tilbake"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 09ef075..9436610 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रिन घुमाउनुहोस्"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार एजुकेसन देखिएको छ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबार एजुकेसन बन्द गरिएको छ"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"एउटा एपबाट अर्को एपमा जान टास्कबार प्रयोग गर्नुहोस्"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"टास्कबार छेउतिर ड्र्याग गरेर एकै पटक दुई वटा एप चलाउनुहोस्"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार लुकाउन टास्कबार थिचिराख्नुहोस्"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"अर्को"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"पछाडि"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index be68c2c..7c5ca0d 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -41,8 +41,8 @@
<string name="hotseat_auto_enrolled" msgid="522100018967146807">"De meestgebruikte apps worden hier weergegeven en kunnen veranderen op basis van je routines"</string>
<string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Sleep apps weg van de onderste rij om app-suggesties te ontvangen"</string>
<string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"App-suggesties toegevoegd aan lege ruimte"</string>
- <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"App-suggesties zijn ingeschakeld"</string>
- <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"App-suggesties zijn uitgeschakeld"</string>
+ <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"App-suggesties staan aan"</string>
+ <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"App-suggesties staan uit"</string>
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Voorspelde app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Swipe helemaal vanaf de rechter- of linkerrand."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Swipe vanaf de rechter- of linkerrand naar het midden van het scherm en laat los."</string>
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Scherm draaien"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Uitleg van taakbalk geopend"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Uitleg van taakbalk gesloten"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gebruik de taakbalk om van app te wisselen"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Sleep naar de zijkant om 2 apps tegelijk te gebruiken"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tik en houd vast om de taakbalk te verbergen"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Volgende"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Terug"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 5b539d3..596a3d1 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"ସ୍କ୍ରିନ ଘୂରାନ୍ତୁ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ଦେଖାଯାଇଛି"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ବନ୍ଦ ହୋଇଯାଇଛି"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ଆପଗୁଡ଼ିକୁ ସ୍ୱିଚ କରିବା ପାଇଁ ଟାସ୍କବାର ବ୍ୟବହାର କରନ୍ତୁ"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ଥରକେ ଦୁଇଟି ଆପ ବ୍ୟବହାର କରିବା ପାଇଁ ପାର୍ଶ୍ୱକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ଟାସ୍କବାରକୁ ଲୁଚାଇବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ପରବର୍ତ୍ତୀ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ପଛକୁ ଫେରନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index bc63fb6..9bc92c5 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"ਸਕ੍ਰੀਨ ਘੁਮਾਓ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਦਿਖਾਇਆ ਗਿਆ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ਐਪਾਂ ਸਵਿੱਚ ਕਰਨ ਲਈ ਟਾਸਕਬਾਰ ਵਰਤੋ"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ਇੱਕ ਵਾਰ ਵਿੱਚ ਦੋ ਐਪਾਂ ਵਰਤਣ ਲਈ ਉਨ੍ਹਾਂ ਨੂੰ ਸਾਈਡ ਵੱਲ ਘਸੀਟੋ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ਟਾਸਕਬਾਰ ਨੂੰ ਲੁਕਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ਅੱਗੇ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ਪਿੱਛੇ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 0c7828a..6b4603e 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Obróć ekran"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Wskazówki na temat paska zadań zostały wyświetlone"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Wskazówki na temat paska zadań zostały zamknięte"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Używaj paska zadań, aby przełączać aplikacje"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Przeciągnij w bok, aby używać 2 aplikacji jednocześnie"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Naciśnij i przytrzymaj, aby ukryć pasek zadań"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Dalej"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Wstecz"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 73afdb3..5b4fa29 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rodar ecrã"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Informação da barra de tarefas apresentada"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Informação da barra de tarefas fechada"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Utilize a barra de ferramentas para alternar entre apps"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arraste para o lado para utilizar duas apps em simultâneo"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Toque sem soltar para ocultar a barra de tarefas"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Anterior"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index e7d63ce..e7ef0d5 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar a tela"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"As dicas sobre a barra de tarefas foram abertas"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"As dicas sobre a barra de tarefas foram fechadas"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Use a barra de tarefas para alternar entre apps"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Arraste para o lado e use dois apps ao mesmo tempo"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantenha a barra de tarefas pressionada para ocultá-la"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Próxima"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Voltar"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 847bb57..72839cf 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotiți ecranul"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Panoul cu informații despre bara de activități s-a afișat"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Panoul cu informații despre bara de activități s-a închis"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Folosiți bara de activități ca să comutați între aplicații"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Trageți în lateral ca să folosiți două aplicații deodată"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Atingeți lung oricând pentru a ascunde bara de activități"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Înainte"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Înapoi"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 5b47295..c894cb6 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Повернуть экран"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Обучение по работе с панелью задач показано"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Обучение по работе с панелью задач скрыто"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Используйте панель задач, чтобы переключать приложения."</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Перетащите в сторону, чтобы использовать два приложения сразу."</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Чтобы скрыть панель задач, коснитесь ее и удерживайте."</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Далее"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 2676afb..3b0dd89 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"තිරය කරකවන්න"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"කාර්ය තීරු අධ්යාපනය දිස් විය"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"කාර්ය තීරු අධ්යාපනය වසා ඇත"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"යෙදුම් මාරු කිරීමට කාර්ය තීරුව භාවිත කරන්න"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"එකවර යෙදුම් දෙකක් භාවිතා කිරීමට පැත්තට අදින්න"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"කාර්ය තීරුව සැඟවීමට ස්පර්ශ කර අල්ලා ගෙන සිටින්න"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ඊළඟ"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"ආපසු"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index f29b0d4..abde935 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Otočiť obrazovku"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila sa výuka k hlavnému panelu"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnému panelu bola zatvorená"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Aplikácie je možné prepínať pomocou panela úloh"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Po presunutí na stranu je možné používať dve aplikácie naraz"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Panel úloh skryjete pridržaním"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Ďalej"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Späť"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 6276c3c..e0aeeab 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Sukanje zaslona"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Poučni nasveti o opravilni vrstici so prikazani."</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Poučni nasveti o opravilni vrstici so zaprti."</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Za preklop aplikacij uporabite opravilno vrstico."</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Povlecite vstran za uporabo dveh aplikacij hkrati."</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pridržite, če želite opravilno vrstico skriti."</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Naprej"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Nazaj"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 6ef41a3..cf7dd8b 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rrotullo ekranin"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukimi i shiritit të detyrave u shfaq"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukimi nga shiriti i detyrave u mbyll"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Përdor shiritin e detyrave për të ndryshuar aplikacionet"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Zvarrit anash për të përdorur të dyja aplikacionet njëherësh"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Preke dhe mbaje prekur për ta fshehur shiritin e detyrave"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Para"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Pas"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 0208108..c5e6340 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте екран"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Едукативно окно из траке задатака се појавило"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Едукативно окно из траке задатака је затворено"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Користите траку задатака да бисте мењали апликације"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Превуците на страну да користите две апликације одједном"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Додирните и задржите за скривање траке задатака"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Даље"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index ed79a77..fc5fc18 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotera skärmen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Information om aktivitetsfältet visades"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Information om aktivitetsfältet stängdes"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Använd aktivitetsfältet för att byta mellan appar"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Dra till sidan om du vill använda två appar samtidigt"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tryck länge för att dölja aktivitetsfältet"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Nästa"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Tillbaka"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 34c64d5..13290f4 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Zungusha skrini"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Paneli ya elimu kwenye upau wa shughuli inaonyeshwa"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Paneli ya elimu kwenye upau wa shughuli imefungwa"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Tumia upau wa shughuli kubadilisha programu"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Buruta pembeni ili utumie programu mbili kwa wakati mmoja"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Gusa na ushikilie ili ufiche upau wa shughuli"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Endelea"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Nyuma"</string>
diff --git a/quickstep/res/values-sw720dp/dimens.xml b/quickstep/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000..2831a6f
--- /dev/null
+++ b/quickstep/res/values-sw720dp/dimens.xml
@@ -0,0 +1,21 @@
+<?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.
+*/
+-->
+<resources>
+ <dimen name="overview_grid_row_spacing">44dp</dimen>
+ <dimen name="overview_page_spacing_grid_portrait">44dp</dimen>
+ <dimen name="overview_page_spacing_grid_landscape">44dp</dimen>
+</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index dc3b253..960d389 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"திரையைச் சுழற்றும்"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் காட்டப்படுகிறது"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் மூடப்பட்டது"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ஆப்ஸிற்கு இடையே மாற பணிப்பட்டியைப் பயன்படுத்தவும்"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ஒரே நேரத்தில் இரு ஆப்ஸை உபயோகிக்க பக்கவாட்டிற்கு இழுக்கவும்"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"பணிப்பட்டியை மறைக்கத் தொட்டுப் பிடிக்கவும்"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"அடுத்து"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"பின்செல்"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index a82a35a..6ae0a28 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"స్క్రీన్ను తిప్పండి"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"టాస్క్బార్ శిక్షణకు సంబంధించిన ప్యానెల్ కనిపించింది"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"టాస్క్బార్ శిక్షణకు సంబంధించిన ప్యానెల్ మూసివేయబడింది"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"యాప్లను స్విచ్ చేయడానికి టాస్క్బార్ను ఉపయోగించండి"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ఒకేసారి రెండు యాప్లను ఉపయోగించడానికి పక్కకు లాగండి"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"టాస్క్బార్ను దాచడానికి తాకి, నొక్కి ఉంచండి"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"తర్వాత"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"వెనుకకు"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 4815c85..bf5e715 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"หมุนหน้าจอ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"แถบงาน Education ปรากฎขึ้น"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ปิดแถบงาน Education แล้ว"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ใช้แถบงานเพื่อเปลี่ยนแอป"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ลากไปด้านข้างเพื่อใช้ 2 แอปพร้อมกัน"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"แตะค้างไว้เพื่อซ่อนแถบงาน"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"ถัดไป"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"กลับ"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index c7521a0..2a0b5ff 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"I-rotate ang screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Lumabas ang edukasyon sa taskbar"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Sarado ang edukasyon sa taskbar"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Gamitin ang taskbar para magpalipat-lipat sa mga app"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"I-drag sa gilid para makagamit ng dalawang app nang sabay"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pindutin nang matagal para itago ang taskbar"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Susunod"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Bumalik"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index f23d476..6fa71a2 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranı döndür"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Görev çubuğu eğitimi görüntülendi"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Görev çubuğu eğitimi kapatıldı"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Görev çubuğundan uygulamalar arasında geçiş yapabilirsiniz"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Tek seferde iki uygulamayı kullanmak için yana sürükleyin"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Görev çubuğunu gizlemek için basılı tutun"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"İleri"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Geri"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 19f5017..f5048e7 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Обернути екран"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Панель завдань Education відкрито"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Панель завдань Education закрито"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Переходьте між додатками за допомогою панелі завдань"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Перетягніть убік, щоб використовувати два додатки одночасно"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Натисніть і втримуйте панель завдань, щоб сховати її"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Далі"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 4b3f141..13ca7e4 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"اسکرین کو گھمائیں"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ٹاکس بار کا تعلیمی پینل ظاہر ہو گیا"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ٹاسک بار کا تعلیمی پینل بند ہو گیا"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"ایپس کو سوئچ کرنے کیلئے ٹاسک بار کا استعمال کریں"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"ایک وقت میں دو ایپس استعمال کرنے کے لیے سائیڈ پر گھسیٹیں"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ٹاسک بار کو کسی بھی وقت چھپانے کیلئے ٹچ کریں اور دبائے رکھیں"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"آگے"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"پیچھے"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 730b23a..468df49 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranni burish"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taʼlim vazifalar paneli chiqdi"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taʼlim vazifalar paneli yopildi"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Ilovalarni vazifalar panelida almashtirish mumkin"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Bir vaqtda ikkita ilova ochish uchun birini yoniga torting"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Vazifalar panelini ustiga bosib turib yashirish mumkin"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Keyingisi"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Orqaga"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index acf77ae..5999a41 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Xoay màn hình"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Đã hiện bảng hướng dẫn trên thanh tác vụ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Đã đóng bảng hướng dẫn trên thanh tác vụ"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Dùng thanh tác vụ để chuyển đổi ứng dụng"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Kéo sang bên để dùng hai ứng dụng cùng một lúc"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Chạm và giữ để ẩn thanh tác vụ"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Tiếp theo"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Quay lại"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index b533820..04dce2b 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"旋转屏幕"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"任务栏教程已显示"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"任务栏教程已关闭"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"使用任务栏切换应用"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"拖动到一侧,以便一次使用两个应用"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"轻触并按住即可隐藏任务栏"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"继续"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 8ff8f69..1e1690d 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"旋轉螢幕"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"顯示咗工作列教學"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"閂咗工作列教學"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"使用工作列即可切換應用程式"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"拖曳至一側即可同時使用兩個應用程式"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"按住即可隱藏工作列"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 2b184e8..9e7179c 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"旋轉螢幕"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"工作列教學課程已顯示"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"工作列教學課程已關閉"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"使用工作列即可切換應用程式"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"拖曳到一邊即可同時使用兩個應用程式"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"按住即可隱藏工作列"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 92729ee..8551ee4 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -89,6 +89,8 @@
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Zungezisa isikrini"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Imfuno yebha yomsebenzi ivelile"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Imfundo yebha yomsebenzi ivaliwe"</string>
+ <string name="taskbar_edu_switch_apps" msgid="6942863327845784813">"Sebenzisa ibha yomsebenzi ukushintsha ama-app"</string>
+ <string name="taskbar_edu_splitscreen" msgid="2663361731630346489">"Hudula ngaseceleni ukuze usebenzise ama-app amabili ngesikhathi esisodwa"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Thinta futhi ubambe, bamba ukuze ufihle ibha yomsebenzi"</string>
<string name="taskbar_edu_next" msgid="4007618274426775841">"Okulandelayo"</string>
<string name="taskbar_edu_previous" msgid="459202320127201702">"Emuva"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index f237d26..671a617 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -25,14 +25,14 @@
<!-- Taskbar -->
<color name="taskbar_background">@color/overview_scrim_dark</color>
- <color name="taskbar_icon_selection_ripple">#E0E0E0</color>
-
+ <color name="taskbar_nav_icon_selection_ripple">#E0E0E0</color>
+ <color name="taskbar_nav_icon_light_color">#ffffff</color>
+ <!-- The dark navigation button color is only used in the rare cases that taskbar isn't drawing
+ its background and the underlying app has requested dark buttons. -->
+ <color name="taskbar_nav_icon_dark_color">#99000000</color>
<color name="taskbar_stashed_handle_light_color">#EBffffff</color>
<color name="taskbar_stashed_handle_dark_color">#99000000</color>
- <color name="rotation_button_light_color">#FFF</color>
- <color name="rotation_button_dark_color">#99000000</color>
-
<!-- Gesture navigation tutorial -->
<color name="gesture_tutorial_back_arrow_color">#FFFFFFFF</color>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 4e6b7b9..5ea94e9 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -36,9 +36,12 @@
<dimen name="overview_task_margin">16dp</dimen>
<dimen name="overview_task_margin_focused">12dp</dimen>
<dimen name="overview_task_margin_grid">4dp</dimen>
+ <item name="overview_max_scale" format="float" type="dimen">0.7</item>
<!-- Overrideable in overlay that provides the Overview Actions. -->
<dimen name="overview_actions_height">48dp</dimen>
+ <dimen name="overview_actions_button_spacing">32dp</dimen>
+ <dimen name="overview_actions_button_spacing_grid">36dp</dimen>
<dimen name="overview_actions_margin_gesture">28dp</dimen>
<dimen name="overview_actions_top_margin_gesture_grid_portrait">19.37dp</dimen>
<dimen name="overview_actions_bottom_margin_gesture_grid_portrait">22dp</dimen>
@@ -49,9 +52,10 @@
<dimen name="overview_grid_side_margin_portrait">60dp</dimen>
<dimen name="overview_grid_side_margin_landscape">52dp</dimen>
- <dimen name="overview_grid_row_spacing_portrait">17.13dp</dimen>
- <dimen name="overview_grid_row_spacing_landscape">13.38dp</dimen>
- <dimen name="overview_grid_focus_vertical_margin">0dp</dimen>
+ <dimen name="overview_grid_row_spacing">36dp</dimen>
+ <dimen name="overview_page_spacing">16dp</dimen>
+ <dimen name="overview_page_spacing_grid_portrait">36dp</dimen>
+ <dimen name="overview_page_spacing_grid_landscape">38dp</dimen>
<!-- These speeds are in dp/s -->
<dimen name="max_task_dismiss_drag_velocity">2.25dp</dimen>
@@ -59,8 +63,6 @@
<dimen name="default_task_dismiss_drag_velocity_grid">1dp</dimen>
<dimen name="default_task_dismiss_drag_velocity_grid_focus_task">5dp</dimen>
- <dimen name="recents_page_spacing">16dp</dimen>
- <dimen name="recents_page_spacing_grid">36dp</dimen>
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
<!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
@@ -214,6 +216,7 @@
<!-- Taskbar -->
<dimen name="taskbar_size">@*android:dimen/taskbar_frame_height</dimen>
+ <dimen name="taskbar_ime_size">48dp</dimen>
<dimen name="taskbar_icon_touch_size">48dp</dimen>
<dimen name="taskbar_icon_drag_icon_size">54dp</dimen>
<dimen name="taskbar_folder_margin">16dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index e10273c..6caed1c 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -221,10 +221,10 @@
<string name="taskbar_edu_closed">Taskbar education closed</string>
<!-- Text in dialog that lets a user know how they can use the taskbar to switch apps on their device.
[CHAR_LIMIT=60] -->
- <string name="taskbar_edu_switch_apps" translatable="false">Use the taskbar to switch apps</string>
+ <string name="taskbar_edu_switch_apps">Use the taskbar to switch apps</string>
<!-- Text in dialog that lets a user know how they can use the taskbar to use multiple apps at once on their device.
[CHAR_LIMIT=60] -->
- <string name="taskbar_edu_splitscreen" translatable="false">Drag to the side to use two apps at once</string>
+ <string name="taskbar_edu_splitscreen">Drag to the side to use two apps at once</string>
<!-- Text in dialog that lets a user know how they can hide the taskbar on their device.
[CHAR_LIMIT=60] -->
<string name="taskbar_edu_stashing">Touch & hold to hide the taskbar</string>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 38e8e72..4269f2d 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -320,6 +320,11 @@
mOverviewCommandHelper = binder.getOverviewCommandHelper();
}
+ @Override
+ public void runOnBindToTouchInteractionService(Runnable r) {
+ mTISBindHelper.runOnBindToTouchInteractionService(r);
+ }
+
private void initUnfoldTransitionProgressProvider() {
final UnfoldTransitionConfig config = UnfoldTransitionFactory.createConfig(this);
if (config.isEnabled()) {
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 51d7914..6e2fadd 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -176,6 +176,7 @@
private static final int LAUNCHER_RESUME_START_DELAY = 100;
private static final int CLOSING_TRANSITION_DURATION_MS = 250;
public static final int SPLIT_LAUNCH_DURATION = 370;
+ public static final int SPLIT_DIVIDER_ANIM_DURATION = 100;
public static final int CONTENT_ALPHA_DURATION = 217;
protected static final int CONTENT_SCALE_DURATION = 350;
@@ -660,10 +661,10 @@
AnimOpenProperties prop = new AnimOpenProperties(mLauncher.getResources(), mDeviceProfile,
windowTargetBounds, launcherIconBounds, v, dragLayerBounds[0], dragLayerBounds[1],
hasSplashScreen, floatingView.isDifferentFromAppIcon());
- int left = (int) (prop.cropCenterXStart - prop.cropWidthStart / 2);
- int top = (int) (prop.cropCenterYStart - prop.cropHeightStart / 2);
- int right = (int) (left + prop.cropWidthStart);
- int bottom = (int) (top + prop.cropHeightStart);
+ int left = prop.cropCenterXStart - prop.cropWidthStart / 2;
+ int top = prop.cropCenterYStart - prop.cropHeightStart / 2;
+ int right = left + prop.cropWidthStart;
+ int bottom = top + prop.cropHeightStart;
// Set the crop here so we can calculate the corner radius below.
crop.set(left, top, right, bottom);
@@ -1214,14 +1215,14 @@
}
/**
- * Returns view on the workspace that corresponds to the closing app in the list of app targets
+ * Returns view on launcher that corresponds to the closing app in the list of app targets
*/
- private @Nullable View findWorkspaceView(RemoteAnimationTargetCompat[] appTargets) {
+ private @Nullable View findLauncherView(RemoteAnimationTargetCompat[] appTargets) {
for (RemoteAnimationTargetCompat appTarget : appTargets) {
if (appTarget.mode == MODE_CLOSING) {
- View workspaceView = findWorkspaceView(appTarget);
- if (workspaceView != null) {
- return workspaceView;
+ View launcherView = findLauncherView(appTarget);
+ if (launcherView != null) {
+ return launcherView;
}
}
}
@@ -1229,9 +1230,9 @@
}
/**
- * Returns view on the workspace that corresponds to the {@param runningTaskTarget}.
+ * Returns view on launcher that corresponds to the {@param runningTaskTarget}.
*/
- private @Nullable View findWorkspaceView(RemoteAnimationTargetCompat runningTaskTarget) {
+ private @Nullable View findLauncherView(RemoteAnimationTargetCompat runningTaskTarget) {
if (runningTaskTarget == null || runningTaskTarget.taskInfo == null) {
return null;
}
@@ -1269,7 +1270,7 @@
}
}
- return mLauncher.getWorkspace().getFirstMatchForAppClose(launchCookieItemId,
+ return mLauncher.getFirstMatchForAppClose(launchCookieItemId,
packageName, UserHandle.of(runningTaskTarget.taskInfo.userId));
}
@@ -1292,7 +1293,7 @@
* Closing animator that animates the window into its final location on the workspace.
*/
private void getClosingWindowAnimators(AnimatorSet animation,
- RemoteAnimationTargetCompat[] targets, View workspaceView) {
+ RemoteAnimationTargetCompat[] targets, View launcherView, PointF velocityPxPerS) {
FloatingIconView floatingIconView = null;
FloatingWidgetView floatingWidget = null;
RectF targetRect = new RectF();
@@ -1308,17 +1309,17 @@
}
// Get floating view and target rect.
- if (workspaceView instanceof LauncherAppWidgetHostView) {
+ if (launcherView instanceof LauncherAppWidgetHostView) {
Size windowSize = new Size(mDeviceProfile.availableWidthPx,
mDeviceProfile.availableHeightPx);
int fallbackBackgroundColor =
FloatingWidgetView.getDefaultBackgroundColor(mLauncher, runningTaskTarget);
floatingWidget = FloatingWidgetView.getFloatingWidgetView(mLauncher,
- (LauncherAppWidgetHostView) workspaceView, targetRect, windowSize,
+ (LauncherAppWidgetHostView) launcherView, targetRect, windowSize,
mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher),
isTransluscent, fallbackBackgroundColor);
- } else if (workspaceView != null) {
- floatingIconView = getFloatingIconView(mLauncher, workspaceView,
+ } else if (launcherView != null) {
+ floatingIconView = getFloatingIconView(mLauncher, launcherView,
true /* hideOriginal */, targetRect, false /* isOpening */);
} else {
targetRect.set(getDefaultWindowTargetRect());
@@ -1329,6 +1330,8 @@
mDeviceProfile);
// Hook up floating views to the closing window animators.
+ final int rotationChange = getRotationChange(targets);
+ Rect windowTargetBounds = getWindowTargetBounds(targets, rotationChange);
if (floatingIconView != null) {
anim.addAnimatorListener(floatingIconView);
floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
@@ -1339,7 +1342,8 @@
// FolderIconView can be seen morphing into the icon shape.
final float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
- RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
+ RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect,
+ windowTargetBounds) {
@Override
public void onUpdate(RectF currentRectF, float progress) {
finalFloatingIconView.update(1f, 255 /* fgAlpha */, currentRectF, progress,
@@ -1356,7 +1360,8 @@
final float floatingWidgetAlpha = isTransluscent ? 0 : 1;
FloatingWidgetView finalFloatingWidget = floatingWidget;
- RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
+ RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect,
+ windowTargetBounds) {
@Override
public void onUpdate(RectF currentRectF, float progress) {
final float fallbackBackgroundAlpha =
@@ -1373,15 +1378,10 @@
}
// Use a fixed velocity to start the animation.
- float velocityPxPerS = DynamicResource.provider(mLauncher)
- .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
- PointF velocity = new PointF(0, -velocityPxPerS);
- animation.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
- true /* animateOverviewScrim */, workspaceView).getAnimators());
animation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
- anim.start(mLauncher, velocity);
+ anim.start(mLauncher, velocityPxPerS);
}
});
}
@@ -1556,22 +1556,30 @@
if (anim == null) {
anim = new AnimatorSet();
- View workspaceView = findWorkspaceView(appTargets);
- boolean isWorkspaceViewVisible = workspaceView != null
- && !mLauncher.isInState(LauncherState.ALL_APPS)
- && !mLauncher.getWorkspace().isOverlayShown();
- boolean playFallBackAnimation = !isWorkspaceViewVisible
- && (launcherIsATargetWithMode(appTargets, MODE_OPENING)
- || mLauncher.isForceInvisible());
+ final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
+ || launcherIsATargetWithMode(appTargets, MODE_OPENING);
+
+ View launcherView = findLauncherView(appTargets);
+ boolean playFallBackAnimation = (launcherView == null
+ && launcherIsForceInvisibleOrOpening)
+ || mLauncher.getWorkspace().isOverlayShown();
boolean playWorkspaceReveal = true;
if (mFromUnlock) {
anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
} else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
&& !playFallBackAnimation) {
- getClosingWindowAnimators(anim, appTargets, workspaceView);
- // We play StaggeredWorkspaceAnim as a part of the closing window animation.
- playWorkspaceReveal = false;
+ // Use a fixed velocity to start the animation.
+ float velocityPxPerS = DynamicResource.provider(mLauncher)
+ .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
+ PointF velocity = new PointF(0, -velocityPxPerS);
+ getClosingWindowAnimators(anim, appTargets, launcherView, velocity);
+ if (!mLauncher.isInState(LauncherState.ALL_APPS)) {
+ anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
+ true /* animateOverviewScrim */, launcherView).getAnimators());
+ // We play StaggeredWorkspaceAnim as a part of the closing window animation.
+ playWorkspaceReveal = false;
+ }
} else {
anim.play(getFallbackClosingWindowAnimators(appTargets));
}
@@ -1584,8 +1592,7 @@
// targets list because it is already visible). In that case, we force
// invisibility on touch down, and only reset it after the animation to home
// is initialized.
- if (launcherIsATargetWithMode(appTargets, MODE_OPENING)
- || mLauncher.isForceInvisible()) {
+ if (launcherIsForceInvisibleOrOpening) {
addCujInstrumentation(
anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
// Only register the content animation for cancellation when state changes
@@ -1765,12 +1772,17 @@
private final float mStartRadius;
private final float mEndRadius;
private final SurfaceTransactionApplier mSurfaceApplier;
+ private final Rect mWindowTargetBounds = new Rect();
- SpringAnimRunner(RemoteAnimationTargetCompat[] appTargets, RectF targetRect) {
+ private final Rect mTmpRect = new Rect();
+
+ SpringAnimRunner(RemoteAnimationTargetCompat[] appTargets, RectF targetRect,
+ Rect windowTargetBounds) {
mAppTargets = appTargets;
mStartRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
mEndRadius = Math.max(1, targetRect.width()) / 2f;
mSurfaceApplier = new SurfaceTransactionApplier(mDragLayer);
+ mWindowTargetBounds.set(windowTargetBounds);
}
public float getCornerRadius(float progress) {
@@ -1791,13 +1803,36 @@
}
if (target.mode == MODE_CLOSING) {
- float alpha = getWindowAlpha(progress);
currentRectF.round(mCurrentRect);
+ // Scale the target window to match the currentRectF.
+ final float scale;
+
+ // We need to infer the crop (we crop the window to match the currentRectF).
+ if (mWindowTargetBounds.height() > mWindowTargetBounds.width()) {
+ scale = Math.min(1f, currentRectF.width() / mWindowTargetBounds.width());
+
+ int unscaledHeight = (int) (mCurrentRect.height() * (1f / scale));
+ int croppedHeight = mWindowTargetBounds.height() - unscaledHeight;
+ mTmpRect.set(0, 0, mWindowTargetBounds.width(),
+ mWindowTargetBounds.height() - croppedHeight);
+ } else {
+ scale = Math.min(1f, currentRectF.height() / mWindowTargetBounds.height());
+
+ int unscaledWidth = (int) (mCurrentRect.width() * (1f / scale));
+ int croppedWidth = mWindowTargetBounds.width() - unscaledWidth;
+ mTmpRect.set(0, 0, mWindowTargetBounds.width() - croppedWidth,
+ mWindowTargetBounds.height());
+ }
+
+ // Match size and position of currentRect.
+ mMatrix.setScale(scale, scale);
+ mMatrix.postTranslate(mCurrentRect.left, mCurrentRect.top);
+
builder.withMatrix(mMatrix)
- .withWindowCrop(mCurrentRect)
- .withAlpha(alpha)
- .withCornerRadius(getCornerRadius(progress));
+ .withWindowCrop(mTmpRect)
+ .withAlpha(getWindowAlpha(progress))
+ .withCornerRadius(getCornerRadius(progress) / scale);
} else if (target.mode == MODE_OPENING) {
mMatrix.setTranslate(mTmpPos.x, mTmpPos.y);
builder.withMatrix(mMatrix)
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index e82c900..4d06956 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -64,6 +64,7 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.PersistedItemArray;
+import com.android.quickstep.logging.SettingsChangeLogger;
import com.android.quickstep.logging.StatsLogCompatManager;
import com.android.systemui.shared.system.SysUiStatsLog;
@@ -97,10 +98,12 @@
private final InvariantDeviceProfile mIDP;
private final AppEventProducer mAppEventProducer;
private final StatsManager mStatsManager;
+ private final Context mContext;
protected boolean mActive = false;
public QuickstepModelDelegate(Context context) {
+ mContext = context;
mAppEventProducer = new AppEventProducer(context, this::onAppTargetEvent);
mIDP = InvariantDeviceProfile.INSTANCE.get(context);
@@ -161,8 +164,7 @@
}
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
for (ItemInfo info : itemsIdMap) {
- FolderInfo parent = info.container > 0
- ? (FolderInfo) itemsIdMap.get(info.container) : null;
+ FolderInfo parent = getContainer(info, itemsIdMap);
StatsLogCompatManager.writeSnapshot(info.buildProto(parent), instanceId);
}
additionalSnapshotEvents(instanceId);
@@ -199,8 +201,7 @@
}
for (ItemInfo info : itemsIdMap) {
- FolderInfo parent = info.container > 0
- ? (FolderInfo) itemsIdMap.get(info.container) : null;
+ FolderInfo parent = getContainer(info, itemsIdMap);
LauncherAtom.ItemInfo itemInfo = info.buildProto(parent);
Log.d(TAG, itemInfo.toString());
StatsEvent statsEvent = StatsLogCompatManager.buildStatsEvent(itemInfo,
@@ -212,6 +213,7 @@
"Successfully logged %d workspace items with instanceId=%d",
itemsIdMap.size(), instanceId.getId()));
additionalSnapshotEvents(instanceId);
+ SettingsChangeLogger.INSTANCE.get(mContext).logSnapshot(instanceId);
return StatsManager.PULL_SUCCESS;
}
);
@@ -222,6 +224,22 @@
}
}
+ private static FolderInfo getContainer(ItemInfo info, IntSparseArrayMap<ItemInfo> itemsIdMap) {
+ if (info.container > 0) {
+ ItemInfo containerInfo = itemsIdMap.get(info.container);
+
+ if (!(containerInfo instanceof FolderInfo)) {
+ Log.e(TAG, String.format(
+ "Item info: %s found with invalid container: %s",
+ info,
+ containerInfo));
+ } else {
+ return (FolderInfo) containerInfo;
+ }
+ }
+ return null;
+ }
+
@Override
public void validateData() {
super.validateData();
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 9d70cfa..e1d89a1 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -44,7 +44,6 @@
import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.WallpaperManagerCompat;
-import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -156,6 +155,10 @@
// Workaround for animating the depth when multiwindow mode changes.
private boolean mIgnoreStateChangesDuringMultiWindowAnimation = false;
+ // Hints that there is potentially content behind Launcher and that we shouldn't optimize by
+ // marking the launcher surface as opaque. Only used in certain Launcher states.
+ private boolean mHasContentBehindLauncher;
+
private View.OnAttachStateChangeListener mOnAttachListener;
public DepthController(Launcher l) {
@@ -199,6 +202,10 @@
mLauncher.getScrimView().addOpaquenessListener(mOpaquenessListener);
}
+ public void setHasContentBehindLauncher(boolean hasContentBehindLauncher) {
+ mHasContentBehindLauncher = hasContentBehindLauncher;
+ }
+
/**
* Sets if the underlying activity is started or not
*/
@@ -311,13 +318,14 @@
}
if (supportsBlur) {
- boolean opaque = mLauncher.getScrimView().isFullyOpaque();
+ boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque();
+ boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg;
- mCurrentBlur = !mCrossWindowBlursEnabled || mBlurDisabledForAppLaunch
+ mCurrentBlur = !mCrossWindowBlursEnabled || mBlurDisabledForAppLaunch || hasOpaqueBg
? 0 : (int) (depth * mMaxBlurRadius);
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
.setBackgroundBlurRadius(mSurface, mCurrentBlur)
- .setOpaque(mSurface, opaque);
+ .setOpaque(mSurface, isSurfaceOpaque);
// Set early wake-up flags when we know we're executing an expensive operation, this way
// SurfaceFlinger will adjust its internal offsets to avoid jank.
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 24a88a4..f1e6747 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -46,16 +46,13 @@
}
};
- // Initialized in init.
- TaskbarControllers mControllers;
-
public FallbackTaskbarUIController(RecentsActivity recentsActivity) {
mRecentsActivity = recentsActivity;
}
@Override
protected void init(TaskbarControllers taskbarControllers) {
- mControllers = taskbarControllers;
+ super.init(taskbarControllers);
mRecentsActivity.setTaskbarUIController(this);
mRecentsActivity.getStateManager().addStateListener(mStateListener);
@@ -63,6 +60,7 @@
@Override
protected void onDestroy() {
+ super.onDestroy();
mRecentsActivity.setTaskbarUIController(null);
mRecentsActivity.getStateManager().removeStateListener(mStateListener);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 1c0c773..5e8db69 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -20,12 +20,10 @@
import android.animation.Animator;
import android.annotation.ColorInt;
-import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
import android.view.TaskTransitionSpec;
-import android.view.View;
import android.view.WindowManagerGlobal;
import androidx.annotation.NonNull;
@@ -62,7 +60,6 @@
this::onStashedInAppChanged;
// Initialized in init.
- private TaskbarControllers mControllers;
private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
private TaskbarKeyguardController mKeyguardController;
private final TaskbarLauncherStateController
@@ -83,7 +80,7 @@
@Override
protected void init(TaskbarControllers taskbarControllers) {
- mControllers = taskbarControllers;
+ super.init(taskbarControllers);
mTaskbarLauncherStateController.init(mControllers, mLauncher);
mTaskbarOverrideBackgroundAlpha = mControllers.taskbarDragLayerController
@@ -101,6 +98,7 @@
@Override
protected void onDestroy() {
+ super.onDestroy();
onLauncherResumedOrPaused(false);
mTaskbarLauncherStateController.onDestroy();
@@ -115,13 +113,6 @@
return !mTaskbarLauncherStateController.isAnimatingToLauncher();
}
- @Override
- protected void updateContentInsets(Rect outContentInsets) {
- int contentHeight = mControllers.taskbarStashController.getContentHeight();
- TaskbarDragLayer dragLayer = mControllers.taskbarActivityContext.getDragLayer();
- outContentInsets.top = dragLayer.getHeight() - contentHeight;
- }
-
/**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
@@ -168,10 +159,6 @@
return mControllers.taskbarDragController.isDragging();
}
- public View getRootView() {
- return mControllers.taskbarActivityContext.getDragLayer();
- }
-
@Override
protected void onStashedInAppChanged() {
onStashedInAppChanged(mLauncher.getDeviceProfile());
@@ -251,4 +238,12 @@
mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
instanceId);
}
+
+ @Override
+ public void setSystemGestureInProgress(boolean inProgress) {
+ super.setSystemGestureInProgress(inProgress);
+ // Launcher's ScrimView will draw the background throughout the gesture. But once the
+ // gesture ends, start drawing taskbar's background again since launcher might stop drawing.
+ forceHideBackground(inProgress);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 4b6dacd..50637a1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -15,16 +15,12 @@
*/
package com.android.launcher3.taskbar;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
-
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y_LONG_CLICK;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
-import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_IME;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_KEYGUARD;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
@@ -35,13 +31,16 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
-import android.content.Context;
+import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.Region.Op;
@@ -62,7 +61,6 @@
import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.Themes;
import com.android.quickstep.AnimatedFloat;
import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.shared.rotation.RotationButton;
@@ -89,12 +87,12 @@
private static final int FLAG_DISABLE_RECENTS = 1 << 8;
private static final int FLAG_DISABLE_BACK = 1 << 9;
private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10;
+ private static final int FLAG_SCREEN_PINNING_ACTIVE = 1 << 11;
private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
- private View.OnLongClickListener mA11yLongClickListener;
private final ArrayList<StatePropertyHolder> mPropertyHolders = new ArrayList<>();
- private final ArrayList<View> mAllButtons = new ArrayList<>();
+ private final ArrayList<ImageView> mAllButtons = new ArrayList<>();
private int mState;
private final TaskbarActivityContext mContext;
@@ -103,11 +101,20 @@
// Used for IME+A11Y buttons
private final ViewGroup mEndContextualContainer;
private final ViewGroup mStartContextualContainer;
+ private final int mLightIconColor;
+ private final int mDarkIconColor;
private final AnimatedFloat mTaskbarNavButtonTranslationY = new AnimatedFloat(
this::updateNavButtonTranslationY);
+ private final AnimatedFloat mTaskbarNavButtonTranslationYForIme = new AnimatedFloat(
+ this::updateNavButtonTranslationY);
+ // Only applies to mTaskbarNavButtonTranslationY
private final AnimatedFloat mNavButtonTranslationYMultiplier = new AnimatedFloat(
this::updateNavButtonTranslationY);
+ private final AnimatedFloat mTaskbarNavButtonDarkIntensity = new AnimatedFloat(
+ this::updateNavButtonDarkIntensity);
+ private final AnimatedFloat mNavButtonDarkIntensityMultiplier = new AnimatedFloat(
+ this::updateNavButtonDarkIntensity);
private final RotationButtonListener mRotationButtonListener = new RotationButtonListener();
private final Rect mFloatingRotationButtonBounds = new Rect();
@@ -125,6 +132,9 @@
mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
mEndContextualContainer = mNavButtonsView.findViewById(R.id.end_contextual_buttons);
mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
+
+ mLightIconColor = context.getColor(R.color.taskbar_nav_icon_light_color);
+ mDarkIconColor = context.getColor(R.color.taskbar_nav_icon_dark_color);
}
/**
@@ -135,16 +145,6 @@
mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
mNavButtonTranslationYMultiplier.value = 1;
- mA11yLongClickListener = view -> {
- mControllers.navButtonController.onButtonClick(BUTTON_A11Y_LONG_CLICK);
- return true;
- };
-
- mPropertyHolders.add(new StatePropertyHolder(
- mControllers.taskbarViewController.getTaskbarIconAlpha()
- .getProperty(ALPHA_INDEX_IME),
- flags -> (flags & FLAG_IME_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
-
boolean isThreeButtonNav = mContext.isThreeButtonNav();
// IME switcher
View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
@@ -157,20 +157,34 @@
mPropertyHolders.add(new StatePropertyHolder(
mControllers.taskbarViewController.getTaskbarIconAlpha()
.getProperty(ALPHA_INDEX_KEYGUARD),
- flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
+ && (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0,
+ MultiValueAlpha.VALUE, 1, 0));
mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
.getKeyguardBgTaskbar(),
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, AnimatedFloat.VALUE, 1, 0));
- // Make sure to remove nav bar buttons translation when notification shade is expanded.
- mPropertyHolders.add(new StatePropertyHolder(mNavButtonTranslationYMultiplier,
- flags -> (flags & FLAG_NOTIFICATION_SHADE_EXPANDED) != 0, AnimatedFloat.VALUE,
- 0, 1));
-
// Force nav buttons (specifically back button) to be visible during setup wizard.
boolean isInSetup = !mContext.isUserSetupComplete();
- if (isThreeButtonNav || isInSetup) {
+ boolean alwaysShowButtons = isThreeButtonNav || isInSetup;
+
+ // Make sure to remove nav bar buttons translation when notification shade is expanded or
+ // IME is showing (add separate translation for IME).
+ int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE;
+ mPropertyHolders.add(new StatePropertyHolder(mNavButtonTranslationYMultiplier,
+ flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
+ 0, 1));
+ // Center nav buttons in new height for IME.
+ float transForIme = (mContext.getDeviceProfile().taskbarSize
+ - mContext.getTaskbarHeightForIme()) / 2f;
+ // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
+ float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
+ mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
+ flags -> (flags & FLAG_IME_VISIBLE) != 0, AnimatedFloat.VALUE, transForIme,
+ defaultButtonTransY));
+
+ if (alwaysShowButtons) {
initButtons(mNavButtonContainer, mEndContextualContainer,
mControllers.navButtonController);
@@ -184,19 +198,16 @@
navButtonsLayoutParams.gravity = Gravity.START;
mNavButtonContainer.requestLayout();
- if (!isThreeButtonNav) {
- // Tint all the nav buttons since there's no taskbar background in SUW.
- for (int i = 0; i < mNavButtonContainer.getChildCount(); i++) {
- if (!(mNavButtonContainer.getChildAt(i) instanceof ImageView)) continue;
- ImageView button = (ImageView) mNavButtonContainer.getChildAt(i);
- button.setImageTintList(ColorStateList.valueOf(Themes.getAttrColor(
- button.getContext(), android.R.attr.textColorPrimary)));
- }
- }
+ // TODO(b/210906568) Dark intensity is currently not propagated during setup, so set
+ // it based on dark theme for now.
+ int mode = mContext.getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK;
+ boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
+ mTaskbarNavButtonDarkIntensity.updateValue(isDarkTheme ? 0 : 1);
}
// Animate taskbar background when any of these flags are enabled
- int flagsToShowBg = FLAG_IME_VISIBLE | FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE
+ int flagsToShowBg = FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE
| FLAG_NOTIFICATION_SHADE_EXPANDED;
mPropertyHolders.add(new StatePropertyHolder(
mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
@@ -240,16 +251,19 @@
mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
mNavButtonContainer, mControllers.navButtonController, R.id.back);
mPropertyHolders.add(new StatePropertyHolder(mBackButton,
- flags -> (flags & FLAG_DISABLE_BACK) == 0));
+ flags -> {
+ // Show only if not disabled, and if not on the keyguard or otherwise only when
+ // the bouncer or a lockscreen app is showing above the keyguard
+ boolean showingOnKeyguard = (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
+ (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0 ||
+ (flags & FLAG_KEYGUARD_OCCLUDED) != 0;
+ return (flags & FLAG_DISABLE_BACK) == 0
+ && ((flags & FLAG_KEYGUARD_VISIBLE) == 0 || showingOnKeyguard);
+ }));
boolean isRtl = Utilities.isRtl(mContext.getResources());
mPropertyHolders.add(new StatePropertyHolder(
mBackButton, flags -> (flags & FLAG_IME_VISIBLE) != 0, View.ROTATION,
isRtl ? 90 : -90, 0));
- // Hide when keyguard is showing, show when bouncer or lock screen app is showing
- mPropertyHolders.add(new StatePropertyHolder(mBackButton,
- flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
- (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0 ||
- (flags & FLAG_KEYGUARD_OCCLUDED) != 0));
// Translate back button to be at end/start of other buttons for keyguard
int navButtonSize = mContext.getResources().getDimensionPixelSize(
R.dimen.taskbar_nav_buttons_size);
@@ -278,7 +292,6 @@
mPropertyHolders.add(new StatePropertyHolder(mA11yButton,
flags -> (flags & FLAG_A11Y_VISIBLE) != 0
&& (flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0));
- mA11yButton.setOnLongClickListener(mA11yLongClickListener);
}
private void parseSystemUiFlags(int sysUiStateFlags) {
@@ -292,6 +305,7 @@
int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0;
+ boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
// TODO(b/202218289) we're getting IME as not visible on lockscreen from system
updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
@@ -301,6 +315,7 @@
updateStateForFlag(FLAG_DISABLE_RECENTS, isRecentsDisabled);
updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled);
updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded);
+ updateStateForFlag(FLAG_SCREEN_PINNING_ACTIVE, isScreenPinningActive);
if (mA11yButton != null) {
// Only used in 3 button
@@ -379,6 +394,16 @@
return mTaskbarNavButtonTranslationY;
}
+ /** Use to set the dark intensity for the all nav+contextual buttons */
+ public AnimatedFloat getTaskbarNavButtonDarkIntensity() {
+ return mTaskbarNavButtonDarkIntensity;
+ }
+
+ /** Use to determine whether to use the dark intensity requested by the underlying app */
+ public AnimatedFloat getNavButtonDarkIntensityMultiplier() {
+ return mNavButtonDarkIntensityMultiplier;
+ }
+
/**
* Does not call {@link #applyState()}. Don't forget to!
*/
@@ -398,8 +423,20 @@
}
private void updateNavButtonTranslationY() {
- mNavButtonsView.setTranslationY(mTaskbarNavButtonTranslationY.value
- * mNavButtonTranslationYMultiplier.value);
+ float normalTranslationY = mTaskbarNavButtonTranslationY.value
+ * mNavButtonTranslationYMultiplier.value;
+ float otherTranslationY = mTaskbarNavButtonTranslationYForIme.value;
+ mNavButtonsView.setTranslationY(normalTranslationY + otherTranslationY);
+ }
+
+ private void updateNavButtonDarkIntensity() {
+ float darkIntensity = mTaskbarNavButtonDarkIntensity.value
+ * mNavButtonDarkIntensityMultiplier.value;
+ int iconColor = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, mLightIconColor,
+ mDarkIconColor);
+ for (ImageView button : mAllButtons) {
+ button.setImageTintList(ColorStateList.valueOf(iconColor));
+ }
}
private ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
@@ -414,6 +451,8 @@
ImageView buttonView = addButton(parent, id, layoutId);
buttonView.setImageResource(drawableId);
buttonView.setOnClickListener(view -> navButtonController.onButtonClick(buttonType));
+ buttonView.setOnLongClickListener(view ->
+ navButtonController.onButtonLongClick(buttonType));
return buttonView;
}
@@ -430,6 +469,12 @@
return mFloatingRotationButtonBounds.contains((int) ev.getX(), (int) ev.getY());
}
+ public void onConfigurationChanged(@Config int configChanges) {
+ if (mFloatingRotationButton != null) {
+ mFloatingRotationButton.onConfigurationChanged(configChanges);
+ }
+ }
+
public void onDestroy() {
mPropertyHolders.clear();
mControllers.rotationButtonController.unregisterListeners();
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 2c80f06..22ca63f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -16,6 +16,8 @@
package com.android.launcher3.taskbar;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Outline;
@@ -23,8 +25,6 @@
import android.view.View;
import android.view.ViewOutlineProvider;
-import androidx.annotation.Nullable;
-
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.RevealOutlineAnimation;
@@ -66,7 +66,10 @@
private final Rect mStashedHandleBounds = new Rect();
private float mStashedHandleRadius;
- private boolean mIsAtStashedRevealBounds = true;
+ // When the reveal animation is cancelled, we can assume it's about to create a new animation,
+ // which should start off at the same point the cancelled one left off.
+ private float mStartProgressForNextRevealAnim;
+ private boolean mWasLastRevealAnimReversed;
public StashedHandleViewController(TaskbarActivityContext activity,
StashedHandleView stashedHandleView) {
@@ -148,15 +151,27 @@
* shape and size. When stashed, the shape is a thin rounded pill. When unstashed, the shape
* morphs into the size of where the taskbar icons will be.
*/
- public @Nullable Animator createRevealAnimToIsStashed(boolean isStashed) {
- if (mIsAtStashedRevealBounds == isStashed) {
- return null;
- }
- mIsAtStashedRevealBounds = isStashed;
+ public Animator createRevealAnimToIsStashed(boolean isStashed) {
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
mStashedHandleRadius, mStashedHandleRadius,
mControllers.taskbarViewController.getIconLayoutBounds(), mStashedHandleBounds);
- return handleRevealProvider.createRevealAnimator(mStashedHandleView, !isStashed);
+
+ boolean isReversed = !isStashed;
+ boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
+ mWasLastRevealAnimReversed = isReversed;
+ if (changingDirection) {
+ mStartProgressForNextRevealAnim = 1f - mStartProgressForNextRevealAnim;
+ }
+
+ ValueAnimator revealAnim = handleRevealProvider.createRevealAnimator(mStashedHandleView,
+ isReversed, mStartProgressForNextRevealAnim);
+ revealAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStartProgressForNextRevealAnim = ((ValueAnimator) animation).getAnimatedFraction();
+ }
+ });
+ return revealAnim;
}
public void onIsStashed(boolean isStashed) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index cc83431..5308a8f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -20,7 +20,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
-import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
@@ -31,7 +30,9 @@
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
+import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -96,6 +97,7 @@
private final WindowManager mWindowManager;
private final @Nullable RoundedCorner mLeftCorner, mRightCorner;
+ private final int mTaskbarHeightForIme;
private WindowManager.LayoutParams mWindowLayoutParams;
private boolean mIsFullscreen;
// The size we should return to when we call setTaskbarWindowFullscreen(false)
@@ -122,10 +124,13 @@
mIsUserSetupComplete = SettingsCache.INSTANCE.get(this).getValue(
Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
- float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size);
- mDeviceProfile.updateIconSize(1, getResources());
+ final Resources resources = getResources();
+ float taskbarIconSize = resources.getDimension(R.dimen.taskbar_icon_size);
+ mDeviceProfile.updateIconSize(1, resources);
float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
- mDeviceProfile.updateIconSize(iconScale, getResources());
+ mDeviceProfile.updateIconSize(iconScale, resources);
+
+ mTaskbarHeightForIme = resources.getDimensionPixelSize(R.dimen.taskbar_ime_size);
mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
@@ -151,8 +156,8 @@
buttonController,
new NavbarButtonsViewController(this, navButtonsView),
new RotationButtonController(this,
- c.getColor(R.color.rotation_button_light_color),
- c.getColor(R.color.rotation_button_dark_color),
+ c.getColor(R.color.taskbar_nav_icon_light_color),
+ c.getColor(R.color.taskbar_nav_icon_dark_color),
R.drawable.ic_sysbar_rotate_button_ccw_start_0,
R.drawable.ic_sysbar_rotate_button_ccw_start_90,
R.drawable.ic_sysbar_rotate_button_cw_start_0,
@@ -197,14 +202,17 @@
// Adjust the frame by the rounded corners (ie. leaving just the bar as the inset) when
// the IME is showing
mWindowLayoutParams.providedInternalImeInsets = Insets.of(0,
- getDefaultTaskbarWindowHeight() - mDeviceProfile.taskbarSize, 0, 0);
+ getDefaultTaskbarWindowHeight() - mTaskbarHeightForIme, 0, 0);
// Initialize controllers after all are constructed.
mControllers.init(sharedState);
updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
- Log.d(TASKBAR_WINDOW_CRASH, "Adding taskbar window");
+ }
+
+ public void onConfigurationChanged(@Config int configChanges) {
+ mControllers.onConfigurationChanged(configChanges);
}
public boolean isThreeButtonNav() {
@@ -340,7 +348,6 @@
setUIController(TaskbarUIController.DEFAULT);
mControllers.onDestroy();
mWindowManager.removeViewImmediate(mDragLayer);
- Log.d(TASKBAR_WINDOW_CRASH, "Removing taskbar window");
}
public void updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit) {
@@ -359,6 +366,7 @@
mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
+ mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
}
/**
@@ -394,6 +402,14 @@
mControllers.rotationButtonController.onBehaviorChanged(displayId, behavior);
}
+ public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+ if (!isUserSetupComplete()) {
+ return;
+ }
+ mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
+ .updateValue(darkIntensity);
+ }
+
/**
* Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
*/
@@ -415,7 +431,9 @@
if (mWindowLayoutParams.height == height || mIsDestroyed) {
return;
}
- if (height != MATCH_PARENT) {
+ if (height == MATCH_PARENT) {
+ height = mDeviceProfile.heightPx;
+ } else {
mLastRequestedNonFullscreenHeight = height;
if (mIsFullscreen) {
// We still need to be fullscreen, so defer any change to our height until we call
@@ -426,6 +444,8 @@
}
}
mWindowLayoutParams.height = height;
+ mWindowLayoutParams.providedInternalImeInsets =
+ Insets.of(0, height - mTaskbarHeightForIme, 0, 0);
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
@@ -436,6 +456,13 @@
return mDeviceProfile.taskbarSize + Math.max(getLeftCornerRadius(), getRightCornerRadius());
}
+ /**
+ * Returns the bottom insets taskbar provides to the IME when IME is visible.
+ */
+ public int getTaskbarHeightForIme() {
+ return mTaskbarHeightForIme;
+ }
+
protected void onTaskbarIconClicked(View view) {
Object tag = view.getTag();
if (tag instanceof Task) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 56730db..c43fbf9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -15,10 +15,15 @@
*/
package com.android.launcher3.taskbar;
+import android.content.pm.ActivityInfo.Config;
+
import androidx.annotation.NonNull;
import com.android.systemui.shared.rotation.RotationButtonController;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Hosts various taskbar controllers to facilitate passing between one another.
*/
@@ -43,6 +48,9 @@
/** Do not store this controller, as it may change at runtime. */
@NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
+ private boolean mAreAllControllersInitialized;
+ private final List<Runnable> mPostInitCallbacks = new ArrayList<>();
+
public TaskbarControllers(TaskbarActivityContext taskbarActivityContext,
TaskbarDragController taskbarDragController,
TaskbarNavButtonController navButtonController,
@@ -81,6 +89,8 @@
* in constructors for now, as some controllers may still be waiting for init().
*/
public void init(TaskbarSharedState sharedState) {
+ mAreAllControllersInitialized = false;
+
taskbarDragController.init(this);
navbarButtonsViewController.init(this);
rotationButtonController.init();
@@ -92,6 +102,16 @@
stashedHandleViewController.init(this);
taskbarStashController.init(this, sharedState);
taskbarEduController.init(this);
+
+ mAreAllControllersInitialized = true;
+ for (Runnable postInitCallback : mPostInitCallbacks) {
+ postInitCallback.run();
+ }
+ mPostInitCallbacks.clear();
+ }
+
+ public void onConfigurationChanged(@Config int configChanges) {
+ navbarButtonsViewController.onConfigurationChanged(configChanges);
}
/**
@@ -108,4 +128,17 @@
stashedHandleViewController.onDestroy();
taskbarAutohideSuspendController.onDestroy();
}
+
+ /**
+ * If all controllers are already initialized, runs the given callback immediately. Otherwise,
+ * queues it to run after calling init() on all controllers. This should likely be used in any
+ * case where one controller is telling another controller to do something inside init().
+ */
+ public void runAfterInit(Runnable callback) {
+ if (mAreAllControllersInitialized) {
+ callback.run();
+ } else {
+ mPostInitCallbacks.add(callback);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 81039d4..a918016 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -44,6 +44,7 @@
private final AnimatedFloat mKeyguardBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
private final AnimatedFloat mNotificationShadeBgTaskbar = new AnimatedFloat(
this::updateBackgroundAlpha);
+ private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
// Used to hide our background color when someone else (e.g. ScrimView) is handling it.
private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha);
@@ -52,6 +53,9 @@
// Initialized in init.
private TaskbarControllers mControllers;
+ private AnimatedFloat mNavButtonDarkIntensityMultiplier;
+
+ private float mLastSetBackgroundAlpha;
public TaskbarDragLayerController(TaskbarActivityContext activity,
TaskbarDragLayer taskbarDragLayer) {
@@ -65,9 +69,13 @@
mControllers = controllers;
mTaskbarDragLayer.init(new TaskbarDragLayerCallbacks());
+ mNavButtonDarkIntensityMultiplier = mControllers.navbarButtonsViewController
+ .getNavButtonDarkIntensityMultiplier();
+
mBgTaskbar.value = 1;
mKeyguardBgTaskbar.value = 1;
mNotificationShadeBgTaskbar.value = 1;
+ mImeBgTaskbar.value = 1;
mBgOverride.value = 1;
updateBackgroundAlpha();
}
@@ -102,6 +110,10 @@
return mNotificationShadeBgTaskbar;
}
+ public AnimatedFloat getImeBgTaskbar() {
+ return mImeBgTaskbar;
+ }
+
public AnimatedFloat getOverrideBackgroundAlpha() {
return mBgOverride;
}
@@ -113,14 +125,23 @@
private void updateBackgroundAlpha() {
final float bgNavbar = mBgNavbar.value;
final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
- * mNotificationShadeBgTaskbar.value;
- mTaskbarDragLayer.setTaskbarBackgroundAlpha(
- mBgOverride.value * Math.max(bgNavbar, bgTaskbar)
- );
+ * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value;
+ mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar);
+ mTaskbarDragLayer.setTaskbarBackgroundAlpha(mLastSetBackgroundAlpha);
+
+ updateNavBarDarkIntensityMultiplier();
}
private void updateBackgroundOffset() {
mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value);
+
+ updateNavBarDarkIntensityMultiplier();
+ }
+
+ private void updateNavBarDarkIntensityMultiplier() {
+ // Zero out the app-requested dark intensity when we're drawing our own background.
+ float effectiveBgAlpha = mLastSetBackgroundAlpha * (1 - mBgOffset.value);
+ mNavButtonDarkIntensityMultiplier.updateValue(1 - effectiveBgAlpha);
}
/**
@@ -160,10 +181,13 @@
}
/**
- * Called to update the {@link InsetsInfo#contentInsets}.
+ * Called to update the {@link InsetsInfo#contentInsets}. This is reported to apps but our
+ * internal launcher will ignore these insets.
*/
public void updateContentInsets(Rect outContentInsets) {
- mControllers.uiController.updateContentInsets(outContentInsets);
+ int contentHeight = mControllers.taskbarStashController
+ .getContentHeightToReportToApps();
+ outContentInsets.top = mTaskbarDragLayer.getHeight() - contentHeight;
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 152b255..7a50d0b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.taskbar;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
@@ -50,13 +49,15 @@
public static final int FLAG_RESUMED = 1 << 0;
public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1;
- public static final int FLAG_TRANSITION_STATE_START_STASHED = 1 << 2;
- public static final int FLAG_TRANSITION_STATE_COMMITTED_STASHED = 1 << 3;
+ public static final int FLAG_TRANSITION_STATE_RUNNING = 1 << 2;
+
+ /** Equivalent to an int with all 1s for binary operation purposes */
+ private static final int FLAGS_ALL = ~0;
private final AnimatedFloat mIconAlignmentForResumedState =
- new AnimatedFloat(this::onIconAlignmentRatioChanged);
+ new AnimatedFloat(this::onIconAlignmentRatioChangedForAppAndHomeTransition);
private final AnimatedFloat mIconAlignmentForGestureState =
- new AnimatedFloat(this::onIconAlignmentRatioChanged);
+ new AnimatedFloat(this::onIconAlignmentRatioChangedForAppAndHomeTransition);
private final AnimatedFloat mIconAlignmentForLauncherState =
new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition);
@@ -65,11 +66,9 @@
private MultiValueAlpha.AlphaProperty mIconAlphaForHome;
private BaseQuickstepLauncher mLauncher;
- private int mPrevState;
+ private Integer mPrevState;
private int mState;
-
- private LauncherState mTargetStateOverride = null;
- private LauncherState mTargetStateOverrideForStateTransition = null;
+ private LauncherState mLauncherState = LauncherState.NORMAL;
private boolean mIsAnimatingToLauncherViaGesture;
private boolean mIsAnimatingToLauncherViaResume;
@@ -79,16 +78,20 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
- mTargetStateOverrideForStateTransition = toState;
- updateStateForFlag(FLAG_TRANSITION_STATE_START_STASHED,
- toState.isTaskbarStashed());
+ if (toState != mLauncherState) {
+ // Treat FLAG_TRANSITION_STATE_RUNNING as a changed flag even if a previous
+ // state transition was already running, so we update the new target.
+ mPrevState &= ~FLAG_TRANSITION_STATE_RUNNING;
+ mLauncherState = toState;
+ }
+ updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true);
applyState();
}
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- updateStateForFlag(FLAG_TRANSITION_STATE_COMMITTED_STASHED,
- finalState.isTaskbarStashed());
+ mLauncherState = finalState;
+ updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false);
applyState();
}
};
@@ -105,9 +108,14 @@
(Consumer<Float>) alpha -> mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1));
mIconAlignmentForResumedState.finishAnimation();
- onIconAlignmentRatioChanged();
+ onIconAlignmentRatioChangedForAppAndHomeTransition();
mLauncher.getStateManager().addStateListener(mStateListener);
+
+ // Initialize to the current launcher state
+ updateStateForFlag(FLAG_RESUMED, launcher.hasBeenResumed());
+ mLauncherState = launcher.getStateManager().getState();
+ applyState(0);
}
public void onDestroy() {
@@ -126,26 +134,15 @@
// If going home, align the icons to hotseat
AnimatorSet animatorSet = new AnimatorSet();
+ // Update stashed flags first to ensure goingToUnstashedLauncherState() returns correctly.
TaskbarStashController stashController = mControllers.taskbarStashController;
stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
- toState.isTaskbarStashed());
+ toState.isTaskbarStashed(mLauncher));
stashController.updateStateForFlag(FLAG_IN_APP, false);
updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
animatorSet.play(stashController.applyStateWithoutStart(duration));
animatorSet.play(applyState(duration, false));
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animator) {
- mTargetStateOverride = null;
- animator.removeListener(this);
- }
-
- @Override
- public void onAnimationStart(Animator animator) {
- mTargetStateOverride = toState;
- }
- });
TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
callbacks.addListener(listener);
@@ -199,10 +196,11 @@
public Animator applyState(long duration, boolean start) {
Animator animator = null;
- if (mPrevState != mState) {
- int changedFlags = mPrevState ^ mState;
- animator = onStateChangeApplied(changedFlags, duration, start);
+ if (mPrevState == null || mPrevState != mState) {
+ // If this is our initial state, treat all flags as changed.
+ int changedFlags = mPrevState == null ? FLAGS_ALL : mPrevState ^ mState;
mPrevState = mState;
+ animator = onStateChangeApplied(changedFlags, duration, start);
}
return animator;
}
@@ -212,7 +210,8 @@
if (hasAnyFlag(changedFlags, FLAG_RESUMED)) {
boolean isResumed = isResumed();
ObjectAnimator anim = mIconAlignmentForResumedState
- .animateToValue(getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
+ .animateToValue(isResumed && goingToUnstashedLauncherState()
+ ? 1 : 0)
.setDuration(duration);
anim.addListener(new AnimatorListenerAdapter() {
@@ -236,7 +235,8 @@
if (hasAnyFlag(changedFlags, FLAG_RECENTS_ANIMATION_RUNNING)) {
boolean isRecentsAnimationRunning = isRecentsAnimationRunning();
Animator animator = mIconAlignmentForGestureState
- .animateToValue(isRecentsAnimationRunning ? 1 : 0);
+ .animateToValue(isRecentsAnimationRunning && goingToUnstashedLauncherState()
+ ? 1 : 0);
if (isRecentsAnimationRunning) {
animator.setDuration(duration);
}
@@ -254,14 +254,21 @@
animatorSet.play(animator);
}
- if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_START_STASHED)) {
- playStateTransitionAnim(isTransitionStateStartStashed(), animatorSet, duration,
- false /* committed */);
+ if (hasAnyFlag(changedFlags, FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING)) {
+ boolean goingToLauncher = hasAnyFlag(FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING);
+ animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(goingToLauncher ? 0 : 1)
+ .setDuration(duration));
}
- if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_COMMITTED_STASHED)) {
- playStateTransitionAnim(isTransitionStateCommittedStashed(), animatorSet, duration,
- true /* committed */);
+ if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_RUNNING)) {
+ boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING);
+ playStateTransitionAnim(animatorSet, duration, committed);
+
+ if (committed && mLauncherState == LauncherState.QUICK_SWITCH) {
+ // We're about to be paused, set immediately to ensure seamless handoff.
+ updateStateForFlag(FLAG_RESUMED, false);
+ applyState(0 /* duration */);
+ }
}
if (start) {
@@ -270,35 +277,41 @@
return animatorSet;
}
- private void playStateTransitionAnim(boolean isTransitionStateStashed,
- AnimatorSet animatorSet, long duration, boolean committed) {
+ /** Returns whether we're going to a state where taskbar icons should align with launcher. */
+ private boolean goingToUnstashedLauncherState() {
+ return !mControllers.taskbarStashController.isInStashedLauncherState();
+ }
+
+ private void playStateTransitionAnim(AnimatorSet animatorSet, long duration,
+ boolean committed) {
+ boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher);
+ float toAlignment = mLauncherState.isTaskbarAlignedWithHotseat(mLauncher) ? 1 : 0;
+
TaskbarStashController controller = mControllers.taskbarStashController;
- controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
- isTransitionStateStashed);
+ controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, isInStashedState);
Animator stashAnimator = controller.applyStateWithoutStart(duration);
if (stashAnimator != null) {
stashAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- if (isTransitionStateStashed && committed) {
+ if (isInStashedState && committed) {
// Reset hotseat alpha to default
mLauncher.getHotseat().setIconsAlpha(1);
}
- mTargetStateOverrideForStateTransition = null;
}
@Override
public void onAnimationStart(Animator animation) {
- mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
+ if (mLauncher.getHotseat().getIconsAlpha() > 0) {
+ mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
+ }
}
});
animatorSet.play(stashAnimator);
- animatorSet.play(mIconAlignmentForLauncherState.animateToValue(
- getCurrentIconAlignmentRatioForLauncherState(),
- isTransitionStateStashed ? 0 : 1));
- } else {
- mTargetStateOverrideForStateTransition = null;
}
+
+ animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment)
+ .setDuration(duration));
}
private boolean isResumed() {
@@ -309,29 +322,18 @@
return (mState & FLAG_RECENTS_ANIMATION_RUNNING) != 0;
}
- private boolean isTransitionStateStartStashed() {
- return (mState & FLAG_TRANSITION_STATE_START_STASHED) != 0;
- }
-
- private boolean isTransitionStateCommittedStashed() {
- return (mState & FLAG_TRANSITION_STATE_COMMITTED_STASHED) != 0;
- }
-
private void onIconAlignmentRatioChangedForStateTransition() {
- onIconAlignmentRatioChanged(
- mTargetStateOverrideForStateTransition != null
- ? mTargetStateOverrideForStateTransition
- : mLauncher.getStateManager().getState(),
- this::getCurrentIconAlignmentRatioForLauncherState);
+ if (!isResumed()) {
+ return;
+ }
+ onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioForLauncherState);
}
- private void onIconAlignmentRatioChanged() {
- onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
- : mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
+ private void onIconAlignmentRatioChangedForAppAndHomeTransition() {
+ onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioBetweenAppAndHome);
}
- private void onIconAlignmentRatioChanged(LauncherState state,
- Supplier<Float> alignmentSupplier) {
+ private void onIconAlignmentRatioChanged(Supplier<Float> alignmentSupplier) {
if (mControllers == null) {
return;
}
@@ -339,12 +341,11 @@
mControllers.taskbarViewController.setLauncherIconAlignment(
alignment, mLauncher.getDeviceProfile());
- mTaskbarBackgroundAlpha.updateValue(1 - alignment);
-
- setIconAlpha(state, alignment);
+ // Switch taskbar and hotseat in last frame
+ setTaskbarViewVisible(alignment < 1);
}
- private float getCurrentIconAlignmentRatio() {
+ private float getCurrentIconAlignmentRatioBetweenAppAndHome() {
return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
}
@@ -352,15 +353,6 @@
return mIconAlignmentForLauncherState.value;
}
- private void setIconAlpha(LauncherState state, float progress) {
- if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
- // If the hotseat icons are visible, then switch taskbar in last frame
- setTaskbarViewVisible(progress < 1);
- } else {
- mIconAlphaForHome.setValue(1 - progress);
- }
- }
-
private void setTaskbarViewVisible(boolean isVisible) {
mIconAlphaForHome.setValue(isVisible ? 1 : 0);
}
@@ -385,8 +377,15 @@
private void endGestureStateOverride(boolean finishedToApp) {
mCallbacks.removeListener(this);
+
+ // Update the resumed state immediately to ensure a seamless handoff
+ boolean launcherResumed = !finishedToApp;
updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, false);
+ updateStateForFlag(FLAG_RESUMED, launcherResumed);
applyState();
+ // Set this last because applyState() might also animate it.
+ mIconAlignmentForResumedState.cancelAnimation();
+ mIconAlignmentForResumedState.updateValue(launcherResumed ? 1 : 0);
TaskbarStashController controller = mControllers.taskbarStashController;
controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index b2b078c..3cdcdf7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -18,7 +18,6 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
-import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
@@ -30,8 +29,8 @@
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.net.Uri;
+import android.os.Handler;
import android.provider.Settings;
-import android.util.Log;
import android.view.Display;
import androidx.annotation.NonNull;
@@ -42,7 +41,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.SettingsCache;
@@ -95,7 +93,8 @@
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
- mNavButtonController = new TaskbarNavButtonController(service);
+ mNavButtonController = new TaskbarNavButtonController(service,
+ SystemUiProxy.INSTANCE.get(mContext), new Handler());
mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar();
mComponentCallbacks = new ComponentCallbacks() {
private Configuration mOldConfig = mContext.getResources().getConfiguration();
@@ -108,6 +107,11 @@
if ((configDiff & configsRequiringRecreate) != 0) {
// Color has changed, recreate taskbar to reload background color & icons.
recreateTaskbar();
+ } else {
+ // Config change might be handled without re-creating the taskbar
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onConfigurationChanged(configDiff);
+ }
}
mOldConfig = newConfig;
}
@@ -207,8 +211,6 @@
}
private void recreateTaskbar() {
- Log.d(TASKBAR_WINDOW_CRASH, "Recreating taskbar: mTaskbarActivityContext="
- + mTaskbarActivityContext);
destroyExistingTaskbar();
DeviceProfile dp =
@@ -231,7 +233,6 @@
mTaskbarActivityContext.setUIController(
createTaskbarUIControllerForActivity(mActivity));
}
- Log.d(TASKBAR_WINDOW_CRASH, "Finished recreating taskbar");
}
public void onSystemUiFlagsChanged(int systemUiStateFlags) {
@@ -269,6 +270,12 @@
}
}
+ public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onNavButtonsDarkIntensityChanged(darkIntensity);
+ }
+ }
+
/**
* Called when the manager is no longer needed
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 6dcfe56..37a9b5e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -184,9 +184,12 @@
}
mContainer.updateHotseatItems(hotseatItemInfos);
- mControllers.taskbarStashController.updateStateForFlag(
- TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, isHotseatEmpty);
- mControllers.taskbarStashController.applyState();
+ final boolean finalIsHotseatEmpty = isHotseatEmpty;
+ mControllers.runAfterInit(() -> {
+ mControllers.taskbarStashController.updateStateForFlag(
+ TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, finalIsHotseatEmpty);
+ mControllers.taskbarStashController.applyState();
+ });
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index a8a0b59..d233365 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -16,9 +16,13 @@
package com.android.launcher3.taskbar;
-import static android.view.Display.DEFAULT_DISPLAY;
-import android.view.inputmethod.InputMethodManager;
+import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS;
+import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+
+import android.os.Bundle;
+import android.os.Handler;
import androidx.annotation.IntDef;
@@ -35,11 +39,16 @@
* Controller for 3 button mode in the taskbar.
* Handles all the functionality of the various buttons, making/routing the right calls into
* launcher or sysui/system.
- *
- * TODO: Create callbacks to hook into UI layer since state will change for more context buttons/
- * assistant invocation.
*/
public class TaskbarNavButtonController {
+
+ /** Allow some time in between the long press for back and recents. */
+ static final int SCREEN_PIN_LONG_PRESS_THRESHOLD = 200;
+ static final int SCREEN_PIN_LONG_PRESS_RESET = SCREEN_PIN_LONG_PRESS_THRESHOLD + 100;
+
+ private long mLastScreenPinLongPress;
+ private boolean mScreenPinned;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
BUTTON_BACK,
@@ -47,7 +56,6 @@
BUTTON_RECENTS,
BUTTON_IME_SWITCH,
BUTTON_A11Y,
- BUTTON_A11Y_LONG_CLICK
})
public @interface TaskbarButton {}
@@ -57,12 +65,21 @@
static final int BUTTON_RECENTS = BUTTON_HOME << 1;
static final int BUTTON_IME_SWITCH = BUTTON_RECENTS << 1;
static final int BUTTON_A11Y = BUTTON_IME_SWITCH << 1;
- static final int BUTTON_A11Y_LONG_CLICK = BUTTON_A11Y << 1;
+
+ private static final int SCREEN_UNPIN_COMBO = BUTTON_BACK | BUTTON_RECENTS;
+ private int mLongPressedButtons = 0;
private final TouchInteractionService mService;
+ private final SystemUiProxy mSystemUiProxy;
+ private final Handler mHandler;
- public TaskbarNavButtonController(TouchInteractionService service) {
+ private final Runnable mResetLongPress = this::resetScreenUnpin;
+
+ public TaskbarNavButtonController(TouchInteractionService service,
+ SystemUiProxy systemUiProxy, Handler handler) {
mService = service;
+ mSystemUiProxy = systemUiProxy;
+ mHandler = handler;
}
public void onButtonClick(@TaskbarButton int buttonType) {
@@ -74,43 +91,115 @@
navigateHome();
break;
case BUTTON_RECENTS:
- navigateToOverview();;
+ navigateToOverview();
break;
case BUTTON_IME_SWITCH:
showIMESwitcher();
break;
case BUTTON_A11Y:
- notifyImeClick(false /* longClick */);
- break;
- case BUTTON_A11Y_LONG_CLICK:
- notifyImeClick(true /* longClick */);
+ notifyA11yClick(false /* longClick */);
break;
}
}
+ public boolean onButtonLongClick(@TaskbarButton int buttonType) {
+ switch (buttonType) {
+ case BUTTON_HOME:
+ startAssistant();
+ return true;
+ case BUTTON_A11Y:
+ notifyA11yClick(true /* longClick */);
+ return true;
+ case BUTTON_BACK:
+ case BUTTON_RECENTS:
+ mLongPressedButtons |= buttonType;
+ return determineScreenUnpin();
+ case BUTTON_IME_SWITCH:
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the user has long pressed back and recents buttons
+ * "together" (within {@link #SCREEN_PIN_LONG_PRESS_THRESHOLD})ms
+ * If so, then requests the system to turn off screen pinning.
+ *
+ * @return true if the long press is a valid user action in attempting to unpin an app
+ * Will always return {@code false} when screen pinning is not active.
+ * NOTE: Returning true does not mean that screen pinning has stopped
+ */
+ private boolean determineScreenUnpin() {
+ long timeNow = System.currentTimeMillis();
+ if (!mScreenPinned) {
+ return false;
+ }
+
+ if (mLastScreenPinLongPress == 0) {
+ // First button long press registered, just mark time and wait for second button press
+ mLastScreenPinLongPress = System.currentTimeMillis();
+ mHandler.postDelayed(mResetLongPress, SCREEN_PIN_LONG_PRESS_RESET);
+ return true;
+ }
+
+ if ((timeNow - mLastScreenPinLongPress) > SCREEN_PIN_LONG_PRESS_THRESHOLD) {
+ // Too long in-between presses, reset the clock
+ resetScreenUnpin();
+ return false;
+ }
+
+ if ((mLongPressedButtons & SCREEN_UNPIN_COMBO) == SCREEN_UNPIN_COMBO) {
+ // Hooray! They did it (finally...)
+ mSystemUiProxy.stopScreenPinning();
+ mHandler.removeCallbacks(mResetLongPress);
+ resetScreenUnpin();
+ }
+ return true;
+ }
+
+ private void resetScreenUnpin() {
+ mLongPressedButtons = 0;
+ mLastScreenPinLongPress = 0;
+ }
+
+ public void updateSysuiFlags(int sysuiFlags) {
+ mScreenPinned = (sysuiFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
+ }
+
private void navigateHome() {
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
}
private void navigateToOverview() {
+ if (mScreenPinned) {
+ return;
+ }
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_TOGGLE);
}
private void executeBack() {
- SystemUiProxy.INSTANCE.getNoCreate().onBackPressed();
+ mSystemUiProxy.onBackPressed();
}
private void showIMESwitcher() {
- SystemUiProxy.INSTANCE.getNoCreate().onImeSwitcherPressed();
+ mSystemUiProxy.onImeSwitcherPressed();
}
- private void notifyImeClick(boolean longClick) {
- SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.getNoCreate();
+ private void notifyA11yClick(boolean longClick) {
if (longClick) {
- systemUiProxy.notifyAccessibilityButtonLongClicked();
+ mSystemUiProxy.notifyAccessibilityButtonLongClicked();
} else {
- systemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
+ mSystemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
}
}
+
+ private void startAssistant() {
+ if (mScreenPinned) {
+ return;
+ }
+ Bundle args = new Bundle();
+ args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
+ mSystemUiProxy.startAssistant(args);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index acb4aa8..7f75850 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import android.animation.Animator;
@@ -48,11 +49,20 @@
public static final int FLAG_STASHED_IN_APP_PINNED = 1 << 2; // app pinning
public static final int FLAG_STASHED_IN_APP_EMPTY = 1 << 3; // no hotseat icons
public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 4; // setup wizard and AllSetActivity
- public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 5;
+ public static final int FLAG_STASHED_IN_APP_IME = 1 << 5; // IME is visible
+ public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 6;
// If we're in an app and any of these flags are enabled, taskbar should be stashed.
- public static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
- | FLAG_STASHED_IN_APP_PINNED | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP;
+ private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
+ | FLAG_STASHED_IN_APP_PINNED | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP
+ | FLAG_STASHED_IN_APP_IME;
+
+ // If any of these flags are enabled, inset apps by our stashed height instead of our unstashed
+ // height. This way the reported insets are consistent even during transitions out of the app.
+ // Currently any flag that causes us to stash in an app is included, except for IME since that
+ // covers the underlying app anyway and thus the app shouldn't change insets.
+ private static final int FLAGS_REPORT_STASHED_INSETS_TO_APP = FLAGS_STASHED_IN_APP
+ & ~FLAG_STASHED_IN_APP_IME;
/**
* How long to stash/unstash when manually invoked via long press.
@@ -60,6 +70,11 @@
public static final long TASKBAR_STASH_DURATION = 300;
/**
+ * How long to stash/unstash when keyboard is appearing/disappearing.
+ */
+ private static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
+
+ /**
* The scale TaskbarView animates to when being stashed.
*/
private static final float STASHED_TASKBAR_SCALE = 0.5f;
@@ -100,6 +115,7 @@
private TaskbarControllers mControllers;
// Taskbar background properties.
private AnimatedFloat mTaskbarBackgroundOffset;
+ private AnimatedFloat mTaskbarImeBgAlpha;
// TaskbarView icon properties.
private AlphaProperty mIconAlphaForStash;
private AnimatedFloat mIconScaleForStash;
@@ -113,6 +129,8 @@
private int mState;
private @Nullable AnimatorSet mAnimator;
+ private boolean mIsSystemGestureInProgress;
+ private boolean mIsImeShowing;
// Evaluate whether the handle should be stashed
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
@@ -137,6 +155,7 @@
TaskbarDragLayerController dragLayerController = controllers.taskbarDragLayerController;
mTaskbarBackgroundOffset = dragLayerController.getTaskbarBackgroundOffset();
+ mTaskbarImeBgAlpha = dragLayerController.getImeBgTaskbar();
TaskbarViewController taskbarViewController = controllers.taskbarViewController;
mIconAlphaForStash = taskbarViewController.getTaskbarIconAlpha().getProperty(
@@ -152,9 +171,14 @@
boolean isManuallyStashedInApp = supportsManualStashing()
&& mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
+ boolean isInSetup = !mActivity.isUserSetupComplete() || sharedState.setupUIVisible;
updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
- updateStateForFlag(FLAG_STASHED_IN_APP_SETUP,
- !mActivity.isUserSetupComplete() || sharedState.setupUIVisible);
+ // TODO(b/204384193): Temporarily disable SUW specific logic
+ // updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
+ if (isInSetup) {
+ // Update the in-app state to ensure isStashed() reflects right state during SUW
+ updateStateForFlag(FLAG_IN_APP, true);
+ }
applyState();
notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
@@ -204,6 +228,13 @@
return hasAnyFlag(FLAGS_STASHED_IN_APP);
}
+ /**
+ * Returns whether the taskbar should be stashed in the current LauncherState.
+ */
+ public boolean isInStashedLauncherState() {
+ return hasAnyFlag(FLAG_IN_STASHED_LAUNCHER_STATE) && supportsVisualStashing();
+ }
+
private boolean hasAnyFlag(int flagMask) {
return hasAnyFlag(mState, flagMask);
}
@@ -220,8 +251,11 @@
return !mIsStashed && (mState & FLAG_IN_APP) != 0;
}
- public int getContentHeight() {
- if (isStashed()) {
+ /**
+ * Returns the height that taskbar will inset when inside apps.
+ */
+ public int getContentHeightToReportToApps() {
+ if (hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) {
boolean isAnimating = mAnimator != null && mAnimator.isStarted();
return mControllers.stashedHandleViewController.isStashedHandleVisible() || isAnimating
? mStashedHeight : 0;
@@ -271,17 +305,27 @@
* Create a stash animation and save to {@link #mAnimator}.
* @param isStashed whether it's a stash animation or an unstash animation
* @param duration duration of the animation
+ * @param startDelay how many milliseconds to delay the animation after starting it.
*/
- private void createAnimToIsStashed(boolean isStashed, long duration) {
+ private void createAnimToIsStashed(boolean isStashed, long duration, long startDelay) {
if (mAnimator != null) {
mAnimator.cancel();
}
mAnimator = new AnimatorSet();
if (!supportsVisualStashing()) {
- // Just hide/show the icons instead of stashing into a handle.
+ // Just hide/show the icons and background instead of stashing into a handle.
mAnimator.play(mIconAlphaForStash.animateToValue(isStashed ? 0 : 1)
.setDuration(duration));
+ mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
+ hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration));
+ mAnimator.setStartDelay(startDelay);
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimator = null;
+ }
+ });
return;
}
@@ -326,11 +370,8 @@
);
}
- Animator stashedHandleRevealAnim = mControllers.stashedHandleViewController
- .createRevealAnimToIsStashed(isStashed);
- if (stashedHandleRevealAnim != null) {
- fullLengthAnimatorSet.play(stashedHandleRevealAnim);
- }
+ fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
+ .createRevealAnimToIsStashed(isStashed));
// Return the stashed handle to its default scale in case it was changed as part of the
// feedforward hint. Note that the reveal animation above also visually scales it.
fullLengthAnimatorSet.play(mTaskbarStashedHandleHintScale.animateToValue(1f));
@@ -342,6 +383,7 @@
mAnimator.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
secondHalfAnimatorSet);
+ mAnimator.setStartDelay(startDelay);
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -400,6 +442,10 @@
mStatePropertyHolder.setState(mState, duration, true);
}
+ public void applyState(long duration, long startDelay) {
+ mStatePropertyHolder.setState(mState, duration, startDelay, true);
+ }
+
public Animator applyStateWithoutStart() {
return applyStateWithoutStart(TASKBAR_STASH_DURATION);
}
@@ -408,11 +454,50 @@
return mStatePropertyHolder.setState(mState, duration, false);
}
+ /**
+ * Should be called when a system gesture starts and settles, so we can defer updating
+ * FLAG_STASHED_IN_APP_IME until after the gesture transition completes.
+ */
+ public void setSystemGestureInProgress(boolean inProgress) {
+ mIsSystemGestureInProgress = inProgress;
+ // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
+ if (!mIsSystemGestureInProgress) {
+ updateStateForFlag(FLAG_STASHED_IN_APP_IME, mIsImeShowing);
+ applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
+ }
+ }
+
+ /**
+ * When hiding the IME, delay the unstash animation to align with the end of the transition.
+ */
+ private long getTaskbarStashStartDelayForIme() {
+ if (mIsImeShowing) {
+ // Only delay when IME is exiting, not entering.
+ return 0;
+ }
+ // This duration is based on input_method_extract_exit.xml.
+ long imeExitDuration = mControllers.taskbarActivityContext.getResources()
+ .getInteger(android.R.integer.config_shortAnimTime);
+ return imeExitDuration - TASKBAR_STASH_DURATION_FOR_IME;
+ }
+
/** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */
public void updateStateForSysuiFlags(int systemUiStateFlags, boolean skipAnim) {
+ long animDuration = TASKBAR_STASH_DURATION;
+ long startDelay = 0;
+
updateStateForFlag(FLAG_STASHED_IN_APP_PINNED,
hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING));
- applyState(skipAnim ? 0 : TASKBAR_STASH_DURATION);
+
+ // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
+ mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
+ if (!mIsSystemGestureInProgress) {
+ updateStateForFlag(FLAG_STASHED_IN_APP_IME, mIsImeShowing);
+ animDuration = TASKBAR_STASH_DURATION_FOR_IME;
+ startDelay = getTaskbarStashStartDelayForIme();
+ }
+
+ applyState(skipAnim ? 0 : animDuration, skipAnim ? 0 : startDelay);
}
/**
@@ -468,16 +553,34 @@
mStashCondition = stashCondition;
}
+ /**
+ * @see #setState(int, long, long, boolean) with a default startDelay = 0.
+ */
public Animator setState(int flags, long duration, boolean start) {
+ return setState(flags, duration, 0 /* startDelay */, start);
+ }
+
+ /**
+ * Applies the latest state, potentially calling onStateChangeApplied() and creating a new
+ * animation (stored in mAnimator) which is started if {@param start} is true.
+ * @param flags The latest flags to apply (see the top of this file).
+ * @param duration The length of the animation.
+ * @param startDelay How long to delay the animation after calling start().
+ * @param start Whether to start mAnimator immediately.
+ * @return mAnimator if mIsStashed changed, else null.
+ */
+ public Animator setState(int flags, long duration, long startDelay, boolean start) {
+ int changedFlags = mPrevFlags ^ flags;
if (mPrevFlags != flags) {
- int changedFlags = mPrevFlags ^ flags;
onStateChangeApplied(changedFlags);
mPrevFlags = flags;
}
boolean isStashed = mStashCondition.test(flags);
if (mIsStashed != isStashed) {
mIsStashed = isStashed;
- createAnimToIsStashed(mIsStashed, duration);
+
+ // This sets mAnimator.
+ createAnimToIsStashed(mIsStashed, duration, startDelay);
if (start) {
mAnimator.start();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index d8360e0..abad906 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -15,7 +15,9 @@
*/
package com.android.launcher3.taskbar;
-import android.graphics.Rect;
+import android.view.View;
+
+import androidx.annotation.CallSuper;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -29,16 +31,23 @@
public static final TaskbarUIController DEFAULT = new TaskbarUIController();
- protected void init(TaskbarControllers taskbarControllers) { }
+ // Initialized in init.
+ protected TaskbarControllers mControllers;
- protected void onDestroy() { }
+ @CallSuper
+ protected void init(TaskbarControllers taskbarControllers) {
+ mControllers = taskbarControllers;
+ }
+
+ @CallSuper
+ protected void onDestroy() {
+ mControllers = null;
+ }
protected boolean isTaskbarTouchable() {
return true;
}
- protected void updateContentInsets(Rect outContentInsets) { }
-
protected void onStashedInAppChanged() { }
public Stream<ItemInfoWithIcon> getAppIconsForEdu() {
@@ -46,4 +55,16 @@
}
public void onTaskbarIconLaunched(WorkspaceItemInfo item) { }
+
+ public View getRootView() {
+ return mControllers.taskbarActivityContext.getDragLayer();
+ }
+
+ /**
+ * Called when swiping from the bottom nav region in fully gestural mode.
+ * @param inProgress True if the animation started, false if we just settled on an end target.
+ */
+ public void setSystemGestureInProgress(boolean inProgress) {
+ mControllers.taskbarStashController.setSystemGestureInProgress(inProgress);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index c47bde9..445a23b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -45,12 +45,11 @@
private static final Runnable NO_OP = () -> { };
public static final int ALPHA_INDEX_HOME = 0;
- public static final int ALPHA_INDEX_IME = 1;
- public static final int ALPHA_INDEX_KEYGUARD = 2;
- public static final int ALPHA_INDEX_STASH = 3;
- public static final int ALPHA_INDEX_RECENTS_DISABLED = 4;
- public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 5;
- private static final int NUM_ALPHA_CHANNELS = 6;
+ public static final int ALPHA_INDEX_KEYGUARD = 1;
+ public static final int ALPHA_INDEX_STASH = 2;
+ public static final int ALPHA_INDEX_RECENTS_DISABLED = 3;
+ public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4;
+ private static final int NUM_ALPHA_CHANNELS = 5;
private final TaskbarActivityContext mActivity;
private final TaskbarView mTaskbarView;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 2fa8b07..0eaea83 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides;
-import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
@@ -30,8 +29,6 @@
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
-import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
-import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.util.FloatProperty;
@@ -43,7 +40,6 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.views.RecentsView;
/**
@@ -73,8 +69,6 @@
getTaskModalnessProperty().set(mRecentsView, state.getOverviewModalness());
RECENTS_GRID_PROGRESS.set(mRecentsView,
state.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f);
-
- applySplitScrollOffset(state);
}
@Override
@@ -102,13 +96,6 @@
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
- PagedOrientationHandler orientationHandler =
- ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
- FloatProperty taskViewsFloat = orientationHandler.getSplitSelectTaskOffset(
- TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
- mLauncher.getDeviceProfile());
- setter.setFloat(mRecentsView, taskViewsFloat,
- toState.getSplitSelectTranslation(mLauncher), LINEAR);
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
@@ -120,16 +107,6 @@
boolean showAsGrid = toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile());
setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
showAsGrid ? INSTANT : FINAL_FRAME);
-
- applySplitScrollOffset(toState);
- }
-
- private void applySplitScrollOffset(@NonNull final LauncherState state) {
- if (state == OVERVIEW_SPLIT_SELECT) {
- mRecentsView.applySplitPrimaryScrollOffset();
- } else {
- mRecentsView.resetSplitPrimaryScrollOffset();
- }
}
abstract FloatProperty getTaskModalnessProperty();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 1f744e1..32ce1c4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -23,13 +23,17 @@
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
+import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;
import android.annotation.TargetApi;
import android.os.Build;
import android.util.FloatProperty;
+import android.util.Pair;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
@@ -37,6 +41,7 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.views.ClearAllButton;
import com.android.quickstep.views.LauncherRecentsView;
@@ -63,6 +68,11 @@
}
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig(), state);
mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
+ // In Overview, we may be layering app surfaces behind Launcher, so we need to notify
+ // DepthController to prevent optimizations which might occlude the layers behind
+ mLauncher.getDepthController().setHasContentBehindLauncher(state.overviewUi);
+
+ handleSplitSelectionState(state, null);
}
@Override
@@ -78,14 +88,12 @@
builder.addListener(
AnimatorListeners.forSuccessCallback(mRecentsView::resetTaskVisuals));
}
+ // In Overview, we may be layering app surfaces behind Launcher, so we need to notify
+ // DepthController to prevent optimizations which might occlude the layers behind
+ builder.addListener(AnimatorListeners.forSuccessCallback(() ->
+ mLauncher.getDepthController().setHasContentBehindLauncher(toState.overviewUi)));
- // Create or dismiss split screen select animations
- LauncherState currentState = mLauncher.getStateManager().getState();
- if (isSplitSelectionState(toState) && !isSplitSelectionState(currentState)) {
- builder.add(mRecentsView.createSplitSelectInitAnimation().buildAnim());
- } else if (!isSplitSelectionState(toState) && isSplitSelectionState(currentState)) {
- builder.add(mRecentsView.cancelSplitSelect(true).buildAnim());
- }
+ handleSplitSelectionState(toState, builder);
setAlphas(builder, config, toState);
builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
@@ -93,10 +101,52 @@
}
/**
- * @return true if {@param toState} is {@link LauncherState#OVERVIEW_SPLIT_SELECT}
+ * Create or dismiss split screen select animations.
+ * @param builder if null then this will run the split select animations right away, otherwise
+ * will add animations to builder.
*/
- private boolean isSplitSelectionState(@NonNull LauncherState toState) {
- return toState == OVERVIEW_SPLIT_SELECT;
+ private void handleSplitSelectionState(@NonNull LauncherState toState,
+ @Nullable PendingAnimation builder) {
+ LauncherState currentState = mLauncher.getStateManager().getState();
+ boolean animate = builder != null;
+ PagedOrientationHandler orientationHandler =
+ ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
+ Pair<FloatProperty, FloatProperty> taskViewsFloat =
+ orientationHandler.getSplitSelectTaskOffset(
+ TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
+ mLauncher.getDeviceProfile());
+
+ if (isSplitSelectionState(currentState, toState)) {
+ // Animation to "dismiss" selected taskView
+ PendingAnimation splitSelectInitAnimation =
+ mRecentsView.createSplitSelectInitAnimation();
+ // Add properties to shift remaining taskViews to get out of placeholder view
+ splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.first,
+ toState.getSplitSelectTranslation(mLauncher), LINEAR);
+ splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
+
+ if (!animate && isSplitSelectionState(currentState, toState)) {
+ splitSelectInitAnimation.buildAnim().start();
+ } else if (animate &&
+ isSplitSelectionState(currentState, toState)) {
+ builder.add(splitSelectInitAnimation.buildAnim());
+ }
+ }
+
+ if (isSplitSelectionState(currentState, toState)) {
+ mRecentsView.applySplitPrimaryScrollOffset();
+ } else {
+ mRecentsView.resetSplitPrimaryScrollOffset();
+ }
+ }
+
+ /**
+ * @return true if {@param toState} is {@link LauncherState#OVERVIEW_SPLIT_SELECT}
+ * and {@param fromState} is not {@link LauncherState#OVERVIEW_SPLIT_SELECT}
+ */
+ private boolean isSplitSelectionState(@NonNull LauncherState fromState,
+ @NonNull LauncherState toState) {
+ return fromState != OVERVIEW_SPLIT_SELECT && toState == OVERVIEW_SPLIT_SELECT;
}
private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index c554fd0..8f89d30 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -69,7 +69,7 @@
}
@Override
- public boolean isTaskbarStashed() {
+ public boolean isTaskbarStashed(Launcher launcher) {
return true;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 4984b95..b733007 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -74,8 +74,7 @@
return super.getVisibleElements(launcher)
& ~OVERVIEW_ACTIONS
& ~CLEAR_ALL_BUTTON
- & ~VERTICAL_SWIPE_INDICATOR
- | TASKBAR;
+ & ~VERTICAL_SWIPE_INDICATOR;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index d396018..08d0a80 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -21,13 +21,11 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.SystemProperties;
-import android.view.View;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
import com.android.launcher3.util.Themes;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.util.LayoutUtils;
@@ -66,10 +64,7 @@
@Override
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
- Workspace workspace = launcher.getWorkspace();
- View workspacePage = workspace.getPageAt(workspace.getCurrentPage());
- float workspacePageWidth = workspacePage != null && workspacePage.getWidth() != 0
- ? workspacePage.getWidth() : launcher.getDeviceProfile().availableWidthPx;
+ float workspacePageWidth = launcher.getDeviceProfile().getWorkspaceWidth();
recentsView.getTaskSize(sTempRect);
float scale = (float) sTempRect.width() / workspacePageWidth;
float parallaxFactor = 0.5f;
@@ -97,7 +92,7 @@
}
@Override
- public boolean isTaskbarStashed() {
+ public boolean isTaskbarStashed(Launcher launcher) {
return true;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index d36e76b..969abc2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
@@ -42,6 +43,10 @@
@Override
public int getWorkspaceScrimColor(Launcher launcher) {
+ DeviceProfile dp = launcher.getDeviceProfile();
+ if (dp.isTaskbarPresentInApps) {
+ return launcher.getColor(R.color.taskbar_background);
+ }
return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
}
@@ -53,6 +58,16 @@
@Override
public int getVisibleElements(Launcher launcher) {
- return TASKBAR;
+ return NONE;
+ }
+
+ @Override
+ public boolean isTaskbarStashed(Launcher launcher) {
+ return !launcher.getDeviceProfile().isTaskbarPresentInApps;
+ }
+
+ @Override
+ public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
+ return false;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 0e2fbbc..75cf5cb 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -17,6 +17,7 @@
import static android.view.View.VISIBLE;
+import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.HINT_STATE_TWO_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -44,6 +45,10 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_SCRIM_OPAQUE_THRESHOLD;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_SCRIM_VISIBLE_THRESHOLD;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import android.animation.ValueAnimator;
@@ -52,6 +57,7 @@
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.SysUINavigationMode;
@@ -171,6 +177,13 @@
mHintToNormalDuration = (int) va.getDuration();
}
config.duration = Math.max(config.duration, mHintToNormalDuration);
+ } else if (fromState == ALL_APPS && toState == NORMAL) {
+ config.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
+ 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
+ 1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
+ config.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(DEACCEL,
+ 1 - ALL_APPS_SCRIM_OPAQUE_THRESHOLD,
+ 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
index 106375a..e79d56b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
@@ -17,8 +17,6 @@
package com.android.launcher3.uioverrides.states;
import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.views.RecentsView;
/**
@@ -31,11 +29,6 @@
}
@Override
- public void onBackPressed(Launcher launcher) {
- launcher.getStateManager().goToState(OVERVIEW);
- }
-
- @Override
public int getVisibleElements(Launcher launcher) {
return SPLIT_PLACHOLDER_VIEW;
}
@@ -43,12 +36,6 @@
@Override
public float getSplitSelectTranslation(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
- int splitPosition = recentsView.getSplitPlaceholder().getActiveSplitStagePosition();
- if (!recentsView.shouldShiftThumbnailsForSplitSelect()) {
- return 0f;
- }
- PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
- int direction = orientationHandler.getSplitTranslationDirectionFactor(splitPosition);
- return launcher.getResources().getDimension(R.dimen.split_placeholder_size) * direction;
+ return recentsView.getSplitSelectTranslation();
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index ff3c517..f6148a7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -236,8 +236,10 @@
// - RecentsView fade (if it's empty)
PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2));
xAnim.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1], LINEAR);
+ // Use QuickSwitchState instead of OverviewState to determine scrim color,
+ // since we need to take potential taskbar into account.
xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
- toState.getWorkspaceScrimColor(mLauncher), LINEAR);
+ QUICK_SWITCH.getWorkspaceScrimColor(mLauncher), LINEAR);
if (mRecentsView.getTaskViewCount() == 0) {
xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
}
@@ -310,6 +312,11 @@
}
});
overviewAnim.start();
+
+ // Create an empty state transition so StateListeners get onStateTransitionStart().
+ mLauncher.getStateManager().createAnimationToNewWorkspace(
+ OVERVIEW, config.duration, StateAnimationConfig.SKIP_ALL_ANIMATIONS)
+ .dispatchOnStart();
return;
}
@@ -384,6 +391,7 @@
config.animFlags = SKIP_ALL_ANIMATIONS;
updateNonOverviewAnim(targetState, config);
nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
+ mNonOverviewAnim.dispatchOnStart();
new WorkspaceRevealAnim(mLauncher, false /* animateOverviewScrim */).start();
} else {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 3c83d25..59ade49 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -52,22 +52,22 @@
/**
* The progress at which all apps content will be fully visible.
*/
- protected static final float ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD = 0.8f;
+ public static final float ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD = 0.8f;
/**
* Minimum clamping progress for fading in all apps content
*/
- protected static final float ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD = 0.5f;
+ public static final float ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD = 0.5f;
/**
* Minimum clamping progress for fading in all apps scrim
*/
- protected static final float ALL_APPS_SCRIM_VISIBLE_THRESHOLD = .1f;
+ public static final float ALL_APPS_SCRIM_VISIBLE_THRESHOLD = .1f;
/**
* Maximum clamping progress for opaque all apps scrim
*/
- protected static final float ALL_APPS_SCRIM_OPAQUE_THRESHOLD = .5f;
+ public static final float ALL_APPS_SCRIM_OPAQUE_THRESHOLD = .5f;
private final PortraitOverviewStateTouchHelper mOverviewPortraitStateTouchHelper;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
index fe69c9b..1bc789b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
@@ -19,6 +19,7 @@
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN;
@@ -47,17 +48,6 @@
private static final String TAG = "StatusBarController";
- /**
- * Window flag: Enable touches to slide out of a window into neighboring
- * windows in mid-gesture instead of being captured for the duration of
- * the gesture.
- *
- * This flag changes the behavior of touch focus for this window only.
- * Touches can slide out of the window but they cannot necessarily slide
- * back in (unless the other window with touch focus permits it).
- */
- private static final int FLAG_SLIPPERY = 0x20000000;
-
private final Launcher mLauncher;
private final SystemUiProxy mSystemUiProxy;
private final float mTouchSlop;
@@ -140,6 +130,15 @@
return true;
}
+ /**
+ * FLAG_SLIPPERY enables touches to slide out of a window into neighboring
+ * windows in mid-gesture instead of being captured for the duration of
+ * the gesture.
+ *
+ * This flag changes the behavior of touch focus for this window only.
+ * Touches can slide out of the window but they cannot necessarily slide
+ * back in (unless the other window with touch focus permits it).
+ */
private void setWindowSlippery(boolean enable) {
Window w = mLauncher.getWindow();
WindowManager.LayoutParams wlp = w.getAttributes();
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 45b2081..9f1e47f 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -55,6 +55,7 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
+import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -73,6 +74,7 @@
import android.view.WindowInsets;
import android.view.animation.Interpolator;
import android.widget.Toast;
+import android.window.PictureInPictureSurfaceTransaction;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -89,6 +91,7 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.tracing.InputConsumerProto;
import com.android.launcher3.tracing.SwipeHandlerProto;
+import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
@@ -121,8 +124,8 @@
import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.function.Consumer;
/**
@@ -153,6 +156,17 @@
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
private boolean mRecentsViewScrollLinked = false;
+ private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks =
+ new ActivityLifecycleCallbacksAdapter() {
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ if (mActivity != activity) {
+ return;
+ }
+ mRecentsView = null;
+ mActivity = null;
+ }
+ };
private static int getFlagForIndex(int index, String name) {
if (DEBUG_STATES) {
@@ -166,45 +180,51 @@
getFlagForIndex(0, "STATE_LAUNCHER_PRESENT");
protected static final int STATE_LAUNCHER_STARTED =
getFlagForIndex(1, "STATE_LAUNCHER_STARTED");
- protected static final int STATE_LAUNCHER_DRAWN = getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
+ protected static final int STATE_LAUNCHER_DRAWN =
+ getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
+ // Called when the Launcher has connected to the touch interaction service (and the taskbar
+ // ui controller is initialized)
+ protected static final int STATE_LAUNCHER_BIND_TO_SERVICE =
+ getFlagForIndex(3, "STATE_LAUNCHER_BIND_TO_SERVICE");
// Internal initialization states
private static final int STATE_APP_CONTROLLER_RECEIVED =
- getFlagForIndex(3, "STATE_APP_CONTROLLER_RECEIVED");
+ getFlagForIndex(4, "STATE_APP_CONTROLLER_RECEIVED");
// Interaction finish states
private static final int STATE_SCALED_CONTROLLER_HOME =
- getFlagForIndex(4, "STATE_SCALED_CONTROLLER_HOME");
+ getFlagForIndex(5, "STATE_SCALED_CONTROLLER_HOME");
private static final int STATE_SCALED_CONTROLLER_RECENTS =
- getFlagForIndex(5, "STATE_SCALED_CONTROLLER_RECENTS");
+ getFlagForIndex(6, "STATE_SCALED_CONTROLLER_RECENTS");
protected static final int STATE_HANDLER_INVALIDATED =
- getFlagForIndex(6, "STATE_HANDLER_INVALIDATED");
+ getFlagForIndex(7, "STATE_HANDLER_INVALIDATED");
private static final int STATE_GESTURE_STARTED =
- getFlagForIndex(7, "STATE_GESTURE_STARTED");
+ getFlagForIndex(8, "STATE_GESTURE_STARTED");
private static final int STATE_GESTURE_CANCELLED =
- getFlagForIndex(8, "STATE_GESTURE_CANCELLED");
+ getFlagForIndex(9, "STATE_GESTURE_CANCELLED");
private static final int STATE_GESTURE_COMPLETED =
- getFlagForIndex(9, "STATE_GESTURE_COMPLETED");
+ getFlagForIndex(10, "STATE_GESTURE_COMPLETED");
private static final int STATE_CAPTURE_SCREENSHOT =
- getFlagForIndex(10, "STATE_CAPTURE_SCREENSHOT");
+ getFlagForIndex(11, "STATE_CAPTURE_SCREENSHOT");
protected static final int STATE_SCREENSHOT_CAPTURED =
- getFlagForIndex(11, "STATE_SCREENSHOT_CAPTURED");
+ getFlagForIndex(12, "STATE_SCREENSHOT_CAPTURED");
private static final int STATE_SCREENSHOT_VIEW_SHOWN =
- getFlagForIndex(12, "STATE_SCREENSHOT_VIEW_SHOWN");
+ getFlagForIndex(13, "STATE_SCREENSHOT_VIEW_SHOWN");
private static final int STATE_RESUME_LAST_TASK =
- getFlagForIndex(13, "STATE_RESUME_LAST_TASK");
+ getFlagForIndex(14, "STATE_RESUME_LAST_TASK");
private static final int STATE_START_NEW_TASK =
- getFlagForIndex(14, "STATE_START_NEW_TASK");
+ getFlagForIndex(15, "STATE_START_NEW_TASK");
private static final int STATE_CURRENT_TASK_FINISHED =
- getFlagForIndex(15, "STATE_CURRENT_TASK_FINISHED");
+ getFlagForIndex(16, "STATE_CURRENT_TASK_FINISHED");
private static final int STATE_FINISH_WITH_NO_END =
- getFlagForIndex(16, "STATE_FINISH_WITH_NO_END");
+ getFlagForIndex(17, "STATE_FINISH_WITH_NO_END");
private static final int LAUNCHER_UI_STATES =
- STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
+ STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED |
+ STATE_LAUNCHER_BIND_TO_SERVICE;
public static final long MAX_SWIPE_DURATION = 350;
public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS;
@@ -415,7 +435,9 @@
setupRecentsViewUi();
linkRecentsViewScroll();
+ activity.runOnBindToTouchInteractionService(this::onLauncherBindToService);
+ mActivity.registerActivityLifecycleCallbacks(mLifecycleCallbacks);
return true;
}
@@ -495,6 +517,11 @@
mStateCallback.setState(STATE_LAUNCHER_STARTED);
}
+ private void onLauncherBindToService() {
+ mStateCallback.setState(STATE_LAUNCHER_BIND_TO_SERVICE);
+ flushOnRecentsAnimationAndLauncherBound();
+ }
+
private void onLauncherPresentAndGestureStarted() {
// Re-setup the recents UI when gesture starts, as the state could have been changed during
// that time by a previous window transition.
@@ -542,9 +569,14 @@
runningTasks = new ActivityManager.RunningTaskInfo[splitTaskIds.length];
for (int i = 0; i < splitTaskIds.length; i++) {
int taskId = splitTaskIds[i];
- ActivityManager.RunningTaskInfo rti = new ActivityManager.RunningTaskInfo();
- rti.taskId = taskId;
- runningTasks[i] = rti;
+ // Order matters here, we want first indexed RunningTaskInfo to be leftTop task
+ for (ActivityManager.RunningTaskInfo rti : mGestureState.getRunningTasks()) {
+ if (taskId == rti.taskId) {
+ runningTasks[i] = rti;
+ break;
+ }
+
+ }
}
} else {
runningTasks = new ActivityManager.RunningTaskInfo[]{mGestureState.getRunningTask()};
@@ -687,14 +719,17 @@
}
private void onAnimatorPlaybackControllerCreated(AnimatorControllerWithResistance anim) {
+ boolean isFirstCreation = mLauncherTransitionController == null;
mLauncherTransitionController = anim;
- mStateCallback.runOnceAtState(STATE_GESTURE_STARTED, () -> {
- // Wait until the gesture is started (touch slop was passed) to start in sync with
- // mWindowTransitionController. This ensures we don't hide the taskbar background when
- // long pressing to stash it, for instance.
- mLauncherTransitionController.getNormalController().dispatchOnStart();
- updateLauncherTransitionProgress();
- });
+ if (isFirstCreation) {
+ mStateCallback.runOnceAtState(STATE_GESTURE_STARTED, () -> {
+ // Wait until the gesture is started (touch slop was passed) to start in sync with
+ // mWindowTransitionController. This ensures we don't hide the taskbar background
+ // when long pressing to stash it, for instance.
+ mLauncherTransitionController.getNormalController().dispatchOnStart();
+ updateLauncherTransitionProgress();
+ });
+ }
}
public Intent getLaunchIntent() {
@@ -794,14 +829,10 @@
}
// Notify when the animation starts
- if (!mRecentsAnimationStartCallbacks.isEmpty()) {
- for (Runnable action : new ArrayList<>(mRecentsAnimationStartCallbacks)) {
- action.run();
- }
- mRecentsAnimationStartCallbacks.clear();
- }
+ flushOnRecentsAnimationAndLauncherBound();
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, false);
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ false /*shown*/, true /*animate*/);
// Only add the callback to enable the input consumer after we actually have the controller
mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
@@ -818,7 +849,8 @@
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, true);
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ true /*shown*/, true /*animate*/);
}
// Defer clearing the controller and the targets until after we've updated the state
@@ -968,8 +1000,8 @@
mStateCallback.setState(STATE_RESUME_LAST_TASK);
}
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(
- mRecentsAnimationTargets.nonApps, true);
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ true /*shown*/, false /*animate*/);
}
break;
}
@@ -1177,7 +1209,7 @@
@UiThread
private void animateToProgress(float start, float end, long duration, Interpolator interpolator,
GestureEndTarget target, PointF velocityPxPerMs) {
- runOnRecentsAnimationStart(() -> animateToProgressInternal(start, end, duration,
+ runOnRecentsAnimationAndLauncherBound(() -> animateToProgressInternal(start, end, duration,
interpolator, target, velocityPxPerMs));
}
@@ -1244,7 +1276,8 @@
HomeAnimationFactory homeAnimFactory =
createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
runningTaskTarget);
- mIsSwipingPipToHome = homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
+ mIsSwipingPipToHome = !mIsSwipeForStagedSplit
+ && homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
final RectFSpringAnim[] windowAnim;
if (mIsSwipingPipToHome) {
mSwipePipToHomeAnimator = createWindowAnimationToPip(
@@ -1539,6 +1572,9 @@
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
+ if (mActivity != null) {
+ mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
+ }
}
/**
@@ -1617,7 +1653,8 @@
mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, true);
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ true /*shown*/, false /*animate*/);
}
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
@@ -1708,7 +1745,7 @@
// If there are no targets or the animation not started, then there is nothing to finish
mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else {
- maybeFinishSwipePipToHome();
+ maybeFinishSwipeToHome();
finishRecentsControllerToHome(
() -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
}
@@ -1717,10 +1754,11 @@
}
/**
- * Resets the {@link #mIsSwipingPipToHome} and notifies SysUI that transition is finished
- * if applicable. This should happen before {@link #finishRecentsControllerToHome(Runnable)}.
+ * Notifies SysUI that transition is finished if applicable and also pass leash transactions
+ * from Launcher to WM.
+ * This should happen before {@link #finishRecentsControllerToHome(Runnable)}.
*/
- private void maybeFinishSwipePipToHome() {
+ private void maybeFinishSwipeToHome() {
if (mIsSwipingPipToHome && mSwipePipToHomeAnimators[0] != null) {
SystemUiProxy.INSTANCE.get(mContext).stopSwipePipToHome(
mSwipePipToHomeAnimator.getComponentName(),
@@ -1731,6 +1769,18 @@
mSwipePipToHomeAnimator.getFinishTransaction(),
mSwipePipToHomeAnimator.getContentOverlay());
mIsSwipingPipToHome = false;
+ } else if (mIsSwipeForStagedSplit) {
+ // Transaction to hide the task to avoid flicker for entering PiP from split-screen.
+ PictureInPictureSurfaceTransaction tx =
+ new PictureInPictureSurfaceTransaction.Builder()
+ .setAlpha(0f)
+ .build();
+ int[] taskIds =
+ LauncherSplitScreenListener.INSTANCE.getNoCreate().getRunningSplitTaskIds();
+ for (int taskId : taskIds) {
+ mRecentsAnimationController.setFinishTaskTransaction(taskId,
+ tx, null /* overlay */);
+ }
}
}
@@ -1785,12 +1835,12 @@
SurfaceTransactionApplier.create(mRecentsView, applier -> {
runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
.setSyncTransactionApplier(applier));
- runOnRecentsAnimationStart(() ->
+ runOnRecentsAnimationAndLauncherBound(() ->
mRecentsAnimationTargets.addReleaseCheck(applier));
});
mRecentsView.addOnScrollChangedListener(mOnRecentsScrollListener);
- runOnRecentsAnimationStart(() ->
+ runOnRecentsAnimationAndLauncherBound(() ->
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
mRecentsAnimationTargets));
mRecentsViewScrollLinked = true;
@@ -1836,14 +1886,26 @@
}
/**
- * Runs the given {@param action} if the recents animation has already started, or queues it to
- * be run when it is next started.
+ * Runs the given {@param action} if the recents animation has already started and Launcher has
+ * been created and bound to the TouchInteractionService, or queues it to be run when it this
+ * next happens.
*/
- protected void runOnRecentsAnimationStart(Runnable action) {
- if (mRecentsAnimationTargets == null) {
- mRecentsAnimationStartCallbacks.add(action);
- } else {
- action.run();
+ private void runOnRecentsAnimationAndLauncherBound(Runnable action) {
+ mRecentsAnimationStartCallbacks.add(action);
+ flushOnRecentsAnimationAndLauncherBound();
+ }
+
+ private void flushOnRecentsAnimationAndLauncherBound() {
+ if (mRecentsAnimationTargets == null ||
+ !mStateCallback.hasStates(STATE_LAUNCHER_BIND_TO_SERVICE)) {
+ return;
+ }
+
+ if (!mRecentsAnimationStartCallbacks.isEmpty()) {
+ for (Runnable action : new ArrayList<>(mRecentsAnimationStartCallbacks)) {
+ action.run();
+ }
+ mRecentsAnimationStartCallbacks.clear();
}
}
@@ -1858,7 +1920,8 @@
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
if (!controller.getFinishTargetIsLauncher()) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps, true);
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ true /*shown*/, true /*animate*/);
}
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index e15aa92..1d4ed4c 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -30,6 +30,7 @@
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
@@ -220,6 +221,7 @@
PointF taskDimension = getTaskDimension(context, dp);
float scale = gridRect.height() / taskDimension.y;
+ scale = Math.min(scale, res.getFloat(R.dimen.overview_max_scale));
int outWidth = Math.round(scale * taskDimension.x);
int outHeight = Math.round(scale * taskDimension.y);
@@ -398,6 +400,11 @@
* (This is a hack to ensure Taskbar draws its background first to avoid flickering.)
*/
public @Nullable View onSettledOnEndTarget(GestureState.GestureEndTarget endTarget) {
+ TaskbarUIController taskbarUIController = getTaskbarController();
+ if (taskbarUIController != null) {
+ taskbarUIController.setSystemGestureInProgress(false);
+ return taskbarUIController.getRootView();
+ }
return null;
}
@@ -533,6 +540,16 @@
pa.addFloat(recentsView, RECENTS_SCALE_PROPERTY,
recentsView.getMaxScaleForFullScreen(), 1, LINEAR);
pa.addFloat(recentsView, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
+
+ pa.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ TaskbarUIController taskbarUIController = getTaskbarController();
+ if (taskbarUIController != null) {
+ taskbarUIController.setSystemGestureInProgress(true);
+ }
+ }
+ });
}
}
}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 9bc98d6..ed0623d 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import android.annotation.Nullable;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.Intent;
@@ -135,6 +136,7 @@
private final int mGestureId;
private ActivityManager.RunningTaskInfo mRunningTask;
+ private ActivityManager.RunningTaskInfo[] mRunningTasks;
private GestureEndTarget mEndTarget;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>();
@@ -235,6 +237,14 @@
}
/**
+ * This will array will contain the task returned by {@link #getRunningTask()}
+ * @return the running tasks for this gesture.
+ */
+ public ActivityManager.RunningTaskInfo[] getRunningTasks() {
+ return mRunningTasks;
+ }
+
+ /**
* @return the running task id for this gesture.
*/
public int getRunningTaskId() {
@@ -249,6 +259,15 @@
}
/**
+ * TODO(b/210903248) refactor to consolidate w/ method above
+ * Updates the running task for the gesture to be the given {@param runningTask}.
+ */
+ public void updateRunningTasks(ActivityManager.RunningTaskInfo[] runningTasks) {
+ mRunningTasks = runningTasks;
+ updateRunningTask(runningTasks[0]);
+ }
+
+ /**
* Updates the last task that appeared during this gesture.
*/
public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) {
@@ -379,11 +398,15 @@
* while STATE_RECENTS_ANIMATION_CANCELED state is being set, and the caller is responsible for
* calling {@link RecentsAnimationController#cleanupScreenshot()}.
*/
+ @Nullable
HashMap<Integer, ThumbnailData> consumeRecentsAnimationCanceledSnapshot() {
- HashMap<Integer, ThumbnailData> data =
- new HashMap<Integer, ThumbnailData>(mRecentsAnimationCanceledSnapshots);
- mRecentsAnimationCanceledSnapshots = null;
- return data;
+ if (mRecentsAnimationCanceledSnapshots != null) {
+ HashMap<Integer, ThumbnailData> data =
+ new HashMap<Integer, ThumbnailData>(mRecentsAnimationCanceledSnapshots);
+ mRecentsAnimationCanceledSnapshots = null;
+ return data;
+ }
+ return null;
}
void setSwipeUpStartTimeMs(long uptimeMs) {
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index aa9435b..719c2ae 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -25,12 +25,10 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.content.Context;
import android.graphics.Rect;
import android.view.MotionEvent;
-import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -132,19 +130,6 @@
pa.addFloat(getDepthController(),
new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
fromDepthRatio, toDepthRatio, LINEAR);
-
- pa.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- LauncherTaskbarUIController taskbarUIController =
- activity.getTaskbarUIController();
- if (taskbarUIController != null) {
- // Launcher's ScrimView will draw the background throughout the gesture.
- taskbarUIController.forceHideBackground(true);
- }
- }
- });
-
}
};
@@ -366,16 +351,4 @@
return NORMAL;
}
}
-
- @Override
- public View onSettledOnEndTarget(@Nullable GestureEndTarget endTarget) {
- View superRet = super.onSettledOnEndTarget(endTarget);
- LauncherTaskbarUIController taskbarUIController = getTaskbarController();
- if (taskbarUIController != null) {
- // Start drawing taskbar's background again since launcher might stop drawing.
- taskbarUIController.forceHideBackground(false);
- return taskbarUIController.getRootView();
- }
- return superRet;
- }
}
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 8a30aad..a72935b 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -115,8 +115,6 @@
}
private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) {
- final ResourceProvider rp = DynamicResource.provider(mActivity);
- final float transY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
RectF iconLocation = new RectF();
FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView,
true /* hideOriginal */, iconLocation, false /* isOpening */);
@@ -127,19 +125,15 @@
return new FloatingViewHomeAnimationFactory(floatingIconView) {
- // There is a delay in loading the icon, so we need to keep the window
- // opaque until it is ready.
- private boolean mIsFloatingIconReady = false;
-
@Nullable
@Override
protected View getViewIgnoredInWorkspaceRevealAnimation() {
return workspaceView;
}
+ @NonNull
@Override
public RectF getWindowTargetRect() {
- super.getWindowTargetRect();
return iconLocation;
}
@@ -152,15 +146,6 @@
}
@Override
- public boolean keepWindowOpaque() {
- if (mIsFloatingIconReady || floatingIconView.isVisibleToUser()) {
- mIsFloatingIconReady = true;
- return false;
- }
- return true;
- }
-
- @Override
public void update(RectF currentRect, float progress, float radius) {
super.update(currentRect, progress, radius);
floatingIconView.update(1f /* alpha */, 255 /* fgAlpha */, currentRect, progress,
@@ -215,11 +200,6 @@
}
@Override
- public boolean keepWindowOpaque() {
- return false;
- }
-
- @Override
public void update(RectF currentRect, float progress, float radius) {
super.update(currentRect, progress, radius);
final float fallbackBackgroundAlpha =
@@ -264,7 +244,7 @@
}
}
- return mActivity.getWorkspace().getFirstMatchForAppClose(launchCookieItemId,
+ return mActivity.getFirstMatchForAppClose(launchCookieItemId,
runningTaskView.getTask().key.getComponent().getPackageName(),
UserHandle.of(runningTaskView.getTask().key.userId));
}
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index 65847f1..a551f55 100644
--- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -24,8 +24,6 @@
import com.android.launcher3.BuildConfig;
import com.android.launcher3.MainProcessInitializer;
-import com.android.launcher3.util.Executors;
-import com.android.quickstep.logging.SettingsChangeLogger;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.ThreadedRendererCompat;
@@ -62,9 +60,5 @@
// Elevate GPU priority for Quickstep and Remote animations.
ThreadedRendererCompat.setContextPriority(
ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
-
- // Initialize settings logger after a default timeout
- Executors.MAIN_EXECUTOR.getHandler()
- .postDelayed(() -> new SettingsChangeLogger(context), SETUP_DELAY_MILLIS);
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index c5f4a53..097850f 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -36,6 +36,7 @@
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.util.StagedSplitBounds;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
@@ -219,6 +220,26 @@
return newTasks;
}
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "RecentTasksList:");
+ writer.println(prefix + " mChangeId=" + mChangeId);
+ writer.println(prefix + " mResultsUi=[id=" + mResultsUi.mRequestId + ", tasks=");
+ for (GroupTask task : mResultsUi) {
+ writer.println(prefix + " t1=" + task.task1.key.id
+ + " t2=" + (task.hasMultipleTasks() ? task.task2.key.id : "-1"));
+ }
+ writer.println(prefix + " ]");
+ int currentUserId = Process.myUserHandle().getIdentifier();
+ ArrayList<GroupedRecentTaskInfo> rawTasks =
+ mSysUiProxy.getRecentTasks(Integer.MAX_VALUE, currentUserId);
+ writer.println(prefix + " rawTasks=[");
+ for (GroupedRecentTaskInfo task : rawTasks) {
+ writer.println(prefix + " t1=" + task.mTaskInfo1.taskId
+ + " t2=" + (task.mTaskInfo2 != null ? task.mTaskInfo2.taskId : "-1"));
+ }
+ writer.println(prefix + " ]");
+ }
+
private static class TaskLoadResult extends ArrayList<GroupTask> {
final int mRequestId;
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index d6efc71..103f350 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -141,6 +141,11 @@
mTaskbarManager.setActivity(this);
}
+ @Override
+ public void runOnBindToTouchInteractionService(Runnable r) {
+ mTISBindHelper.runOnBindToTouchInteractionService(r);
+ }
+
public void setTaskbarUIController(FallbackTaskbarUIController taskbarUIController) {
mTaskbarUIController = taskbarUIController;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index dd6392c..b502676 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -23,6 +23,7 @@
import android.view.RemoteAnimationTarget;
import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
@@ -77,7 +78,7 @@
public void notifyAnimationCanceled() {
mCancelled = true;
- onAnimationCanceled(null);
+ onAnimationCanceled(new HashMap<>());
}
// Called only in Q platform
@@ -167,16 +168,17 @@
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
* is passed back for rendering screenshot to replace live tile.
*/
- default void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {}
+ default void onRecentsAnimationCanceled(
+ @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {}
/**
* Callback made whenever the recents animation is finished.
*/
- default void onRecentsAnimationFinished(RecentsAnimationController controller) {}
+ default void onRecentsAnimationFinished(@NonNull RecentsAnimationController controller) {}
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
- default void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {}
+ default void onTasksAppeared(@NonNull RemoteAnimationTargetCompat[] appearedTaskTarget) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index ac97dd6..5d77a6e 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -24,6 +24,7 @@
import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
+import android.content.Intent;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
@@ -42,6 +43,7 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -176,7 +178,7 @@
@Override
public void onTaskRemoved(int taskId) {
- Task.TaskKey stubKey = new Task.TaskKey(taskId, 0, null, null, 0, 0);
+ Task.TaskKey stubKey = new Task.TaskKey(taskId, 0, new Intent(), null, 0, 0);
mThumbnailCache.remove(stubKey);
mIconCache.onTaskRemoved(stubKey);
}
@@ -219,6 +221,11 @@
mThumbnailChangeListeners.remove(listener);
}
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "RecentsModel:");
+ mTaskList.dump(" ", writer);
+ }
+
/**
* Listener for receiving various task properties changes
*/
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index b031c47..ed1a06d 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -77,7 +77,7 @@
for (int i = 0; i < mRemoteTargetHandles.length; i++) {
RemoteAnimationTargetCompat primaryTaskTarget = targets.apps[i];
mRemoteTargetHandles[i].mTransformParams.setTargetSet(
- createRemoteAnimationTargetsForTarget(primaryTaskTarget, targets));
+ createRemoteAnimationTargetsForTarget(targets, null));
mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
}
return mRemoteTargetHandles;
@@ -95,47 +95,68 @@
}
/**
- * Assigns the provided splitIDs to the {@link #mRemoteTargetHandles}, with index 0 will beint
+ * Assigns the provided splitIDs to the {@link #mRemoteTargetHandles}, with index 0 will being
* the left/top task, index 1 right/bottom
*/
public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets,
int[] splitIds) {
- RemoteAnimationTargetCompat primaryTaskTarget;
- RemoteAnimationTargetCompat secondaryTaskTarget;
+ RemoteAnimationTargetCompat topLeftTarget; // only one set if single/fullscreen task
+ RemoteAnimationTargetCompat bottomRightTarget;
if (mRemoteTargetHandles.length == 1) {
// If we're not in split screen, the splitIds count doesn't really matter since we
// should always hit this case.
mRemoteTargetHandles[0].mTransformParams.setTargetSet(targets);
if (targets.apps.length > 0) {
// Unclear why/when target.apps length == 0, but it sure does happen :(
- primaryTaskTarget = targets.apps[0];
- mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
+ topLeftTarget = targets.apps[0];
+ mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget, null);
}
} else {
// split screen
- primaryTaskTarget = targets.findTask(splitIds[0]);
- secondaryTaskTarget = targets.findTask(splitIds[1]);
+ topLeftTarget = targets.findTask(splitIds[0]);
+ bottomRightTarget = targets.findTask(splitIds[1]);
+ // remoteTargetHandle[0] denotes topLeft task, so we pass in the bottomRight to exclude,
+ // vice versa
mStagedSplitBounds = new StagedSplitBounds(
- primaryTaskTarget.screenSpaceBounds,
- secondaryTaskTarget.screenSpaceBounds, splitIds[0], splitIds[1]);
+ topLeftTarget.screenSpaceBounds,
+ bottomRightTarget.screenSpaceBounds, splitIds[0], splitIds[1]);
mRemoteTargetHandles[0].mTransformParams.setTargetSet(
- createRemoteAnimationTargetsForTarget(primaryTaskTarget, targets));
- mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget,
+ createRemoteAnimationTargetsForTarget(targets, bottomRightTarget));
+ mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget,
mStagedSplitBounds);
mRemoteTargetHandles[1].mTransformParams.setTargetSet(
- createRemoteAnimationTargetsForTarget(secondaryTaskTarget, targets));
- mRemoteTargetHandles[1].mTaskViewSimulator.setPreview(secondaryTaskTarget,
+ createRemoteAnimationTargetsForTarget(targets, topLeftTarget));
+ mRemoteTargetHandles[1].mTaskViewSimulator.setPreview(bottomRightTarget,
mStagedSplitBounds);
}
return mRemoteTargetHandles;
}
+ /**
+ * Ensures that we aren't excluding ancillary targets such as home/recents
+ *
+ * @param targetToExclude Will be excluded from the resulting return value.
+ * Pass in {@code null} to not exclude anything
+ * @return RemoteAnimationTargets where all the app targets from the passed in
+ * {@param targets} are included except {@param targetToExclude}
+ */
private RemoteAnimationTargets createRemoteAnimationTargetsForTarget(
- RemoteAnimationTargetCompat target,
- RemoteAnimationTargets targets) {
- return new RemoteAnimationTargets(new RemoteAnimationTargetCompat[]{target},
+ RemoteAnimationTargets targets,
+ @Nullable RemoteAnimationTargetCompat targetToExclude) {
+ int finalLength = targets.unfilteredApps.length - (targetToExclude == null ? 0 : 1);
+ RemoteAnimationTargetCompat[] targetsWithoutExcluded =
+ new RemoteAnimationTargetCompat[finalLength];
+ int i = 0;
+ for (RemoteAnimationTargetCompat targetCompat : targets.unfilteredApps) {
+ if (targetCompat == targetToExclude) {
+ continue;
+ }
+ targetsWithoutExcluded[i] = targetCompat;
+ i++;
+ }
+ return new RemoteAnimationTargets(targetsWithoutExcluded,
targets.wallpapers, targets.nonApps, targets.targetMode);
}
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index b36cb0a..8e9b668 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -183,8 +183,6 @@
public void setAnimation(RectFSpringAnim anim) { }
- public boolean keepWindowOpaque() { return false; }
-
public void update(RectF currentRect, float progress, float radius) { }
public void onCancel() { }
@@ -338,9 +336,6 @@
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
float alpha = mAnimationFactory.getWindowAlpha(progress);
- if (mAnimationFactory.keepWindowOpaque()) {
- alpha = 1f;
- }
mLocalTransformParams
.setTargetAlpha(alpha)
.setCornerRadius(cornerRadius);
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 4239739..67e7f88 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -39,7 +39,6 @@
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -52,12 +51,12 @@
import com.android.wm.shell.pip.IPipAnimationListener;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
import com.android.wm.shell.transition.IShellTransitions;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
import java.util.ArrayList;
import java.util.Arrays;
@@ -84,14 +83,16 @@
MAIN_EXECUTOR.execute(() -> clearProxy());
};
- // Save the listeners passed into the proxy since when set/register these listeners,
- // setProxy may not have been called, eg. OverviewProxyService is not connected yet.
- private IPipAnimationListener mPendingPipAnimationListener;
- private ISplitScreenListener mPendingSplitScreenListener;
- private IStartingWindowListener mPendingStartingWindowListener;
- private ISmartspaceCallback mPendingSmartspaceCallback;
- private IRecentTasksListener mPendingRecentTasksListener;
- private final ArrayList<RemoteTransitionCompat> mPendingRemoteTransitions = new ArrayList<>();
+ // Save the listeners passed into the proxy since OverviewProxyService may not have been bound
+ // yet, and we'll need to set/register these listeners with SysUI when they do. Note that it is
+ // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
+ // in case SysUI needs to rebind.
+ private IPipAnimationListener mPipAnimationListener;
+ private ISplitScreenListener mSplitScreenListener;
+ private IStartingWindowListener mStartingWindowListener;
+ private ISmartspaceCallback mSmartspaceCallback;
+ private IRecentTasksListener mRecentTasksListener;
+ private final ArrayList<RemoteTransitionCompat> mRemoteTransitions = new ArrayList<>();
// Used to dedupe calls to SystemUI
private int mLastShelfHeight;
@@ -168,29 +169,23 @@
mRecentTasks = recentTasks;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
- if (mPendingPipAnimationListener != null && mPip != null) {
- setPinnedStackAnimationListener(mPendingPipAnimationListener);
- mPendingPipAnimationListener = null;
+ if (mPipAnimationListener != null && mPip != null) {
+ setPinnedStackAnimationListener(mPipAnimationListener);
}
- if (mPendingSplitScreenListener != null && mSplitScreen != null) {
- registerSplitScreenListener(mPendingSplitScreenListener);
- mPendingSplitScreenListener = null;
+ if (mSplitScreenListener != null && mSplitScreen != null) {
+ registerSplitScreenListener(mSplitScreenListener);
}
- if (mPendingStartingWindowListener != null && mStartingWindow != null) {
- setStartingWindowListener(mPendingStartingWindowListener);
- mPendingStartingWindowListener = null;
+ if (mStartingWindowListener != null && mStartingWindow != null) {
+ setStartingWindowListener(mStartingWindowListener);
}
- if (mPendingSmartspaceCallback != null && mSmartspaceTransitionController != null) {
- setSmartspaceCallback(mPendingSmartspaceCallback);
- mPendingSmartspaceCallback = null;
+ if (mSmartspaceCallback != null && mSmartspaceTransitionController != null) {
+ setSmartspaceCallback(mSmartspaceCallback);
}
- for (int i = mPendingRemoteTransitions.size() - 1; i >= 0; --i) {
- registerRemoteTransition(mPendingRemoteTransitions.get(i));
+ for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
+ registerRemoteTransition(mRemoteTransitions.get(i));
}
- mPendingRemoteTransitions.clear();
- if (mPendingRecentTasksListener != null && mRecentTasks != null) {
- registerRecentTasksListener(mPendingRecentTasksListener);
- mPendingRecentTasksListener = null;
+ if (mRecentTasksListener != null && mRecentTasks != null) {
+ registerRecentTasksListener(mRecentTasksListener);
}
if (mPendingSetNavButtonAlpha != null) {
@@ -469,8 +464,6 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call handleImageBundleAsScreenshot");
}
- } else if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.NO_SCREENSHOT, "sysuiproxy, no proxy available");
}
}
@@ -516,9 +509,8 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
}
- } else {
- mPendingPipAnimationListener = listener;
}
+ mPipAnimationListener = listener;
}
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
@@ -556,9 +548,8 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerSplitScreenListener");
}
- } else {
- mPendingSplitScreenListener = listener;
}
+ mSplitScreenListener = listener;
}
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
@@ -569,17 +560,17 @@
Log.w(TAG, "Failed call unregisterSplitScreenListener");
}
}
- mPendingSplitScreenListener = null;
+ mSplitScreenListener = null;
}
/** Start multiple tasks in split-screen simultaneously. */
public void startTasks(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions,
- @SplitConfigurationOptions.StagePosition int sidePosition,
+ @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio,
RemoteTransitionCompat remoteTransition) {
if (mSystemUiProxy != null) {
try {
mSplitScreen.startTasks(mainTaskId, mainOptions, sideTaskId, sideOptions,
- sidePosition, remoteTransition.getTransition());
+ sidePosition, splitRatio, remoteTransition.getTransition());
} catch (RemoteException e) {
Log.w(TAG, "Failed call startTask");
}
@@ -591,22 +582,22 @@
*/
public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,
Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
- RemoteAnimationAdapter adapter) {
+ float splitRatio, RemoteAnimationAdapter adapter) {
if (mSystemUiProxy != null) {
try {
mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,
- sideOptions, sidePosition, adapter);
+ sideOptions, sidePosition, splitRatio, adapter);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startTasksWithLegacyTransition");
}
}
}
- public void startShortcut(String packageName, String shortcutId, int stage, int position,
+ public void startShortcut(String packageName, String shortcutId, int position,
Bundle options, UserHandle user) {
if (mSplitScreen != null) {
try {
- mSplitScreen.startShortcut(packageName, shortcutId, stage, position, options,
+ mSplitScreen.startShortcut(packageName, shortcutId, position, options,
user);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startShortcut");
@@ -614,11 +605,11 @@
}
}
- public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
+ public void startIntent(PendingIntent intent, Intent fillInIntent, int position,
Bundle options) {
if (mSplitScreen != null) {
try {
- mSplitScreen.startIntent(intent, fillInIntent, stage, position, options);
+ mSplitScreen.startIntent(intent, fillInIntent, position, options);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntent");
}
@@ -690,8 +681,9 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRemoteTransition");
}
- } else {
- mPendingRemoteTransitions.add(remoteTransition);
+ }
+ if (!mRemoteTransitions.contains(remoteTransition)) {
+ mRemoteTransitions.add(remoteTransition);
}
}
@@ -703,7 +695,7 @@
Log.w(TAG, "Failed call registerRemoteTransition");
}
}
- mPendingRemoteTransitions.remove(remoteTransition);
+ mRemoteTransitions.remove(remoteTransition);
}
//
@@ -720,9 +712,8 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
- } else {
- mPendingStartingWindowListener = listener;
}
+ mStartingWindowListener = listener;
}
//
@@ -736,9 +727,8 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
- } else {
- mPendingSmartspaceCallback = callback;
}
+ mSmartspaceCallback = callback;
}
//
@@ -752,9 +742,8 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerRecentTasksListener", e);
}
- } else {
- mPendingRecentTasksListener = listener;
}
+ mRecentTasksListener = listener;
}
public void unregisterRecentTasksListener(IRecentTasksListener listener) {
@@ -765,7 +754,7 @@
Log.w(TAG, "Failed call unregisterRecentTasksListener");
}
}
- mPendingRecentTasksListener = null;
+ mRecentTasksListener = null;
}
public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index e69330a..d3b17f8 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import android.app.ActivityManager;
import android.content.Context;
@@ -27,6 +28,7 @@
import android.os.Bundle;
import android.os.SystemProperties;
import android.util.Log;
+import android.view.RemoteAnimationTarget;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -42,6 +44,7 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import java.util.Arrays;
import java.util.HashMap;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
@@ -150,6 +153,17 @@
public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
+ // Convert appTargets to type RemoteAnimationTarget for all apps except Home app
+ RemoteAnimationTarget[] nonHomeApps = Arrays.stream(appearedTaskTargets)
+ .filter(remoteAnimationTarget ->
+ remoteAnimationTarget.activityType != ACTIVITY_TYPE_HOME)
+ .map(RemoteAnimationTargetCompat::unwrap)
+ .toArray(RemoteAnimationTarget[]::new);
+
+ RemoteAnimationTarget[] nonAppTargets =
+ SystemUiProxy.INSTANCE.getNoCreate()
+ .onGoingToRecentsLegacy(false, nonHomeApps);
+
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode()
&& activityInterface.getCreatedActivity() != null) {
RecentsView recentsView =
@@ -158,7 +172,7 @@
recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId,
appearedTaskTargets,
new RemoteAnimationTargetCompat[0] /* wallpaper */,
- new RemoteAnimationTargetCompat[0] /* nonApps */);
+ RemoteAnimationTargetCompat.wrap(nonAppTargets) /* nonApps */);
return;
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 0246849..276e1c2 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -23,6 +23,7 @@
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
import android.annotation.SuppressLint;
+import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Matrix;
@@ -54,6 +55,7 @@
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.util.ArrayList;
import java.util.List;
@@ -115,8 +117,9 @@
* Does NOT add split options in the following scenarios:
* * The taskView to add split options is already showing split screen tasks
* * There aren't at least 2 tasks in overview to show split options for
+ * * Device is in "Lock task mode"
* * The taskView to show split options for is the focused task AND we haven't started
- * scrolling in overview (if we haven't scrolled, there's a split overview action so
+ * scrolling in overview (if we haven't scrolled, there's a split overview action button so
* we don't need this menu option)
*/
private static void addSplitOptions(List<SystemShortcut> outShortcuts,
@@ -130,7 +133,11 @@
boolean isFocusedTask = deviceProfile.overviewShowAsGrid && taskView.isFocusedTask();
boolean isTaskInExpectedScrollPosition =
recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
- if (taskViewHasMultipleTasks || notEnoughTasksToSplit ||
+ ActivityManager activityManager =
+ (ActivityManager) taskView.getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ boolean isLockTaskMode = activityManager.isInLockTaskMode();
+
+ if (taskViewHasMultipleTasks || notEnoughTasksToSplit || isLockTaskMode ||
(isFocusedTask && isTaskInExpectedScrollPosition)) {
return;
}
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 8c4ba97..f507ea3 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -72,7 +72,13 @@
@Override
public SystemShortcut getShortcut(BaseDraggingActivity activity,
TaskIdAttributeContainer taskContainer) {
- return new AppInfo(activity, taskContainer.getItemInfo());
+ TaskView taskView = taskContainer.getTaskView();
+ AppInfo.SplitAccessibilityInfo accessibilityInfo =
+ new AppInfo.SplitAccessibilityInfo(taskView.containsMultipleTasks(),
+ TaskUtils.getTitle(taskView.getContext(), taskContainer.getTask()),
+ taskContainer.getA11yNodeId()
+ );
+ return new AppInfo(activity, taskContainer.getItemInfo(), accessibilityInfo);
}
@Override
@@ -236,6 +242,7 @@
}
}
+ /** @Deprecated */
TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory(R.drawable.ic_split_screen,
R.string.recent_task_option_split_screen, LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 142fafe..5d9a537 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -28,6 +28,7 @@
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_IN_INTERPOLATOR;
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.QuickstepTransitionManager.SPLIT_DIVIDER_ANIM_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -83,6 +84,7 @@
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import java.util.ArrayList;
+import java.util.List;
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
@@ -196,7 +198,8 @@
boolean showAsGrid = dp.overviewShowAsGrid;
boolean parallaxCenterAndAdjacentTask =
taskIndex != recentsView.getCurrentPage() && !showAsGrid;
- int startScroll = recentsView.getScrollOffset(taskIndex);
+ int taskRectTranslationPrimary = recentsView.getScrollOffset(taskIndex);
+ int taskRectTranslationSecondary = showAsGrid ? (int) v.getGridTranslationY() : 0;
RemoteTargetHandle[] topMostSimulators = null;
@@ -213,9 +216,10 @@
tvsLocal.fullScreenProgress.value = 0;
tvsLocal.recentsViewScale.value = 1;
- tvsLocal.setScroll(startScroll);
tvsLocal.setIsGridTask(v.isGridTask());
- tvsLocal.setGridTranslationY(v.getGridTranslationY());
+ tvsLocal.getOrientationState().getOrientationHandler().set(tvsLocal,
+ TaskViewSimulator::setTaskRectTranslation, taskRectTranslationPrimary,
+ taskRectTranslationSecondary);
// Fade in the task during the initial 20% of the animation
out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0, 1,
@@ -314,7 +318,7 @@
mt[i] = localMt;
Matrix localMti = new Matrix();
- localMti.invert(localMt);
+ localMt.invert(localMti);
mti[i] = localMti;
}
@@ -534,7 +538,8 @@
nonAppTargets, depthController, pa);
if (launcherClosing) {
// TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
- TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets, true);
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets,
+ true /*shown*/, true /*animate*/, pa);
}
Animator childStateAnimation = null;
@@ -590,19 +595,88 @@
}
public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
- boolean shown) {
- // TODO(b/182592057): make this part of the animations instead.
- if (nonApps != null && nonApps.length > 0) {
- SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- for (int i = 0; i < nonApps.length; ++i) {
- final RemoteAnimationTargetCompat targ = nonApps[i];
- final SurfaceControl leash = targ.leash.getSurfaceControl();
- if (targ.windowType == TYPE_DOCK_DIVIDER && leash != null) {
- t.setVisibility(leash, shown);
+ boolean shown, boolean animate) {
+ setSplitAuxiliarySurfacesShown(nonApps, shown, animate,null);
+ }
+
+ private static void setSplitAuxiliarySurfacesShown(
+ @NonNull RemoteAnimationTargetCompat[] nonApps, boolean shown, boolean animate,
+ @Nullable PendingAnimation splitLaunchAnimation) {
+ if (nonApps == null || nonApps.length == 0) {
+ return;
+ }
+
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ List<SurfaceControl> auxiliarySurfaces = new ArrayList<>(nonApps.length);
+ boolean hasSurfaceToAnimate = false;
+ for (int i = 0; i < nonApps.length; ++i) {
+ final RemoteAnimationTargetCompat targ = nonApps[i];
+ final SurfaceControl leash = targ.leash.getSurfaceControl();
+ if (targ.windowType == TYPE_DOCK_DIVIDER && leash != null) {
+ auxiliarySurfaces.add(leash);
+ hasSurfaceToAnimate = true;
+ }
+ }
+ if (!hasSurfaceToAnimate) {
+ return;
+ }
+
+ if (!animate) {
+ for (SurfaceControl leash : auxiliarySurfaces) {
+ t.setAlpha(leash, shown ? 1 : 0);
+ if (shown) {
+ t.show(leash);
+ } else {
+ t.hide(leash);
}
}
t.apply();
- t.close();
+ return;
+ }
+
+ ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
+ dockFadeAnimator.addUpdateListener(valueAnimator -> {
+ float progress = valueAnimator.getAnimatedFraction();
+ for (SurfaceControl leash : auxiliarySurfaces) {
+ t.setAlpha(leash, shown ? progress : 1 - progress);
+ }
+ t.apply();
+ });
+ dockFadeAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ if (shown) {
+ for (SurfaceControl leash : auxiliarySurfaces) {
+ t.setAlpha(leash, 0);
+ t.show(leash);
+ }
+ t.apply();
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (!shown) {
+ for (SurfaceControl leash : auxiliarySurfaces) {
+ t.hide(leash);
+ }
+ t.apply();
+ }
+ t.close();
+ }
+ });
+ dockFadeAnimator.setDuration(SPLIT_DIVIDER_ANIM_DURATION);
+ if (splitLaunchAnimation != null) {
+ // If split apps are launching, we want to delay showing the divider bar until the very
+ // end once the apps are mostly in place. This is because we aren't moving the divider
+ // leash in the relative position with the launching apps.
+ dockFadeAnimator.setStartDelay(
+ splitLaunchAnimation.getDuration() - SPLIT_DIVIDER_ANIM_DURATION);
+ splitLaunchAnimation.add(dockFadeAnimator);
+ } else {
+ dockFadeAnimator.start();
}
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 377edbe..38d6448 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -289,6 +288,12 @@
.onSystemBarAttributesChanged(displayId, behavior));
}
+ @Override
+ public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+ executeForTaskbarManager(() -> mTaskbarManager
+ .onNavButtonsDarkIntensityChanged(darkIntensity));
+ }
+
private void executeForTaskbarManager(final Runnable r) {
MAIN_EXECUTOR.execute(() -> {
if (mTaskbarManager == null) {
@@ -355,7 +360,6 @@
@Override
public void onCreate() {
super.onCreate();
- Log.d(TASKBAR_WINDOW_CRASH, "TIS created");
// Initialize anything here that is needed in direct boot mode.
// Everything else should be initialized in onUserUnlocked() below.
mMainChoreographer = Choreographer.getInstance();
@@ -517,7 +521,6 @@
@Override
public void onDestroy() {
Log.d(TAG, "Touch service destroyed: user=" + getUserId());
- Log.d(TASKBAR_WINDOW_CRASH, "TIS destroyed");
sIsInitialized = false;
if (mDeviceState.isUserUnlocked()) {
mInputConsumer.unregisterInputConsumer();
@@ -662,8 +665,8 @@
gestureState.updatePreviouslyAppearedTaskIds(
previousGestureState.getPreviouslyAppearedTaskIds());
} else {
- gestureState.updateRunningTask(TraceHelper.allowIpcs("getRunningTask.0",
- () -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
+ gestureState.updateRunningTasks(TraceHelper.allowIpcs("getRunningTask.0",
+ () -> mAM.getRunningTasks(false /* filterOnlyVisibleRecents */)));
}
return gestureState;
}
@@ -970,6 +973,7 @@
pw.println(" resumed=" + resumed);
pw.println(" mConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
+ RecentsModel.INSTANCE.get(this).dump("", pw);
pw.println("ProtoTrace:");
pw.println(" file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
}
diff --git a/quickstep/src/com/android/quickstep/ViewUtils.java b/quickstep/src/com/android/quickstep/ViewUtils.java
index 184ab17..e290be8 100644
--- a/quickstep/src/com/android/quickstep/ViewUtils.java
+++ b/quickstep/src/com/android/quickstep/ViewUtils.java
@@ -15,8 +15,10 @@
*/
package com.android.quickstep;
+import android.graphics.HardwareRenderer;
import android.os.Handler;
import android.view.View;
+import android.view.ViewRootImpl;
import com.android.launcher3.Utilities;
import com.android.systemui.shared.system.ViewRootImplCompat;
@@ -45,9 +47,9 @@
return new FrameHandler(view, onFinishRunnable, canceled).schedule();
}
- private static class FrameHandler implements LongConsumer {
+ private static class FrameHandler implements HardwareRenderer.FrameDrawingCallback {
- final ViewRootImplCompat mViewRoot;
+ final ViewRootImpl mViewRoot;
final Runnable mFinishCallback;
final BooleanSupplier mCancelled;
final Handler mHandler;
@@ -55,14 +57,14 @@
int mDeferFrameCount = 1;
FrameHandler(View view, Runnable finishCallback, BooleanSupplier cancelled) {
- mViewRoot = new ViewRootImplCompat(view);
+ mViewRoot = view.getViewRootImpl();
mFinishCallback = finishCallback;
mCancelled = cancelled;
mHandler = new Handler();
}
@Override
- public void accept(long l) {
+ public void onFrameDraw(long frame) {
Utilities.postAsyncCallback(mHandler, this::onFrame);
}
@@ -83,7 +85,7 @@
}
private boolean schedule() {
- if (mViewRoot.isValid()) {
+ if (mViewRoot.getView() != null) {
mViewRoot.registerRtFrameCallback(this);
mViewRoot.getView().invalidate();
return true;
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 50b69dc..ff175f1 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -24,14 +24,22 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
+import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
+import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;
+import android.util.FloatProperty;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateHandler;
@@ -100,5 +108,31 @@
setter.setViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity),
config.getInterpolator(ANIM_SCRIM_FADE, LINEAR));
+
+ RecentsState currentState = mActivity.getStateManager().getState();
+ if (isSplitSelectionState(state) && !isSplitSelectionState(currentState)) {
+ setter.add(mRecentsView.createSplitSelectInitAnimation().buildAnim());
+ }
+
+ Pair<FloatProperty, FloatProperty> taskViewsFloat =
+ mRecentsView.getPagedOrientationHandler().getSplitSelectTaskOffset(
+ TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
+ mActivity.getDeviceProfile());
+ setter.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
+ if (isSplitSelectionState(state)) {
+ mRecentsView.applySplitPrimaryScrollOffset();
+ setter.setFloat(mRecentsView, taskViewsFloat.first,
+ mRecentsView.getSplitSelectTranslation(), LINEAR);
+ } else {
+ mRecentsView.resetSplitPrimaryScrollOffset();
+ setter.setFloat(mRecentsView, taskViewsFloat.first, 0, LINEAR);
+ }
+ }
+
+ /**
+ * @return true if {@param toState} is {@link RecentsState#OVERVIEW_SPLIT_SELECT}
+ */
+ private boolean isSplitSelectionState(@NonNull RecentsState toState) {
+ return toState == OVERVIEW_SPLIT_SELECT;
}
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 95095fa..6d22b17 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -16,34 +16,35 @@
package com.android.quickstep.fallback;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
-import static com.android.quickstep.ViewUtils.postFrameDrawn;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.HOME;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
+import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
-import android.content.res.Configuration;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.FallbackActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -74,6 +75,7 @@
@Override
public void startHome() {
mActivity.startHome();
+ AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
}
/**
@@ -206,11 +208,14 @@
}
@Override
+ public void initiateSplitSelect(TaskView taskView,
+ @SplitConfigurationOptions.StagePosition int stagePosition) {
+ super.initiateSplitSelect(taskView, stagePosition);
+ mActivity.getStateManager().goToState(OVERVIEW_SPLIT_SELECT);
+ }
+
+ @Override
public void onStateTransitionStart(RecentsState toState) {
- if (toState == HOME) {
- // Clean-up logic that occurs when recents is no longer in use/visible.
- reset();
- }
setOverviewStateEnabled(true);
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.isFullScreen());
@@ -219,13 +224,17 @@
@Override
public void onStateTransitionComplete(RecentsState finalState) {
+ if (finalState == HOME) {
+ // Clean-up logic that occurs when recents is no longer in use/visible.
+ reset();
+ }
boolean isOverlayEnabled = finalState == DEFAULT || finalState == MODAL_TASK;
setOverlayEnabled(isOverlayEnabled);
setFreezeViewVisibility(false);
if (isOverlayEnabled) {
- postFrameDrawn(this, () -> runActionOnRemoteHandles(remoteTargetHandle ->
- remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)));
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
}
}
@@ -244,12 +253,4 @@
// Do not let touch escape to siblings below this view.
return result || mActivity.getStateManager().getState().overviewUi();
}
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
-
- // Reset modal state if full configuration changes
- setModalStateEnabled(false);
- }
}
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index 917b58a..15feb18 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -51,6 +51,8 @@
FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN | FLAG_OVERVIEW_UI);
public static final RecentsState HOME = new RecentsState(3, 0);
public static final RecentsState BG_LAUNCHER = new LauncherState(4, 0);
+ public static final RecentsState OVERVIEW_SPLIT_SELECT = new RecentsState(5,
+ FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_OVERVIEW_UI);
public final int ordinal;
private final int mFlags;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
index 510820a..162ace4 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
@@ -24,6 +24,8 @@
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
+import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_GESTURE;
+import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
import static com.android.launcher3.Utilities.squaredHypot;
import android.animation.Animator;
@@ -64,8 +66,6 @@
private static final String OPA_BUNDLE_TRIGGER = "triggered_by";
// From //java/com/google/android/apps/gsa/assistant/shared/proto/opa_trigger.proto.
private static final int OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE = 83;
- private static final String INVOCATION_TYPE_KEY = "invocation_type";
- private static final int INVOCATION_TYPE_GESTURE = 1;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index 7ae0fc8..a0cd0d7 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -40,10 +40,11 @@
import com.android.launcher3.AutoInstallsLayout;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logging.InstanceIdSequence;
+import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.DeviceGridState;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SettingsCache;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
@@ -53,12 +54,19 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.Optional;
/**
* Utility class to log launcher settings changes
*/
public class SettingsChangeLogger implements
NavigationModeChangeListener, OnSharedPreferenceChangeListener {
+
+ /**
+ * Singleton instance
+ */
+ public static MainThreadInitializedObject<SettingsChangeLogger> INSTANCE =
+ new MainThreadInitializedObject<>(SettingsChangeLogger::new);
private static final String TAG = "SettingsChangeLogger";
private static final String ROOT_TAG = "androidx.preference.PreferenceScreen";
@@ -66,12 +74,15 @@
private final Context mContext;
private final ArrayMap<String, LoggablePref> mLoggablePrefs;
+ private final StatsLogManager mStatsLogManager;
private Mode mNavMode;
- private boolean mNotificationDotsEnabled;
+ private StatsLogManager.LauncherEvent mNotificationDotsEvent;
+ private StatsLogManager.LauncherEvent mHomeScreenSuggestionEvent;
- public SettingsChangeLogger(Context context) {
+ private SettingsChangeLogger(Context context) {
mContext = context;
+ mStatsLogManager = StatsLogManager.newInstance(mContext);
mLoggablePrefs = loadPrefKeys(context);
mNavMode = SysUINavigationMode.INSTANCE.get(context).addModeChangeListener(this);
@@ -118,14 +129,21 @@
}
private void onNotificationDotsChanged(boolean isDotsEnabled) {
- mNotificationDotsEnabled = isDotsEnabled;
- dispatchUserEvent();
+ StatsLogManager.LauncherEvent mEvent =
+ isDotsEnabled ? LAUNCHER_NOTIFICATION_DOT_ENABLED
+ : LAUNCHER_NOTIFICATION_DOT_DISABLED;
+
+ // Log only when the setting is actually changed and not during initialization.
+ if (mNotificationDotsEvent != null && mNotificationDotsEvent != mEvent) {
+ mStatsLogManager.logger().log(mNotificationDotsEvent);
+ }
+ mNotificationDotsEvent = mEvent;
}
@Override
public void onNavigationModeChanged(Mode newMode) {
mNavMode = newMode;
- dispatchUserEvent();
+ mStatsLogManager.logger().log(newMode.launcherEvent);
}
@Override
@@ -134,27 +152,27 @@
|| KEY_WORKSPACE_SIZE.equals(key)
|| KEY_THEMED_ICONS.equals(key)
|| mLoggablePrefs.containsKey(key)) {
- dispatchUserEvent();
+
+ mHomeScreenSuggestionEvent = getDevicePrefs(mContext)
+ .getBoolean(LAST_PREDICTION_ENABLED_STATE, true)
+ ? LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED
+ : LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED;
+
+ mStatsLogManager.logger().log(mHomeScreenSuggestionEvent);
}
}
- private void dispatchUserEvent() {
- StatsLogger logger = StatsLogManager.newInstance(mContext).logger()
- .withInstanceId(new InstanceIdSequence().newInstanceId());
+ /**
+ * Takes snapshot of all eligible launcher settings and log them with the provided instance ID.
+ */
+ public void logSnapshot(InstanceId snapshotInstanceId) {
+ StatsLogger logger = mStatsLogManager.logger().withInstanceId(snapshotInstanceId);
- logger.log(mNotificationDotsEnabled
- ? LAUNCHER_NOTIFICATION_DOT_ENABLED
- : LAUNCHER_NOTIFICATION_DOT_DISABLED);
- logger.log(mNavMode.launcherEvent);
- logger.log(getDevicePrefs(mContext).getBoolean(LAST_PREDICTION_ENABLED_STATE, true)
- ? LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED
- : LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED);
-
- StatsLogManager.LauncherEvent gridSizeChangedEvent =
- new DeviceGridState(mContext).getWorkspaceSizeEvent();
- if (gridSizeChangedEvent != null) {
- logger.log(gridSizeChangedEvent);
- }
+ Optional.ofNullable(mNotificationDotsEvent).ifPresent(logger::log);
+ Optional.ofNullable(mNavMode).map(mode -> mode.launcherEvent).ifPresent(logger::log);
+ Optional.ofNullable(mHomeScreenSuggestionEvent).ifPresent(logger::log);
+ Optional.ofNullable(new DeviceGridState(mContext).getWorkspaceSizeEvent()).ifPresent(
+ logger::log);
SharedPreferences prefs = getPrefs(mContext);
if (FeatureFlags.ENABLE_THEMED_ICONS.get()) {
diff --git a/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
new file mode 100644
index 0000000..861ff96
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/BaseUnfoldMoveFromCenterAnimator.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.annotation.CallSuper;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Animation that moves launcher icons and widgets from center to the sides (final position)
+ */
+public abstract class BaseUnfoldMoveFromCenterAnimator implements TransitionProgressListener {
+
+ private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimation;
+
+ private final Map<ViewGroup, Boolean> mOriginalClipToPadding = new HashMap<>();
+ private final Map<ViewGroup, Boolean> mOriginalClipChildren = new HashMap<>();
+
+ public BaseUnfoldMoveFromCenterAnimator(WindowManager windowManager) {
+ mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager,
+ new LauncherViewsMoveFromCenterTranslationApplier());
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionStarted() {
+ mMoveFromCenterAnimation.updateDisplayProperties();
+ onPrepareViewsForAnimation();
+ onTransitionProgress(0f);
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionProgress(float progress) {
+ mMoveFromCenterAnimation.onTransitionProgress(progress);
+ }
+
+ @CallSuper
+ @Override
+ public void onTransitionFinished() {
+ mMoveFromCenterAnimation.onTransitionFinished();
+ mMoveFromCenterAnimation.clearRegisteredViews();
+
+ mOriginalClipChildren.clear();
+ mOriginalClipToPadding.clear();
+ }
+
+ protected void onPrepareViewsForAnimation() {
+
+ }
+
+ protected void registerViewForAnimation(View view) {
+ mMoveFromCenterAnimation.registerViewForAnimation(view);
+ }
+
+ protected void disableClipping(ViewGroup view) {
+ mOriginalClipToPadding.put(view, view.getClipToPadding());
+ mOriginalClipChildren.put(view, view.getClipChildren());
+ view.setClipToPadding(false);
+ view.setClipChildren(false);
+ }
+
+ protected void restoreClipping(ViewGroup view) {
+ final Boolean originalClipToPadding = mOriginalClipToPadding.get(view);
+ if (originalClipToPadding != null) {
+ view.setClipToPadding(originalClipToPadding);
+ }
+ final Boolean originalClipChildren = mOriginalClipChildren.get(view);
+ if (originalClipChildren != null) {
+ view.setClipChildren(originalClipChildren);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index b0c68c5..de7dbd6 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -49,7 +49,6 @@
import com.android.internal.app.ChooserActivity;
import com.android.launcher3.BuildConfig;
-import com.android.launcher3.testing.TestProtocol;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.utilities.BitmapUtil;
@@ -78,9 +77,6 @@
public static void saveScreenshot(SystemUiProxy systemUiProxy, Bitmap screenshot,
Rect screenshotBounds,
Insets visibleInsets, Task.TaskKey task) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.NO_SCREENSHOT, "image action utils calling into sysuiproxy");
- }
systemUiProxy.handleImageBundleAsScreenshot(BitmapUtil.hardwareBitmapToBundle(screenshot),
screenshotBounds, visibleInsets, task);
}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index b39412b..6b6bd6a 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -18,14 +18,17 @@
import static com.android.launcher3.Utilities.comp;
import android.annotation.Nullable;
-import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import androidx.core.view.OneShotPreDrawListener;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.util.HorizontalInsettableView;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
/**
@@ -43,6 +46,7 @@
private HorizontalInsettableView mQsbInsettable;
private final ScopedUnfoldTransitionProgressProvider mProgressProvider;
+ private final NaturalRotationUnfoldProgressProvider mNaturalOrientationProgressProvider;
public LauncherUnfoldAnimationController(
Launcher launcher,
@@ -51,10 +55,19 @@
mLauncher = launcher;
mProgressProvider = new ScopedUnfoldTransitionProgressProvider(
unfoldTransitionProgressProvider);
+ mNaturalOrientationProgressProvider = new NaturalRotationUnfoldProgressProvider(launcher,
+ WindowManagerGlobal.getWindowManagerService(), mProgressProvider);
+ mNaturalOrientationProgressProvider.init();
+ // Animated in all orientations
mProgressProvider.addCallback(new UnfoldMoveFromCenterWorkspaceAnimator(launcher,
windowManager));
- mProgressProvider.addCallback(new QsbAnimationListener());
+
+ // Animated only in natural orientation
+ mNaturalOrientationProgressProvider
+ .addCallback(new QsbAnimationListener());
+ mNaturalOrientationProgressProvider
+ .addCallback(new UnfoldMoveFromCenterHotseatAnimator(launcher, windowManager));
}
/**
@@ -66,17 +79,8 @@
mQsbInsettable = (HorizontalInsettableView) hotseat.getQsb();
}
- final ViewTreeObserver obs = mLauncher.getWorkspace().getViewTreeObserver();
- obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (obs.isAlive()) {
- mProgressProvider.setReadyToHandleTransition(true);
- obs.removeOnPreDrawListener(this);
- }
- return true;
- }
- });
+ OneShotPreDrawListener.add(mLauncher.getWorkspace(),
+ () -> mProgressProvider.setReadyToHandleTransition(true));
}
/**
@@ -92,6 +96,7 @@
*/
public void onDestroy() {
mProgressProvider.destroy();
+ mNaturalOrientationProgressProvider.destroy();
}
private class QsbAnimationListener implements TransitionProgressListener {
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 9c6fd3d..8ccab71 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -162,7 +162,7 @@
*/
public void setDeviceProfile(DeviceProfile deviceProfile) {
boolean oldMultipleOrientationsSupported = isMultipleOrientationSupportedByDevice();
- setFlag(FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY, !deviceProfile.allowRotation);
+ setFlag(FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY, !deviceProfile.isTablet);
if (mListenersInitialized) {
boolean newMultipleOrientationsSupported = isMultipleOrientationSupportedByDevice();
// If isMultipleOrientationSupportedByDevice is changed, init or destroy listeners
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index c784d82..5253e8c 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -18,6 +18,7 @@
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -30,7 +31,6 @@
import android.view.SurfaceControl;
import android.window.TransitionInfo;
-
import androidx.annotation.Nullable;
import com.android.launcher3.statehandlers.DepthController;
@@ -64,7 +64,6 @@
private @StagePosition int mStagePosition;
private Task mInitialTask;
private Task mSecondTask;
- private Rect mInitialBounds;
private boolean mRecentsAnimationRunning;
/** If not null, this is the TaskView we want to launch from */
@Nullable
@@ -86,7 +85,6 @@
Rect initialBounds) {
mInitialTask = task;
mStagePosition = stagePosition;
- mInitialBounds = initialBounds;
}
/**
@@ -95,7 +93,7 @@
public void setSecondTaskId(Task task, Consumer<Boolean> callback) {
mSecondTask = task;
launchTasks(mInitialTask, mSecondTask, mStagePosition, callback,
- false /* freezeTaskList */);
+ false /* freezeTaskList */, DEFAULT_SPLIT_RATIO);
}
/**
@@ -107,14 +105,15 @@
TaskView.TaskIdAttributeContainer[] taskIdAttributeContainers =
groupedTaskView.getTaskIdAttributeContainers();
launchTasks(taskIdAttributeContainers[0].getTask(), taskIdAttributeContainers[1].getTask(),
- taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList);
+ taskIdAttributeContainers[0].getStagePosition(), callback, freezeTaskList,
+ groupedTaskView.getSplitRatio());
}
/**
* @param stagePosition representing location of task1
*/
public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition,
- Consumer<Boolean> callback, boolean freezeTaskList) {
+ Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
// Assume initial task is for top/left part of screen
final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
? new int[]{task1.key.id, task2.key.id}
@@ -123,7 +122,7 @@
RemoteSplitLaunchTransitionRunner animationRunner =
new RemoteSplitLaunchTransitionRunner(task1, task2);
mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
- null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
+ null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio,
new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR,
ActivityThread.currentActivityThread().getApplicationThread()));
} else {
@@ -140,7 +139,7 @@
}
mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(),
taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
- adapter);
+ splitRatio, adapter);
}
}
@@ -228,7 +227,6 @@
mInitialTask = null;
mSecondTask = null;
mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
- mInitialBounds = null;
mRecentsAnimationRunning = false;
mLaunchingTaskView = null;
}
@@ -240,8 +238,4 @@
public boolean isSplitSelectActive() {
return mInitialTask != null && mSecondTask == null;
}
-
- public Rect getInitialBounds() {
- return mInitialBounds;
- }
}
diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
index 3b4fd31..3b1c150 100644
--- a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
+++ b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
@@ -22,10 +22,10 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
+import android.view.ViewRootImpl;
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
-import com.android.systemui.shared.system.ViewRootImplCompat;
import java.util.function.Consumer;
@@ -41,7 +41,7 @@
private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
private final SurfaceControl mBarrierSurfaceControl;
- private final ViewRootImplCompat mTargetViewRootImpl;
+ private final ViewRootImpl mTargetViewRootImpl;
private final Handler mApplyHandler;
private int mLastSequenceNumber = 0;
@@ -50,8 +50,8 @@
* @param targetView The view in the surface that acts as synchronization anchor.
*/
public SurfaceTransactionApplier(View targetView) {
- mTargetViewRootImpl = new ViewRootImplCompat(targetView);
- mBarrierSurfaceControl = mTargetViewRootImpl.getRenderSurfaceControl();
+ mTargetViewRootImpl = targetView.getViewRootImpl();
+ mBarrierSurfaceControl = mTargetViewRootImpl.getSurfaceControl();
mApplyHandler = new Handler(this::onApplyMessage);
}
@@ -109,7 +109,7 @@
if (targetView == null) {
// No target view, no applier
callback.accept(null);
- } else if (new ViewRootImplCompat(targetView).isValid()) {
+ } else if (targetView.isAttachedToWindow()) {
// Already attached, we're good to go
callback.accept(new SurfaceTransactionApplier(targetView));
} else {
diff --git a/quickstep/src/com/android/quickstep/util/TISBindHelper.java b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
index 92c60c8..7b122c6 100644
--- a/quickstep/src/com/android/quickstep/util/TISBindHelper.java
+++ b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
@@ -26,6 +26,7 @@
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.TouchInteractionService.TISBinder;
+import java.util.ArrayList;
import java.util.function.Consumer;
/**
@@ -44,9 +45,11 @@
private final Runnable mConnectionRunnable = this::internalBindToTIS;
private final Context mContext;
private final Consumer<TISBinder> mConnectionCallback;
+ private final ArrayList<Runnable> mPendingConnectedCallbacks = new ArrayList<>();
private short mConnectionAttempts;
private boolean mTisServiceBound;
+ private boolean mIsConnected;
public TISBindHelper(Context context, Consumer<TISBinder> connectionCallback) {
mContext = context;
@@ -66,7 +69,13 @@
}
Log.d(TAG, "TIS service connected");
+ mIsConnected = true;
mConnectionCallback.accept((TISBinder) iBinder);
+ // Flush the pending callbacks
+ for (Runnable r : mPendingConnectedCallbacks) {
+ r.run();
+ }
+ mPendingConnectedCallbacks.clear();
resetServiceBindRetryState();
}
@@ -79,6 +88,16 @@
internalBindToTIS();
}
+ /**
+ * Runs the given {@param r} runnable when the service is connected.
+ */
+ public void runOnBindToTouchInteractionService(Runnable r) {
+ if (mIsConnected) {
+ r.run();
+ } else {
+ mPendingConnectedCallbacks.add(r);
+ }
+ }
/**
* Binds to {@link TouchInteractionService}. If the binding fails, attempts to retry via
@@ -120,5 +139,7 @@
public void onDestroy() {
internalUnbindToTIS();
resetServiceBindRetryState();
+ mIsConnected = false;
+ mPendingConnectedCallbacks.clear();
}
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 7d396ba..f676091 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -102,7 +102,8 @@
private StagedSplitBounds mStagedSplitBounds;
private boolean mDrawsBelowRecents;
private boolean mIsGridTask;
- private float mGridTranslationY;
+ private int mTaskRectTranslationX;
+ private int mTaskRectTranslationY;
public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
mContext = context;
@@ -157,15 +158,11 @@
fullTaskSize = new Rect(mTaskRect);
mOrientationState.getOrientationHandler()
.setSplitTaskSwipeRect(mDp, mTaskRect, mStagedSplitBounds, mStagePosition);
- if (mIsGridTask) {
- mTaskRect.offset(0, (int) mGridTranslationY);
- }
+ mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
} else {
fullTaskSize = mTaskRect;
}
- if (mIsGridTask) {
- fullTaskSize.offset(0, (int) mGridTranslationY);
- }
+ fullTaskSize.offset(mTaskRectTranslationX, mTaskRectTranslationY);
return mOrientationState.getFullScreenScaleAndPivot(fullTaskSize, mDp, mPivot);
}
@@ -225,10 +222,11 @@
}
/**
- * Sets the y-translation when overview is in grid.
+ * Apply translations on TaskRect's starting location.
*/
- public void setGridTranslationY(float gridTranslationY) {
- mGridTranslationY = gridTranslationY;
+ public void setTaskRectTranslation(int taskRectTranslationX, int taskRectTranslationY) {
+ mTaskRectTranslationX = taskRectTranslationX;
+ mTaskRectTranslationY = taskRectTranslationY;
}
/**
@@ -336,19 +334,19 @@
// Apply TaskView matrix: taskRect, translate
mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
- mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
+ mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
taskPrimaryTranslation.value);
mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
taskSecondaryTranslation.value);
+ mOrientationState.getOrientationHandler().setPrimary(
+ mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
// Apply RecentsView matrix
mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
recentsViewSecondaryTranslation.value);
- mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
+ mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
recentsViewPrimaryTranslation.value);
- mOrientationState.getOrientationHandler().set(
- mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
applyWindowToHomeRotation(mMatrix);
// Crop rect is the inverse of thumbnail matrix
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
new file mode 100644
index 0000000..dc97dd6
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.launcher3.Hotseat;
+import com.android.launcher3.Launcher;
+
+/**
+ * Animation that moves hotseat icons from center to the sides (final position)
+ */
+public class UnfoldMoveFromCenterHotseatAnimator extends BaseUnfoldMoveFromCenterAnimator {
+
+ private final Launcher mLauncher;
+
+ public UnfoldMoveFromCenterHotseatAnimator(Launcher launcher, WindowManager windowManager) {
+ super(windowManager);
+ mLauncher = launcher;
+ }
+
+ @Override
+ protected void onPrepareViewsForAnimation() {
+ Hotseat hotseat = mLauncher.getHotseat();
+
+ ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
+ disableClipping(hotseat);
+
+ for (int i = 0; i < hotseatIcons.getChildCount(); i++) {
+ View child = hotseatIcons.getChildAt(i);
+ registerViewForAnimation(child);
+ }
+ }
+
+ @Override
+ public void onTransitionFinished() {
+ restoreClipping(mLauncher.getHotseat());
+ super.onTransitionFinished();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
index 95403b2..3d72398 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
@@ -16,44 +16,28 @@
package com.android.quickstep.util;
import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowManager;
import com.android.launcher3.CellLayout;
-import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
-import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
-import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
-
-import java.util.HashMap;
-import java.util.Map;
/**
* Animation that moves launcher icons and widgets from center to the sides (final position)
*/
-public class UnfoldMoveFromCenterWorkspaceAnimator
- implements UnfoldTransitionProgressProvider.TransitionProgressListener {
+public class UnfoldMoveFromCenterWorkspaceAnimator extends BaseUnfoldMoveFromCenterAnimator {
private final Launcher mLauncher;
- private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimation;
-
- private final Map<ViewGroup, Boolean> mOriginalClipToPadding = new HashMap<>();
- private final Map<ViewGroup, Boolean> mOriginalClipChildren = new HashMap<>();
public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager) {
+ super(windowManager);
mLauncher = launcher;
- mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager,
- new LauncherViewsMoveFromCenterTranslationApplier());
}
@Override
- public void onTransitionStarted() {
- mMoveFromCenterAnimation.updateDisplayProperties();
-
+ protected void onPrepareViewsForAnimation() {
Workspace workspace = mLauncher.getWorkspace();
- Hotseat hotseat = mLauncher.getHotseat();
// App icons and widgets
workspace
@@ -65,57 +49,17 @@
for (int i = 0; i < itemsContainer.getChildCount(); i++) {
View child = itemsContainer.getChildAt(i);
- mMoveFromCenterAnimation.registerViewForAnimation(child);
+ registerViewForAnimation(child);
}
});
disableClipping(workspace);
-
- // Hotseat icons
- ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
- disableClipping(hotseat);
-
- for (int i = 0; i < hotseatIcons.getChildCount(); i++) {
- View child = hotseatIcons.getChildAt(i);
- mMoveFromCenterAnimation.registerViewForAnimation(child);
- }
-
- onTransitionProgress(0f);
- }
-
- @Override
- public void onTransitionProgress(float progress) {
- mMoveFromCenterAnimation.onTransitionProgress(progress);
}
@Override
public void onTransitionFinished() {
- mMoveFromCenterAnimation.onTransitionFinished();
- mMoveFromCenterAnimation.clearRegisteredViews();
-
restoreClipping(mLauncher.getWorkspace());
mLauncher.getWorkspace().forEachVisiblePage(page -> restoreClipping((CellLayout) page));
- restoreClipping(mLauncher.getHotseat());
-
- mOriginalClipChildren.clear();
- mOriginalClipToPadding.clear();
- }
-
- private void disableClipping(ViewGroup view) {
- mOriginalClipToPadding.put(view, view.getClipToPadding());
- mOriginalClipChildren.put(view, view.getClipChildren());
- view.setClipToPadding(false);
- view.setClipChildren(false);
- }
-
- private void restoreClipping(ViewGroup view) {
- final Boolean originalClipToPadding = mOriginalClipToPadding.get(view);
- if (originalClipToPadding != null) {
- view.setClipToPadding(originalClipToPadding);
- }
- final Boolean originalClipChildren = mOriginalClipChildren.get(view);
- if (originalClipChildren != null) {
- view.setClipChildren(originalClipChildren);
- }
+ super.onTransitionFinished();
}
}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index dbdcf19..e5664c6 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -19,6 +19,7 @@
import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS;
import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.Gravity.START;
import static com.android.launcher3.Utilities.prefixTextWithIcon;
import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
@@ -38,26 +39,51 @@
import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.widget.FrameLayout;
import android.widget.TextView;
+import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.systemui.shared.recents.model.Task;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.time.Duration;
import java.util.Locale;
@TargetApi(Build.VERSION_CODES.Q)
public final class DigitalWellBeingToast {
+
+ private static final float THRESHOLD_LEFT_ICON_ONLY = 0.4f;
+ private static final float THRESHOLD_RIGHT_ICON_ONLY = 0.6f;
+
+ /** Will span entire width of taskView with full text */
+ private static final int SPLIT_BANNER_FULLSCREEN = 0;
+ /** Used for grid task view, only showing icon and time */
+ private static final int SPLIT_GRID_BANNER_LARGE = 1;
+ /** Used for grid task view, only showing icon */
+ private static final int SPLIT_GRID_BANNER_SMALL = 2;
+ @IntDef(value = {
+ SPLIT_BANNER_FULLSCREEN,
+ SPLIT_GRID_BANNER_LARGE,
+ SPLIT_GRID_BANNER_SMALL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface SPLIT_BANNER_CONFIG{}
+
static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS);
static final int MINUTE_MS = 60000;
@@ -74,7 +100,16 @@
private View mBanner;
private ViewOutlineProvider mOldBannerOutlineProvider;
private float mBannerOffsetPercentage;
- private float mVerticalOffset = 0f;
+ /**
+ * Clips rect provided by {@link #mOldBannerOutlineProvider} when in the model state to
+ * hide this banner as the taskView scales up and down
+ */
+ private float mModalOffset = 0f;
+ @Nullable
+ private StagedSplitBounds mStagedSplitBounds;
+ private int mSplitBannerConfig = SPLIT_BANNER_FULLSCREEN;
+ private float mSplitOffsetTranslationY;
+ private float mSplitOffsetTranslationX;
public DigitalWellBeingToast(BaseDraggingActivity activity, TaskView taskView) {
mActivity = activity;
@@ -103,7 +138,7 @@
}
public String getText() {
- return getText(mAppRemainingTimeMs);
+ return getText(mAppRemainingTimeMs, false /* forContentDesc */);
}
public boolean hasLimit() {
@@ -138,6 +173,31 @@
});
}
+ public void setSplitConfiguration(StagedSplitBounds stagedSplitBounds) {
+ mStagedSplitBounds = stagedSplitBounds;
+ if (mStagedSplitBounds == null ||
+ !mActivity.getDeviceProfile().overviewShowAsGrid ||
+ mTaskView.isFocusedTask()) {
+ mSplitBannerConfig = SPLIT_BANNER_FULLSCREEN;
+ return;
+ }
+
+ // For portrait grid only height of task changes, not width. So we keep the text the same
+ if (!mActivity.getDeviceProfile().isLandscape) {
+ mSplitBannerConfig = SPLIT_GRID_BANNER_LARGE;
+ return;
+ }
+
+ // For landscape grid, for 30% width we only show icon, otherwise show icon and time
+ if (mTask.key.id == mStagedSplitBounds.leftTopTaskId) {
+ mSplitBannerConfig = mStagedSplitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY ?
+ SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
+ } else {
+ mSplitBannerConfig = mStagedSplitBounds.leftTaskPercent > THRESHOLD_RIGHT_ICON_ONLY ?
+ SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
+ }
+ }
+
private String getReadableDuration(
Duration duration,
FormatWidth formatWidthHourAndMinute,
@@ -181,30 +241,33 @@
.formatMeasures(new Measure(0, MeasureUnit.MINUTE));
}
- private String getReadableDuration(
- Duration duration,
- FormatWidth formatWidthHourAndMinute,
- @StringRes int durationLessThanOneMinuteStringId) {
- return getReadableDuration(
- duration,
- formatWidthHourAndMinute,
- durationLessThanOneMinuteStringId,
- /* forceFormatWidth= */ false);
- }
-
- private String getRoundedUpToMinuteReadableDuration(long remainingTime) {
+ /**
+ * Returns text to show for the banner depending on {@link #mSplitBannerConfig}
+ * If {@param forContentDesc} is {@code true}, this will always return the full
+ * string corresponding to {@link #SPLIT_BANNER_FULLSCREEN}
+ */
+ private String getText(long remainingTime, boolean forContentDesc) {
final Duration duration = Duration.ofMillis(
remainingTime > MINUTE_MS ?
(remainingTime + MINUTE_MS - 1) / MINUTE_MS * MINUTE_MS :
remainingTime);
- return getReadableDuration(
- duration, FormatWidth.NARROW, R.string.shorter_duration_less_than_one_minute);
- }
+ String readableDuration = getReadableDuration(duration,
+ FormatWidth.NARROW,
+ R.string.shorter_duration_less_than_one_minute,
+ false /* forceFormatWidth */);
+ if (forContentDesc || mSplitBannerConfig == SPLIT_BANNER_FULLSCREEN) {
+ return mActivity.getString(
+ R.string.time_left_for_app,
+ readableDuration);
+ }
- private String getText(long remainingTime) {
- return mActivity.getString(
- R.string.time_left_for_app,
- getRoundedUpToMinuteReadableDuration(remainingTime));
+ if (mSplitBannerConfig == SPLIT_GRID_BANNER_SMALL) {
+ // show no text
+ return "";
+ } else { // SPLIT_GRID_BANNER_LARGE
+ // only show time
+ return readableDuration;
+ }
}
public void openAppUsageSettings(View view) {
@@ -232,7 +295,7 @@
mActivity.getString(
R.string.task_contents_description_with_remaining_time,
task.titleDescription,
- getText(appRemainingTimeMs)) :
+ getText(appRemainingTimeMs, true /* forContentDesc */)) :
task.titleDescription;
}
@@ -261,10 +324,18 @@
private void setupAndAddBanner() {
FrameLayout.LayoutParams layoutParams =
(FrameLayout.LayoutParams) mBanner.getLayoutParams();
- layoutParams.gravity = BOTTOM | CENTER_HORIZONTAL;
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
mTaskView.getThumbnail().getLayoutParams()).bottomMargin;
- mBanner.setTranslationY(mBannerOffsetPercentage * mBanner.getHeight());
+ PagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
+ Pair<Float, Float> translations = orientationHandler
+ .setDwbLayoutParamsAndGetTranslations(mTaskView.getMeasuredWidth(),
+ mTaskView.getMeasuredHeight(), mStagedSplitBounds, deviceProfile,
+ mTaskView.getThumbnails(), mTask.key.id, mBanner);
+ mSplitOffsetTranslationX = translations.first;
+ mSplitOffsetTranslationY = translations.second;
+ updateTranslationY();
+ updateTranslationX();
mTaskView.addView(mBanner);
}
@@ -274,7 +345,9 @@
@Override
public void getOutline(View view, Outline outline) {
mOldBannerOutlineProvider.getOutline(view, outline);
- outline.offset(0, Math.round(-view.getTranslationY() + mVerticalOffset));
+ float verticalTranslation = -view.getTranslationY() + mModalOffset
+ + mSplitOffsetTranslationY;
+ outline.offset(0, Math.round(verticalTranslation));
}
});
mBanner.setClipToOutline(true);
@@ -282,13 +355,33 @@
void updateBannerOffset(float offsetPercentage, float verticalOffset) {
if (mBanner != null && mBannerOffsetPercentage != offsetPercentage) {
- mVerticalOffset = verticalOffset;
+ mModalOffset = verticalOffset;
mBannerOffsetPercentage = offsetPercentage;
- mBanner.setTranslationY(offsetPercentage * mBanner.getHeight() + mVerticalOffset);
+ updateTranslationY();
mBanner.invalidateOutline();
}
}
+ private void updateTranslationY() {
+ if (mBanner == null) {
+ return;
+ }
+
+ mBanner.setTranslationY(
+ (mBannerOffsetPercentage * mBanner.getHeight()) +
+ mModalOffset +
+ mSplitOffsetTranslationY
+ );
+ }
+
+ private void updateTranslationX() {
+ if (mBanner == null) {
+ return;
+ }
+
+ mBanner.setTranslationX(mSplitOffsetTranslationX);
+ }
+
void setBannerColorTint(int color, float amount) {
if (mBanner == null) {
return;
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index 325ec04..18ab3bb 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -17,8 +17,9 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -43,7 +44,7 @@
private SplitPlaceholderView mSplitPlaceholderView;
private RectF mStartingPosition;
- private final Launcher mLauncher;
+ private final BaseDraggingActivity mActivity;
private final boolean mIsRtl;
private final Rect mOutline = new Rect();
private PagedOrientationHandler mOrientationHandler;
@@ -59,7 +60,7 @@
public FloatingTaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
+ mActivity = BaseActivity.fromContext(context);
mIsRtl = Utilities.isRtl(getResources());
}
@@ -114,7 +115,7 @@
public void updateInitialPositionForView(TaskView originalView) {
View thumbnail = originalView.getThumbnail();
Rect viewBounds = new Rect(0, 0, thumbnail.getWidth(), thumbnail.getHeight());
- Utilities.getBoundsForViewInDragLayer(mLauncher.getDragLayer(), thumbnail, viewBounds,
+ Utilities.getBoundsForViewInDragLayer(mActivity.getDragLayer(), thumbnail, viewBounds,
true /* ignoreTransform */, null /* recycle */,
mStartingPosition);
mStartingPosition.offset(originalView.getTranslationX(), originalView.getTranslationY());
@@ -129,9 +130,7 @@
public void update(RectF position, float progress, float windowRadius) {
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
- float dX = mIsRtl
- ? position.left - (lp.getMarginStart() - lp.width)
- : position.left - lp.getMarginStart();
+ float dX = position.left - mStartingPosition.left;
float dY = position.top - lp.topMargin;
setTranslationX(dX);
@@ -152,27 +151,31 @@
mOrientationHandler.setSecondaryScale(mSplitPlaceholderView.getIconView(), childScaleY);
}
+ public void updateOrientationHandler(PagedOrientationHandler orientationHandler) {
+ mOrientationHandler = orientationHandler;
+ mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated());
+ }
+
protected void initPosition(RectF pos, InsettableFrameLayout.LayoutParams lp) {
mStartingPosition.set(pos);
lp.ignoreInsets = true;
// Position the floating view exactly on top of the original
lp.topMargin = Math.round(pos.top);
if (mIsRtl) {
- lp.setMarginStart(Math.round(mLauncher.getDeviceProfile().widthPx - pos.right));
+ lp.setMarginStart(mActivity.getDeviceProfile().widthPx - Math.round(pos.right));
} else {
lp.setMarginStart(Math.round(pos.left));
}
+
// Set the properties here already to make sure they are available when running the first
// animation frame.
- int left = mIsRtl
- ? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width
- : lp.leftMargin;
+ int left = (int) pos.left;
layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
}
public void addAnimation(PendingAnimation animation, RectF startingBounds, Rect endBounds,
View viewToCover, boolean fadeWithThumbnail) {
- final BaseDragLayer dragLayer = mLauncher.getDragLayer();
+ final BaseDragLayer dragLayer = mActivity.getDragLayer();
int[] dragLayerBounds = new int[2];
dragLayer.getLocationOnScreen(dragLayerBounds);
SplitOverlayProperties prop = new SplitOverlayProperties(endBounds,
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index bb5728d..7e4f9d0 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -1,5 +1,6 @@
package com.android.quickstep.views;
+import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -49,17 +50,20 @@
private final float[] mIcon2CenterCoords = new float[2];
private TransformingTouchDelegate mIcon2TouchDelegate;
@Nullable private StagedSplitBounds mSplitBoundsConfig;
+ private final DigitalWellBeingToast mDigitalWellBeingToast2;
+
public GroupedTaskView(Context context) {
- super(context);
+ this(context, null);
}
public GroupedTaskView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, 0);
}
public GroupedTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mDigitalWellBeingToast2 = new DigitalWellBeingToast(mActivity, this);
}
@Override
@@ -76,7 +80,7 @@
mSecondaryTask = secondary;
mTaskIdContainer[1] = secondary.key.id;
mTaskIdAttributeContainer[1] = new TaskIdAttributeContainer(secondary, mSnapshotView2,
- STAGE_POSITION_BOTTOM_OR_RIGHT);
+ mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT);
mTaskIdAttributeContainer[0].setStagePosition(STAGE_POSITION_TOP_OR_LEFT);
mSnapshotView2.bind(secondary);
mSplitBoundsConfig = splitBoundsConfig;
@@ -101,7 +105,9 @@
mIconLoadRequest2 = iconCache.updateIconInBackground(mSecondaryTask,
(task) -> {
setIcon(mIconView2, task.icon);
- // TODO(199936292) Digital Wellbeing for individual tasks?
+ mDigitalWellBeingToast2.initialize(mSecondaryTask);
+ mDigitalWellBeingToast2.setSplitConfiguration(mSplitBoundsConfig);
+ mDigitalWellBeingToast.setSplitConfiguration(mSplitBoundsConfig);
});
}
} else {
@@ -117,19 +123,19 @@
}
}
- protected boolean showTaskMenuWithContainer(IconView iconView) {
- if (mActivity.getDeviceProfile().overviewShowAsGrid) {
- return TaskMenuViewWithArrow.Companion.showForTask(mTaskIdAttributeContainer[0]);
- } else {
- return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
- }
- }
-
public void updateSplitBoundsConfig(StagedSplitBounds stagedSplitBounds) {
mSplitBoundsConfig = stagedSplitBounds;
invalidate();
}
+ public float getSplitRatio() {
+ if (mSplitBoundsConfig != null) {
+ return mSplitBoundsConfig.appsStackedVertically
+ ? mSplitBoundsConfig.topTaskPercent : mSplitBoundsConfig.leftTaskPercent;
+ }
+ return DEFAULT_SPLIT_RATIO;
+ }
+
@Override
public boolean offerTouchToChildren(MotionEvent event) {
computeAndSetIconTouchDelegate(mIconView2, mIcon2CenterCoords, mIcon2TouchDelegate);
@@ -156,16 +162,27 @@
@Nullable
@Override
public RunnableList launchTaskAnimated() {
- getRecentsView().getSplitPlaceholder().launchTasks(this /*groupedTaskView*/,
- null /*callback*/,
+ if (mTask == null || mSecondaryTask == null) {
+ return null;
+ }
+
+ RunnableList endCallback = new RunnableList();
+ RecentsView recentsView = getRecentsView();
+ // Callbacks run from remote animation when recents animation not currently running
+ recentsView.getSplitPlaceholder().launchTasks(this /*groupedTaskView*/,
+ success -> endCallback.executeAllAndDestroy(),
false /* freezeTaskList */);
- return null;
+
+ // Callbacks get run from recentsView for case when recents animation already running
+ recentsView.addSideTaskLaunchCallback(endCallback);
+ return endCallback;
}
@Override
public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
- STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList);
+ STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList,
+ getSplitRatio());
}
@Override
@@ -237,7 +254,7 @@
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
getPagedOrientationHandler().setSplitIconParams(mIconView, mIconView2,
- taskIconHeight, mSnapshotView.getWidth(), mSnapshotView.getHeight(),
+ taskIconHeight, mSnapshotView.getMeasuredWidth(), mSnapshotView.getMeasuredHeight(),
isRtl, deviceProfile, mSplitBoundsConfig);
}
@@ -246,4 +263,23 @@
super.updateSnapshotRadius();
mSnapshotView2.setFullscreenParams(mCurrentFullscreenParams);
}
+
+ @Override
+ protected void setIconAndDimTransitionProgress(float progress, boolean invert) {
+ super.setIconAndDimTransitionProgress(progress, invert);
+ // Value set by super call
+ float scale = mIconView.getAlpha();
+ mIconView2.setAlpha(scale);
+ mDigitalWellBeingToast2.updateBannerOffset(1f - scale,
+ mCurrentFullscreenParams.mCurrentDrawnInsets.top
+ + mCurrentFullscreenParams.mCurrentDrawnInsets.bottom);
+ }
+
+ @Override
+ public void setColorTint(float amount, int tintColor) {
+ super.setColorTint(amount, tintColor);
+ mIconView2.setIconColorTint(tintColor, amount);
+ mSnapshotView2.setDimAlpha(amount);
+ mDigitalWellBeingToast2.setBannerColorTint(tintColor, amount);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index ccb1a99..5895c05 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -87,6 +87,14 @@
return mDrawable;
}
+ public int getDrawableWidth() {
+ return mDrawableWidth;
+ }
+
+ public int getDrawableHeight() {
+ return mDrawableHeight;
+ }
+
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 3cba392..e0395ea 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -21,11 +21,9 @@
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
-import static com.android.quickstep.ViewUtils.postFrameDrawn;
import android.annotation.TargetApi;
import android.content.Context;
-import android.content.res.Configuration;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -33,6 +31,7 @@
import androidx.annotation.Nullable;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statehandlers.DepthController;
@@ -71,6 +70,7 @@
@Override
public void startHome() {
mActivity.getStateManager().goToState(NORMAL);
+ AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
}
@Override
@@ -93,10 +93,6 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
- if (toState == NORMAL || toState == SPRING_LOADED) {
- // Clean-up logic that occurs when recents is no longer in use/visible.
- reset();
- }
setOverviewStateEnabled(toState.overviewUi);
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.getOverviewFullscreenProgress() == 1);
@@ -105,13 +101,17 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == NORMAL || finalState == SPRING_LOADED) {
+ // Clean-up logic that occurs when recents is no longer in use/visible.
+ reset();
+ }
boolean isOverlayEnabled = finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK;
setOverlayEnabled(isOverlayEnabled);
setFreezeViewVisibility(false);
if (isOverlayEnabled) {
- postFrameDrawn(this, () -> runActionOnRemoteHandles(remoteTargetHandle ->
- remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)));
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
}
}
@@ -168,12 +168,4 @@
super.initiateSplitSelect(taskView, stagePosition);
mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
}
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- // If overview is in modal state when rotate, reset it to overview state without running
- // animation.
- setModalStateEnabled(false);
- }
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index f3b6a63..0294828 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -20,10 +20,12 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
@@ -31,7 +33,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.SysUINavigationMode;
@@ -82,7 +83,7 @@
private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
private final MultiValueAlpha mMultiValueAlpha;
- private View mSplitButton;
+ private Button mSplitButton;
@ActionsHiddenFlags
private int mHiddenFlags;
@@ -114,10 +115,6 @@
protected void onFinishInflate() {
super.onFinishInflate();
findViewById(R.id.action_screenshot).setOnClickListener(this);
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.NO_SCREENSHOT, "Inflated OverviewActionsView and added screenshot"
- + " listener.");
- }
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
@@ -129,19 +126,11 @@
* @param callbacks for callbacks, or {@code null} to clear the listener.
*/
public void setCallbacks(T callbacks) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.NO_SCREENSHOT, "OverviewActionsView setCallbacks: " + callbacks);
- }
mCallbacks = callbacks;
}
@Override
public void onClick(View view) {
- if (TestProtocol.sDebugTracing) {
- Log.d(TestProtocol.NO_SCREENSHOT, "OverviewActionsView - onClick"
- + " callbacks: " + mCallbacks + " view id: " + view.getId() + " "
- + " is screenshot? " + (view.getId() == R.id.action_screenshot));
- }
if (mCallbacks == null) {
return;
}
@@ -228,7 +217,18 @@
public void setDp(DeviceProfile dp) {
mDp = dp;
updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ dp.isVerticalBarLayout() ? 0 : dp.overviewActionsButtonSpacing,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ params.weight = dp.isVerticalBarLayout() ? 1 : 0;
+ findViewById(R.id.action_split_space).setLayoutParams(params);
+
requestLayout();
+
+ mSplitButton.setCompoundDrawablesWithIntrinsicBounds(
+ (dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical),
+ 0, 0, 0);
}
public void setSplitButtonVisible(boolean visible) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 1c948ab..02261af 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -91,6 +91,7 @@
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseBooleanArray;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
@@ -107,6 +108,7 @@
import android.widget.OverScroller;
import android.widget.Toast;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.core.graphics.ColorUtils;
@@ -181,6 +183,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Objects;
import java.util.function.Consumer;
/**
@@ -627,7 +630,7 @@
* this doesn't get adjusted to reflect the new child count after the taskView is dismissed/
* removed from recentsView
*/
- private int mSplitHiddenTaskViewIndex;
+ private int mSplitHiddenTaskViewIndex = -1;
@Nullable
private FloatingTaskView mFirstFloatingTaskView;
@Nullable
@@ -747,7 +750,7 @@
int primarySize = mOrientationHandler.getPrimaryValue(getWidth(), getHeight());
int scroll = OverScroll.dampedScroll(getUndampedOverScrollShift(), primarySize);
- mOrientationHandler.set(canvas, CANVAS_TRANSLATE, scroll);
+ mOrientationHandler.setPrimary(canvas, CANVAS_TRANSLATE, scroll);
if (mOverScrollShift != scroll) {
mOverScrollShift = scroll;
@@ -822,7 +825,7 @@
@Override
public void onTaskIconChanged(String pkg, UserHandle user) {
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView tv = getTaskViewAt(i);
+ TaskView tv = requireTaskViewAt(i);
Task task = tv.getTask();
if (task != null && task.key != null && pkg.equals(task.key.getPackageName())
&& task.key.userId == user.getIdentifier()) {
@@ -1039,6 +1042,17 @@
}
}
+ public boolean isTaskViewFullyVisible(TaskView tv) {
+ if (showAsGrid()) {
+ int screenStart = mOrientationHandler.getPrimaryScroll(this);
+ int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(this);
+ return isTaskViewFullyWithinBounds(tv, screenStart, screenEnd);
+ } else {
+ // For now, just check if it's the active task
+ return indexOfChild(tv) == getNextPage();
+ }
+ }
+
@Nullable
private TaskView getLastGridTaskView() {
return getLastGridTaskView(getTopRowIdArray(), getBottomRowIdArray());
@@ -1085,6 +1099,15 @@
&& taskEnd <= end);
}
+ private boolean isTaskViewFullyWithinBounds(TaskView tv, int start, int end) {
+ int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
+ showAsFullscreen(), showAsGrid());
+ int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
+ showAsFullscreen()));
+ int taskEnd = taskStart + taskSize;
+ return taskStart >= start && taskEnd <= end;
+ }
+
/**
* Returns true if the task is in expected scroll position.
*
@@ -1104,7 +1127,7 @@
}
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
int[] taskIds = taskView.getTaskIds();
if (taskIds[0] == taskId || taskIds[1] == taskId) {
return taskView;
@@ -1121,20 +1144,6 @@
// Reset the running task when leaving overview since it can still have a reference to
// its thumbnail
mTmpRunningTasks = null;
- if (mSplitSelectStateController.isSplitSelectActive()) {
- cancelSplitSelect(false);
- }
- // Remove grouped tasks and recycle once we exit overview
- int taskCount = getTaskViewCount();
- for (int i = 0; i < taskCount; i++) {
- View v = getTaskViewAt(i);
- if (!(v instanceof GroupedTaskView)) {
- return;
- }
- GroupedTaskView gtv = (GroupedTaskView) v;
- gtv.onTaskListVisibilityChanged(false);
- removeView(gtv);
- }
mSplitBoundsConfig = null;
}
updateLocusId();
@@ -1181,7 +1190,7 @@
if (showAsGrid()) {
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (isTaskViewVisible(taskView) && taskView.offerTouchToChildren(ev)) {
// Keep consuming events to pass to delegate
return true;
@@ -1244,7 +1253,7 @@
@Override
protected void onNotSnappingToPageInFreeScroll() {
int finalPos = mScroller.getFinalX();
- if (!showAsGrid() && finalPos > mMinScroll && finalPos < mMaxScroll) {
+ if (finalPos > mMinScroll && finalPos < mMaxScroll) {
int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
@@ -1258,6 +1267,19 @@
? mMaxScroll
: getScrollForPage(mNextPage);
+ if (showAsGrid()) {
+ if (isSplitSelectionActive()) {
+ return;
+ }
+ TaskView taskView = getTaskViewAt(mNextPage);
+ // Only snap to fully visible focused task.
+ if (taskView == null
+ || !taskView.isFocusedTask()
+ || !isTaskViewFullyVisible(taskView)) {
+ return;
+ }
+ }
+
mScroller.setFinalX(pageSnapped);
// Ensure the scroll/snap doesn't happen too fast;
int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
@@ -1363,7 +1385,7 @@
// Removing views sets the currentPage to 0, so we save this and restore it after
// the new set of views are added
- int previousPage = mCurrentPage;
+ int previousCurrentPage = mCurrentPage;
removeAllViews();
// Add views as children based on whether it's grouped or single task
@@ -1387,7 +1409,14 @@
if (!taskGroups.isEmpty()) {
addView(mClearAllButton);
}
- setCurrentPage(previousPage);
+
+ boolean settlingOnNewTask = mNextPage != INVALID_PAGE;
+ if (settlingOnNewTask) {
+ // Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll.
+ mCurrentPage = previousCurrentPage;
+ } else {
+ setCurrentPage(previousCurrentPage);
+ }
// Keep same previous focused task
TaskView newFocusedTaskView = getTaskViewByTaskId(focusedTaskId);
@@ -1413,12 +1442,12 @@
}
int targetPage = -1;
- if (mNextPage == INVALID_PAGE) {
+ if (!settlingOnNewTask) {
// Set the current page to the running task, but not if settling on new task.
if (runningTaskId != -1) {
targetPage = indexOfChild(newRunningTaskView);
} else if (getTaskViewCount() > 0) {
- targetPage = indexOfChild(getTaskViewAt(0));
+ targetPage = indexOfChild(requireTaskViewAt(0));
}
} else if (currentTaskId != -1) {
currentTaskView = getTaskViewByTaskId(currentTaskId);
@@ -1452,7 +1481,7 @@
private void removeTasksViewsAndClearAllButton() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- removeView(getTaskViewAt(i));
+ removeView(requireTaskViewAt(i));
}
if (indexOfChild(mClearAllButton) != -1) {
removeView(mClearAllButton);
@@ -1498,7 +1527,7 @@
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (mIgnoreResetTaskId != taskView.getTaskIds()[0]) {
taskView.resetViewTransforms();
taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
@@ -1508,6 +1537,16 @@
}
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ // resetTaskVisuals is called at the end of dismiss animation which could update
+ // primary and secondary translation of the live tile cut out. We will need to do so
+ // here accordingly.
+ runActionOnRemoteHandles(remoteTargetHandle -> {
+ TaskViewSimulator simulator = remoteTargetHandle.getTaskViewSimulator();
+ simulator.taskPrimaryTranslation.value = 0;
+ simulator.taskSecondaryTranslation.value = 0;
+ simulator.fullScreenProgress.value = 0;
+ simulator.recentsViewScale.value = 1;
+ });
// Similar to setRunningTaskHidden below, reapply the state before runningTaskView is
// null.
if (!mRunningTaskShowScreenshot) {
@@ -1529,7 +1568,7 @@
mFullscreenProgress = fullscreenProgress;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
+ requireTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
}
mClearAllButton.setFullscreenProgress(fullscreenProgress);
@@ -1591,7 +1630,7 @@
|| !mOrientationHandler.equals(oldOrientationHandler)) {
// Changed orientations, update controllers so they intercept accordingly.
mActivity.getDragLayer().recreateControllers();
- setModalStateEnabled(false);
+ onOrientationChanged();
}
boolean isInLandscape = mOrientationState.getTouchRotation() != ROTATION_0
@@ -1610,6 +1649,15 @@
setCurrentPage(mCurrentPage);
}
+ private void onOrientationChanged() {
+ // If overview is in modal state when rotate, reset it to overview state without running
+ // animation.
+ setModalStateEnabled(false);
+ if (isSplitSelectionActive()) {
+ onRotateInSplitSelectionState();
+ }
+ }
+
// Update task size and padding that are dependent on DeviceProfile and insets.
private void updateSizeAndPadding() {
DeviceProfile dp = mActivity.getDeviceProfile();
@@ -1656,7 +1704,7 @@
float accumulatedTranslationX = 0;
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
taskView.updateTaskSize();
taskView.getPrimaryNonGridTranslationProperty().set(taskView, accumulatedTranslationX);
taskView.getSecondaryNonGridTranslationProperty().set(taskView, 0f);
@@ -1802,7 +1850,7 @@
// Update the task data for the in/visible children
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
Task task = taskView.getTask();
int index = indexOfChild(taskView);
boolean visible;
@@ -1945,7 +1993,7 @@
}
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (taskView.getTaskViewId() == taskViewId) {
return taskView;
}
@@ -2043,7 +2091,7 @@
int runningIndex = getCurrentPage();
AnimatorSet as = new AnimatorSet();
for (int i = 0; i < getTaskViewCount(); i++) {
- View taskView = getTaskViewAt(i);
+ View taskView = requireTaskViewAt(i);
if (runningIndex == i && taskView.getAlpha() != 0) {
continue;
}
@@ -2054,7 +2102,7 @@
private void updateChildTaskOrientations() {
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).setOrientationState(mOrientationState);
+ requireTaskViewAt(i).setOrientationState(mOrientationState);
}
TaskMenuView tv = (TaskMenuView) getTopOpenViewWithType(mActivity, TYPE_TASK_MENU);
if (tv != null) {
@@ -2126,17 +2174,14 @@
*/
protected boolean shouldAddStubTaskView(RunningTaskInfo[] runningTaskInfos) {
if (runningTaskInfos.length > 1) {
- // * Always create new view for GroupedTaskView
- // * Remove existing associated taskViews for tasks currently in split
- for (RunningTaskInfo rti : runningTaskInfos) {
- TaskView taskView = getTaskViewByTaskId(rti.taskId);
- if (taskView == null) {
- continue;
- }
- taskView.onTaskListVisibilityChanged(false);
- removeView(taskView);
- }
- return true;
+ TaskView primaryTaskView = getTaskViewByTaskId(runningTaskInfos[0].taskId);
+ TaskView secondaryTaskView = getTaskViewByTaskId(runningTaskInfos[1].taskId);
+ int leftTopTaskViewId =
+ (primaryTaskView == null) ? -1 : primaryTaskView.getTaskViewId();
+ int rightBottomTaskViewId =
+ (secondaryTaskView == null) ? -1 : secondaryTaskView.getTaskViewId();
+ // Add a new stub view if both taskIds don't match any taskViews
+ return leftTopTaskViewId != rightBottomTaskViewId || leftTopTaskViewId == -1;
}
RunningTaskInfo runningTaskInfo = runningTaskInfos[0];
return runningTaskInfo != null && getTaskViewByTaskId(runningTaskInfo.taskId) == null;
@@ -2187,7 +2232,7 @@
measure(makeMeasureSpec(getMeasuredWidth(), EXACTLY),
makeMeasureSpec(getMeasuredHeight(), EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
- } else if (!needGroupTaskView && getTaskViewByTaskId(taskInfo.taskId) != null) {
+ } else if (getTaskViewByTaskId(taskInfo.taskId) != null) {
runningTaskViewId = getTaskViewByTaskId(taskInfo.taskId).getTaskViewId();
}
@@ -2202,7 +2247,7 @@
updateChildTaskOrientations();
// Reload the task list
- mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
+ reloadIfNeeded();
}
/**
@@ -2259,7 +2304,7 @@
mTaskIconScaledDown = isScaledDown;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
+ requireTaskViewAt(i).setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
}
}
}
@@ -2275,7 +2320,7 @@
mTaskIconScaledDown = false;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
taskView.setIconScaleAnimStartProgress(0f);
taskView.animateIconScaleAndDimIntoView();
}
@@ -2347,7 +2392,7 @@
mTopRowIdSet.clear();
}
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
int taskWidthAndSpacing = taskView.getLayoutParams().width + mPageSpacing;
// Evenly distribute tasks between rows unless rearranging due to task dismissal, in
// which case keep tasks in their respective rows. For the running task, don't join
@@ -2412,7 +2457,7 @@
if (j == focusedTaskIndex) {
continue;
}
- widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+ widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
@@ -2431,7 +2476,7 @@
if (j == focusedTaskIndex) {
continue;
}
- widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+ widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
}
float currentTaskTranslationX = mIsRtl ? widthOffset : -widthOffset;
@@ -2509,7 +2554,7 @@
}
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX
+ snappedTaskNonGridScrollAdjustment);
}
@@ -2550,7 +2595,7 @@
mGridProgress = gridProgress;
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setGridProgress(gridProgress);
+ requireTaskViewAt(i).setGridProgress(gridProgress);
}
mClearAllButton.setGridProgress(gridProgress);
}
@@ -2612,10 +2657,8 @@
clampToProgress(FINAL_FRAME, 0, 0.5f));
});
}
- boolean isTaskInBottomGridRow = showAsGrid() && !mTopRowIdSet.contains(
- taskView.getTaskViewId()) && taskView.getTaskViewId() != mFocusedTaskViewId;
anim.setFloat(taskView, VIEW_ALPHA, 0,
- clampToProgress(isTaskInBottomGridRow ? ACCEL : FINAL_FRAME, 0, 0.5f));
+ clampToProgress(isOnGridBottomRow(taskView) ? ACCEL : FINAL_FRAME, 0, 0.5f));
FloatProperty<TaskView> secondaryViewTranslate =
taskView.getSecondaryDissmissTranslationProperty();
int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
@@ -2715,7 +2758,7 @@
mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
// Pick the next focused task from the preferred row.
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (taskView == dismissedTaskView) {
continue;
}
@@ -2820,7 +2863,7 @@
+ (taskCount - 1) * halfAdditionalDismissTranslationOffset,
END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1);
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
anim.setFloat(taskView, TaskView.GRID_END_TRANSLATION_X, longGridRowWidthDiff,
clampToProgress(LINEAR, dismissTranslationInterpolationEnd, 1));
dismissTranslationInterpolationEnd = Utilities.boundToRange(
@@ -3122,14 +3165,10 @@
}
} else {
// Update focus task and its size.
- if (finalIsFocusedTaskDismissed) {
- if (finalNextFocusedTaskView != null) {
- mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
- mTopRowIdSet.remove(mFocusedTaskViewId);
- finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
- } else {
- mFocusedTaskViewId = -1;
- }
+ if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
+ mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
+ mTopRowIdSet.remove(mFocusedTaskViewId);
+ finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
updateTaskSize(/*isTaskDismissal=*/ true);
updateChildTaskOrientations();
@@ -3140,7 +3179,7 @@
// Rebalance tasks in the grid
int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
- TaskView taskView = getTaskViewAt(highestVisibleTaskIndex);
+ TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
boolean shouldRebalance;
int screenStart = mOrientationHandler.getPrimaryScroll(
@@ -3193,6 +3232,7 @@
}
}
}
+ pageBeginTransition();
setCurrentPage(pageToSnapTo);
// Update various scroll-dependent UI.
dispatchScrollChanged();
@@ -3237,7 +3277,7 @@
IntArray topArray = new IntArray(mTopRowIdSet.size());
int taskViewCount = getTaskViewCount();
for (int i = 0; i < taskViewCount; i++) {
- int taskViewId = getTaskViewAt(i).getTaskViewId();
+ int taskViewId = requireTaskViewAt(i).getTaskViewId();
if (mTopRowIdSet.contains(taskViewId)) {
topArray.add(taskViewId);
}
@@ -3256,7 +3296,7 @@
IntArray bottomArray = new IntArray(bottomRowIdArraySize);
int taskViewCount = getTaskViewCount();
for (int i = 0; i < taskViewCount; i++) {
- int taskViewId = getTaskViewAt(i).getTaskViewId();
+ int taskViewId = requireTaskViewAt(i).getTaskViewId();
if (!mTopRowIdSet.contains(taskViewId) && taskViewId != mFocusedTaskViewId) {
bottomArray.add(taskViewId);
}
@@ -3311,7 +3351,7 @@
* {@link #mFirstFloatingTaskView}.
*/
public boolean shouldShiftThumbnailsForSplitSelect() {
- return !mActivity.getDeviceProfile().isTablet;
+ return !mActivity.getDeviceProfile().isTablet || !mActivity.getDeviceProfile().isLandscape;
}
protected void onDismissAnimationEnds() {
@@ -3326,7 +3366,7 @@
int count = getTaskViewCount();
for (int i = 0; i < count; i++) {
- addDismissedTaskAnimations(getTaskViewAt(i), duration, anim);
+ addDismissedTaskAnimations(requireTaskViewAt(i), duration, anim);
}
mPendingAnimation = anim;
@@ -3449,7 +3489,7 @@
mContentAlpha = alpha;
int runningTaskId = getTaskIdsForRunningTaskView()[0];
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
- TaskView child = getTaskViewAt(i);
+ TaskView child = requireTaskViewAt(i);
int[] childTaskIds = child.getTaskIds();
if (!mRunningTaskTileHidden ||
(childTaskIds[0] != runningTaskId && childTaskIds[1] != runningTaskId)) {
@@ -3497,6 +3537,7 @@
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateRecentsRotation();
+ onOrientationChanged();
}
/**
@@ -3550,6 +3591,14 @@
return child instanceof TaskView ? (TaskView) child : null;
}
+ /**
+ * A version of {@link #getTaskViewAt} when the caller is sure about the input index.
+ */
+ @NonNull
+ private TaskView requireTaskViewAt(int index) {
+ return Objects.requireNonNull(getTaskViewAt(index));
+ }
+
public void setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener listener) {
mOnEmptyMessageUpdatedListener = listener;
}
@@ -3766,7 +3815,7 @@
protected void setTaskViewsResistanceTranslation(float translation) {
mTaskViewsSecondaryTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView task = getTaskViewAt(i);
+ TaskView task = requireTaskViewAt(i);
task.getTaskResistanceTranslationProperty().set(task, translation / getScaleY());
}
runActionOnRemoteHandles(
@@ -3776,14 +3825,14 @@
private void updateTaskViewsSnapshotRadius() {
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).updateSnapshotRadius();
+ requireTaskViewAt(i).updateSnapshotRadius();
}
}
protected void setTaskViewsPrimarySplitTranslation(float translation) {
mTaskViewsPrimarySplitTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView task = getTaskViewAt(i);
+ TaskView task = requireTaskViewAt(i);
task.getPrimarySplitTranslationProperty().set(task, translation);
}
}
@@ -3791,7 +3840,7 @@
protected void setTaskViewsSecondarySplitTranslation(float translation) {
mTaskViewsSecondarySplitTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
if (taskView == mSplitHiddenTaskView) {
continue;
}
@@ -3803,13 +3852,18 @@
* Apply scroll offset to children of RecentsView when entering split select.
*/
public void applySplitPrimaryScrollOffset() {
+ float taskSplitScrollOffsetPrimary = 0f;
+ float clearAllSplitScrollOffsetPrimar = 0f;
if (isSplitPlaceholderFirstInGrid()) {
- for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).setSplitScrollOffsetPrimary(mSplitPlaceholderSize);
- }
+ taskSplitScrollOffsetPrimary = mSplitPlaceholderSize;
} else if (isSplitPlaceholderLastInGrid()) {
- mClearAllButton.setSplitSelectScrollOffsetPrimary(-mSplitPlaceholderSize);
+ clearAllSplitScrollOffsetPrimar = -mSplitPlaceholderSize;
}
+
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ requireTaskViewAt(i).setSplitScrollOffsetPrimary(taskSplitScrollOffsetPrimary);
+ }
+ mClearAllButton.setSplitSelectScrollOffsetPrimary(clearAllSplitScrollOffsetPrimar);
}
/**
@@ -3847,7 +3901,7 @@
*/
public void resetSplitPrimaryScrollOffset() {
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).setSplitScrollOffsetPrimary(0);
+ requireTaskViewAt(i).setSplitScrollOffsetPrimary(0);
}
mClearAllButton.setSplitSelectScrollOffsetPrimary(0);
}
@@ -3927,111 +3981,12 @@
pendingAnimation.buildAnim().start();
}
- public PendingAnimation cancelSplitSelect(boolean animate) {
- SplitSelectStateController splitController = mSplitSelectStateController;
- @StagePosition int stagePosition = splitController.getActiveSplitStagePosition();
- Rect initialBounds = splitController.getInitialBounds();
- splitController.resetState();
- int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
- PendingAnimation pendingAnim = new PendingAnimation(duration);
- mSplitToast.cancel();
- mSplitUnsupportedToast.cancel();
- if (!animate) {
- resetFromSplitSelectionState();
- return pendingAnim;
- }
-
- addViewInLayout(mSplitHiddenTaskView, mSplitHiddenTaskViewIndex,
- mSplitHiddenTaskView.getLayoutParams());
- mSplitHiddenTaskView.setAlpha(0);
- int[] oldScroll = new int[getChildCount()];
- getPageScrolls(oldScroll, false,
- view -> view.getVisibility() != GONE && view != mSplitHiddenTaskView);
-
- int[] newScroll = new int[getChildCount()];
- getPageScrolls(newScroll, false, SIMPLE_SCROLL_LOGIC);
-
- boolean needsCurveUpdates = false;
- for (int i = mSplitHiddenTaskViewIndex; i >= 0; i--) {
- View child = getChildAt(i);
- if (child == mSplitHiddenTaskView) {
- TaskView taskView = (TaskView) child;
-
- int dir = mOrientationHandler.getSplitTaskViewDismissDirection(stagePosition,
- mActivity.getDeviceProfile());
- FloatProperty<TaskView> dismissingTaskViewTranslate;
- Rect hiddenBounds = new Rect(taskView.getLeft(), taskView.getTop(),
- taskView.getRight(), taskView.getBottom());
- int distanceDelta = 0;
- if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE) {
- dismissingTaskViewTranslate = taskView
- .getSecondaryDissmissTranslationProperty();
- distanceDelta = initialBounds.top - hiddenBounds.top;
- taskView.layout(initialBounds.left, hiddenBounds.top, initialBounds.right,
- hiddenBounds.bottom);
- } else {
- dismissingTaskViewTranslate = taskView
- .getPrimaryDismissTranslationProperty();
- distanceDelta = initialBounds.left - hiddenBounds.left;
- taskView.layout(hiddenBounds.left, initialBounds.top, hiddenBounds.right,
- initialBounds.bottom);
- if (dir == PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE) {
- distanceDelta *= -1;
- }
- }
- pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView,
- dismissingTaskViewTranslate,
- distanceDelta));
- pendingAnim.add(ObjectAnimator.ofFloat(mSplitHiddenTaskView, ALPHA, 1));
- } else {
- // If insertion is on last index (furthest from clear all), we directly add the view
- // else we translate all views to the right of insertion index further right,
- // ignore views to left
- if (showAsGrid()) {
- // TODO(b/186800707) handle more elegantly for grid
- continue;
- }
- int scrollDiff = newScroll[i] - oldScroll[i];
- if (scrollDiff != 0) {
- FloatProperty translationProperty = child instanceof TaskView
- ? ((TaskView) child).getPrimaryDismissTranslationProperty()
- : mOrientationHandler.getPrimaryViewTranslate();
-
- ResourceProvider rp = DynamicResource.provider(mActivity);
- SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_END)
- .setDampingRatio(
- rp.getFloat(R.dimen.dismiss_task_trans_x_damping_ratio))
- .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_x_stiffness));
- pendingAnim.add(ObjectAnimator.ofFloat(child, translationProperty, scrollDiff)
- .setDuration(duration), ACCEL, sp);
- needsCurveUpdates = true;
- }
- }
- }
-
- if (needsCurveUpdates) {
- pendingAnim.addOnFrameCallback(this::updateCurveProperties);
- }
-
- pendingAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- // TODO(b/186800707) Figure out how to undo for grid view
- // Need to handle cases where dismissed task is
- // * Top Row
- // * Bottom Row
- // * Focused Task
- updateGridProperties();
- resetFromSplitSelectionState();
- }
- });
-
- return pendingAnim;
- }
-
/** TODO(b/181707736) More gracefully handle exiting split selection state */
- private void resetFromSplitSelectionState() {
- if (!showAsGrid()) {
+ protected void resetFromSplitSelectionState() {
+ if (mSplitHiddenTaskViewIndex == -1) {
+ return;
+ }
+ if (!mActivity.getDeviceProfile().overviewShowAsGrid) {
int pageToSnapTo = mCurrentPage;
if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
pageToSnapTo += 1;
@@ -4044,7 +3999,6 @@
resetTaskVisuals();
mSplitHiddenTaskViewIndex = -1;
if (mSplitHiddenTaskView != null) {
- mSplitHiddenTaskView.setTranslationY(0);
mSplitHiddenTaskView.setVisibility(VISIBLE);
mSplitHiddenTaskView = null;
}
@@ -4060,6 +4014,41 @@
}
}
+ /**
+ * Returns how much additional translation there should be for each of the child TaskViews.
+ * Note that the translation can be its primary or secondary dimension.
+ */
+ public float getSplitSelectTranslation() {
+ int splitPosition = getSplitPlaceholder().getActiveSplitStagePosition();
+ if (!shouldShiftThumbnailsForSplitSelect()) {
+ return 0f;
+ }
+ PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
+ int direction = orientationHandler.getSplitTranslationDirectionFactor(
+ splitPosition, mActivity.getDeviceProfile());
+ return mActivity.getResources().getDimension(R.dimen.split_placeholder_size) * direction;
+ }
+
+ protected void onRotateInSplitSelectionState() {
+ mOrientationHandler.getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
+ mActivity.getDeviceProfile(),
+ mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
+ mTempRectF.set(mTempRect);
+ // TODO(194414938) set correct corner radius
+ mFirstFloatingTaskView.updateOrientationHandler(mOrientationHandler);
+ mFirstFloatingTaskView.update(mTempRectF, /*progress=*/1f, /*windowRadius=*/0f);
+
+ PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
+ Pair<FloatProperty, FloatProperty> taskViewsFloat =
+ orientationHandler.getSplitSelectTaskOffset(
+ TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
+ mActivity.getDeviceProfile());
+ taskViewsFloat.first.set(this, getSplitSelectTranslation());
+ taskViewsFloat.second.set(this, 0f);
+
+ applySplitPrimaryScrollOffset();
+ }
+
private void updateDeadZoneRects() {
// Get the deadzone rect surrounding the clear all button to not dismiss overview to home
mClearAllButtonDeadZoneRect.setEmpty();
@@ -4074,8 +4063,8 @@
mTaskViewDeadZoneRect.setEmpty();
int count = getTaskViewCount();
if (count > 0) {
- final View taskView = getTaskViewAt(0);
- getTaskViewAt(count - 1).getHitRect(mTaskViewDeadZoneRect);
+ final View taskView = requireTaskViewAt(0);
+ requireTaskViewAt(count - 1).getHitRect(mTaskViewDeadZoneRect);
mTaskViewDeadZoneRect.union(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
taskView.getBottom());
}
@@ -4245,8 +4234,10 @@
mPendingAnimation.addEndListener(isSuccess -> {
if (isSuccess) {
if (tv.getTaskIds()[1] != -1) {
+ // TODO(b/194414938): make this part of the animations instead.
TaskViewUtils.setSplitAuxiliarySurfacesShown(mRemoteTargetHandles[0]
- .getTransformParams().getTargetSet().nonApps, true);
+ .getTransformParams().getTargetSet().nonApps,
+ true /*shown*/, false /*animate*/);
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) {
finishRecentsAnimation(false /* toRecents */, null);
@@ -4359,15 +4350,22 @@
RemoteTargetGluer gluer = new RemoteTargetGluer(getContext(), getSizeStrategy());
mRemoteTargetHandles = gluer.assignTargetsForSplitScreen(recentsAnimationTargets);
mSplitBoundsConfig = gluer.getStagedSplitBounds();
- if (mSyncTransactionApplier != null) {
- // Add release check to the targets from the RemoteTargetGluer and not the targets
- // passed in because in the event we're in split screen, we use the passed in targets
- // to create new RemoteAnimationTargets in assignTargetsForSplitScreen(), and the
- // mSyncTransactionApplier doesn't get transferred over
- runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle
- .getTransformParams().getTargetSet()
- .addReleaseCheck(mSyncTransactionApplier));
- }
+ // Add release check to the targets from the RemoteTargetGluer and not the targets
+ // passed in because in the event we're in split screen, we use the passed in targets
+ // to create new RemoteAnimationTargets in assignTargetsForSplitScreen(), and the
+ // mSyncTransactionApplier doesn't get transferred over
+ runActionOnRemoteHandles(remoteTargetHandle -> {
+ final TransformParams params = remoteTargetHandle.getTransformParams();
+ if (mSyncTransactionApplier != null) {
+ params.setSyncTransactionApplier(mSyncTransactionApplier);
+ params.getTargetSet().addReleaseCheck(mSyncTransactionApplier);
+ }
+
+ TaskViewSimulator tvs = remoteTargetHandle.getTaskViewSimulator();
+ tvs.setOrientationState(mOrientationState);
+ tvs.setDp(mActivity.getDeviceProfile());
+ tvs.recentsViewScale.value = 1;
+ });
TaskView runningTaskView = getRunningTaskView();
if (runningTaskView instanceof GroupedTaskView) {
@@ -4377,12 +4375,6 @@
// notified.
((GroupedTaskView) runningTaskView).updateSplitBoundsConfig(mSplitBoundsConfig);
}
- for (RemoteTargetHandle remoteTargetHandle : mRemoteTargetHandles) {
- TaskViewSimulator tvs = remoteTargetHandle.getTaskViewSimulator();
- tvs.setOrientationState(mOrientationState);
- tvs.setDp(mActivity.getDeviceProfile());
- tvs.recentsViewScale.value = 1;
- }
}
/** Helper to avoid writing some for-loops to iterate over {@link #mRemoteTargetHandles} */
@@ -4504,9 +4496,8 @@
}
private int getFirstViewIndex() {
- return mShowAsGridLastOnLayout && mFocusedTaskViewId != -1
- ? indexOfChild(getFocusedTaskView())
- : 0;
+ TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
+ return focusedTaskView != null ? indexOfChild(focusedTaskView) : 0;
}
private int getLastViewIndex() {
@@ -4556,7 +4547,7 @@
final int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- TaskView taskView = getTaskViewAt(i);
+ TaskView taskView = requireTaskViewAt(i);
float scrollDiff = taskView.getScrollAdjustment(showAsFullscreen, showAsGrid);
int pageScroll = newPageScrolls[i] + (int) scrollDiff;
if ((mIsRtl && pageScroll < clearAllScroll + clearAllWidth)
@@ -4682,6 +4673,15 @@
return position != -1 ? position : bottomRowIdArray.indexOf(taskView.getTaskViewId());
}
+ /**
+ * @return true if the task in on the top of the grid
+ */
+ public boolean isOnGridBottomRow(TaskView taskView) {
+ return showAsGrid()
+ && !mTopRowIdSet.contains(taskView.getTaskViewId())
+ && taskView.getTaskViewId() != mFocusedTaskViewId;
+ }
+
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated;
if (navbarRotation == 0) {
@@ -4715,7 +4715,7 @@
int overlayEnabledPage = mOverlayEnabled ? getNextPage() : -1;
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
- getTaskViewAt(i).setOverlayEnabled(i == overlayEnabledPage);
+ requireTaskViewAt(i).setOverlayEnabled(i == overlayEnabledPage);
}
}
@@ -4869,7 +4869,7 @@
mColorTint = tintAmount;
for (int i = 0; i < getTaskViewCount(); i++) {
- getTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
+ requireTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
}
Drawable scrimBg = mActivity.getScrimView().getBackground();
@@ -4938,6 +4938,62 @@
}
@Override
+ public boolean scrollLeft() {
+ if (!showAsGrid()) {
+ return super.scrollLeft();
+ }
+
+ int targetPage = getNextPage();
+ if (targetPage >= 0) {
+ // Find the next page that is not fully visible.
+ TaskView taskView = getTaskViewAt(targetPage);
+ while ((taskView == null || isTaskViewFullyVisible(taskView)) && targetPage - 1 >= 0) {
+ taskView = getTaskViewAt(--targetPage);
+ }
+ // Target a scroll where targetPage is on left of screen but still fully visible.
+ int lastTaskEnd = (mIsRtl
+ ? mLastComputedGridSize.left
+ : mLastComputedGridSize.right)
+ + (mIsRtl ? mPageSpacing : -mPageSpacing);
+ int normalTaskEnd = mIsRtl
+ ? mLastComputedGridTaskSize.left
+ : mLastComputedGridTaskSize.right;
+ int targetScroll = getScrollForPage(targetPage) + normalTaskEnd - lastTaskEnd;
+ // Find a page that is close to targetScroll while not over it.
+ while (targetPage - 1 >= 0
+ && (mIsRtl
+ ? getScrollForPage(targetPage - 1) < targetScroll
+ : getScrollForPage(targetPage - 1) > targetScroll)) {
+ targetPage--;
+ }
+ snapToPage(targetPage);
+ return true;
+ }
+
+ return mAllowOverScroll;
+ }
+
+ @Override
+ public boolean scrollRight() {
+ if (!showAsGrid()) {
+ return super.scrollRight();
+ }
+
+ int targetPage = getNextPage();
+ if (targetPage < getChildCount()) {
+ // Find the next page that is not fully visible.
+ TaskView taskView = getTaskViewAt(targetPage);
+ while ((taskView != null && isTaskViewFullyVisible(taskView))
+ && targetPage + 1 < getChildCount()) {
+ taskView = getTaskViewAt(++targetPage);
+ }
+ snapToPage(targetPage);
+ return true;
+ }
+ return mAllowOverScroll;
+ }
+
+ @Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
dispatchScrollChanged();
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index 179fd68..06a5793 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -45,7 +45,10 @@
companion object {
const val TAG = "TaskMenuViewWithArrow"
- fun showForTask(taskContainer: TaskIdAttributeContainer): Boolean {
+ fun showForTask(
+ taskContainer: TaskIdAttributeContainer,
+ alignSecondRow: Boolean = false
+ ): Boolean {
val activity = BaseDraggingActivity
.fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
val taskMenuViewWithArrow = activity.layoutInflater
@@ -55,7 +58,7 @@
false
) as TaskMenuViewWithArrow<*>
- return taskMenuViewWithArrow.populateAndShowForTask(taskContainer)
+ return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignSecondRow)
}
}
@@ -78,6 +81,9 @@
CLOSE_FADE_DURATION = CLOSE_CHILD_FADE_DURATION
}
+ private var alignSecondRow: Boolean = false
+ private val extraSpaceForSecondRowAlignment: Int
+ get() = if (alignSecondRow) optionMeasuredHeight else 0
private val menuWidth = context.resources.getDimensionPixelSize(R.dimen.task_menu_width_grid)
private lateinit var taskView: TaskView
@@ -91,10 +97,14 @@
else
0
+ private var iconView: IconView? = null
+ private var scrim: View? = null
+ private val scrimAlpha = 0.8f
+
override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0
override fun getTargetObjectLocation(outPos: Rect?) {
- popupContainer.getDescendantRectRelativeToSelf(taskView.iconView, outPos)
+ popupContainer.getDescendantRectRelativeToSelf(taskContainer.iconView, outPos)
}
override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
@@ -112,18 +122,35 @@
optionLayout = findViewById(KtR.id.menu_option_layout)
}
- private fun populateAndShowForTask(taskContainer: TaskIdAttributeContainer): Boolean {
+ private fun populateAndShowForTask(
+ taskContainer: TaskIdAttributeContainer,
+ alignSecondRow: Boolean
+ ): Boolean {
if (isAttachedToWindow) {
return false
}
taskView = taskContainer.taskView
this.taskContainer = taskContainer
+ this.alignSecondRow = alignSecondRow
if (!populateMenu()) return false
+ addScrim()
show()
return true
}
+ private fun addScrim() {
+ scrim = View(context).apply {
+ layoutParams = FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT
+ )
+ setBackgroundColor(Themes.getAttrColor(context, R.attr.overviewScrimColor))
+ alpha = 0f
+ }
+ popupContainer.addView(scrim)
+ }
+
/** @return true if successfully able to populate task view menu, false otherwise
*/
private fun populateMenu(): Boolean {
@@ -180,18 +207,50 @@
}
override fun onCreateOpenAnimation(anim: AnimatorSet) {
- anim.play(
- ObjectAnimator.ofFloat(
- taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA,
- TaskView.MAX_PAGE_SCRIM_ALPHA
+ scrim?.let {
+ anim.play(
+ ObjectAnimator.ofFloat(it, View.ALPHA, 0f, scrimAlpha)
+ .setDuration(OPEN_DURATION.toLong())
)
- )
+ }
}
override fun onCreateCloseAnimation(anim: AnimatorSet) {
- anim.play(
- ObjectAnimator.ofFloat(taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA, 0f)
- )
+ scrim?.let {
+ anim.play(
+ ObjectAnimator.ofFloat(it, View.ALPHA, scrimAlpha, 0f)
+ .setDuration(CLOSE_DURATION.toLong())
+ )
+ }
+ }
+
+ override fun closeComplete() {
+ super.closeComplete()
+ popupContainer.removeView(scrim)
+ popupContainer.removeView(iconView)
+ }
+
+ /**
+ * Copy the iconView from taskView to dragLayer so it can stay on top of the scrim.
+ * It needs to be called after [getTargetObjectLocation] because [mTempRect] needs to be
+ * populated.
+ */
+ private fun copyIconToDragLayer(insets: Rect) {
+ iconView = IconView(context).apply {
+ layoutParams = FrameLayout.LayoutParams(
+ taskContainer.iconView.width,
+ taskContainer.iconView.height
+ )
+ x = mTempRect.left.toFloat() - insets.left
+ y = mTempRect.top.toFloat() - insets.top
+ drawable = taskContainer.iconView.drawable
+ setDrawableSize(
+ taskContainer.iconView.drawableWidth,
+ taskContainer.iconView.drawableHeight
+ )
+ }
+
+ popupContainer.addView(iconView)
}
/**
@@ -217,7 +276,10 @@
val dragLayer: InsettableFrameLayout = popupContainer
val insets = dragLayer.insets
- // Put to the right of the icon if there is space, which means left aligned with the menu
+ copyIconToDragLayer(insets)
+
+ // Put this menu to the right of the icon if there is space,
+ // which means the arrow is left aligned with the menu
val rightAlignedMenuStartX = mTempRect.left - widthWithArrow
val leftAlignedMenuStartX = mTempRect.right + extraHorizontalSpace
mIsLeftAligned = if (mIsRtl) {
@@ -229,18 +291,17 @@
var menuStartX = if (mIsLeftAligned) leftAlignedMenuStartX else rightAlignedMenuStartX
- // Offset y so that the arrow and first row are center-aligned with the original icon.
+ // Offset y so that the arrow and row are center-aligned with the original icon.
val iconHeight = mTempRect.height()
- val optionHeight = optionMeasuredHeight
- val yOffset = (optionHeight - iconHeight) / 2
- var menuStartY = mTempRect.top - yOffset
+ val yOffset = (optionMeasuredHeight - iconHeight) / 2
+ var menuStartY = mTempRect.top - yOffset - extraSpaceForSecondRowAlignment
// Insets are added later, so subtract them now.
menuStartX -= insets.left
menuStartY -= insets.top
- setX(menuStartX.toFloat())
- setY(menuStartY.toFloat())
+ x = menuStartX.toFloat()
+ y = menuStartY.toFloat()
val lp = layoutParams as FrameLayout.LayoutParams
val arrowLp = mArrow.layoutParams as FrameLayout.LayoutParams
@@ -251,7 +312,8 @@
override fun addArrow() {
popupContainer.addView(mArrow)
mArrow.x = getArrowX()
- mArrow.y = y + (optionMeasuredHeight / 2) - (mArrowHeight / 2)
+ mArrow.y = y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) +
+ extraSpaceForSecondRowAlignment
updateArrowColor()
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index d91669a..d833877 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -19,6 +19,7 @@
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static com.android.launcher3.Utilities.comp;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
@@ -290,21 +291,31 @@
float cornerRadius) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mTask != null && getTaskView().isRunningTask() && !getTaskView().showScreenshot()) {
- canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mClearPaint);
- canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius,
+ // TODO(b/189265196): Temporary fix to align the surface with the cutout perfectly.
+ // Round up only when the live tile task is displayed in Overview.
+ float rounding = comp(mFullscreenParams.mFullscreenProgress);
+ float left = x + rounding / 2;
+ float top = y + rounding / 2;
+ float right = width - rounding;
+ float bottom = height - rounding;
+
+ canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius,
+ mClearPaint);
+ canvas.drawRoundRect(left, top, right, bottom, cornerRadius, cornerRadius,
mDimmingPaintAfterClearing);
return;
}
}
- // Draw the background in all cases, except when the thumbnail data is opaque
+ // Always draw the background since the snapshots might be translucent or partially empty
+ // (For example, tasks been reparented out of dismissing split root when drag-to-dismiss
+ // split screen).
+ canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mBackgroundPaint);
+
final boolean drawBackgroundOnly = mTask == null || mTask.isLocked || mBitmapShader == null
|| mThumbnailData == null;
- if (drawBackgroundOnly || mThumbnailData.isTranslucent) {
- canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mBackgroundPaint);
- if (drawBackgroundOnly) {
- return;
- }
+ if (drawBackgroundOnly) {
+ return;
}
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 67128f0..6a2c997e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -30,6 +30,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -38,6 +39,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.annotation.IdRes;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
@@ -364,7 +366,7 @@
protected Task mTask;
protected TaskThumbnailView mSnapshotView;
protected IconView mIconView;
- private final DigitalWellBeingToast mDigitalWellBeingToast;
+ protected final DigitalWellBeingToast mDigitalWellBeingToast;
private float mFullscreenProgress;
private float mGridProgress;
private float mNonGridScale = 1;
@@ -468,7 +470,9 @@
stubInfo.user = componentKey.user;
stubInfo.intent = new Intent().setComponent(componentKey.componentName);
stubInfo.title = task.title;
- stubInfo.screenId = getRecentsView().indexOfChild(this);
+ if (getRecentsView() != null) {
+ stubInfo.screenId = getRecentsView().indexOfChild(this);
+ }
return stubInfo;
}
@@ -539,7 +543,7 @@
mTask = task;
mTaskIdContainer[0] = mTask.key.id;
mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView,
- STAGE_POSITION_UNDEFINED);
+ mIconView, STAGE_POSITION_UNDEFINED);
mSnapshotView.bind(task);
setOrientationState(orientedState);
}
@@ -597,7 +601,9 @@
if (confirmSecondSplitSelectApp()) {
return;
}
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
+ RecentsView recentsView = getRecentsView();
+ RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask() && remoteTargetHandles != null) {
if (!mIsClickableAsLiveTile) {
return;
}
@@ -610,9 +616,7 @@
}
mIsClickableAsLiveTile = false;
- RecentsView recentsView = getRecentsView();
RemoteAnimationTargets targets;
- RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
if (remoteTargetHandles.length == 1) {
targets = remoteTargetHandles[0].getTransformParams().getTargetSet();
} else {
@@ -626,11 +630,8 @@
Arrays.stream(topLeftParams.getTargetSet().wallpapers),
Arrays.stream(rightBottomParams.getTargetSet().wallpapers))
.toArray(RemoteAnimationTargetCompat[]::new);
- RemoteAnimationTargetCompat[] nonApps = Stream.concat(
- Arrays.stream(topLeftParams.getTargetSet().nonApps),
- Arrays.stream(rightBottomParams.getTargetSet().nonApps))
- .toArray(RemoteAnimationTargetCompat[]::new);
- targets = new RemoteAnimationTargets(apps, wallpapers, nonApps,
+ targets = new RemoteAnimationTargets(apps, wallpapers,
+ topLeftParams.getTargetSet().nonApps,
topLeftParams.getTargetSet().targetMode);
}
if (targets == null) {
@@ -675,7 +676,7 @@
* second app. {@code false} otherwise
*/
private boolean confirmSecondSplitSelectApp() {
- boolean isSelectingSecondSplitApp = mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+ boolean isSelectingSecondSplitApp = getRecentsView().isSplitSelectionActive();
if (isSelectingSecondSplitApp) {
getRecentsView().confirmSplitSelect(this);
}
@@ -837,10 +838,14 @@
}
protected boolean showTaskMenuWithContainer(IconView iconView) {
+ TaskIdAttributeContainer menuContainer =
+ mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1];
if (mActivity.getDeviceProfile().overviewShowAsGrid) {
- return TaskMenuViewWithArrow.Companion.showForTask(mTaskIdAttributeContainer[0]);
+ boolean alignSecondRow = getRecentsView().isOnGridBottomRow(menuContainer.getTaskView())
+ && mActivity.getDeviceProfile().isLandscape;
+ return TaskMenuViewWithArrow.Companion.showForTask(menuContainer, alignSecondRow);
} else {
- return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
+ return TaskMenuView.showForTask(menuContainer);
}
}
@@ -906,7 +911,7 @@
return deviceProfile.overviewShowAsGrid && !isFocusedTask();
}
- private void setIconAndDimTransitionProgress(float progress, boolean invert) {
+ protected void setIconAndDimTransitionProgress(float progress, boolean invert) {
if (invert) {
progress = 1 - progress;
}
@@ -1300,10 +1305,14 @@
getContext().getText(R.string.accessibility_close)));
final Context context = getContext();
- // TODO(b/200609838) Determine which task to run A11y action on when in split screen
- for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
- mActivity.getDeviceProfile(), mTaskIdAttributeContainer[0])) {
- info.addAction(s.createAccessibilityAction(context));
+ for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
+ if (taskContainer == null) {
+ continue;
+ }
+ for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
+ mActivity.getDeviceProfile(), taskContainer)) {
+ info.addAction(s.createAccessibilityAction(context));
+ }
}
if (mDigitalWellBeingToast.hasLimit()) {
@@ -1334,12 +1343,16 @@
return true;
}
- // TODO(b/200609838) Determine which task to run A11y action on when in split screen
- for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
- mActivity.getDeviceProfile(), mTaskIdAttributeContainer[0])) {
- if (s.hasHandlerForAction(action)) {
- s.onClick(this);
- return true;
+ for (TaskIdAttributeContainer taskContainer : mTaskIdAttributeContainer) {
+ if (taskContainer == null) {
+ continue;
+ }
+ for (SystemShortcut s : TaskOverlayFactory.getEnabledShortcuts(this,
+ mActivity.getDeviceProfile(), taskContainer)) {
+ if (s.hasHandlerForAction(action)) {
+ s.onClick(this);
+ return true;
+ }
}
}
@@ -1517,6 +1530,7 @@
private final float mCornerRadius;
private final float mWindowCornerRadius;
+ public float mFullscreenProgress;
public RectF mCurrentDrawnInsets = new RectF();
public float mCurrentDrawnCornerRadius;
/** The current scale we apply to the thumbnail to adjust for new left/right insets. */
@@ -1534,6 +1548,8 @@
*/
public void setProgress(float fullscreenProgress, float parentScale, float taskViewScale,
int previewWidth, DeviceProfile dp, PreviewPositionHelper pph) {
+ mFullscreenProgress = fullscreenProgress;
+
RectF insets = pph.getInsetsToDrawInFullscreen(dp);
float currentInsetsLeft = insets.left * fullscreenProgress;
@@ -1556,20 +1572,25 @@
mScale = previewWidth / (previewWidth + currentInsetsLeft + currentInsetsRight);
}
}
-
}
public class TaskIdAttributeContainer {
private final TaskThumbnailView mThumbnailView;
private final Task mTask;
+ private final IconView mIconView;
/** Defaults to STAGE_POSITION_UNDEFINED if in not a split screen task view */
private @SplitConfigurationOptions.StagePosition int mStagePosition;
+ @IdRes
+ private final int mA11yNodeId;
public TaskIdAttributeContainer(Task task, TaskThumbnailView thumbnailView,
- int stagePosition) {
+ IconView iconView, int stagePosition) {
this.mTask = task;
this.mThumbnailView = thumbnailView;
+ this.mIconView = iconView;
this.mStagePosition = stagePosition;
+ this.mA11yNodeId = (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) ?
+ R.id.split_bottomRight_appInfo : R.id.split_topLeft_appInfo;
}
public TaskThumbnailView getThumbnailView() {
@@ -1588,6 +1609,10 @@
return TaskView.this;
}
+ public IconView getIconView() {
+ return mIconView;
+ }
+
public int getStagePosition() {
return mStagePosition;
}
@@ -1595,5 +1620,9 @@
void setStagePosition(@SplitConfigurationOptions.StagePosition int stagePosition) {
this.mStagePosition = stagePosition;
}
+
+ public int getA11yNodeId() {
+ return mA11yNodeId;
+ }
}
}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
new file mode 100644
index 0000000..ba1a60d
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -0,0 +1,159 @@
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.SCREEN_PIN_LONG_PRESS_THRESHOLD;
+import static com.android.quickstep.OverviewCommandHelper.TYPE_HOME;
+import static com.android.quickstep.OverviewCommandHelper.TYPE_TOGGLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.quickstep.OverviewCommandHelper;
+import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TouchInteractionService;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class TaskbarNavButtonControllerTest {
+
+ private final static int DISPLAY_ID = 2;
+
+ @Mock
+ SystemUiProxy mockSystemUiProxy;
+ @Mock
+ TouchInteractionService mockService;
+ @Mock
+ OverviewCommandHelper mockCommandHelper;
+ @Mock
+ Handler mockHandler;
+
+ private TaskbarNavButtonController mNavButtonController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
+ when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
+ mNavButtonController = new TaskbarNavButtonController(mockService,
+ mockSystemUiProxy, mockHandler);
+ }
+
+ @Test
+ public void testPressBack() {
+ mNavButtonController.onButtonClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).onBackPressed();
+ }
+
+ @Test
+ public void testPressImeSwitcher() {
+ mNavButtonController.onButtonClick(BUTTON_IME_SWITCH);
+ verify(mockSystemUiProxy, times(1)).onImeSwitcherPressed();
+ }
+
+ @Test
+ public void testPressA11yShortClick() {
+ mNavButtonController.onButtonClick(BUTTON_A11Y);
+ verify(mockSystemUiProxy, times(1))
+ .notifyAccessibilityButtonClicked(DISPLAY_ID);
+ }
+
+ @Test
+ public void testPressA11yLongClick() {
+ mNavButtonController.onButtonLongClick(BUTTON_A11Y);
+ verify(mockSystemUiProxy, times(1)).notifyAccessibilityButtonLongClicked();
+ }
+
+ @Test
+ public void testLongPressHome() {
+ mNavButtonController.onButtonLongClick(BUTTON_HOME);
+ verify(mockSystemUiProxy, times(1)).startAssistant(any());
+ }
+
+ @Test
+ public void testPressHome() {
+ mNavButtonController.onButtonClick(BUTTON_HOME);
+ verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
+ }
+
+ @Test
+ public void testPressRecents() {
+ mNavButtonController.onButtonClick(BUTTON_RECENTS);
+ verify(mockCommandHelper, times(1)).addCommand(TYPE_TOGGLE);
+ }
+
+ @Test
+ public void testPressRecentsWithScreenPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonClick(BUTTON_RECENTS);
+ verify(mockCommandHelper, times(0)).addCommand(TYPE_TOGGLE);
+ }
+
+ @Test
+ public void testLongPressBackRecentsNotPinned() {
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsTooLongPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ try {
+ Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressBackRecentsMultipleAttemptPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ try {
+ Thread.sleep(SCREEN_PIN_LONG_PRESS_THRESHOLD + 5);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(0)).stopScreenPinning();
+
+ // Try again w/in threshold
+ mNavButtonController.onButtonLongClick(BUTTON_RECENTS);
+ mNavButtonController.onButtonLongClick(BUTTON_BACK);
+ verify(mockSystemUiProxy, times(1)).stopScreenPinning();
+ }
+
+ @Test
+ public void testLongPressHomeScreenPinned() {
+ mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
+ mNavButtonController.onButtonLongClick(BUTTON_HOME);
+ verify(mockSystemUiProxy, times(0)).startAssistant(any());
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 93be6fb..237e426 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -37,6 +37,7 @@
import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.OverviewActions;
import com.android.launcher3.tapl.OverviewTask;
+import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
@@ -321,17 +322,18 @@
@Test
@PortraitLandscape
public void testOverviewForTablet() throws Exception {
- if (!mLauncher.isTablet()) {
+ // TODO(b/210158657): Re-enable for OOP
+ if (!mLauncher.isTablet() || !TestHelpers.isInLauncherProcess()) {
return;
}
- for (int i = 2; i <= 12; i++) {
+ for (int i = 2; i <= 14; i++) {
startTestActivity(i);
}
Overview overview = mLauncher.pressHome().switchToOverview();
executeOnLauncher(
- launcher -> assertTrue("Don't have at least 11 tasks",
- getTaskCount(launcher) >= 11));
+ launcher -> assertTrue("Don't have at least 13 tasks",
+ getTaskCount(launcher) >= 13));
// Test scroll the first task off screen
overview.scrollCurrentTaskOffScreen();
diff --git a/res/drawable/ic_split_horizontal.xml b/res/drawable/ic_split_horizontal.xml
new file mode 100644
index 0000000..ee710d0
--- /dev/null
+++ b/res/drawable/ic_split_horizontal.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="16dp"
+ android:viewportWidth="20"
+ android:viewportHeight="16">
+ <path
+ android:pathData="M18,14L13,14L13,2L18,2L18,14ZM20,14L20,2C20,0.9 19.1,-0 18,-0L13,-0C11.9,-0 11,0.9 11,2L11,14C11,15.1 11.9,16 13,16L18,16C19.1,16 20,15.1 20,14ZM7,14L2,14L2,2L7,2L7,14ZM9,14L9,2C9,0.9 8.1,-0 7,-0L2,-0C0.9,-0 -0,0.9 -0,2L-0,14C-0,15.1 0.9,16 2,16L7,16C8.1,16 9,15.1 9,14Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/drawable/ic_split_left.xml b/res/drawable/ic_split_left.xml
new file mode 100644
index 0000000..fc9f699
--- /dev/null
+++ b/res/drawable/ic_split_left.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="16dp"
+ android:viewportWidth="20"
+ android:viewportHeight="16">
+ <path
+ android:pathData="M-0,2L-0,14C-0,15.1 0.9,16 2,16L7,16C8.1,16 9,15.1 9,14L9,2C9,0.9 8.1,-0 7,-0L2,-0C0.9,-0 -0,0.9 -0,2ZM13,2L18,2L18,14L13,14L13,2ZM11,2L11,14C11,15.1 11.9,16 13,16L18,16C19.1,16 20,15.1 20,14L20,2C20,0.9 19.1,-0 18,-0L13,-0C11.9,-0 11,0.9 11,2Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/drawable/ic_split_right.xml b/res/drawable/ic_split_right.xml
new file mode 100644
index 0000000..cc15622
--- /dev/null
+++ b/res/drawable/ic_split_right.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="16dp"
+ android:viewportWidth="20"
+ android:viewportHeight="16">
+ <path
+ android:pathData="M20,14L20,2C20,0.9 19.1,-0 18,-0L13,-0C11.9,-0 11,0.9 11,2L11,14C11,15.1 11.9,16 13,16L18,16C19.1,16 20,15.1 20,14ZM7,14L2,14L2,2L7,2L7,14ZM9,14L9,2C9,0.9 8.1,-0 7,-0L2,-0C0.9,-0 -0,0.9 -0,2L-0,14C-0,15.1 0.9,16 2,16L7,16C8.1,16 9,15.1 9,14Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/drawable/ic_split_top.xml b/res/drawable/ic_split_top.xml
new file mode 100644
index 0000000..f8c15bd
--- /dev/null
+++ b/res/drawable/ic_split_top.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="16dp"
+ android:height="20dp"
+ android:viewportWidth="16"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M14,0H2C0.9,0 0,0.9 0,2V7C0,8.1 0.9,9 2,9H14C15.1,9 16,8.1 16,7V2C16,0.9 15.1,0 14,0ZM14,13V18H2V13H14ZM14,11H2C0.9,11 0,11.9 0,13V18C0,19.1 0.9,20 2,20H14C15.1,20 16,19.1 16,18V13C16,11.9 15.1,11 14,11Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/drawable/ic_split_vertical.xml b/res/drawable/ic_split_vertical.xml
new file mode 100644
index 0000000..9bc9785
--- /dev/null
+++ b/res/drawable/ic_split_vertical.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M18,4V9H6V4H18ZM18,2H6C4.9,2 4,2.9 4,4V9C4,10.1 4.9,11 6,11H18C19.1,11 20,10.1 20,9V4C20,2.9 19.1,2 18,2ZM18,15V20H6V15H18ZM18,13H6C4.9,13 4,13.9 4,15V20C4,21.1 4.9,22 6,22H18C19.1,22 20,21.1 20,20V15C20,13.9 19.1,13 18,13Z"
+ android:fillColor="#000000"/>
+</vector>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index e9e1478..18fa12f 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Kortpad is nie beskikbaar nie"</string>
<string name="home_screen" msgid="5629429142036709174">"Tuis"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Verdeelde skerm"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Verdeel bo"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Verdeel links"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Verdeel regs"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Programinligting vir %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Raak en hou om \'n legstuk te skuif."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en hou om \'n legstuk te skuif of gebruik gepasmaakte handelinge."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 99c08f1..f75e7e1 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"አቋራጭ አይገኝም"</string>
<string name="home_screen" msgid="5629429142036709174">"መነሻ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"የተከፈለ ማያ ገጽ"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"ወደ ላይ ክፈል"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"ወደ ግራ ክፈል"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"ወደ ቀኝ ክፈል"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"የመተግበሪያ መረጃ ለ%1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ምግብርን ለማንቀሳቀስ ይንኩ እና ይያዙ።"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ምግብርን ለማንቀሳቀስ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ ያድርጉ እና ይያዙ።"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 8f293df..8571d46 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"الاختصار غير متاح"</string>
<string name="home_screen" msgid="5629429142036709174">"الشاشة الرئيسية"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"تقسيم الشاشة"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"تقسيم للأعلى"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"تقسيم لليسار"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"تقسيم لليمين"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"معلومات تطبيق %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"انقر مع الاستمرار لنقل أداة"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"انقر مرتين مع تثبيت إصبعك لنقل أداة أو استخدام الإجراءات المخصّصة."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 7f92939..5dc35cb 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"শ্বৰ্টকাট নাই"</string>
<string name="home_screen" msgid="5629429142036709174">"গৃহ স্ক্ৰীন"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"বিভাজিত স্ক্ৰীন"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"একেবাৰে ওপৰৰফালে বিভাজন কৰক"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"বাওঁফালে বিভাজন কৰক"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"সোঁফালে বিভাজন কৰক"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sৰ বাবে এপৰ তথ্য"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ৱিজেট স্থানান্তৰ কৰিবলৈ টিপি ধৰি ৰাখক।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"কোনো ৱিজেট স্থানান্তৰ কৰিবলৈ দুবাৰ টিপি ধৰি ৰাখক অথবা কাষ্টম কাৰ্য ব্যৱহাৰ কৰক।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 96d363a..c2ca56d 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Qısayol əlçatan deyil"</string>
<string name="home_screen" msgid="5629429142036709174">"Əsas səhifə"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekran bölünməsi"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Yuxarı ayırın"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Sola ayırın"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Sağa ayırın"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilə bağlı tətbiq məlumatı"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidceti daşımaq üçün toxunub saxlayın."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidceti daşımaq üçün iki dəfə toxunub saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 10b26e2..b10ae18 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Prečica nije dostupna"</string>
<string name="home_screen" msgid="5629429142036709174">"Početni ekran"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podeljeni ekran"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Podeli u vrhu"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Podeli levo"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Podeli desno"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji za: %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite radi pomeranja vidžeta."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da biste pomerali vidžet ili koristite prilagođene radnje."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 4b0b6a1..3d6bde4 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Ярлык недаступны"</string>
<string name="home_screen" msgid="5629429142036709174">"Галоўны экран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Падзелены экран"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Падзяліць уверсе"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Падзяліць злева"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Падзяліць справа"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Інфармацыя пра праграму для: %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Націсніце і ўтрымлівайце віджэт для перамяшчэння."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Дакраніцеся двойчы і ўтрымлівайце, каб перамясціць віджэт або выкарыстоўваць спецыяльныя дзеянні."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 42d5712..661c710 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Няма достъп до прекия път"</string>
<string name="home_screen" msgid="5629429142036709174">"Начален екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделен екран"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Разделяне в горната част"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Разделяне в лявата част"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Разделяне в дясната част"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Информация за приложението за %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Докоснете и задръжте за преместване на приспособление"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Докоснете двукратно и задръжте за преместване на приспособление или използвайте персонал. действия."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 92be881..299a014 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"শর্টকাটগুলি অনুপলব্ধ"</string>
<string name="home_screen" msgid="5629429142036709174">"হোম"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"স্প্লিট স্ক্রিন"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"স্ক্রিনের উপরের দিকে স্প্লিট করুন"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"স্ক্রিনের বাঁদিকে স্প্লিট করুন"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"স্ক্রিনের ডানদিকে স্প্লিট করুন"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-এর জন্য অ্যাপ সম্পর্কিত তথ্য"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"কোনও উইজেট সরাতে সেটি টাচ করে ধরে রাখুন।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"একটি উইজেট সরাতে বা কাস্টম অ্যাকশন ব্যবহার করতে ডবল ট্যাপ করে ধরে রাখুন।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index da5ffab..50b2b3c 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Prečica nije dostupna"</string>
<string name="home_screen" msgid="5629429142036709174">"Početni ekran"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podijeljeni ekran"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Podijeli nagore"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Podijeli ulijevo"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Podijeli udesno"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite da pomjerite vidžet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da pomjerite vidžet ili da koristite prilagođene radnje."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index f9a56bb..a0f03c8 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"La drecera no està disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Inici"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Divideix a la part superior"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Divideix a l\'esquerra"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Divideix a la dreta"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informació de l\'aplicació %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Fes doble toc i mantén premut per moure un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Fes doble toc i mantén premut per moure un widget o per utilitzar accions personalitzades."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index f0f9266..a92e936 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Zkratka není k dispozici"</string>
<string name="home_screen" msgid="5629429142036709174">"Domů"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdělená obrazovka"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Rozdělit nahoře"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Rozdělit vlevo"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Rozdělit vpravo"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informace o aplikaci %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Klepnutím a podržením přesunete widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a podržením přesunete widget, případně použijte vlastní akce."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 5400eb1..ee339c4 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Genvejen er ikke tilgængelig"</string>
<string name="home_screen" msgid="5629429142036709174">"Startskærm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Opdel skærm"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Vis øverst"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Vis i venstre side"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Vis i højre side"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinfo for %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Hold en widget nede for at flytte den."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryk to gange, og hold en widget nede for at flytte den eller bruge tilpassede handlinger."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index e884423..a0c784f 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Verknüpfung nicht verfügbar"</string>
<string name="home_screen" msgid="5629429142036709174">"Startbildschirm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Splitscreen"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Oben teilen"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Links teilen"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Rechts teilen"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"App-Info für %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Zum Verschieben des Widgets berühren und halten"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Doppeltippen und halten, um ein Widget zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 538506c..b78db22 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Η συντόμευση δεν είναι διαθέσιμη"</string>
<string name="home_screen" msgid="5629429142036709174">"Αρχική οθόνη"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Διαχωρισμός οθόνης"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Διαχωρισμός επάνω"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Διαχωρισμός αριστερά"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Διαχωρισμός δεξιά"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Πληροφορίες εφαρμογής για %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Πατήστε παρατετ. για μετακίνηση γραφ. στοιχείου."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Πατήστε δύο φορές παρατεταμένα για μετακίνηση γραφικού στοιχείου ή χρήση προσαρμοσμένων ενεργειών."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index f5be3b4..29a726c 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Shortcut isn\'t available"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Split top"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Split left"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Split right"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index f5be3b4..29a726c 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Shortcut isn\'t available"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Split top"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Split left"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Split right"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index f5be3b4..29a726c 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Shortcut isn\'t available"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Split top"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Split left"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Split right"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index f5be3b4..29a726c 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Shortcut isn\'t available"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Split top"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Split left"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Split right"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 3b78b7f..f975d5c 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Shortcut isn\'t available"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Split top"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Split left"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Split right"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch & hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 3bd5f22..314a3af 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"El acceso directo no está disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Pantalla principal"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Dividir en la parte superior"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Dividir a la izquierda"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Dividir a la derecha"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la app de %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén presionado para mover un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Presiona dos veces y mantén presionado para mover un widget o usar acciones personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 8fc279b..2401054 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Acceso directo no disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Dividir parte superior"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Dividir parte izquierda"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Dividir parte derecha"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la aplicación %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén pulsado un widget para moverlo."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dos veces y mantén pulsado un widget para moverlo o usar acciones personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 72b88d3..e483041 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Otsetee pole saadaval"</string>
<string name="home_screen" msgid="5629429142036709174">"Avakuva"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Jagatud ekraanikuva"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Jaga üles"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Jaga vasakule"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Jaga paremale"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Rakenduse teave: %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidina teisaldamiseks puudutage ja hoidke all."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidina teisaldamiseks või kohandatud toimingute kasutamiseks topeltpuudutage ja hoidke all."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 6f6c0ca..f1cc45e 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Lasterbideak ez daude erabilgarri"</string>
<string name="home_screen" msgid="5629429142036709174">"Hasierako pantaila"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Zatitu pantaila"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Zatitu goialdean"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Zatitu ezkerraldean"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Zatitu eskuinaldean"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s aplikazioari buruzko informazioa"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Eduki sakatuta widget bat mugitzeko."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Sakatu birritan eta eduki sakatuta widget bat mugitzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 13ed7b2..a7b1020 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"میانبر دردسترس نیست"</string>
<string name="home_screen" msgid="5629429142036709174">"صفحه اصلی"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"صفحهٔ دونیمه"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"تقسیم از بالا"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"تقسیم از چپ"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"تقسیم از راست"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"اطلاعات برنامه %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"برای جابهجا کردن ابزارک، لمس کنید و نگه دارید."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابهجا کردن ابزارک یا استفاده از کنشهای سفارشی، دوضربه بزنید و نگه دارید."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 68bc053..874c85d 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Pikakuvake ei ole käytettävissä."</string>
<string name="home_screen" msgid="5629429142036709174">"Etusivu"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Jaettu näyttö"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Ylhäällä"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Vasemmalla"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Oikealla"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Sovellustiedot: %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Kosketa pitkään, niin voit siirtää widgetiä."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Kaksoisnapauta ja paina pitkään, niin voit siirtää widgetiä tai käyttää muokattuja toimintoja."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index e9988c6..9a77c87 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Le raccourci n\'est pas disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Accueil"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Diviser dans la partie supérieure"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Diviser à gauche"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Diviser à droite"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Renseignements sur l\'appli pour %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Maintenez le doigt sur un widget pour le déplacer."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Touchez 2x un widget et maintenez le doigt dessus pour le déplacer ou utiliser des actions personnalisées."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 7e28c83..f071db9 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Raccourci non disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Accueil"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Affichée en haut"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Affichée à gauche"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Affichée à droite"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Infos sur l\'appli pour %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Appuyez de manière prolongée sur un widget pour le déplacer."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Appuyez deux fois et maintenez la pression pour déplacer widget ou utiliser actions personnalisées."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 094af61..3986aa4 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"O atallo non está dispoñible"</string>
<string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Dividir (arriba)"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Dividir (esquerda)"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Dividir (dereita)"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información da aplicación para %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén premido un widget para movelo."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dúas veces un widget e manteno premido para movelo ou utiliza accións personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index de47dfb..fae3773 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"શૉર્ટકટ ઉપલબ્ધ નથી"</string>
<string name="home_screen" msgid="5629429142036709174">"હોમ સ્ક્રીન"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"સ્ક્રીનને વિભાજિત કરો"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"ઉપર વિભાજિત કરો"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"ડાબે વિભાજિત કરો"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"જમણે વિભાજિત કરો"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s માટે ઍપ માહિતી"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"વિજેટ ખસેડવા ટચ કરીને થોડી વાર દબાવી રાખો."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"વિજેટ ખસેડવા બે વાર ટૅપ કરીને દબાવી રાખો અથવા કસ્ટમ ક્રિયાઓનો ઉપયોગ કરો."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -67,7 +71,7 @@
<string name="all_apps_search_results" msgid="5889367432531296759">"શોધ પરિણામો"</string>
<string name="all_apps_button_personal_label" msgid="1315764287305224468">"વ્યક્તિગત ઍપની સૂચિ"</string>
<string name="all_apps_button_work_label" msgid="7270707118948892488">"કાર્યસ્થળની ઍપની સૂચિ"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"દૂર કરો"</string>
+ <string name="remove_drop_target_label" msgid="7812859488053230776">"કાઢી નાખો"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"અનઇન્સ્ટોલ કરો"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ઍપની માહિતી"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
@@ -113,7 +117,7 @@
<string name="auto_add_shortcuts_label" msgid="3698776050751790653">"ઍપના આઇકન હોમ સ્ક્રીન પર ઉમેરો"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"નવી ઍપ માટે"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"અજાણ્યો"</string>
- <string name="abandoned_clean_this" msgid="7610119707847920412">"દૂર કરો"</string>
+ <string name="abandoned_clean_this" msgid="7610119707847920412">"કાઢી નાખો"</string>
<string name="abandoned_search" msgid="891119232568284442">"શોધો"</string>
<string name="abandoned_promises_title" msgid="7096178467971716750">"આ ઍપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
<string name="abandoned_promise_explanation" msgid="3990027586878167529">"આ આયકન માટેની ઍપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી. તમે તેને દૂર કરી શકો છો અથવા ઍપ્લિકેશન માટે શોધ કરી અને તેને મેન્યુઅલી ઇન્સ્ટોલ કરી શકો છો."</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index b9de9fc..6290cd1 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"शॉर्टकट उपलब्ध नहीं है"</string>
<string name="home_screen" msgid="5629429142036709174">"होम स्क्रीन"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"स्क्रीन को ऊपर के हिस्से में स्प्लिट करें"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"स्क्रीन को बाएं हिस्से में स्प्लिट करें"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"स्क्रीन को दाएं हिस्से में स्प्लिट करें"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s के लिए ऐप्लिकेशन की जानकारी"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"किसी विजेट को एक से दूसरी जगह ले जाने के लिए, उसे दबाकर रखें."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"किसी विजेट को एक से दूसरी जगह ले जाने के लिए, उस पर दो बार टैप करके दबाकर रखें या पसंद के मुताबिक कार्रवाइयां इस्तेमाल करें."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 899bd31..75e47a1 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Prečac nije dostupan"</string>
<string name="home_screen" msgid="5629429142036709174">"Početni zaslon"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podijeljeni zaslon"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Podijeli gore"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Podijeli lijevo"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Podijeli desno"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite da biste premjestili widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite pritisak da biste premjestili widget ili upotrijebite prilagođene radnje"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 8ea2386..71a8d69 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"A gyorsparancs nem áll rendelkezésre"</string>
<string name="home_screen" msgid="5629429142036709174">"Kezdőképernyő"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Osztott képernyő"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Osztás a képernyő tetején"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Osztás a képernyő bal oldalán"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Osztás a képernyő jobb oldalán"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Alkalmazásinformáció a következőhöz: %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tartsa lenyomva a modult az áthelyezéshez."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Modul áthelyezéséhez koppintson duplán, tartsa nyomva az ujját, vagy használjon egyéni műveleteket."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index b757d2b..3d65a3e 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Դյուրանցումն անհասանելի է"</string>
<string name="home_screen" msgid="5629429142036709174">"Հիմնական էկրան"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Տրոհել էկրանը"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Հավելվածը վերևում"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Հավելվածը ձախ կողմում"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Հավելվածը աջ կողմում"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Տեղեկություններ %1$s հավելվածի մասին"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Հպեք և պահեք՝ վիջեթ տեղափոխելու համար։"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Կրկնակի հպեք և պահեք՝ վիջեթ տեղափոխելու համար, կամ օգտվեք հատուկ գործողություններից։"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 1846883..f106774 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Pintasan tidak tersedia"</string>
<string name="home_screen" msgid="5629429142036709174">"Layar utama"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Layar terpisah"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Pisahkan ke atas"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Pisahkan ke kiri"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Pisahkan ke kanan"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Info aplikasi untuk %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh lama untuk memindahkan widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketuk dua kali & tahan untuk memindahkan widget atau gunakan tindakan khusus."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 2b0a97f..1397b88 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Flýtileið er ekki tiltæk"</string>
<string name="home_screen" msgid="5629429142036709174">"Heim"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Skipta skjá"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Skipta efst"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Skipta vinstra megin"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Skipta hægra megin"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Upplýsingar um forrit fyrir %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Haltu fingri á græju til að færa hana."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ýttu tvisvar og haltu fingri á græju til að færa hana eða notaðu sérsniðnar aðgerðir."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 0235ef0..ff0b6c0 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"La scorciatoia non è disponibile"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Schermo diviso"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Dividi in alto"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Dividi a sinistra"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Dividi a destra"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informazioni sull\'app %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tocca e tieni premuto per spostare un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tocca due volte e tieni premuto per spostare un widget o per usare le azioni personalizzate."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 52fe570..3d0774f 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"קיצור הדרך אינו זמין"</string>
<string name="home_screen" msgid="5629429142036709174">"בית"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"מסך מפוצל"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"פיצול למעלה"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"פיצול שמאלה"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"פיצול ימינה"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"פרטים על האפליקציה %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"כדי להעביר ווידג\'ט למקום אחר יש לגעת ולא להרפות."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"כדי להעביר ווידג\'ט למקום אחר או להשתמש בפעולות מותאמות אישית, יש ללחוץ פעמיים ולא להרפות."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index d789a39..f1db158 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ショートカットは使用できません"</string>
<string name="home_screen" msgid="5629429142036709174">"ホーム"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割画面"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"上に分割"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"左に分割"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"右に分割"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s のアプリ情報"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"長押ししてウィジェットを移動してください。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ウィジェットをダブルタップして長押ししながら移動するか、カスタム操作を使用してください。"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$dx%2$d"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 6dd7cbe..a0cbbc7 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"მალსახმობი მიუწვდომელია"</string>
<string name="home_screen" msgid="5629429142036709174">"მთავარი გვერდი"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ეკრანის გაყოფა"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"გაყოფილი ზემოთ"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"გაყოფილი მარცხნივ"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"გაყოფილი მარჯვნივ"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-ის აპის ინფო"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ორმაგი შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index f5c0410..529a00f 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Таңбаша қолжетімді емес"</string>
<string name="home_screen" msgid="5629429142036709174">"Негізгі экран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлу"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Жоғарыдан шығару"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Сол жақтан шығару"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Оң жақтан шығару"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s қолданбасы туралы ақпарат"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетті жылжыту үшін басып тұрыңыз."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетті жылжыту үшін екі рет түртіңіз де, ұстап тұрыңыз немесе арнаулы әрекеттерді пайдаланыңыз."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 8089b94..f8560aa 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ផ្លូវកាត់មិនអាចប្រើបានទេ"</string>
<string name="home_screen" msgid="5629429142036709174">"អេក្រង់ដើម"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"មុខងារបំបែកអេក្រង់"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"បំបែកខាងលើ"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"បំបែកខាងឆ្វេង"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"បំបែកខាងស្ដាំ"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"ព័ត៌មានកម្មវិធីសម្រាប់ %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ចុចឱ្យជាប់ដើម្បីផ្លាស់ទីធាតុក្រាហ្វិក។"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ចុចពីរដង រួចសង្កត់ឱ្យជាប់ ដើម្បីផ្លាស់ទីធាតុក្រាហ្វិក ឬប្រើសកម្មភាពតាមបំណង។"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index e358d29..9eda419 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ಶಾರ್ಟ್ಕಟ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="home_screen" msgid="5629429142036709174">"ಹೋಮ್"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"ಮೇಲಕ್ಕೆ ವಿಭಜಿಸಿ"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"ಎಡಕ್ಕೆ ವಿಭಜಿಸಿ"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"ಬಲಕ್ಕೆ ವಿಭಜಿಸಿ"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ಗಾಗಿ ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ವಿಜೆಟ್ ಸರಿಸಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ವಿಜೆಟ್ ಸರಿಸಲು ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index e2d29d4..9859752 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"바로가기를 사용할 수 없음"</string>
<string name="home_screen" msgid="5629429142036709174">"홈"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"화면 분할"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"위쪽으로 분할"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"왼쪽으로 분할"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"오른쪽으로 분할"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 앱 정보"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"길게 터치하여 위젯을 이동하세요."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"두 번 탭한 다음 길게 터치하여 위젯을 이동하거나 맞춤 작업을 사용하세요."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 8769ef1..5378ca5 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Кыска жол жок"</string>
<string name="home_screen" msgid="5629429142036709174">"Башкы экран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлүү"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Өйдө бөлүү"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Солго бөлүү"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Оңго бөлүү"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s колдонмосу жөнүндө маалымат"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетти кое бербей басып туруп жылдырыңыз."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетти жылдыруу үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 83c9ae3..e47fefd 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ບໍ່ສາມາດໃຊ້ທາງລັດໄດ້"</string>
<string name="home_screen" msgid="5629429142036709174">"ໂຮມສະກຣີນ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ແບ່ງໜ້າຈໍ"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"ແບ່ງເທິງ"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"ແບ່ງຊ້າຍ"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"ແບ່ງຂວາ"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"ຂໍ້ມູນແອັບສຳລັບ %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ແຕະຄ້າງໄວ້ເພື່ອຍ້າຍວິດເຈັດ."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຍ້າຍວິດເຈັດ ຫຼື ໃຊ້ຄຳສັ່ງກຳນົດເອງ."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 5876cdb..e4fdfc6 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Sparčiojo klavišo negalima naudoti"</string>
<string name="home_screen" msgid="5629429142036709174">"Pagrindinis"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Išskaidyto ekrano režimas"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Išskaidyti viršun"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Išskaidyti kairėn"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Išskaidyti dešinėn"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Programos „%1$s“ informacija"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dukart pal. ir palaik., kad perkeltumėte valdiklį."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dukart palieskite ir palaikykite, kad perkeltumėte valdiklį ar naudotumėte tinkintus veiksmus."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index d262b23..f02d4fb 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Saīsne nav pieejama."</string>
<string name="home_screen" msgid="5629429142036709174">"Sākums"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Sadalīt ekrānu"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Sadalījums augšdaļā"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Sadalījums pa kreisi"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Sadalījums pa labi"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s: informācija par lietotni"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Lai pārvietotu logrīku, pieskarieties un turiet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Lai pārvietotu logrīku, uz tā veiciet dubultskārienu un turiet. Varat arī veikt pielāgotas darbības."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 3936a67..0bc7043 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Кратенката не е достапна"</string>
<string name="home_screen" msgid="5629429142036709174">"Почетен екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Поделен екран"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Подели нагоре"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Подели налево"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Подели надесно"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Податоци за апликација за %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Допрете и задржете за да преместите виџет."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Допрете двапати и задржете за да преместите виџет или користете приспособени дејства."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 613db56..5c626db 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"കുറുക്കുവഴി ലഭ്യമല്ല"</string>
<string name="home_screen" msgid="5629429142036709174">"ഹോം"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"സ്ക്രീൻ വിഭജന മോഡ്"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"മുകളിലേക്ക് വിഭജിക്കുക"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"ഇടതുഭാഗത്തേക്ക് വിഭജിക്കുക"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"വലതുഭാഗത്തേക്ക് വിഭജിക്കുക"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s എന്നതിന്റെ ആപ്പ് വിവരങ്ങൾ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"വിജറ്റ് നീക്കാൻ സ്പർശിച്ച് പിടിക്കുക."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"വിജറ്റ് നീക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യൂ, ഹോൾഡ് ചെയ്യൂ അല്ലെങ്കിൽ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കൂ."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 99b3d2f..e6fcefa 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Товчлол алга"</string>
<string name="home_screen" msgid="5629429142036709174">"Нүүр"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Дэлгэцийг хуваах"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Дээш хуваах"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Зүүн тийш хуваах"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Баруун тийш хуваах"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-н аппын мэдээлэл"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетийг зөөх бол хүрээд, удаан дарна уу."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетийг зөөх эсвэл захиалгат үйлдлийг ашиглахын тулд хоёр товшоод, удаан дарна уу."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 4b9ef33..34bdcd2 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"शॉर्टकट उपलब्ध नाही"</string>
<string name="home_screen" msgid="5629429142036709174">"होम"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"सर्वात वरती स्प्लिट करा"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"डावीकडे स्प्लिट करा"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"उजवीकडे स्प्लिट करा"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s साठी ॲपशी संबंधित माहिती"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"विजेट हलवण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"विजेट हलवण्यासाठी किंवा कस्टम कृती वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 07e96cc..d39a213 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Pintasan tidak tersedia"</string>
<string name="home_screen" msgid="5629429142036709174">"Rumah"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Skrin pisah"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Pisah atas"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Pisah kiri"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Pisah kanan"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Maklumat apl untuk %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh & tahan untuk menggerakkan widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketik dua kali & tahan untuk menggerakkan widget atau menggunakan tindakan tersuai."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 787b877..0d4c8fa 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ဖြတ်လမ်း မရနိုင်ပါ"</string>
<string name="home_screen" msgid="5629429142036709174">"ပင်မစာမျက်နှာ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"ထိပ်ပိုင်း အခွဲ"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"ဘက်ဘက် အခွဲ"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"ညာဘက် အခွဲ"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s အတွက် အက်ပ်အချက်အလက်"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ဝိဂျက်ကို ရွှေ့ရန် တို့ပြီး ဖိထားပါ။"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ဝိဂျက်ကို ရွှေ့ရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -126,7 +130,7 @@
<string name="action_move_here" msgid="2170188780612570250">"၎င်းအား ဤသို့ ရွှေ့ပါ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ပင်မ ဖန်မျက်နှာပြင်သို့ ထည့်ပြီး၏"</string>
<string name="item_removed" msgid="851119963877842327">"၎င်းအား ဖယ်ရှားပြီး၏"</string>
- <string name="undo" msgid="4151576204245173321">"နောက်ပြန်"</string>
+ <string name="undo" msgid="4151576204245173321">"နောက်ပြန်ရန်"</string>
<string name="action_move" msgid="4339390619886385032">"၎င်းအား ရွှေ့ပါ"</string>
<string name="move_to_empty_cell" msgid="2833711483015685619">"အတန်း <xliff:g id="NUMBER_0">%1$s</xliff:g> အတိုင် <xliff:g id="NUMBER_1">%2$s</xliff:g> သို့ ရွှေ့ပါ"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> သို့ နေရာရွှေ့ပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index c588d3c..6dff142 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Snarveien er ikke tilgjengelig"</string>
<string name="home_screen" msgid="5629429142036709174">"Startskjerm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delt skjerm"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Splitt øverst"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Splitt til venstre"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Splitt til høyre"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformasjon for %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Trykk og hold for å flytte en modul."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dobbelttrykk og hold inne for å flytte en modul eller bruke tilpassede handlinger."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 091820b..b735d02 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"सर्टकट उपलब्ध छैन"</string>
<string name="home_screen" msgid="5629429142036709174">"होम"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रिन"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"सिरानतिर स्प्लिट गर्नुहोस्"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"बायाँतिर स्प्लिट गर्नुहोस्"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"दायाँतिर स्प्लिट गर्नुहोस्"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s का हकमा एपसम्बन्धी जानकारी"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"कुनै विजेट सार्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"कुनै विजेट सार्न वा आफ्नो रोजाइका कारबाही प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 04a93c9..51730a0 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Snelkoppeling is niet beschikbaar"</string>
<string name="home_screen" msgid="5629429142036709174">"Startscherm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Gesplitst scherm"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Gesplitst scherm boven"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Gesplitst scherm links"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Gesplitst scherm rechts"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"App-info voor %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tik en houd vast om een widget te verplaatsen."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en houd vast om een widget te verplaatsen of aangepaste acties te gebruiken."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index fb2da8a..1149e02 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ଶର୍ଟକଟ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="home_screen" msgid="5629429142036709174">"ମୂଳପୃଷ୍ଠା"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ସ୍କ୍ରିନକୁ ସ୍ପ୍ଲିଟ୍ କରନ୍ତୁ"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"ଶୀର୍ଷକୁ ସ୍ପ୍ଲିଟ କରନ୍ତୁ"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"ବାମପତକୁ ସ୍ପ୍ଲିଟ କରନ୍ତୁ"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"ଡାହାଣପଟକୁ ସ୍ପ୍ଲିଟ କରନ୍ତୁ"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ପାଇଁ ଆପ ସୂଚନା"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ଦୁଇଥର-ଟାପ୍ କରି ଧରି ରଖନ୍ତୁ କିମ୍ବା କଷ୍ଟମ୍ କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 994faf8..2d70d7f 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ਸ਼ਾਰਟਕੱਟ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="home_screen" msgid="5629429142036709174">"ਮੁੱਖ ਪੰਨਾ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"ਸਿਖਰ \'ਤੇ ਵੰਡੋ"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"ਖੱਬੇ ਪਾਸੇ ਵੰਡੋ"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"ਸੱਜੇ ਪਾਸੇ ਵੰਡੋ"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ਲਈ ਐਪ ਜਾਣਕਾਰੀ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ਕਿਸੇ ਵਿਜੇਟ ਨੂੰ ਲਿਜਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ਵਿਜੇਟ ਲਿਜਾਉਣ ਲਈ ਜਾਂ ਵਿਉਂਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤਣ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰਕੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 6a588b7..f730e68 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Skrót nie jest dostępny"</string>
<string name="home_screen" msgid="5629429142036709174">"Ekran główny"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podziel ekran"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Podziel u góry"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Podziel po lewej"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Podziel po prawej"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacje o aplikacji: %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Naciśnij i przytrzymaj, aby przenieść widżet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Naciśnij dwukrotnie i przytrzymaj, aby przenieść widżet lub użyć działań niestandardowych."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index a3c225a..0ddef70 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"O atalho não está disponível"</string>
<string name="home_screen" msgid="5629429142036709174">"Página inicial"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ecrã dividido"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Divisão na parte superior"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Divisão à esquerda"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Divisão à direita"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações da app para %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque sem soltar para mover um widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes sem soltar para mover um widget ou utilizar ações personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 55d9c81..7beedcb 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"O atalho não está disponível"</string>
<string name="home_screen" msgid="5629429142036709174">"Início"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Tela dividida"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Dividir para cima"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Dividir para a esquerda"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Dividir para a direita"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações do app %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque e mantenha pressionado para mover um widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes e mantenha a tela pressionada para mover um widget ou usar ações personalizadas."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 304113d..14db745 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Comanda rapidă nu este disponibilă"</string>
<string name="home_screen" msgid="5629429142036709174">"Pagina de pornire"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ecran împărțit"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Împărțiți în sus"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Împărțiți în stânga"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Împărțiți în dreapta"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informații despre aplicație pentru %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Atingeți și țineți apăsat pentru a muta un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Atingeți de două ori și țineți apăsat pentru a muta un widget sau folosiți acțiuni personalizate."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 2d9495b..4e72d40 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Ярлык недоступен"</string>
<string name="home_screen" msgid="5629429142036709174">"Главный экран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделить экран"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Приложение сверху"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Приложение слева"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Приложение справа"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Сведения о приложении \"%1$s\""</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Нажмите и удерживайте для переноса виджета."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Чтобы использовать специальные действия или перенести виджет, нажмите на него дважды и удерживайте."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
@@ -67,7 +71,7 @@
<string name="all_apps_search_results" msgid="5889367432531296759">"Результаты поиска"</string>
<string name="all_apps_button_personal_label" msgid="1315764287305224468">"Открыть список личных приложений"</string>
<string name="all_apps_button_work_label" msgid="7270707118948892488">"Открыть список приложений для работы"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Удалить"</string>
+ <string name="remove_drop_target_label" msgid="7812859488053230776">"Убрать"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Удалить"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"О приложении"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 3214233..17531bd 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"කෙටි මග ලබා ගත නොහැකිය"</string>
<string name="home_screen" msgid="5629429142036709174">"මුල් පිටුව"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"බෙදුම් තිරය"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"ඉහළ බෙදන්න"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"වම බෙදන්න"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"දකුණ බෙදන්න"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s සඳහා යෙදුම් තතු"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"විජට් එකක් ගෙන යාමට ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"විජට් එකක් ගෙන යාමට හෝ අභිරුචි ක්රියා භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 1ba5cf1..3f212dc 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Skratky nie sú k dispozícii"</string>
<string name="home_screen" msgid="5629429142036709174">"Domov"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdeliť obrazovku"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Rozdeliť hore"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Rozdeliť vľavo"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Rozdeliť vpravo"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informácie o aplikácii pre %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržaním presuňte miniaplikáciu."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a pridržaním presuňte miniaplikáciu alebo použite vlastné akcie."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index a0525cf..485a525 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Bližnjica ni na voljo"</string>
<string name="home_screen" msgid="5629429142036709174">"Začetni zaslon"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Razdeljen zaslon"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Zgornja stran razdeljenega zaslona"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Leva stran razdeljenega zaslona"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Desna stran razdeljenega zaslona"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Podatki o aplikaciji za: %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržite pripomoček, da ga premaknete."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvakrat se dotaknite pripomočka in ga pridržite, da ga premaknete, ali pa uporabite dejanja po meri."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 218a745..88ed4fa 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Shkurtorja nuk është e disponueshme"</string>
<string name="home_screen" msgid="5629429142036709174">"Ekrani bazë"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekrani i ndarë"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Ndaj lart"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Ndaj majtas"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Ndaj djathtas"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacioni i aplikacionit për %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Prek dhe mbaj shtypur një miniaplikacion për ta zhvendosur."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Trokit dy herë dhe mbaje shtypur një miniapliikacion për ta zhvendosur atë ose për të përdorur veprimet e personalizuara."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 8668b96..e719db6 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Пречица није доступна"</string>
<string name="home_screen" msgid="5629429142036709174">"Почетни екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Подељени екран"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Подели у врху"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Подели лево"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Подели десно"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Информације о апликацији за: %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Додирните и задржите ради померања виџета."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двапут додирните и задржите да бисте померали виџет или користите прилагођене радње."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 1a47df2..e590ec9 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Genvägen är inte tillgänglig"</string>
<string name="home_screen" msgid="5629429142036709174">"Startskärm"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delad skärm"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Upptill på delad skärm"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Till vänster på delad skärm"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Till höger på delad skärm"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformation för %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tryck länge för att flytta en widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryck snabbt två gånger och håll kvar för att flytta en widget eller använda anpassade åtgärder."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index af7ac67..fa58703 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Hakuna njia ya mkato"</string>
<string name="home_screen" msgid="5629429142036709174">"Skrini ya kwanza"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Gawa skrini"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Gawanya sehemu ya juu"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Gawanya sehemu ya kushoto"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Gawanya sehemu ya kulia"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Maelezo ya programu ya %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Gusa na ushikilie ili usogeze wijeti."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Gusa mara mbili na ushikilie ili usogeze wijeti au utumie vitendo maalum."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 4f1e21e..2fa95f8 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ஷார்ட்கட் இல்லை"</string>
<string name="home_screen" msgid="5629429142036709174">"முகப்பு"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"திரைப் பிரிப்பு"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"மேற்புறமாகப் பிரி"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"இடதுபுறமாகப் பிரி"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"வலதுபுறமாகப் பிரி"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sக்கான ஆப்ஸ் தகவல்கள்"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"விட்ஜெட்டை நகர்த்தத் தொட்டுப் பிடிக்கவும்."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"விட்ஜெட்டை நகர்த்த இருமுறை தட்டிப் பிடிக்கவும் அல்லது பிரத்தியேகச் செயல்களைப் பயன்படுத்தவும்."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index faeea40..ce364bd 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"షార్ట్కట్ అందుబాటులో లేదు"</string>
<string name="home_screen" msgid="5629429142036709174">"మొదటి ట్యాబ్"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"స్క్రీన్ను విభజించు"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"స్ప్లిట్ ఎగువన"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"స్ప్లిట్ ఎడమవైపు"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"స్ప్లిట్ కుడివైపు"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s కోసం యాప్ సమాచారం"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"విడ్జెట్ను తరలించడానికి తాకి & నొక్కి ఉంచండి."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"విడ్జెట్ను తరలించడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కండి & హోల్డ్ చేయి."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -77,7 +81,7 @@
<string name="permdesc_install_shortcut" msgid="923466509822011139">"వినియోగదారు ప్రమేయం లేకుండా షార్ట్కట్లను జోడించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_read_settings" msgid="1941457408239617576">"హోమ్ సెట్టింగ్లు మరియు షార్ట్కట్లను చదవడం"</string>
<string name="permdesc_read_settings" msgid="5833423719057558387">"హోమ్లో సెట్టింగ్లు మరియు షార్ట్కట్లను చదవడానికి యాప్ను అనుమతిస్తుంది."</string>
- <string name="permlab_write_settings" msgid="3574213698004620587">"హోమ్ సెట్టింగ్లు మరియు షార్ట్కట్లను వ్రాయడం"</string>
+ <string name="permlab_write_settings" msgid="3574213698004620587">"హోమ్ సెట్టింగ్లు మరియు షార్ట్కట్లను రాయడం"</string>
<string name="permdesc_write_settings" msgid="5440712911516509985">"హోమ్లో సెట్టింగ్లు మరియు షార్ట్కట్లను మార్చడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="msg_no_phone_permission" msgid="9208659281529857371">"ఫోన్ కాల్స్ను చేసేందుకు <xliff:g id="APP_NAME">%1$s</xliff:g>కి అనుమతి లేదు"</string>
<string name="gadget_error_text" msgid="740356548025791839">"విడ్జెట్ను లోడ్ చేయడం సాధ్యం కాలేదు"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 9278186..768bff6 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"ทางลัดไม่พร้อมใช้งาน"</string>
<string name="home_screen" msgid="5629429142036709174">"หน้าแรก"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"แบ่งหน้าจอ"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"แยกไปด้านบน"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"แยกไปทางซ้าย"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"แยกไปทางขวา"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"ข้อมูลแอปสำหรับ %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"แตะค้างไว้เพื่อย้ายวิดเจ็ต"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"แตะสองครั้งค้างไว้เพื่อย้ายวิดเจ็ตหรือใช้การดำเนินการที่กำหนดเอง"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 1e93180..49465c5 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Hindi available ang shortcut"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Hatiin sa itaas"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Hatiin sa kaliwa"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Hatiin sa kanan"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Impormasyon ng app para sa %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pindutin nang matagal para ilipat ang widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"I-double tap at pindutin nang matagal para ilipat ang widget o gumamit ng mga custom na pagkilos."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 735681e..bb0e1a8 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Kısayol kullanılamıyor"</string>
<string name="home_screen" msgid="5629429142036709174">"Ana ekran"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Bölünmüş ekran"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Üst tarafta böl"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Sol tarafta böl"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Sağ tarafta böl"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s uygulama bilgileri"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget\'ı taşımak için dokunup basılı tutun."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Widget\'ı taşımak veya özel işlemleri kullanmak için iki kez dokunup basılı tutun."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index f0f2951..998ad84 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Ярлик недоступний"</string>
<string name="home_screen" msgid="5629429142036709174">"Головний екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Розділити екран"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Розділити вгорі"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Розділити зліва"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Розділити справа"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Інформація про додаток для %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Натисніть і втримуйте, щоб перемістити віджет."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двічі натисніть і втримуйте віджет, щоб перемістити його або виконати інші дії."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 21a4bc0..1b4a3d1 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"شارٹ کٹ دستیاب نہیں ہے"</string>
<string name="home_screen" msgid="5629429142036709174">"ہوم"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"اسپلٹ اسکرین"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"اوپر کی طرف تقسیم کریں"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"بائیں طرف تقسیم کریں"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"دائیں طرف تقسیم کریں"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s کے لیے ایپ کی معلومات"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ویجیٹ منتقل کرنے کے لیے ٹچ کریں اور پکڑ کر رکھیں۔"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ویجیٹ کو منتقل کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کے لیے دوبار تھپتھپائیں اور پکڑ کر رکھیں۔"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 8010fc8..8984af8 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Tezkor tugmadan foydalanib bo‘lmaydi"</string>
<string name="home_screen" msgid="5629429142036709174">"Bosh ekran"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekranni ikkiga ajratish"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Yuqoriga ajratish"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Chapga ajratish"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Oʻngga ajratish"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilovasi axboroti"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidjetni bosib turgan holatda suring."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ikki marta bosib va bosib turgan holatda vidjetni tanlang yoki maxsus amaldan foydalaning."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 65c204f..6972ee3 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Lối tắt không khả dụng"</string>
<string name="home_screen" msgid="5629429142036709174">"Màn hình chính"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Chia đôi màn hình"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Chia đôi màn hình lên phía trên cùng"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Chia đôi màn hình về bên trái"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Chia đôi màn hình về bên phải"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Thông tin ứng dụng cho %1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Chạm và giữ để di chuyển một tiện ích."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Nhấn đúp và giữ để di chuyển một tiện ích hoặc sử dụng các thao tác tùy chỉnh."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 1cd0d31..c7eb21e 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"无法使用快捷方式"</string>
<string name="home_screen" msgid="5629429142036709174">"主屏幕"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分屏"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"上分屏"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"左分屏"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"右分屏"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的应用信息"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"轻触并按住微件即可移动该微件。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"点按两次并按住微件即可移动该微件或使用自定义操作。"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index e5bf742..a278327 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"沒有可用的捷徑"</string>
<string name="home_screen" msgid="5629429142036709174">"主畫面"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割螢幕"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"頂部分割"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"左側分割"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"右側分割"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的應用程式資料"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"輕觸並按住即可移動小工具。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"㩒兩下之後㩒住,就可以郁小工具或者用自訂操作。"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 4cc63ed..a2cfcc7 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"目前無法使用捷徑"</string>
<string name="home_screen" msgid="5629429142036709174">"主畫面"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割畫面"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"分割上方畫面"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"分割左側畫面"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"分割右側畫面"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"「%1$s」的應用程式資訊"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"按住即可移動小工具。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"輕觸兩下並按住即可移動小工具或使用自訂操作。"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 6da6772..ca01769 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -28,6 +28,10 @@
<string name="shortcut_not_available" msgid="2536503539825726397">"Isinqamuleli asitholakali"</string>
<string name="home_screen" msgid="5629429142036709174">"Ikhaya"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Hlukanisa isikrini"</string>
+ <string name="split_screen_position_top" msgid="1504965011158689649">"Hlukanisa phezulu"</string>
+ <string name="split_screen_position_left" msgid="7537793098851830883">"Hlukanisa ngakwesobunxele"</string>
+ <string name="split_screen_position_right" msgid="1569377524925193369">"Hlukanisa ngakwesokudla"</string>
+ <string name="split_app_info_accessibility" msgid="5475288491241414932">"Ulwazi lwe-App ye-%1$s"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Thinta uphinde ubambe ukuze uhambise iwijethi."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Thepha kabili uphinde ubambe ukuze uhambise iwijethi noma usebenzise izindlela ezingokwezifiso."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 08f0089..08570eb 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -154,7 +154,15 @@
<attr name="demoModeLayoutId" format="reference" />
<attr name="isScalable" format="boolean" />
<attr name="devicePaddingId" format="reference" />
- <attr name="gridEnabled" format="boolean" />
+ <!-- By default all categories are enabled -->
+ <attr name="deviceCategory" format="integer" >
+ <!-- Enable on phone only -->
+ <flag name="phone" value="1" />
+ <!-- Enable on tablets only -->
+ <flag name="tablet" value="2" />
+ <!-- Enable on multi display devices only -->
+ <flag name="multi_display" value="4" />
+ </attr>
</declare-styleable>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 78f3f11..6d223e7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -300,6 +300,7 @@
<dimen name="snackbar_elevation">3dp</dimen>
<dimen name="snackbar_min_text_size">12sp</dimen>
<dimen name="snackbar_max_text_size">14sp</dimen>
+ <dimen name="snackbar_max_width">504dp</dimen>
<!-- Developer Options -->
<dimen name="developer_options_filter_margins">10dp</dimen>
@@ -321,6 +322,9 @@
<!-- Size of the maximum radius for the enforced rounded rectangles. -->
<dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
+<!-- Base Swipe Detector, speed in dp/s -->
+ <dimen name="base_swift_detector_fling_release_velocity">1dp</dimen>
+
<!-- Overview placeholder to compile in Launcher3 without Quickstep -->
<dimen name="task_thumbnail_icon_size">0dp</dimen>
<dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
@@ -328,6 +332,8 @@
<dimen name="overview_task_margin">0dp</dimen>
<dimen name="overview_task_margin_focused">0dp</dimen>
<dimen name="overview_task_margin_grid">0dp</dimen>
+ <dimen name="overview_actions_button_spacing">0dp</dimen>
+ <dimen name="overview_actions_button_spacing_grid">0dp</dimen>
<dimen name="overview_actions_margin_gesture">0dp</dimen>
<dimen name="overview_actions_top_margin_gesture_grid_portrait">0dp</dimen>
<dimen name="overview_actions_bottom_margin_gesture_grid_portrait">0dp</dimen>
@@ -336,10 +342,10 @@
<dimen name="overview_actions_margin_three_button">0dp</dimen>
<dimen name="overview_grid_side_margin_portrait">0dp</dimen>
<dimen name="overview_grid_side_margin_landscape">0dp</dimen>
- <dimen name="overview_grid_row_spacing_portrait">0dp</dimen>
- <dimen name="overview_grid_row_spacing_landscape">0dp</dimen>
- <dimen name="recents_page_spacing">0dp</dimen>
- <dimen name="recents_page_spacing_grid">0dp</dimen>
+ <dimen name="overview_grid_row_spacing">0dp</dimen>
+ <dimen name="overview_page_spacing">0dp</dimen>
+ <dimen name="overview_page_spacing_grid_portrait">0dp</dimen>
+ <dimen name="overview_page_spacing_grid_landscape">0dp</dimen>
<dimen name="split_placeholder_size">110dp</dimen>
<dimen name="task_menu_width_grid">200dp</dimen>
diff --git a/res/values/id.xml b/res/values/id.xml
index ebc4075..508caff 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -21,6 +21,10 @@
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
<item type="id" name="view_type_widgets_search_header" />
+ <!-- Used for A11y actions in staged split to identify each task uniquely -->
+ <item type="id" name="split_topLeft_appInfo" />
+ <item type="id" name="split_bottomRight_appInfo" />
+
<!-- Do not change, must be kept in sync with sysui navbar button IDs for tests! -->
<item type="id" name="home" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5f53d4e..868b5f3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -40,9 +40,10 @@
<!-- Options for recent tasks -->
<!-- Title for an option to enter split screen mode for a given app -->
<string name="recent_task_option_split_screen">Split screen</string>
- <string translatable="false" name="split_screen_position_top">Split top</string>
- <string translatable="false" name="split_screen_position_left">Split left</string>
- <string translatable="false" name="split_screen_position_right">Split right</string>
+ <string name="split_screen_position_top">Split top</string>
+ <string name="split_screen_position_left">Split left</string>
+ <string name="split_screen_position_right">Split right</string>
+ <string name="split_app_info_accessibility">App info for %1$s</string>
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
diff --git a/res/xml/default_workspace_6x5.xml b/res/xml/default_workspace_6x5.xml
new file mode 100644
index 0000000..b078cfd
--- /dev/null
+++ b/res/xml/default_workspace_6x5.xml
@@ -0,0 +1,76 @@
+<?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.
+-->
+
+<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
+
+ <!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
+ <!-- Mail Calendar Gallery Store Internet Camera -->
+ <resolve
+ launcher:container="-101"
+ launcher:screen="0"
+ launcher:x="0"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
+ <favorite launcher:uri="mailto:" />
+ </resolve>
+
+ <resolve
+ launcher:container="-101"
+ launcher:screen="1"
+ launcher:x="1"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_CALENDAR;end" />
+ </resolve>
+
+ <resolve
+ launcher:container="-101"
+ launcher:screen="2"
+ launcher:x="2"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
+ <favorite launcher:uri="#Intent;type=images/*;end" />
+ </resolve>
+
+ <resolve
+ launcher:container="-101"
+ launcher:screen="3"
+ launcher:x="3"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MARKET;end" />
+ <favorite launcher:uri="market://details?id=com.android.launcher" />
+ </resolve>
+
+ <resolve
+ launcher:container="-101"
+ launcher:screen="4"
+ launcher:x="4"
+ launcher:y="0" >
+ <favorite
+ launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" />
+ <favorite launcher:uri="http://www.example.com/" />
+ </resolve>
+
+ <!-- Resolve camera intent if GoogleCamera is not available e.g. on emulator -->
+ <resolve
+ launcher:container="-101"
+ launcher:screen="5"
+ launcher:x="5"
+ launcher:y="0" >
+ <favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" />
+ <favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
+ </resolve>
+
+</favorites>
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index e030f81..08698e7 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -25,7 +25,8 @@
launcher:numFolderColumns="3"
launcher:numHotseatIcons="3"
launcher:dbFile="launcher_3_by_3.db"
- launcher:defaultLayoutId="@xml/default_workspace_3x3" >
+ launcher:defaultLayoutId="@xml/default_workspace_3x3"
+ launcher:deviceCategory="phone|multi_display" >
<display-option
launcher:name="Super Short Stubby"
@@ -53,7 +54,8 @@
launcher:numFolderColumns="4"
launcher:numHotseatIcons="4"
launcher:dbFile="launcher_4_by_4.db"
- launcher:defaultLayoutId="@xml/default_workspace_4x4" >
+ launcher:defaultLayoutId="@xml/default_workspace_4x4"
+ launcher:deviceCategory="phone|multi_display" >
<display-option
launcher:name="Short Stubby"
@@ -105,7 +107,8 @@
launcher:numFolderColumns="4"
launcher:numHotseatIcons="5"
launcher:dbFile="launcher.db"
- launcher:defaultLayoutId="@xml/default_workspace_5x5" >
+ launcher:defaultLayoutId="@xml/default_workspace_5x5"
+ launcher:deviceCategory="phone|multi_display" >
<display-option
launcher:name="Large Phone"
@@ -133,4 +136,32 @@
</grid-option>
+ <grid-option
+ launcher:name="6_by_5"
+ launcher:numRows="5"
+ launcher:numColumns="6"
+ launcher:numFolderRows="3"
+ launcher:numFolderColumns="3"
+ launcher:numHotseatIcons="6"
+ launcher:numAllAppsColumns="6"
+ launcher:dbFile="launcher_6_by_5.db"
+ launcher:defaultLayoutId="@xml/default_workspace_6x5"
+ launcher:deviceCategory="tablet" >
+
+ <display-option
+ launcher:name="Tablet"
+ launcher:minWidthDps="900"
+ launcher:minHeightDps="820"
+ launcher:minCellHeightDps="104"
+ launcher:minCellWidthDps="80"
+ launcher:iconImageSize="60"
+ launcher:iconTextSize="14"
+ launcher:borderSpaceDps="16"
+ launcher:allAppsIconSize="60"
+ launcher:allAppsIconTextSize="14"
+ launcher:allAppsCellSpacingDps="16"
+ launcher:canBeDefault="true" />
+
+ </grid-option>
+
</profiles>
\ No newline at end of file
diff --git a/res/xml/device_profiles_split.xml b/res/xml/device_profiles_split.xml
deleted file mode 100644
index 2fad0c9..0000000
--- a/res/xml/device_profiles_split.xml
+++ /dev/null
@@ -1,137 +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.
--->
-
-<profiles xmlns:launcher="http://schemas.android.com/apk/res-auto" >
-
- <grid-option
- launcher:name="3_by_3"
- launcher:numRows="3"
- launcher:numColumns="3"
- launcher:numFolderRows="2"
- launcher:numFolderColumns="3"
- launcher:numHotseatIcons="3"
- launcher:dbFile="launcher_3_by_3.db"
- launcher:defaultLayoutId="@xml/default_workspace_3x3" >
-
- <display-option
- launcher:name="Super Short Stubby"
- launcher:minWidthDps="255"
- launcher:minHeightDps="300"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Shorter Stubby"
- launcher:minWidthDps="255"
- launcher:minHeightDps="400"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- </grid-option>
-
- <grid-option
- launcher:name="4_by_4"
- launcher:numRows="4"
- launcher:numColumns="4"
- launcher:numFolderRows="3"
- launcher:numFolderColumns="4"
- launcher:numHotseatIcons="4"
- launcher:dbFile="launcher_4_by_4.db"
- launcher:defaultLayoutId="@xml/default_workspace_4x4" >
-
- <display-option
- launcher:name="Short Stubby"
- launcher:minWidthDps="275"
- launcher:minHeightDps="420"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Stubby"
- launcher:minWidthDps="255"
- launcher:minHeightDps="450"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Nexus S"
- launcher:minWidthDps="296"
- launcher:minHeightDps="491.33"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Nexus 4"
- launcher:minWidthDps="359"
- launcher:minHeightDps="567"
- launcher:iconImageSize="54"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Nexus 5"
- launcher:minWidthDps="335"
- launcher:minHeightDps="567"
- launcher:iconImageSize="54"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- </grid-option>
-
- <grid-option
- launcher:name="5_by_5"
- launcher:numRows="5"
- launcher:numColumns="5"
- launcher:numFolderRows="4"
- launcher:numFolderColumns="4"
- launcher:numHotseatIcons="5"
- launcher:numExtendedHotseatIcons="8"
- launcher:dbFile="launcher.db"
- launcher:defaultLayoutId="@xml/default_workspace_5x5" >
-
- <display-option
- launcher:name="Large Phone"
- launcher:minWidthDps="406"
- launcher:minHeightDps="694"
- launcher:iconImageSize="56"
- launcher:iconTextSize="14.4"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Large Phone Split Display"
- launcher:minWidthDps="406"
- launcher:minHeightDps="694"
- launcher:iconImageSize="56"
- launcher:iconTextSize="14.4"
- launcher:canBeDefault="true" />
-
- <display-option
- launcher:name="Shorter Stubby"
- launcher:minWidthDps="255"
- launcher:minHeightDps="400"
- launcher:iconImageSize="48"
- launcher:iconTextSize="13.0"
- launcher:canBeDefault="true" />
-
- </grid-option>
-
-</profiles>
\ No newline at end of file
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index e64ea90..d2b9dfe 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -16,13 +16,10 @@
package com.android.launcher3;
-import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
-
import static com.android.launcher3.ResourceUtils.pxFromDp;
import static com.android.launcher3.Utilities.dpiFromPx;
import static com.android.launcher3.Utilities.pxFromSp;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
-import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -64,7 +61,6 @@
public final boolean isPhone;
public final boolean transposeLayoutWithOrientation;
public final boolean isTwoPanels;
- public final boolean allowRotation;
// Device properties in current orientation
public final boolean isLandscape;
@@ -191,6 +187,7 @@
public final int overviewActionsMarginThreeButtonPx;
public final int overviewActionsTopMarginGesturePx;
public final int overviewActionsBottomMarginGesturePx;
+ public final int overviewActionsButtonSpacing;
public int overviewPageSpacing;
public int overviewRowSpacing;
public int overviewGridSideMargin;
@@ -244,12 +241,7 @@
availableHeightPx = windowBounds.availableSize.y;
mInfo = info;
- // If the device's pixel density was scaled (usually via settings for A11y), use the
- // original dimensions to determine if rotation is allowed of not.
- float originalSmallestWidth = dpiFromPx(Math.min(widthPx, heightPx), DENSITY_DEVICE_STABLE);
- allowRotation = originalSmallestWidth >= MIN_TABLET_WIDTH;
- // Tablet UI does not support emulated landscape.
- isTablet = allowRotation && info.isTablet(windowBounds);
+ isTablet = info.isTablet(windowBounds);
isPhone = !isTablet;
isTwoPanels = isTablet && useTwoPanels;
@@ -380,25 +372,35 @@
R.dimen.overview_actions_top_margin_gesture_grid_landscape);
overviewActionsBottomMarginGesturePx = res.getDimensionPixelSize(
R.dimen.overview_actions_bottom_margin_gesture_grid_landscape);
+ overviewPageSpacing = res.getDimensionPixelSize(
+ R.dimen.overview_page_spacing_grid_landscape);
} else {
overviewActionsTopMarginGesturePx = res.getDimensionPixelSize(
R.dimen.overview_actions_top_margin_gesture_grid_portrait);
overviewActionsBottomMarginGesturePx = res.getDimensionPixelSize(
R.dimen.overview_actions_bottom_margin_gesture_grid_portrait);
+ overviewPageSpacing = res.getDimensionPixelSize(
+ R.dimen.overview_page_spacing_grid_portrait);
}
+ overviewActionsButtonSpacing = res.getDimensionPixelSize(
+ R.dimen.overview_actions_button_spacing_grid);
} else {
overviewActionsTopMarginGesturePx = res.getDimensionPixelSize(
R.dimen.overview_actions_margin_gesture);
overviewActionsBottomMarginGesturePx = overviewActionsTopMarginGesturePx;
+ overviewActionsButtonSpacing = res.getDimensionPixelSize(
+ R.dimen.overview_actions_button_spacing);
+ overviewPageSpacing = res.getDimensionPixelSize(R.dimen.overview_page_spacing);
}
overviewActionsMarginThreeButtonPx = res.getDimensionPixelSize(
R.dimen.overview_actions_margin_three_button);
- overviewPageSpacing = overviewShowAsGrid
- ? res.getDimensionPixelSize(R.dimen.recents_page_spacing_grid)
- : res.getDimensionPixelSize(R.dimen.recents_page_spacing);
- overviewRowSpacing = isLandscape
- ? res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing_landscape)
- : res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing_portrait);
+ // Grid task's top margin is only overviewTaskIconSizePx + overviewTaskMarginGridPx, but
+ // overviewTaskThumbnailTopMarginPx is applied to all TaskThumbnailView, so exclude the
+ // extra margin when calculating row spacing.
+ int extraTopMargin = overviewTaskThumbnailTopMarginPx - overviewTaskIconSizePx
+ - overviewTaskMarginGridPx;
+ overviewRowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing)
+ - extraTopMargin;
overviewGridSideMargin = isLandscape
? res.getDimensionPixelSize(R.dimen.overview_grid_side_margin_landscape)
: res.getDimensionPixelSize(R.dimen.overview_grid_side_margin_portrait);
@@ -822,15 +824,23 @@
Point padding = getTotalWorkspacePadding();
int numColumns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
- int cellLayoutTotalPadding =
- isTwoPanels ? 4 * cellLayoutPaddingLeftRightPx : 2 * cellLayoutPaddingLeftRightPx;
- int screenWidthPx = availableWidthPx - padding.x - cellLayoutTotalPadding;
+ int screenWidthPx = getWorkspaceWidth(padding);
result.x = calculateCellWidth(screenWidthPx, cellLayoutBorderSpacePx.x, numColumns);
result.y = calculateCellHeight(availableHeightPx - padding.y
- cellLayoutBottomPaddingPx, cellLayoutBorderSpacePx.y, inv.numRows);
return result;
}
+ public int getWorkspaceWidth() {
+ return getWorkspaceWidth(getTotalWorkspacePadding());
+ }
+
+ public int getWorkspaceWidth(Point workspacePadding) {
+ int cellLayoutTotalPadding =
+ isTwoPanels ? 4 * cellLayoutPaddingLeftRightPx : 2 * cellLayoutPaddingLeftRightPx;
+ return availableWidthPx - workspacePadding.x - cellLayoutTotalPadding;
+ }
+
public Point getTotalWorkspacePadding() {
updateWorkspacePadding();
return new Point(workspacePadding.left + workspacePadding.right,
@@ -1031,7 +1041,6 @@
writer.println(prefix + "DeviceProfile:");
writer.println(prefix + "\t1 dp = " + mMetrics.density + " px");
- writer.println(prefix + "\tallowRotation:" + allowRotation);
writer.println(prefix + "\tisTablet:" + isTablet);
writer.println(prefix + "\tisPhone:" + isPhone);
writer.println(prefix + "\ttransposeLayoutWithOrientation:"
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index d844b87..ff7a90c 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -42,6 +42,7 @@
import android.util.Xml;
import android.view.Display;
+import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -58,6 +59,8 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -70,6 +73,13 @@
public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_PHONE, TYPE_MULTI_DISPLAY, TYPE_TABLET})
+ public @interface DeviceType{}
+ public static final int TYPE_PHONE = 0;
+ public static final int TYPE_MULTI_DISPLAY = 1;
+ public static final int TYPE_TABLET = 2;
+
private static final String KEY_IDP_GRID_NAME = "idp_grid_name";
private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
@@ -106,7 +116,7 @@
public float[] iconTextSize;
public int iconBitmapSize;
public int fillResIconDpi;
- public boolean isSplitDisplay;
+ public @DeviceType int deviceType;
public PointF[] minCellSize;
@@ -198,13 +208,21 @@
String gridName = getCurrentGridName(context);
// Get the display info based on default display and interpolate it to existing display
+ Info defaultInfo = DisplayController.INSTANCE.get(context).getInfo();
+ @DeviceType int defaultDeviceType = getDeviceType(defaultInfo);
DisplayOption defaultDisplayOption = invDistWeightedInterpolate(
- DisplayController.INSTANCE.get(context).getInfo(),
- getPredefinedDeviceProfiles(context, gridName, false, false), false);
+ defaultInfo,
+ getPredefinedDeviceProfiles(context, gridName, defaultDeviceType,
+ /*allowDisabledGrid=*/false),
+ defaultDeviceType);
Info myInfo = new Info(context, display);
+ @DeviceType int deviceType = getDeviceType(myInfo);
DisplayOption myDisplayOption = invDistWeightedInterpolate(
- myInfo, getPredefinedDeviceProfiles(context, gridName, false, false), false);
+ myInfo,
+ getPredefinedDeviceProfiles(context, gridName, deviceType,
+ /*allowDisabledGrid=*/false),
+ deviceType);
DisplayOption result = new DisplayOption(defaultDisplayOption.grid)
.add(myDisplayOption);
@@ -220,7 +238,7 @@
System.arraycopy(defaultDisplayOption.borderSpaces, 0, result.borderSpaces, 0,
COUNT_SIZES);
- initGrid(context, myInfo, result, false);
+ initGrid(context, myInfo, result, deviceType);
}
/**
@@ -246,6 +264,18 @@
}
}
+ private static @DeviceType int getDeviceType(Info displayInfo) {
+ // Each screen has two profiles (portrait/landscape), so devices with four or more
+ // supported profiles implies two or more internal displays.
+ if (displayInfo.supportedBounds.size() >= 4 && ENABLE_TWO_PANEL_HOME.get()) {
+ return TYPE_MULTI_DISPLAY;
+ } else if (displayInfo.supportedBounds.stream().allMatch(displayInfo::isTablet)) {
+ return TYPE_TABLET;
+ } else {
+ return TYPE_PHONE;
+ }
+ }
+
public static String getCurrentGridName(Context context) {
return Utilities.isGridOptionsEnabled(context)
? Utilities.getPrefs(context).getString(KEY_IDP_GRID_NAME, null) : null;
@@ -253,23 +283,19 @@
private String initGrid(Context context, String gridName) {
Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
- // Each screen has two profiles (portrait/landscape), so devices with four or more
- // supported profiles implies two or more internal displays.
- boolean isSplitDisplay =
- displayInfo.supportedBounds.size() >= 4 && ENABLE_TWO_PANEL_HOME.get();
+ @DeviceType int deviceType = getDeviceType(displayInfo);
ArrayList<DisplayOption> allOptions =
- getPredefinedDeviceProfiles(context, gridName, isSplitDisplay,
+ getPredefinedDeviceProfiles(context, gridName, deviceType,
RestoreDbTask.isPending(context));
DisplayOption displayOption =
- invDistWeightedInterpolate(displayInfo, allOptions, isSplitDisplay);
- initGrid(context, displayInfo, displayOption, isSplitDisplay);
+ invDistWeightedInterpolate(displayInfo, allOptions, deviceType);
+ initGrid(context, displayInfo, displayOption, deviceType);
return displayOption.grid.name;
}
- private void initGrid(
- Context context, Info displayInfo, DisplayOption displayOption,
- boolean isSplitDisplay) {
+ private void initGrid(Context context, Info displayInfo, DisplayOption displayOption,
+ @DeviceType int deviceType) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
GridOption closestProfile = displayOption.grid;
numRows = closestProfile.numRows;
@@ -281,12 +307,16 @@
numFolderColumns = closestProfile.numFolderColumns;
isScalable = closestProfile.isScalable;
devicePaddingId = closestProfile.devicePaddingId;
- this.isSplitDisplay = isSplitDisplay;
+ this.deviceType = deviceType;
mExtraAttrs = closestProfile.extraAttrs;
iconSize = displayOption.iconSizes;
- iconBitmapSize = ResourceUtils.pxFromDp(iconSize[INDEX_DEFAULT], metrics);
+ float maxIconSize = iconSize[0];
+ for (int i = 1; i < iconSize.length; i++) {
+ maxIconSize = Math.max(maxIconSize, iconSize[i]);
+ }
+ iconBitmapSize = ResourceUtils.pxFromDp(maxIconSize, metrics);
fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
iconTextSize = displayOption.textSizes;
@@ -299,11 +329,11 @@
horizontalMargin = displayOption.horizontalMargin;
numShownHotseatIcons = closestProfile.numHotseatIcons;
- numDatabaseHotseatIcons = isSplitDisplay
+ numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;
numAllAppsColumns = closestProfile.numAllAppsColumns;
- numDatabaseAllAppsColumns = isSplitDisplay
+ numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;
if (!Utilities.isGridOptionsEnabled(context)) {
@@ -323,7 +353,7 @@
defaultWallpaperSize = new Point(displayInfo.currentSize);
for (WindowBounds bounds : displayInfo.supportedBounds) {
localSupportedProfiles.add(new DeviceProfile.Builder(context, this, displayInfo)
- .setUseTwoPanels(isSplitDisplay)
+ .setUseTwoPanels(deviceType == TYPE_MULTI_DISPLAY)
.setWindowBounds(bounds).build());
// Wallpaper size should be the maximum of the all possible sizes Launcher expects
@@ -346,11 +376,6 @@
defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
}
- @Nullable
- public TypedValue getAttrValue(int attr) {
- return mExtraAttrs == null ? null : mExtraAttrs.get(attr);
- }
-
public void addOnChangeListener(OnIDPChangeListener listener) {
mChangeListeners.add(listener);
}
@@ -385,12 +410,11 @@
}
}
- private static ArrayList<DisplayOption> getPredefinedDeviceProfiles(
- Context context, String gridName, boolean isSplitDisplay, boolean allowDisabledGrid) {
+ private static ArrayList<DisplayOption> getPredefinedDeviceProfiles(Context context,
+ String gridName, @DeviceType int deviceType, boolean allowDisabledGrid) {
ArrayList<DisplayOption> profiles = new ArrayList<>();
- int xmlResource = isSplitDisplay ? R.xml.device_profiles_split : R.xml.device_profiles;
- try (XmlResourceParser parser = context.getResources().getXml(xmlResource)) {
+ try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
@@ -398,8 +422,8 @@
if ((type == XmlPullParser.START_TAG)
&& GridOption.TAG_NAME.equals(parser.getName())) {
- GridOption gridOption =
- new GridOption(context, Xml.asAttributeSet(parser), isSplitDisplay);
+ GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser),
+ deviceType);
if (gridOption.isEnabled || allowDisabledGrid) {
final int displayDepth = parser.getDepth();
while (((type = parser.next()) != XmlPullParser.END_TAG
@@ -446,9 +470,8 @@
*/
public List<GridOption> parseAllGridOptions(Context context) {
List<GridOption> result = new ArrayList<>();
- int xmlResource = isSplitDisplay ? R.xml.device_profiles_split : R.xml.device_profiles;
- try (XmlResourceParser parser = context.getResources().getXml(xmlResource)) {
+ try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG
@@ -456,7 +479,7 @@
if ((type == XmlPullParser.START_TAG)
&& GridOption.TAG_NAME.equals(parser.getName())) {
GridOption option =
- new GridOption(context, Xml.asAttributeSet(parser), isSplitDisplay);
+ new GridOption(context, Xml.asAttributeSet(parser), deviceType);
if (option.isEnabled) {
result.add(option);
}
@@ -510,12 +533,12 @@
}
private static DisplayOption invDistWeightedInterpolate(
- Info displayInfo, ArrayList<DisplayOption> points, boolean isSplitDisplay) {
+ Info displayInfo, ArrayList<DisplayOption> points, @DeviceType int deviceType) {
int minWidthPx = Integer.MAX_VALUE;
int minHeightPx = Integer.MAX_VALUE;
for (WindowBounds bounds : displayInfo.supportedBounds) {
boolean isTablet = displayInfo.isTablet(bounds);
- if (isTablet && isSplitDisplay) {
+ if (isTablet && deviceType == TYPE_MULTI_DISPLAY) {
// For split displays, take half width per page
minWidthPx = Math.min(minWidthPx, bounds.availableSize.x / 2);
minHeightPx = Math.min(minHeightPx, bounds.availableSize.y);
@@ -555,13 +578,10 @@
}
out.multiply(1.0f / weights);
- // Since the bitmaps are persisted, ensure that the default bitmap size is same as
+ // Since the bitmaps are persisted, ensure that all bitmap sizes are not larger than
// predefined size to avoid cache invalidation
- out.iconSizes[INDEX_DEFAULT] =
- closestPoint.iconSizes[INDEX_DEFAULT];
- for (int i = INDEX_DEFAULT + 1; i < COUNT_SIZES; i++) {
- out.iconSizes[i] = Math.min(out.iconSizes[i],
- out.iconSizes[INDEX_DEFAULT]);
+ for (int i = INDEX_DEFAULT; i < COUNT_SIZES; i++) {
+ out.iconSizes[i] = Math.min(out.iconSizes[i], closestPoint.iconSizes[i]);
}
return out;
@@ -642,6 +662,12 @@
public static final String TAG_NAME = "grid-option";
+ private static final int DEVICE_CATEGORY_PHONE = 1 << 0;
+ private static final int DEVICE_CATEGORY_TABLET = 1 << 1;
+ private static final int DEVICE_CATEGORY_MULTI_DISPLAY = 1 << 2;
+ private static final int DEVICE_CATEGORY_ALL =
+ DEVICE_CATEGORY_PHONE | DEVICE_CATEGORY_TABLET | DEVICE_CATEGORY_MULTI_DISPLAY;
+
public final String name;
public final int numRows;
public final int numColumns;
@@ -665,7 +691,7 @@
private final SparseArray<TypedValue> extraAttrs;
- public GridOption(Context context, AttributeSet attrs, boolean isSplitDisplay) {
+ public GridOption(Context context, AttributeSet attrs, @DeviceType int deviceType) {
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridDisplayOption);
name = a.getString(R.styleable.GridDisplayOption_name);
@@ -673,7 +699,7 @@
numColumns = a.getInt(R.styleable.GridDisplayOption_numColumns, 0);
dbFile = a.getString(R.styleable.GridDisplayOption_dbFile);
- defaultLayoutId = a.getResourceId(isSplitDisplay && a.hasValue(
+ defaultLayoutId = a.getResourceId(deviceType == TYPE_MULTI_DISPLAY && a.hasValue(
R.styleable.GridDisplayOption_defaultSplitDisplayLayoutId)
? R.styleable.GridDisplayOption_defaultSplitDisplayLayoutId
: R.styleable.GridDisplayOption_defaultLayoutId, 0);
@@ -700,7 +726,15 @@
devicePaddingId = a.getResourceId(
R.styleable.GridDisplayOption_devicePaddingId, 0);
- isEnabled = a.getBoolean(R.styleable.GridDisplayOption_gridEnabled, true);
+ int deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
+ DEVICE_CATEGORY_ALL);
+ isEnabled = (deviceType == TYPE_PHONE
+ && ((deviceCategory & DEVICE_CATEGORY_PHONE) == DEVICE_CATEGORY_PHONE))
+ || (deviceType == TYPE_TABLET
+ && ((deviceCategory & DEVICE_CATEGORY_TABLET) == DEVICE_CATEGORY_TABLET))
+ || (deviceType == TYPE_MULTI_DISPLAY
+ && ((deviceCategory & DEVICE_CATEGORY_MULTI_DISPLAY)
+ == DEVICE_CATEGORY_MULTI_DISPLAY));
a.recycle();
extraAttrs = Themes.createValueMap(context, attrs,
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8154168..81a0d5b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -29,6 +29,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
@@ -39,6 +40,7 @@
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
+import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -55,6 +57,7 @@
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
+import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -90,6 +93,7 @@
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.UserHandle;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
@@ -215,6 +219,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -1632,6 +1637,8 @@
AbstractFloatingView.closeOpenViews(this, false, TYPE_ALL & ~TYPE_REBIND_SAFE);
finishAutoCancelActionMode();
+ DragView.removeAllViews(this);
+
if (mPendingRequestArgs != null) {
outState.putParcelable(RUNTIME_STATE_PENDING_REQUEST_ARGS, mPendingRequestArgs);
}
@@ -2674,6 +2681,79 @@
}
}
+ /**
+ * Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
+ * animation.
+ *
+ * @param preferredItemId The id of the preferred item to match to if it exists.
+ * @param packageName The package name of the app to match.
+ * @param user The user of the app to match.
+ */
+ public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user) {
+ final ItemInfoMatcher preferredItem = (info, cn) ->
+ info != null && info.id == preferredItemId;
+ final ItemInfoMatcher packageAndUserAndApp = (info, cn) ->
+ info != null
+ && info.itemType == ITEM_TYPE_APPLICATION
+ && info.user.equals(user)
+ && info.getTargetComponent() != null
+ && TextUtils.equals(info.getTargetComponent().getPackageName(),
+ packageName);
+
+ if (isInState(LauncherState.ALL_APPS)) {
+ return getFirstMatch(Collections.singletonList(mAppsView.getActiveRecyclerView()),
+ preferredItem, packageAndUserAndApp);
+ } else {
+ List<ViewGroup> containers = new ArrayList<>(mWorkspace.getPanelCount() + 1);
+ containers.add(mWorkspace.getHotseat().getShortcutsAndWidgets());
+ mWorkspace.forEachVisiblePage(page
+ -> containers.add(((CellLayout) page).getShortcutsAndWidgets()));
+
+ // Order: Preferred item by itself or in folder, then by matching package/user
+ if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
+ return getFirstMatch(containers, preferredItem, forFolderMatch(preferredItem),
+ packageAndUserAndApp, forFolderMatch(packageAndUserAndApp));
+ } else {
+ // Do not use Folder as a criteria, since it'll cause a crash when trying to draw
+ // FolderAdaptiveIcon as the background.
+ return getFirstMatch(containers, preferredItem, packageAndUserAndApp);
+ }
+ }
+ }
+
+ /**
+ * Finds the first view matching the ordered operators across the given viewgroups in order.
+ * @param containers List of ViewGroups to scan, in order of preference.
+ * @param operators List of operators, in order starting from best matching operator.
+ */
+ private static View getFirstMatch(Iterable<ViewGroup> containers,
+ final ItemInfoMatcher... operators) {
+ for (ItemInfoMatcher operator : operators) {
+ for (ViewGroup container : containers) {
+ View match = mapOverViewGroup(container, operator);
+ if (match != null) {
+ return match;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the first view matching the operator in the given ViewGroups, or null if none.
+ * Forward iteration matters.
+ */
+ private static View mapOverViewGroup(ViewGroup container, ItemInfoMatcher op) {
+ final int itemCount = container.getChildCount();
+ for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
+ View item = container.getChildAt(itemIdx);
+ if (op.matchesInfo((ItemInfo) item.getTag())) {
+ return item;
+ }
+ }
+ return null;
+ }
+
private ValueAnimator createNewAppBounceAnimation(View v, int i) {
ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v)
.setDuration(ItemInstallQueue.NEW_SHORTCUT_BOUNCE_DURATION);
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index 64f1d95..e59eac8 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -16,6 +16,7 @@
private static final String XML = ".xml";
public static final String LAUNCHER_DB = "launcher.db";
+ public static final String LAUNCHER_6_BY_5_DB = "launcher_6_by_5.db";
public static final String LAUNCHER_4_BY_5_DB = "launcher_4_by_5.db";
public static final String LAUNCHER_4_BY_4_DB = "launcher_4_by_4.db";
public static final String LAUNCHER_3_BY_3_DB = "launcher_3_by_3.db";
@@ -32,6 +33,7 @@
public static final List<String> GRID_DB_FILES = Collections.unmodifiableList(Arrays.asList(
LAUNCHER_DB,
+ LAUNCHER_6_BY_5_DB,
LAUNCHER_4_BY_5_DB,
LAUNCHER_4_BY_4_DB,
LAUNCHER_3_BY_3_DB,
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 15378e0..be2cd88 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -57,10 +57,9 @@
public static final int ALL_APPS_CONTENT = 1 << 1;
public static final int VERTICAL_SWIPE_INDICATOR = 1 << 2;
public static final int OVERVIEW_ACTIONS = 1 << 3;
- public static final int TASKBAR = 1 << 4;
- public static final int CLEAR_ALL_BUTTON = 1 << 5;
- public static final int WORKSPACE_PAGE_INDICATOR = 1 << 6;
- public static final int SPLIT_PLACHOLDER_VIEW = 1 << 7;
+ public static final int CLEAR_ALL_BUTTON = 1 << 4;
+ public static final int WORKSPACE_PAGE_INDICATOR = 1 << 5;
+ public static final int SPLIT_PLACHOLDER_VIEW = 1 << 6;
// Flag indicating workspace has multiple pages visible.
public static final int FLAG_MULTI_PAGE = BaseState.getFlag(0);
@@ -186,7 +185,7 @@
}
public int getVisibleElements(Launcher launcher) {
- return HOTSEAT_ICONS | WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR | TASKBAR;
+ return HOTSEAT_ICONS | WORKSPACE_PAGE_INDICATOR | VERTICAL_SWIPE_INDICATOR;
}
/**
@@ -197,10 +196,16 @@
return (getVisibleElements(launcher) & elements) == elements;
}
- public boolean isTaskbarStashed() {
+ /** Returns whether taskbar is stashed and thus should replace hotseat with a handle */
+ public boolean isTaskbarStashed(Launcher launcher) {
return false;
}
+ /** Returns whether taskbar is aligned with the hotseat vs position inside apps */
+ public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
+ return !isTaskbarStashed(launcher);
+ }
+
/**
* Fraction shift in the vertical translation UI and related properties
*
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index cefadf7..2c14f07 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -252,7 +252,7 @@
if (0 <= mCurrentPage && mCurrentPage < getPageCount()) {
newPosition = getScrollForPage(mCurrentPage) + mCurrentPageScrollDiff;
}
- mOrientationHandler.set(this, VIEW_SCROLL_TO, newPosition);
+ mOrientationHandler.setPrimary(this, VIEW_SCROLL_TO, newPosition);
mScroller.startScroll(mScroller.getCurrX(), 0, newPosition - mScroller.getCurrX(), 0);
forceFinishScroller();
}
@@ -556,7 +556,7 @@
int oldPos = mOrientationHandler.getPrimaryScroll(this);
int newPos = mScroller.getCurrX();
if (oldPos != newPos) {
- mOrientationHandler.set(this, VIEW_SCROLL_TO, mScroller.getCurrX());
+ mOrientationHandler.setPrimary(this, VIEW_SCROLL_TO, mScroller.getCurrX());
}
if (mAllowOverScroll) {
@@ -1280,7 +1280,7 @@
mLastMotionRemainder = delta - movedDelta;
if (delta != 0) {
- mOrientationHandler.set(this, VIEW_SCROLL_BY, movedDelta);
+ mOrientationHandler.setPrimary(this, VIEW_SCROLL_BY, movedDelta);
if (mAllowOverScroll) {
final float pulledToX = oldScroll + delta;
@@ -1749,20 +1749,23 @@
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
final boolean pagesFlipped = isPageOrderFlipped();
- int offset = (mAllowOverScroll ? 0 : 1);
- info.setScrollable(getPageCount() > offset);
- if (getCurrentPage() < getPageCount() - offset) {
+ info.setScrollable(getPageCount() > 0);
+ int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+ if (getCurrentPage() < getPageCount() - getPanelCount()
+ || (getCurrentPage() == getPageCount() - getPanelCount()
+ && primaryScroll != getScrollForPage(getPageCount() - getPanelCount()))) {
info.addAction(pagesFlipped ?
- AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD
- : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD
+ : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
info.addAction(mIsRtl ?
AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT
: AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);
}
- if (getCurrentPage() >= offset) {
+ if (getCurrentPage() > 0
+ || (getCurrentPage() == 0 && primaryScroll != getScrollForPage(0))) {
info.addAction(pagesFlipped ?
- AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD
- : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD
+ : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
info.addAction(mIsRtl ?
AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT
: AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);
@@ -1807,16 +1810,16 @@
} break;
case android.R.id.accessibilityActionPageRight: {
if (!mIsRtl) {
- return scrollRight();
+ return scrollRight();
} else {
- return scrollLeft();
+ return scrollLeft();
}
}
case android.R.id.accessibilityActionPageLeft: {
if (!mIsRtl) {
- return scrollLeft();
+ return scrollLeft();
} else {
- return scrollRight();
+ return scrollRight();
}
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 203df0a..281dfea 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -26,7 +26,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
-import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
@@ -51,7 +50,6 @@
import android.os.Message;
import android.os.Parcelable;
import android.os.UserHandle;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -3146,62 +3144,6 @@
return layouts;
}
- /**
- * Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
- * animation.
- *
- * @param preferredItemId The id of the preferred item to match to if it exists.
- * @param packageName The package name of the app to match.
- * @param user The user of the app to match.
- */
- public View getFirstMatchForAppClose(int preferredItemId, String packageName, UserHandle user) {
- final ItemOperator preferredItem = (ItemInfo info, View view) ->
- info != null && info.id == preferredItemId;
- final ItemOperator preferredItemInFolder = (info, view) -> {
- if (info instanceof FolderInfo) {
- FolderInfo folderInfo = (FolderInfo) info;
- for (WorkspaceItemInfo shortcutInfo : folderInfo.contents) {
- if (preferredItem.evaluate(shortcutInfo, view)) {
- return true;
- }
- }
- }
- return false;
- };
- final ItemOperator packageAndUserAndApp = (ItemInfo info, View view) ->
- info != null
- && info.itemType == ITEM_TYPE_APPLICATION
- && info.user.equals(user)
- && info.getTargetComponent() != null
- && TextUtils.equals(info.getTargetComponent().getPackageName(),
- packageName);
- final ItemOperator packageAndUserAndAppInFolder = (info, view) -> {
- if (info instanceof FolderInfo) {
- FolderInfo folderInfo = (FolderInfo) info;
- for (WorkspaceItemInfo shortcutInfo : folderInfo.contents) {
- if (packageAndUserAndApp.evaluate(shortcutInfo, view)) {
- return true;
- }
- }
- }
- return false;
- };
-
- List<CellLayout> cellLayouts = new ArrayList<>(getPanelCount() + 1);
- cellLayouts.add(getHotseat());
- forEachVisiblePage(page -> cellLayouts.add((CellLayout) page));
-
- // Order: Preferred item, App icons in hotseat/workspace, app in folder in hotseat/workspace
- if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
- return getFirstMatch(cellLayouts, preferredItem, preferredItemInFolder,
- packageAndUserAndApp, packageAndUserAndAppInFolder);
- } else {
- // Do not use Folder as a criteria, since it'll cause a crash when trying to draw
- // FolderAdaptiveIcon as the background.
- return getFirstMatch(cellLayouts, preferredItem, packageAndUserAndApp);
- }
- }
-
public View getHomescreenIconByItemId(final int id) {
return getFirstMatch((info, v) -> info != null && info.id == id);
}
@@ -3227,23 +3169,6 @@
return value[0];
}
- /**
- * Finds the first view matching the ordered operators across the given cell layouts by order.
- * @param cellLayouts List of CellLayouts to scan, in order of preference.
- * @param operators List of operators, in order starting from best matching operator.
- */
- View getFirstMatch(Iterable<CellLayout> cellLayouts, final ItemOperator... operators) {
- for (ItemOperator operator : operators) {
- for (CellLayout cellLayout : cellLayouts) {
- View match = mapOverCellLayout(cellLayout, operator);
- if (match != null) {
- return match;
- }
- }
- }
- return null;
- }
-
void clearDropTargets() {
mapOverItems(new ItemOperator() {
@Override
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
index 729523f..8d77b4b 100644
--- a/src/com/android/launcher3/anim/PropertySetter.java
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -16,6 +16,7 @@
package com.android.launcher3.anim;
+import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.util.FloatProperty;
import android.util.IntProperty;
@@ -64,4 +65,9 @@
TimeInterpolator interpolator) {
property.setValue(target, value);
}
+
+ default void add(Animator animatorSet) {
+ animatorSet.setDuration(0);
+ animatorSet.start();
+ }
}
diff --git a/src/com/android/launcher3/anim/RevealOutlineAnimation.java b/src/com/android/launcher3/anim/RevealOutlineAnimation.java
index f99dabc..f5a746f 100644
--- a/src/com/android/launcher3/anim/RevealOutlineAnimation.java
+++ b/src/com/android/launcher3/anim/RevealOutlineAnimation.java
@@ -26,9 +26,27 @@
/** Sets the progress, from 0 to 1, of the reveal animation. */
abstract void setProgress(float progress);
+ /**
+ * @see #createRevealAnimator(View, boolean, float) where startProgress is set to 0.
+ */
public ValueAnimator createRevealAnimator(final View revealView, boolean isReversed) {
- ValueAnimator va =
- isReversed ? ValueAnimator.ofFloat(1f, 0f) : ValueAnimator.ofFloat(0f, 1f);
+ return createRevealAnimator(revealView, isReversed, 0f /* startProgress */);
+ }
+
+ /**
+ * Animates the given View's ViewOutline according to {@link #setProgress(float)}.
+ * @param revealView The View whose outline we are animating.
+ * @param isReversed Whether we are hiding rather than revealing the View.
+ * @param startProgress The progress at which to start the newly created animation. Useful if
+ * the previous reveal animation was cancelled and we want to create a new animation where it
+ * left off. Note that if isReversed=true, we start at 1 - startProgress (and go to 0).
+ * @return The Animator, which the caller must start.
+ */
+ public ValueAnimator createRevealAnimator(final View revealView, boolean isReversed,
+ float startProgress) {
+ ValueAnimator va = isReversed
+ ? ValueAnimator.ofFloat(1f - startProgress, 0f)
+ : ValueAnimator.ofFloat(startProgress, 1f);
final float elevation = revealView.getElevation();
va.addListener(new AnimatorListenerAdapter() {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 98cb5ae..2d31aa4 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,9 +92,6 @@
public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
"ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
- public static final BooleanFlag ENABLE_ONE_SEARCH = new DeviceFlag("ENABLE_ONE_SEARCH", false,
- "Use homescreen search box to complete allApps searches");
-
public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(
"ENABLE_TWOLINE_ALLAPPS", false, "Enables two line label inside all apps.");
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index fa65945..c37613f 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -565,4 +565,19 @@
iv.setImageDrawable(drawable);
return iv;
}
+
+ /**
+ * Removes any stray DragView from the DragLayer.
+ */
+ public static void removeAllViews(ActivityContext activity) {
+ BaseDragLayer dragLayer = activity.getDragLayer();
+ // Iterate in reverse order. DragView is added later to the dragLayer,
+ // and will be one of the last views.
+ for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
+ View child = dragLayer.getChildAt(i);
+ if (child instanceof DragView) {
+ dragLayer.removeView(child);
+ }
+ }
+ }
}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 13ad90e..d3351dc 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -31,6 +31,8 @@
import android.util.ArraySet;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Workspace;
@@ -215,6 +217,19 @@
}
public synchronized void addItem(Context context, ItemInfo item, boolean newItem) {
+ addItem(context, item, newItem, null);
+ }
+
+ public synchronized void addItem(
+ Context context, ItemInfo item, boolean newItem, @Nullable LoaderMemoryLogger logger) {
+ if (logger != null) {
+ logger.addLog(
+ Log.DEBUG,
+ TAG,
+ String.format("Adding item to ID map: %s", item.toString()),
+ /* stackTrace= */ null);
+ }
+
itemsIdMap.put(item.id, item);
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
index 0fc4c2d..fa11d4e 100644
--- a/src/com/android/launcher3/model/DeviceGridState.java
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -16,6 +16,8 @@
package com.android.launcher3.model;
+import static com.android.launcher3.InvariantDeviceProfile.DeviceType;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_2;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_3;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_4;
@@ -25,15 +27,10 @@
import android.content.SharedPreferences;
import android.text.TextUtils;
-import androidx.annotation.IntDef;
-
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
-import com.android.launcher3.util.IntSet;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
import java.util.Objects;
@@ -46,20 +43,6 @@
public static final String KEY_HOTSEAT_COUNT = "migration_src_hotseat_count";
public static final String KEY_DEVICE_TYPE = "migration_src_device_type";
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({TYPE_PHONE, TYPE_MULTI_DISPLAY, TYPE_TABLET})
- public @interface DeviceType{}
- public static final int TYPE_PHONE = 0;
- public static final int TYPE_MULTI_DISPLAY = 1;
- public static final int TYPE_TABLET = 2;
-
- private static final IntSet COMPATIBLE_TYPES = IntSet.wrap(TYPE_PHONE, TYPE_MULTI_DISPLAY);
-
- public static boolean deviceTypeCompatible(@DeviceType int typeA, @DeviceType int typeB) {
- return typeA == typeB
- || (COMPATIBLE_TYPES.contains(typeA) && COMPATIBLE_TYPES.contains(typeB));
- }
-
private final String mGridSizeString;
private final int mNumHotseat;
private final @DeviceType int mDeviceType;
@@ -67,11 +50,7 @@
public DeviceGridState(InvariantDeviceProfile idp) {
mGridSizeString = String.format(Locale.ENGLISH, "%d,%d", idp.numColumns, idp.numRows);
mNumHotseat = idp.numDatabaseHotseatIcons;
- mDeviceType = idp.supportedProfiles.size() > 2
- ? TYPE_MULTI_DISPLAY
- : idp.supportedProfiles.stream().allMatch(dp -> dp.isTablet)
- ? TYPE_TABLET
- : TYPE_PHONE;
+ mDeviceType = idp.deviceType;
}
public DeviceGridState(Context context) {
@@ -135,7 +114,6 @@
if (this == other) return true;
if (other == null) return false;
return mNumHotseat == other.mNumHotseat
- && deviceTypeCompatible(mDeviceType, other.mDeviceType)
&& Objects.equals(mGridSizeString, other.mGridSizeString);
}
}
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 47df538..08b38e8 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -383,18 +383,23 @@
info.cellY = getInt(cellYIndex);
}
+ public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
+ checkAndAddItem(info, dataModel, null);
+ }
+
/**
* Adds the {@param info} to {@param dataModel} if it does not overlap with any other item,
* otherwise marks it for deletion.
*/
- public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
+ public void checkAndAddItem(
+ ItemInfo info, BgDataModel dataModel, LoaderMemoryLogger logger) {
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
// Ensure that it is a valid intent. An exception here will
// cause the item loading to get skipped
ShortcutKey.fromItemInfo(info);
}
if (checkItemPlacement(info)) {
- dataModel.addItem(mContext, info, false);
+ dataModel.addItem(mContext, info, false, logger);
} else {
markDeleted("Item position overlap");
}
diff --git a/src/com/android/launcher3/model/LoaderMemoryLogger.java b/src/com/android/launcher3/model/LoaderMemoryLogger.java
new file mode 100644
index 0000000..f48efcb
--- /dev/null
+++ b/src/com/android/launcher3/model/LoaderMemoryLogger.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Helper logger that collects logs while {@code LoaderTask#run} executes and prints them all iff
+ * an exception is caught in {@code LoaderTask#run}.
+ */
+public class LoaderMemoryLogger {
+
+ private static final String TAG = "LoaderMemoryLogger";
+
+ private final ArrayList<LogEntry> mLogEntries = new ArrayList<>();
+
+ protected LoaderMemoryLogger() {}
+
+ protected void addLog(int logLevel, String tag, String log) {
+ addLog(logLevel, tag, log, null);
+ }
+
+ protected void addLog(
+ int logLevel, String tag, String log, Exception stackTrace) {
+ switch (logLevel) {
+ case Log.ASSERT:
+ case Log.ERROR:
+ case Log.DEBUG:
+ case Log.INFO:
+ case Log.VERBOSE:
+ case Log.WARN:
+ mLogEntries.add(new LogEntry(logLevel, tag, log, stackTrace));
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid log level provided: " + logLevel);
+
+ }
+ }
+
+ protected void clearLogs() {
+ mLogEntries.clear();
+ }
+
+ protected void printLogs() {
+ for (LogEntry logEntry : mLogEntries) {
+ String tag = String.format("%s: %s", TAG, logEntry.mLogTag);
+ String logString = logEntry.mStackStrace == null
+ ? logEntry.mLogString
+ : String.format(
+ "%s\n%s",
+ logEntry.mLogString,
+ Log.getStackTraceString(logEntry.mStackStrace));
+
+ Log.println(logEntry.mLogLevel, tag, logString);
+ }
+ clearLogs();
+ }
+
+ private static class LogEntry {
+
+ protected final int mLogLevel;
+ protected final String mLogTag;
+ protected final String mLogString;
+ @Nullable protected final Exception mStackStrace;
+
+ protected LogEntry(
+ int logLevel, String logTag, String logString, @Nullable Exception stackStrace) {
+ mLogLevel = logLevel;
+ mLogTag = logTag;
+ mLogString = logString;
+ mStackStrace = stackStrace;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index a4f6f7a..2a0f9a6 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -52,6 +52,8 @@
import android.util.LongSparseArray;
import android.util.TimingLogger;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
@@ -197,11 +199,12 @@
Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
TimingLogger logger = new TimingLogger(TAG, "run");
+ LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
Trace.beginSection("LoadWorkspace");
try {
- loadWorkspace(allShortcuts);
+ loadWorkspace(allShortcuts, memoryLogger);
} finally {
Trace.endSection();
}
@@ -311,9 +314,13 @@
mModelDelegate.modelLoadComplete();
transaction.commit();
+ memoryLogger.clearLogs();
} catch (CancellationException e) {
// Loader stopped, ignore
logASplit(logger, "Cancelled");
+ } catch (Exception e) {
+ memoryLogger.printLogs();
+ throw e;
} finally {
logger.dumpToLog();
}
@@ -325,13 +332,21 @@
this.notify();
}
- private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts) {
+ private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger logger) {
loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI,
- null /* selection */);
+ null /* selection */, logger);
}
- protected void loadWorkspace(List<ShortcutInfo> allDeepShortcuts, Uri contentUri,
- String selection) {
+ protected void loadWorkspace(
+ List<ShortcutInfo> allDeepShortcuts, Uri contentUri, String selection) {
+ loadWorkspace(allDeepShortcuts, contentUri, selection, null);
+ }
+
+ protected void loadWorkspace(
+ List<ShortcutInfo> allDeepShortcuts,
+ Uri contentUri,
+ String selection,
+ @Nullable LoaderMemoryLogger logger) {
final Context context = mApp.getContext();
final ContentResolver contentResolver = context.getContentResolver();
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
@@ -635,7 +650,7 @@
}
}
- c.checkAndAddItem(info, mBgDataModel);
+ c.checkAndAddItem(info, mBgDataModel, logger);
} else {
throw new RuntimeException("Unexpected null WorkspaceItemInfo");
}
@@ -654,7 +669,7 @@
// no special handling required for restored folders
c.markRestored();
- c.checkAndAddItem(folderInfo, mBgDataModel);
+ c.checkAndAddItem(folderInfo, mBgDataModel, logger);
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index b72f462..1e8e3ca 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -25,6 +25,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SETTINGS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_TASKSWITCHER;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WALLPAPERS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
import static com.android.launcher3.LauncherSettings.Favorites.EXTENDED_CONTAINERS;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
@@ -55,6 +56,7 @@
import com.android.launcher3.logger.LauncherAtom.Shortcut;
import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
import com.android.launcher3.logger.LauncherAtom.TaskSwitcherContainer;
+import com.android.launcher3.logger.LauncherAtom.WallpapersContainer;
import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.util.ContentWriter;
@@ -374,6 +376,7 @@
protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
itemBuilder.setIsWork(!Process.myUserHandle().equals(user));
+ itemBuilder.setRank(rank);
return itemBuilder;
}
@@ -428,6 +431,10 @@
return ContainerInfo.newBuilder()
.setTaskSwitcherContainer(TaskSwitcherContainer.getDefaultInstance())
.build();
+ case CONTAINER_WALLPAPERS:
+ return ContainerInfo.newBuilder()
+ .setWallpapersContainer(WallpapersContainer.getDefaultInstance())
+ .build();
case EXTENDED_CONTAINERS:
return ContainerInfo.newBuilder()
.setExtendedContainers(getExtendedContainer())
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 826c79b..af87275 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -41,8 +41,8 @@
implements View.OnClickListener {
private final int mIconResId;
- private final int mLabelResId;
- private final int mAccessibilityActionId;
+ protected final int mLabelResId;
+ protected int mAccessibilityActionId;
protected final T mTarget;
protected final ItemInfo mItemInfo;
@@ -139,11 +139,43 @@
public static class AppInfo<T extends Context & ActivityContext> extends SystemShortcut<T> {
+ @Nullable
+ private SplitAccessibilityInfo mSplitA11yInfo;
+
public AppInfo(T target, ItemInfo itemInfo) {
super(R.drawable.ic_info_no_shadow, R.string.app_info_drop_target_label, target,
itemInfo);
}
+ /**
+ * Constructor used by overview for staged split to provide custom A11y information.
+ *
+ * Future improvements considerations:
+ * Have the logic in {@link #createAccessibilityAction(Context)} be moved to super
+ * call in {@link SystemShortcut#createAccessibilityAction(Context)} by having
+ * SystemShortcut be aware of TaskContainers and staged split.
+ * That way it could directly create the correct node info for any shortcut that supports
+ * split, but then we'll need custom resIDs for each pair of shortcuts.
+ */
+ public AppInfo(T target, ItemInfo itemInfo, SplitAccessibilityInfo accessibilityInfo) {
+ this(target, itemInfo);
+ mSplitA11yInfo = accessibilityInfo;
+ mAccessibilityActionId = accessibilityInfo.nodeId;
+ }
+
+ @Override
+ public AccessibilityNodeInfo.AccessibilityAction createAccessibilityAction(
+ Context context) {
+ if (mSplitA11yInfo != null && mSplitA11yInfo.containsMultipleTasks) {
+ String accessibilityLabel = context.getString(R.string.split_app_info_accessibility,
+ mSplitA11yInfo.taskTitle);
+ return new AccessibilityNodeInfo.AccessibilityAction(mAccessibilityActionId,
+ accessibilityLabel);
+ } else {
+ return super.createAccessibilityAction(context);
+ }
+ }
+
@Override
public void onClick(View view) {
dismissTaskMenuView(mTarget);
@@ -153,6 +185,19 @@
mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
.log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP);
}
+
+ public static class SplitAccessibilityInfo {
+ public final boolean containsMultipleTasks;
+ public final CharSequence taskTitle;
+ public final int nodeId;
+
+ public SplitAccessibilityInfo(boolean containsMultipleTasks,
+ CharSequence taskTitle, int nodeId) {
+ this.containsMultipleTasks = containsMultipleTasks;
+ this.taskTitle = taskTitle;
+ this.nodeId = nodeId;
+ }
+ }
}
public static final Factory<BaseDraggingActivity> INSTALL = (activity, itemInfo) -> {
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 8f607a1..d994dbe 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,8 +16,8 @@
package com.android.launcher3.provider;
-import static com.android.launcher3.model.DeviceGridState.TYPE_MULTI_DISPLAY;
-import static com.android.launcher3.model.DeviceGridState.TYPE_PHONE;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.app.backup.BackupManager;
@@ -87,12 +87,6 @@
}
private static boolean performRestore(Context context, DatabaseHelper helper) {
- if (!DeviceGridState.deviceTypeCompatible(
- new DeviceGridState(LauncherAppState.getIDP(context)).getDeviceType(),
- Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE))) {
- // DO NOT restore if the device types are incompatible.
- return false;
- }
SQLiteDatabase db = helper.getWritableDatabase();
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
RestoreDbTask task = new RestoreDbTask();
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index f348a33..0c39632 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -49,6 +49,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import java.util.Collections;
@@ -253,12 +254,13 @@
case ALLOW_ROTATION_PREFERENCE_KEY:
DeviceProfile deviceProfile = InvariantDeviceProfile.INSTANCE.get(
getContext()).getDeviceProfile(getContext());
- if (deviceProfile.allowRotation) {
+ if (deviceProfile.isTablet) {
// Launcher supports rotation by default. No need to show this setting.
return false;
}
// Initialize the UI once
- preference.setDefaultValue(false);
+ preference.setDefaultValue(
+ RotationHelper.getAllowRotationDefaultValue(deviceProfile));
return true;
case FLAGS_PREFERENCE_KEY:
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 7a23caa..e036943 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -185,4 +185,11 @@
@RequiresApi(api = Build.VERSION_CODES.R)
public void updateWindowInsets(WindowInsets.Builder updatedInsetsBuilder,
WindowInsets oldInsets) { }
+
+ /**
+ * Runs the given {@param r} runnable when this activity binds to the touch interaction service.
+ */
+ public void runOnBindToTouchInteractionService(Runnable r) {
+ r.run();
+ }
}
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 87871b1..867fd99 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -18,6 +18,10 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
+
+import static com.android.launcher3.Utilities.dpiFromPx;
+import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@@ -25,7 +29,6 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
-import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.UiThreadHelper;
/**
@@ -38,6 +41,17 @@
public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
+ /**
+ * Returns the default value of {@link #ALLOW_ROTATION_PREFERENCE_KEY} preference.
+ */
+ public static boolean getAllowRotationDefaultValue(DeviceProfile deviceProfile) {
+ // If the device's pixel density was scaled (usually via settings for A11y), use the
+ // original dimensions to determine if rotation is allowed of not.
+ float originalSmallestWidth = dpiFromPx(
+ Math.min(deviceProfile.widthPx, deviceProfile.heightPx), DENSITY_DEVICE_STABLE);
+ return originalSmallestWidth >= MIN_TABLET_WIDTH;
+ }
+
public static final int REQUEST_NONE = 0;
public static final int REQUEST_ROTATE = 1;
public static final int REQUEST_LOCK = 2;
@@ -51,7 +65,7 @@
/**
* Rotation request made by
- * {@link ActivityTracker.SchedulerCallback}.
+ * {@link com.android.launcher3.util.ActivityTracker.SchedulerCallback}.
* This supersedes any other request.
*/
private int mStateHandlerRequest = REQUEST_NONE;
@@ -84,7 +98,7 @@
mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
}
mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
- mActivity.getDeviceProfile().allowRotation);
+ getAllowRotationDefaultValue(mActivity.getDeviceProfile()));
} else {
if (mSharedPrefs != null) {
mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
@@ -98,7 +112,7 @@
if (mDestroyed) return;
boolean wasRotationEnabled = mHomeRotationEnabled;
mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
- mActivity.getDeviceProfile().allowRotation);
+ getAllowRotationDefaultValue(mActivity.getDeviceProfile()));
if (mHomeRotationEnabled != wasRotationEnabled) {
notifyChange();
}
@@ -106,7 +120,7 @@
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
- boolean ignoreAutoRotateSettings = dp.allowRotation;
+ boolean ignoreAutoRotateSettings = dp.isTablet;
if (mIgnoreAutoRotateSettings != ignoreAutoRotateSettings) {
setIgnoreAutoRotateSettings(ignoreAutoRotateSettings);
notifyChange();
@@ -143,7 +157,7 @@
public void initialize() {
if (!mInitialized) {
mInitialized = true;
- setIgnoreAutoRotateSettings(mActivity.getDeviceProfile().allowRotation);
+ setIgnoreAutoRotateSettings(mActivity.getDeviceProfile().isTablet);
mActivity.addOnDeviceProfileChangeListener(this);
notifyChange();
}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 5fe5450..d52594e 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -90,9 +90,4 @@
public float getWorkspaceBackgroundAlpha(Launcher launcher) {
return 0.2f;
}
-
- @Override
- public int getVisibleElements(Launcher launcher) {
- return (super.getVisibleElements(launcher) | HOTSEAT_ICONS) & ~TASKBAR;
- }
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 9a74fb1..673b011 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -122,9 +122,7 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
- public static final String TASKBAR_WINDOW_CRASH = "b/201305599";
public static final String TASK_VIEW_ID_CRASH = "b/195430732";
public static final String NO_DROP_TARGET = "b/195031154";
public static final String NULL_INT_SET = "b/200572078";
- public static final String NO_SCREENSHOT = "b/202414125";
}
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 1276ece..52c3581 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -17,6 +17,7 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import android.content.Context;
import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
@@ -26,6 +27,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.R;
+
import java.util.LinkedList;
import java.util.Queue;
@@ -44,10 +47,9 @@
private static final boolean DBG = false;
private static final String TAG = "BaseSwipeDetector";
private static final float ANIMATION_DURATION = 1200;
- /** The minimum release velocity in pixels per millisecond that triggers fling.*/
- private static final float RELEASE_VELOCITY_PX_MS = 1.0f;
private static final PointF sTempPoint = new PointF();
+ private final float mReleaseVelocity;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
protected final boolean mIsRtl;
@@ -64,6 +66,7 @@
private boolean mIsSettingState;
protected boolean mIgnoreSlopWhenSettling;
+ protected Context mContext;
private enum ScrollState {
IDLE,
@@ -71,10 +74,14 @@
SETTLING // onDragEnd
}
- protected BaseSwipeDetector(@NonNull ViewConfiguration config, boolean isRtl) {
+ protected BaseSwipeDetector(@NonNull Context context, @NonNull ViewConfiguration config,
+ boolean isRtl) {
mTouchSlop = config.getScaledTouchSlop();
mMaxVelocity = config.getScaledMaximumFlingVelocity();
mIsRtl = isRtl;
+ mContext = context;
+ mReleaseVelocity = mContext.getResources()
+ .getDimensionPixelSize(R.dimen.base_swift_detector_fling_release_velocity);
}
public static long calculateDuration(float velocity, float progressNeeded) {
@@ -120,7 +127,7 @@
}
public boolean isFling(float velocity) {
- return Math.abs(velocity) > RELEASE_VELOCITY_PX_MS;
+ return Math.abs(velocity) > mReleaseVelocity;
}
public boolean onTouchEvent(MotionEvent ev) {
@@ -236,7 +243,7 @@
} else {
mSubtractDisplacement.x = mDisplacement.x > 0 ? mTouchSlop : -mTouchSlop;
mSubtractDisplacement.y = mDisplacement.y > 0 ? mTouchSlop : -mTouchSlop;
- }
+ }
}
protected abstract boolean shouldScrollStart(PointF displacement);
diff --git a/src/com/android/launcher3/touch/BothAxesSwipeDetector.java b/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
index 944391e..6e2f0d8 100644
--- a/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BothAxesSwipeDetector.java
@@ -21,7 +21,6 @@
import android.view.ViewConfiguration;
import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
@@ -43,13 +42,7 @@
private int mScrollDirections;
public BothAxesSwipeDetector(@NonNull Context context, @NonNull Listener l) {
- this(ViewConfiguration.get(context), l, Utilities.isRtl(context.getResources()));
- }
-
- @VisibleForTesting
- protected BothAxesSwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
- boolean isRtl) {
- super(config, isRtl);
+ super(context, ViewConfiguration.get(context), Utilities.isRtl(context.getResources()));
mListener = l;
}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 498f6db..a94ad7c 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -36,6 +36,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ShapeDrawable;
import android.util.FloatProperty;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
@@ -101,12 +102,12 @@
}
@Override
- public <T> void set(T target, Int2DAction<T> action, int param) {
+ public <T> void setPrimary(T target, Int2DAction<T> action, int param) {
action.call(target, 0, param);
}
@Override
- public <T> void set(T target, Float2DAction<T> action, float param) {
+ public <T> void setPrimary(T target, Float2DAction<T> action, float param) {
action.call(target, 0, param);
}
@@ -116,6 +117,12 @@
}
@Override
+ public <T> void set(T target, Int2DAction<T> action, int primaryParam,
+ int secondaryParam) {
+ action.call(target, secondaryParam, primaryParam);
+ }
+
+ @Override
public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
return event.getY(pointerIndex);
}
@@ -248,7 +255,7 @@
}
@Override
- public int getSplitTranslationDirectionFactor(int stagePosition) {
+ public int getSplitTranslationDirectionFactor(int stagePosition, DeviceProfile deviceProfile) {
if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
return -1;
} else {
@@ -302,6 +309,46 @@
return new PointF(margin, 0);
}
+ @Override
+ public Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
+ int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
+ View[] thumbnailViews, int desiredTaskId, View banner) {
+ float translationX = 0;
+ float translationY = 0;
+ FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
+ banner.setPivotX(0);
+ banner.setPivotY(0);
+ banner.setRotation(getDegreesRotated());
+ translationX = banner.getHeight();
+ FrameLayout.LayoutParams snapshotParams =
+ (FrameLayout.LayoutParams) thumbnailViews[0]
+ .getLayoutParams();
+ bannerParams.gravity = TOP | START;
+ if (splitBounds == null) {
+ // Single, fullscreen case
+ bannerParams.width = taskViewHeight - snapshotParams.topMargin;
+ return new Pair<>(translationX, Integer.valueOf(snapshotParams.topMargin).floatValue());
+ }
+
+ // Set correct width
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ bannerParams.width = thumbnailViews[0].getMeasuredHeight();
+ } else {
+ bannerParams.width = thumbnailViews[1].getMeasuredHeight();
+ }
+
+ // Set translations
+ if (desiredTaskId == splitBounds.rightBottomTaskId) {
+ translationY = (snapshotParams.topMargin + taskViewHeight)
+ * (splitBounds.leftTaskPercent) +
+ (taskViewHeight * splitBounds.dividerWidthPercent);
+ }
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ translationY = snapshotParams.topMargin;
+ }
+ return new Pair<>(translationX, translationY);
+ }
+
/* ---------- The following are only used by TaskViewTouchHandler. ---------- */
@Override
@@ -350,7 +397,7 @@
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
// Add "left" side of phone which is actually the top
return Collections.singletonList(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_left,
+ R.drawable.ic_split_left, R.string.split_screen_position_left,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
}
@@ -456,8 +503,8 @@
}
@Override
- public FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
- DeviceProfile deviceProfile) {
- return primary;
+ public Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
+ FloatProperty secondary, DeviceProfile deviceProfile) {
+ return new Pair<>(primary, secondary);
}
}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 95336cd..19c4639 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -24,6 +24,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ShapeDrawable;
import android.util.FloatProperty;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -65,9 +66,10 @@
Float2DAction<Canvas> CANVAS_TRANSLATE = Canvas::translate;
Float2DAction<Matrix> MATRIX_POST_TRANSLATE = Matrix::postTranslate;
- <T> void set(T target, Int2DAction<T> action, int param);
- <T> void set(T target, Float2DAction<T> action, float param);
+ <T> void setPrimary(T target, Int2DAction<T> action, int param);
+ <T> void setPrimary(T target, Float2DAction<T> action, float param);
<T> void setSecondary(T target, Float2DAction<T> action, float param);
+ <T> void set(T target, Int2DAction<T> action, int primaryParam, int secondaryParam);
float getPrimaryDirection(MotionEvent event, int pointerIndex);
float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
int getMeasuredSize(View view);
@@ -93,7 +95,8 @@
int getScrollOffsetStart(View view, Rect insets);
int getScrollOffsetEnd(View view, Rect insets);
int getSecondaryTranslationDirectionFactor();
- int getSplitTranslationDirectionFactor(@StagePosition int stagePosition);
+ int getSplitTranslationDirectionFactor(@StagePosition int stagePosition,
+ DeviceProfile deviceProfile);
ChildBounds getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild);
void setMaxScroll(AccessibilityEvent event, int maxScroll);
boolean getRecentsRtlSetting(Resources resources);
@@ -112,8 +115,8 @@
float getSecondaryValue(float x, float y);
boolean isLayoutNaturalToLauncher();
- FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
- DeviceProfile deviceProfile);
+ Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
+ FloatProperty secondary, DeviceProfile deviceProfile);
int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
/**
@@ -188,6 +191,10 @@
*/
PointF getAdditionalInsetForTaskMenu(float margin);
+ Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
+ int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
+ View[] thumbnailViews, int desiredTaskId, View banner);
+
// The following are only used by TaskViewTouchHandler.
/** @return Either VERTICAL or HORIZONTAL. */
SingleAxisSwipeDetector.Direction getUpDownSwipeDirection();
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 835c240..ad9f95c 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -16,9 +16,11 @@
package com.android.launcher3.touch;
+import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
@@ -35,6 +37,7 @@
import android.graphics.RectF;
import android.graphics.drawable.ShapeDrawable;
import android.util.FloatProperty;
+import android.util.Pair;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.VelocityTracker;
@@ -101,12 +104,12 @@
}
@Override
- public <T> void set(T target, Int2DAction<T> action, int param) {
+ public <T> void setPrimary(T target, Int2DAction<T> action, int param) {
action.call(target, param, 0);
}
@Override
- public <T> void set(T target, Float2DAction<T> action, float param) {
+ public <T> void setPrimary(T target, Float2DAction<T> action, float param) {
action.call(target, param, 0);
}
@@ -116,6 +119,12 @@
}
@Override
+ public <T> void set(T target, Int2DAction<T> action, int primaryParam,
+ int secondaryParam) {
+ action.call(target, primaryParam, secondaryParam);
+ }
+
+ @Override
public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
return event.getX(pointerIndex);
}
@@ -254,8 +263,8 @@
}
@Override
- public int getSplitTranslationDirectionFactor(int stagePosition) {
- if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
+ public int getSplitTranslationDirectionFactor(int stagePosition, DeviceProfile deviceProfile) {
+ if (deviceProfile.isLandscape && stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
return -1;
} else {
return 1;
@@ -314,6 +323,50 @@
return new PointF(0, 0);
}
+ @Override
+ public Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
+ int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
+ View[] thumbnailViews, int desiredTaskId, View banner) {
+ float translationX = 0;
+ float translationY = 0;
+ FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
+ banner.setPivotX(0);
+ banner.setPivotY(0);
+ banner.setRotation(getDegreesRotated());
+ if (splitBounds == null) {
+ // Single, fullscreen case
+ bannerParams.width = MATCH_PARENT;
+ bannerParams.gravity = BOTTOM | CENTER_HORIZONTAL;
+ return new Pair<>(translationX, translationY);
+ }
+
+ bannerParams.gravity = BOTTOM | ((deviceProfile.isLandscape) ? START : CENTER_HORIZONTAL);
+
+ // Set correct width
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ bannerParams.width = thumbnailViews[0].getMeasuredWidth();
+ } else {
+ bannerParams.width = thumbnailViews[1].getMeasuredWidth();
+ }
+
+ // Set translations
+ if (deviceProfile.isLandscape) {
+ if (desiredTaskId == splitBounds.rightBottomTaskId) {
+ translationX = ((taskViewWidth * splitBounds.leftTaskPercent)
+ + (taskViewWidth * splitBounds.dividerWidthPercent));
+ }
+ } else {
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ FrameLayout.LayoutParams snapshotParams =
+ (FrameLayout.LayoutParams) thumbnailViews[0]
+ .getLayoutParams();
+ translationY = -((taskViewHeight - snapshotParams.topMargin)
+ * (1f - splitBounds.topTaskPercent));
+ }
+ }
+ return new Pair<>(translationX, translationY);
+ }
+
/* ---------- The following are only used by TaskViewTouchHandler. ---------- */
@Override
@@ -363,28 +416,27 @@
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
List<SplitPositionOption> options = new ArrayList<>(1);
// Add both left and right options if we're in tablet mode
- // TODO: Add in correct icons
if (dp.isTablet && dp.isLandscape) {
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_right,
+ R.drawable.ic_split_right, R.string.split_screen_position_right,
STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_left,
+ R.drawable.ic_split_left, R.string.split_screen_position_left,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
} else {
if (dp.isSeascape()) {
// Add left/right options
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_right,
+ R.drawable.ic_split_right, R.string.split_screen_position_right,
STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
} else if (dp.isLandscape) {
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_left,
+ R.drawable.ic_split_left, R.string.split_screen_position_left,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
} else {
// Only add top option
options.add(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_top,
+ R.drawable.ic_split_top, R.string.split_screen_position_top,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
}
}
@@ -535,17 +587,18 @@
if (deviceProfile.isLandscape) {
primaryIconParams.gravity = TOP | START;
- primaryIconView.setTranslationX(primarySnapshotWidth - primaryIconView.getWidth());
+ primaryIconView.setTranslationX(
+ primarySnapshotWidth - primaryIconView.getMeasuredWidth());
primaryIconView.setTranslationY(0);
secondaryIconParams.gravity = TOP | START;
secondaryIconView.setTranslationX(primarySnapshotWidth + dividerBar);
} else {
primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
- primaryIconView.setTranslationX(-(primaryIconView.getWidth()) / 2f);
+ primaryIconView.setTranslationX(-(primaryIconView.getMeasuredWidth()) / 2f);
primaryIconView.setTranslationY(0);
secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
- secondaryIconView.setTranslationX(secondaryIconView.getWidth() / 2f);
+ secondaryIconView.setTranslationX(secondaryIconView.getMeasuredWidth() / 2f);
}
secondaryIconView.setTranslationY(0);
primaryIconView.setLayoutParams(primaryIconParams);
@@ -565,12 +618,12 @@
}
@Override
- public FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
- DeviceProfile dp) {
- if (dp.isLandscape) { // or seascape
- return primary;
+ public Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
+ FloatProperty secondary, DeviceProfile deviceProfile) {
+ if (deviceProfile.isLandscape) { // or seascape
+ return new Pair<>(primary, secondary);
} else {
- return secondary;
+ return new Pair<>(secondary, primary);
}
}
}
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 539e3f8..de5f99c 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -16,6 +16,7 @@
package com.android.launcher3.touch;
+import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_VERTICAL;
import static android.view.Gravity.END;
import static android.view.Gravity.START;
@@ -29,6 +30,7 @@
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.util.Pair;
import android.view.Surface;
import android.view.View;
import android.widget.FrameLayout;
@@ -37,7 +39,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.views.BaseDragLayer;
@@ -53,7 +54,7 @@
}
@Override
- public int getSplitTranslationDirectionFactor(int stagePosition) {
+ public int getSplitTranslationDirectionFactor(int stagePosition, DeviceProfile deviceProfile) {
if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
return -1;
} else {
@@ -107,6 +108,47 @@
}
@Override
+ public Pair<Float, Float> setDwbLayoutParamsAndGetTranslations(int taskViewWidth,
+ int taskViewHeight, StagedSplitBounds splitBounds, DeviceProfile deviceProfile,
+ View[] thumbnailViews, int desiredTaskId, View banner) {
+ float translationX = 0;
+ float translationY = 0;
+ FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
+ banner.setPivotX(0);
+ banner.setPivotY(0);
+ banner.setRotation(getDegreesRotated());
+ FrameLayout.LayoutParams snapshotParams =
+ (FrameLayout.LayoutParams) thumbnailViews[0]
+ .getLayoutParams();
+ bannerParams.gravity = BOTTOM | END;
+ translationX = taskViewWidth - banner.getHeight();
+ if (splitBounds == null) {
+ // Single, fullscreen case
+ bannerParams.width = taskViewHeight - snapshotParams.topMargin;
+ translationY = banner.getHeight();
+ return new Pair<>(translationX, translationY);
+ }
+
+ // Set correct width
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ bannerParams.width = thumbnailViews[1].getMeasuredHeight();
+ } else {
+ bannerParams.width = thumbnailViews[0].getMeasuredHeight();
+ }
+
+ // Set translations
+ if (desiredTaskId == splitBounds.rightBottomTaskId) {
+ translationY = -(taskViewHeight - snapshotParams.topMargin)
+ * (1f - splitBounds.leftTaskPercent)
+ + banner.getHeight();
+ }
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ translationY = banner.getHeight();
+ }
+ return new Pair<>(translationX, translationY);
+ }
+
+ @Override
public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
return dp.widthPx - rect.right;
}
@@ -115,7 +157,7 @@
public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
// Add "right" option which is actually the top
return Collections.singletonList(new SplitPositionOption(
- R.drawable.ic_split_screen, R.string.split_screen_position_right,
+ R.drawable.ic_split_right, R.string.split_screen_position_right,
STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
}
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index f751b7d..5c599c0 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -106,13 +106,15 @@
public SingleAxisSwipeDetector(@NonNull Context context, @NonNull Listener l,
@NonNull Direction dir) {
- this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources()));
+ super(context, ViewConfiguration.get(context), Utilities.isRtl(context.getResources()));
+ mListener = l;
+ mDir = dir;
}
@VisibleForTesting
- protected SingleAxisSwipeDetector(@NonNull ViewConfiguration config, @NonNull Listener l,
- @NonNull Direction dir, boolean isRtl) {
- super(config, isRtl);
+ protected SingleAxisSwipeDetector(@NonNull Context context, @NonNull ViewConfiguration config,
+ @NonNull Listener l, @NonNull Direction dir, boolean isRtl) {
+ super(context, config, isRtl);
mListener = l;
mDir = dir;
}
diff --git a/src/com/android/launcher3/util/ActivityLifecycleCallbacksAdapter.java b/src/com/android/launcher3/util/ActivityLifecycleCallbacksAdapter.java
new file mode 100644
index 0000000..baa8418
--- /dev/null
+++ b/src/com/android/launcher3/util/ActivityLifecycleCallbacksAdapter.java
@@ -0,0 +1,29 @@
+package com.android.launcher3.util;
+
+import android.app.Activity;
+import android.app.Application.ActivityLifecycleCallbacks;
+import android.os.Bundle;
+
+public interface ActivityLifecycleCallbacksAdapter extends ActivityLifecycleCallbacks {
+
+ default void onActivityCreated(Activity activity, Bundle bundle) {
+ }
+
+ default void onActivityDestroyed(Activity activity) {
+ }
+
+ default void onActivityPaused(Activity activity) {
+ }
+
+ default void onActivityResumed(Activity activity) {
+ }
+
+ default void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
+ }
+
+ default void onActivityStarted(Activity activity) {
+ }
+
+ default void onActivityStopped(Activity activity) {
+ }
+}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 2068c29..c050c6c 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -261,6 +261,13 @@
PortraitSize realSize = new PortraitSize(newInfo.currentSize.x, newInfo.currentSize.y);
PortraitSize expectedSize = oldInfo.mInternalDisplays.get(
ApiWrapper.getUniqueId(display));
+ if (newInfo.supportedBounds.size() != oldInfo.supportedBounds.size()) {
+ Log.e("b/198965093",
+ "Inconsistent number of displays"
+ + "\ndisplay state: " + display.getState()
+ + "\noldInfo.supportedBounds: " + oldInfo.supportedBounds
+ + "\nnewInfo.supportedBounds: " + newInfo.supportedBounds);
+ }
if (!realSize.equals(expectedSize) && display.getState() == Display.STATE_OFF) {
Log.e("b/198965093", "Display size changed while display is off, ignoring change");
return;
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index ab3083d..7917410 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -20,6 +20,7 @@
import android.os.UserHandle;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -85,8 +86,16 @@
}
static ItemInfoMatcher ofShortcutKeys(Set<ShortcutKey> keys) {
- return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
- keys.contains(ShortcutKey.fromItemInfo(info));
+ return (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
+ && keys.contains(ShortcutKey.fromItemInfo(info));
+ }
+
+ /**
+ * Returns a matcher for items within folders.
+ */
+ static ItemInfoMatcher forFolderMatch(ItemInfoMatcher childOperator) {
+ return (info, cn) -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
+ .anyMatch(childOperator::matchesInfo);
}
/**
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
index 326141d..11cd07c 100644
--- a/src/com/android/launcher3/util/MultiValueAlpha.java
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -128,6 +128,9 @@
public void setConsumer(Consumer<Float> consumer) {
mConsumer = consumer;
+ if (mConsumer != null) {
+ mConsumer.accept(mValue);
+ }
}
@Override
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 53b1c3e..cb714b2 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -68,6 +68,11 @@
public @interface StageType {}
///////////////////////////////////
+ /**
+ * Default split ratio for launching app pair from overview.
+ */
+ public static final float DEFAULT_SPLIT_RATIO = 0.5f;
+
public static class SplitPositionOption {
public final int iconResId;
public final int textResId;
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 8b7ad46..dc3ee43 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -88,7 +88,6 @@
private IconLoadResult mIconLoadResult;
- // Draw the drawable of the BubbleTextView behind ClipIconView to reveal the built in shadow.
private View mBtvDrawable;
private ClipIconView mClipIconView;
@@ -349,10 +348,23 @@
}
}
- if (!mIsOpening && btvIcon != null) {
+ setOriginalDrawableBackground(btvIcon);
+ invalidate();
+ }
+
+ /**
+ * Draws the drawable of the BubbleTextView behind ClipIconView
+ *
+ * This is used to:
+ * - Have icon displayed while Adaptive Icon is loading
+ * - Displays the built in shadow to ensure a clean handoff
+ *
+ * Allows nullable as this may be cleared when drawing is deferred to ClipIconView.
+ */
+ private void setOriginalDrawableBackground(@Nullable Drawable btvIcon) {
+ if (!mIsOpening) {
mBtvDrawable.setBackground(btvIcon);
}
- invalidate();
}
/**
@@ -457,10 +469,12 @@
@Override
public void onAnimationStart(Animator animator) {
- if (mIconLoadResult != null && mIconLoadResult.isIconLoaded) {
+ if ((mIconLoadResult != null && mIconLoadResult.isIconLoaded)
+ || (!mIsOpening && mBtvDrawable.getBackground() != null)) {
+ // No need to wait for icon load since we can display the BubbleTextView drawable.
setVisibility(View.VISIBLE);
}
- if (!mIsOpening) {
+ if (!mIsOpening && mOriginalIcon != null) {
// When closing an app, we want the item on the workspace to be invisible immediately
setIconAndDotVisible(mOriginalIcon, false);
}
@@ -520,6 +534,7 @@
IconLoadResult result = new IconLoadResult(info,
btvIcon == null ? false : btvIcon.isThemed());
+ result.btvDrawable = btvIcon;
final long fetchIconId = sFetchIconId++;
MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(() -> {
@@ -558,6 +573,7 @@
view.mIconLoadResult = fetchIcon(launcher, originalView,
(ItemInfo) originalView.getTag(), isOpening);
}
+ view.setOriginalDrawableBackground(view.mIconLoadResult.btvDrawable);
}
sIconLoadResult = null;
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index e2e3be7..f32f904 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -158,7 +158,7 @@
if (mContract == null) {
return;
}
- View icon = mLauncher.getWorkspace().getFirstMatchForAppClose(-1,
+ View icon = mLauncher.getFirstMatchForAppClose(-1,
mContract.componentName.getPackageName(), mContract.user);
boolean iconChanged = mIcon != icon;
@@ -182,7 +182,7 @@
lp.topMargin = Math.round(mIconPosition.top);
}
}
- if (iconChanged && !mIconBounds.isEmpty()) {
+ if (mIcon != null && iconChanged && !mIconBounds.isEmpty()) {
// Record the icon display
setCurrentIconVisible(true);
Canvas c = mPicture.beginRecording(mIconBounds.width(), mIconBounds.height());
diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java
index 49fcd2e..e582114 100644
--- a/src/com/android/launcher3/views/Snackbar.java
+++ b/src/com/android/launcher3/views/Snackbar.java
@@ -28,8 +28,9 @@
import android.view.MotionEvent;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -44,7 +45,7 @@
private static final long HIDE_DURATION_MS = 180;
private static final int TIMEOUT_DURATION_MS = 4000;
- private final BaseDraggingActivity mActivity;
+ private final ActivityContext mActivity;
private Runnable mOnDismissed;
public Snackbar(Context context, AttributeSet attrs) {
@@ -53,12 +54,19 @@
public Snackbar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mActivity = BaseDraggingActivity.fromContext(context);
+ mActivity = ActivityContext.lookupContext(context);
inflate(context, R.layout.snackbar, this);
}
- public static void show(BaseDraggingActivity activity, int labelStringResId,
- int actionStringResId, Runnable onDismissed, Runnable onActionClicked) {
+ /** Show a snackbar with just a label. */
+ public static <T extends Context & ActivityContext> void show(T activity, int labelStringRedId,
+ Runnable onDismissed) {
+ show(activity, labelStringRedId, NO_ID, onDismissed, null);
+ }
+
+ /** Show a snackbar with a label and action. */
+ public static <T extends Context & ActivityContext> void show(T activity, int labelStringResId,
+ int actionStringResId, Runnable onDismissed, @Nullable Runnable onActionClicked) {
closeOpenViews(activity, true, TYPE_SNACKBAR);
Snackbar snackbar = new Snackbar(activity, null);
// Set some properties here since inflated xml only contains the children.
@@ -80,20 +88,42 @@
int maxMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_max_margin_left_right);
int minMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_min_margin_left_right);
int marginBottom = res.getDimensionPixelSize(R.dimen.snackbar_margin_bottom);
+ int absoluteMaxWidth = res.getDimensionPixelSize(R.dimen.snackbar_max_width);
Rect insets = activity.getDeviceProfile().getInsets();
- int maxWidth = dragLayer.getWidth() - minMarginLeftRight * 2 - insets.left - insets.right;
- int minWidth = dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right;
+ int maxWidth = Math.min(
+ dragLayer.getWidth() - minMarginLeftRight * 2 - insets.left - insets.right,
+ absoluteMaxWidth);
+ int minWidth = Math.min(
+ dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right,
+ absoluteMaxWidth);
params.width = minWidth;
params.setMargins(0, 0, 0, marginBottom + insets.bottom);
TextView labelView = snackbar.findViewById(R.id.label);
- TextView actionView = snackbar.findViewById(R.id.action);
String labelText = res.getString(labelStringResId);
- String actionText = res.getString(actionStringResId);
- int totalContentWidth = (int) (labelView.getPaint().measureText(labelText)
- + actionView.getPaint().measureText(actionText))
+ labelView.setText(labelText);
+
+ TextView actionView = snackbar.findViewById(R.id.action);
+ float actionWidth;
+ if (actionStringResId != NO_ID) {
+ String actionText = res.getString(actionStringResId);
+ actionWidth = actionView.getPaint().measureText(actionText)
+ + actionView.getPaddingRight() + actionView.getPaddingLeft();
+ actionView.setText(actionText);
+ actionView.setOnClickListener(v -> {
+ if (onActionClicked != null) {
+ onActionClicked.run();
+ }
+ snackbar.mOnDismissed = null;
+ snackbar.close(true);
+ });
+ } else {
+ actionWidth = 0;
+ actionView.setVisibility(GONE);
+ }
+
+ int totalContentWidth = (int) (labelView.getPaint().measureText(labelText) + actionWidth)
+ labelView.getPaddingRight() + labelView.getPaddingLeft()
- + actionView.getPaddingRight() + actionView.getPaddingLeft()
+ padding * 2;
if (totalContentWidth > params.width) {
// The text doesn't fit in our standard width so update width to accommodate.
@@ -113,17 +143,8 @@
params.width = maxWidth;
}
}
- labelView.setText(labelText);
- actionView.setText(actionText);
- actionView.setOnClickListener(v -> {
- if (onActionClicked != null) {
- onActionClicked.run();
- }
- snackbar.mOnDismissed = null;
- snackbar.close(true);
- });
- snackbar.mOnDismissed = onDismissed;
+ snackbar.mOnDismissed = onDismissed;
snackbar.setAlpha(0);
snackbar.setScaleX(0.8f);
snackbar.setScaleY(0.8f);
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 4390211..618ab41 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -250,5 +250,21 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
+ <activity-alias android:name="Activity13" android:exported="true"
+ android:label="TestActivity13"
+ android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
+ <activity-alias android:name="Activity14" android:exported="true"
+ android:label="TestActivity14"
+ android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
</application>
</manifest>
diff --git a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
index 472e1a1..260f556 100644
--- a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
+++ b/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -58,6 +59,7 @@
private TouchEventGenerator mGenerator;
private SingleAxisSwipeDetector mDetector;
private int mTouchSlop;
+ Context mContext;
@Mock
private SingleAxisSwipeDetector.Listener mMockListener;
@@ -69,12 +71,13 @@
public void setup() {
MockitoAnnotations.initMocks(this);
mGenerator = new TouchEventGenerator((ev) -> mDetector.onTouchEvent(ev));
- ViewConfiguration orgConfig = ViewConfiguration
- .get(InstrumentationRegistry.getTargetContext());
+ mContext = InstrumentationRegistry.getTargetContext();
+ ViewConfiguration orgConfig = ViewConfiguration.get(mContext);
doReturn(orgConfig.getScaledMaximumFlingVelocity()).when(mMockConfig)
.getScaledMaximumFlingVelocity();
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_BOTH, false);
mTouchSlop = orgConfig.getScaledTouchSlop();
doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop();
@@ -84,7 +87,8 @@
@Test
public void testDragStart_verticalPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 - mTouchSlop);
@@ -94,7 +98,8 @@
@Test
public void testDragStart_verticalNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, VERTICAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, VERTICAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
mGenerator.move(0, 100, 100 + mTouchSlop);
@@ -112,7 +117,8 @@
@Test
public void testDragStart_horizontalPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
@@ -123,7 +129,8 @@
@Test
public void testDragStart_horizontalNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, false);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, false);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
@@ -134,7 +141,8 @@
@Test
public void testDragStart_horizontalRtlPositive() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, true);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, true);
mDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
mGenerator.put(0, 100, 100);
@@ -145,7 +153,8 @@
@Test
public void testDragStart_horizontalRtlNegative() {
- mDetector = new SingleAxisSwipeDetector(mMockConfig, mMockListener, HORIZONTAL, true);
+ mDetector = new SingleAxisSwipeDetector(mContext,
+ mMockConfig, mMockListener, HORIZONTAL, true);
mDetector.setDetectableScrollConditions(DIRECTION_NEGATIVE, false);
mGenerator.put(0, 100, 100);
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 44f2719..075505e 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -38,6 +38,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.system.OsConstants;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -83,6 +84,7 @@
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -147,7 +149,7 @@
}
sDumpWasGenerated = true;
Log.d("b/195319692", "sDumpWasGenerated := true", new Exception());
- result = "memory dump filename: " + fileName;
+ result = "saved memory dump as an artifact";
} catch (Throwable e) {
Log.e(TAG, "dumpHprofData failed", e);
result = "failed to save memory dump";
@@ -327,7 +329,12 @@
*/
protected <T> T getOnUiThread(final Callable<T> callback) {
try {
- return mMainThreadExecutor.submit(callback).get();
+ return mMainThreadExecutor.submit(callback).get(DEFAULT_UI_TIMEOUT,
+ TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ Log.e(TAG, "Timeout in getOnUiThread, sending SIGABRT", e);
+ Process.sendSignal(Process.myPid(), OsConstants.SIGABRT);
+ throw new RuntimeException(e);
} catch (Throwable e) {
throw new RuntimeException(e);
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index c90d283..5b940a8 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -80,12 +80,8 @@
assertTrue(message, failed);
}
- private int pagesPerScreen() {
- return mLauncher.isTwoPanels() ? 2 : 1;
- }
-
- private boolean isWorkspaceScrollable(Launcher launcher) {
- return launcher.getWorkspace().getPageCount() > pagesPerScreen();
+ public static boolean isWorkspaceScrollable(Launcher launcher) {
+ return launcher.getWorkspace().getPageCount() > launcher.getWorkspace().getPanelCount();
}
private int getCurrentWorkspacePage(Launcher launcher) {
@@ -192,7 +188,7 @@
executeOnLauncher(
launcher -> assertEquals(
"Ensuring workspace scrollable didn't switch to next screen",
- pagesPerScreen(), getCurrentWorkspacePage(launcher)));
+ workspace.pagesPerScreen(), getCurrentWorkspacePage(launcher)));
executeOnLauncher(
launcher -> assertTrue("ensureScrollable didn't make workspace scrollable",
isWorkspaceScrollable(launcher)));
@@ -209,7 +205,7 @@
workspace.flingForward();
executeOnLauncher(
launcher -> assertEquals("Flinging forward didn't switch workspace to next screen",
- pagesPerScreen(), getCurrentWorkspacePage(launcher)));
+ workspace.pagesPerScreen(), getCurrentWorkspacePage(launcher)));
assertTrue("Launcher internal state is not Home", isInState(() -> LauncherState.NORMAL));
// Test starting a workspace app.
@@ -427,6 +423,18 @@
waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
}
+ @Test
+ @PortraitLandscape
+ public void testDeleteFromWorkspace() throws Exception {
+ // test delete both built-in apps and user-installed app from workspace
+ for (String appName : new String[] {"Gmail", "Play Store", APP_NAME}) {
+ final AppIcon appIcon = createShortcutIfNotExist(appName);
+ Workspace workspace = mLauncher.getWorkspace().deleteAppIcon(appIcon);
+ assertNull(appName + " app was found after being deleted from workspace",
+ workspace.tryGetWorkspaceAppIcon(appName));
+ }
+ }
+
public static String getAppPackageName() {
return getInstrumentation().getContext().getPackageName();
}
diff --git a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java
new file mode 100644
index 0000000..b048cd4
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java
@@ -0,0 +1,285 @@
+/*
+ * 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.ui.workspace;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.tapl.Workspace;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TaplTestsLauncher3;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Tests for two panel workspace.
+ *
+ * Note running these tests will clear the workspace on the device.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest {
+
+ Workspace mWorkspace;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ TaplTestsLauncher3.initialize(this);
+ mWorkspace = mLauncher.getWorkspace();
+ }
+
+ @Test
+ public void testDragIconToRightPanel() {
+ if (!mLauncher.isTwoPanels()) {
+ return;
+ }
+
+ // Pre verifying the screens
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1);
+ assertItemsOnPage(launcher, 0, "Play Store", "Maps");
+ assertPageEmpty(launcher, 1);
+ });
+
+ mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Chrome"), 1);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1);
+ assertItemsOnPage(launcher, 0, "Maps", "Play Store");
+ assertItemsOnPage(launcher, 1, "Chrome");
+ });
+ }
+
+ @Test
+ public void testDragIconToPage2() {
+ if (!mLauncher.isTwoPanels()) {
+ return;
+ }
+
+ // Pre verifying the screens
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1);
+ assertItemsOnPage(launcher, 0, "Play Store", "Maps");
+ assertPageEmpty(launcher, 1);
+ });
+
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), 2);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1, 2, 3);
+ assertItemsOnPage(launcher, 0, "Play Store");
+ assertPageEmpty(launcher, 1);
+ assertItemsOnPage(launcher, 2, "Maps");
+ assertPageEmpty(launcher, 3);
+ });
+ }
+
+ @Test
+ public void testDragIconToPage3() {
+ if (!mLauncher.isTwoPanels()) {
+ return;
+ }
+
+ // Pre verifying the screens
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1);
+ assertItemsOnPage(launcher, 0, "Play Store", "Maps");
+ assertPageEmpty(launcher, 1);
+ });
+
+ mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Phone"), 3);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1, 2, 3);
+ assertItemsOnPage(launcher, 0, "Play Store", "Maps");
+ assertPageEmpty(launcher, 1);
+ assertPageEmpty(launcher, 2);
+ assertItemsOnPage(launcher, 3, "Phone");
+ });
+ }
+
+
+ @Test
+ public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() {
+ if (!mLauncher.isTwoPanels()) {
+ return;
+ }
+
+ // Pre verifying the screens
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1);
+ assertItemsOnPage(launcher, 0, "Play Store", "Maps");
+ assertPageEmpty(launcher, 1);
+ });
+
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), 3);
+ mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Chrome"), 0);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1, 2, 3);
+ assertItemsOnPage(launcher, 0, "Play Store");
+ assertPageEmpty(launcher, 1);
+ assertItemsOnPage(launcher, 2, "Chrome");
+ assertItemsOnPage(launcher, 3, "Maps");
+ });
+
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), -1);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1, 2, 3);
+ assertItemsOnPage(launcher, 0, "Play Store");
+ assertItemsOnPage(launcher, 1, "Maps");
+ assertItemsOnPage(launcher, 2, "Chrome");
+ assertPageEmpty(launcher, 3);
+ });
+
+ // Move Chrome to the right panel as well, to make sure pages are not deleted whichever
+ // page is the empty one
+ mWorkspace.flingForward();
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Chrome"), 1);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1, 2, 3);
+ assertItemsOnPage(launcher, 0, "Play Store");
+ assertItemsOnPage(launcher, 1, "Maps");
+ assertPageEmpty(launcher, 2);
+ assertItemsOnPage(launcher, 3, "Chrome");
+ });
+ }
+
+
+ @Test
+ public void testEmptyPagesGetRemovedIfBothPagesAreEmpty() {
+ if (!mLauncher.isTwoPanels()) {
+ return;
+ }
+
+ // Pre verifying the screens
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1);
+ assertItemsOnPage(launcher, 0, "Play Store", "Maps");
+ assertPageEmpty(launcher, 1);
+ });
+
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Play Store"), 2);
+ mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Camera"), 1);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1, 2, 3);
+ assertItemsOnPage(launcher, 0, "Maps");
+ assertPageEmpty(launcher, 1);
+ assertItemsOnPage(launcher, 2, "Play Store");
+ assertItemsOnPage(launcher, 3, "Camera");
+ });
+
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Camera"), -1);
+ mWorkspace.flingForward();
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Play Store"), -2);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1);
+ assertItemsOnPage(launcher, 0, "Play Store", "Maps");
+ assertItemsOnPage(launcher, 1, "Camera");
+ });
+ }
+
+ @Test
+ public void testMiddleEmptyPagesGetRemoved() {
+ if (!mLauncher.isTwoPanels()) {
+ return;
+ }
+
+ // Pre verifying the screens
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1);
+ assertItemsOnPage(launcher, 0, "Play Store", "Maps");
+ assertPageEmpty(launcher, 1);
+ });
+
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), 2);
+ mWorkspace.dragIcon(mWorkspace.getHotseatAppIcon("Messages"), 3);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1, 2, 3, 4, 5);
+ assertItemsOnPage(launcher, 0, "Play Store");
+ assertPageEmpty(launcher, 1);
+ assertItemsOnPage(launcher, 2, "Maps");
+ assertPageEmpty(launcher, 3);
+ assertPageEmpty(launcher, 4);
+ assertItemsOnPage(launcher, 5, "Messages");
+ });
+
+ mWorkspace.flingBackward();
+ mWorkspace.dragIcon(mWorkspace.getWorkspaceAppIcon("Maps"), 2);
+
+ executeOnLauncher(launcher -> {
+ assertPagesExist(launcher, 0, 1, 4, 5);
+ assertItemsOnPage(launcher, 0, "Play Store");
+ assertPageEmpty(launcher, 1);
+ assertItemsOnPage(launcher, 4, "Maps");
+ assertItemsOnPage(launcher, 5, "Messages");
+ });
+ }
+
+ private void assertPageEmpty(Launcher launcher, int pageId) {
+ CellLayout page = launcher.getWorkspace().getScreenWithId(pageId);
+ assertNotNull("Page " + pageId + " does NOT exist.", page);
+ assertEquals("Page " + pageId + " is NOT empty. Number of items on the page:", 0,
+ page.getShortcutsAndWidgets().getChildCount());
+ }
+
+ private void assertPagesExist(Launcher launcher, int... pageIds) {
+ int pageCount = launcher.getWorkspace().getPageCount();
+ assertEquals("Existing page count does NOT match.", pageIds.length, pageCount);
+ for (int i = 0; i < pageCount; i++) {
+ CellLayout page = (CellLayout) launcher.getWorkspace().getPageAt(i);
+ int pageId = launcher.getWorkspace().getIdForScreen(page);
+ assertEquals("The page's id at index " + i + " does NOT match.", pageId,
+ pageIds[i]);
+ }
+ }
+
+ private void assertItemsOnPage(Launcher launcher, int pageId, String... itemTitles) {
+ Set<String> itemTitleSet = Arrays.stream(itemTitles).collect(Collectors.toSet());
+ CellLayout page = launcher.getWorkspace().getScreenWithId(pageId);
+ int itemCount = page.getShortcutsAndWidgets().getChildCount();
+ for (int i = 0; i < itemCount; i++) {
+ ItemInfo itemInfo = (ItemInfo) page.getShortcutsAndWidgets().getChildAt(i).getTag();
+ if (itemInfo != null) {
+ assertTrue("There was an extra item on page " + pageId + ": " + itemInfo.title,
+ itemTitleSet.remove(itemInfo.title));
+ }
+ }
+ assertTrue("Could NOT find some of the items on page " + pageId + ": "
+ + itemTitleSet.stream().collect(Collectors.joining(",")),
+ itemTitleSet.isEmpty());
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index d5479fb..3eb8cf1 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -212,7 +212,7 @@
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get overview actions")) {
verifyActiveContainer();
- UiObject2 overviewActions = mLauncher.waitForLauncherObject("action_buttons");
+ UiObject2 overviewActions = mLauncher.waitForOverviewObject("action_buttons");
return new OverviewActions(overviewActions, mLauncher);
}
}
@@ -224,19 +224,16 @@
return mLauncher.hasLauncherObject(mLauncher.getOverviewObjectSelector("clear_all"));
}
- /* TODO(b/197630182): Once b/188790554 is fixed, remove instanceof check. Currently, when
- swiping from app to overview in Fallback Recents, taskbar remains and no action buttons
- are visible, so we are only testing Overview for now, not BaseOverview. */
private void verifyActionsViewVisibility() {
- if (!(this instanceof Overview) || !hasTasks()) {
+ if (!hasTasks()) {
return;
}
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to assert overview actions view visibility")) {
if (mLauncher.isTablet() && !isOverviewSnappedToFocusedTaskForTablet()) {
- mLauncher.waitUntilLauncherObjectGone("action_buttons");
+ mLauncher.waitUntilOverviewObjectGone("action_buttons");
} else {
- mLauncher.waitForLauncherObject("action_buttons");
+ mLauncher.waitForOverviewObject("action_buttons");
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 2fbe460..631e8f1 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -544,11 +544,11 @@
: TestHelpers.getSystemHealthMessage(getContext(), mTestStartTime);
if (systemHealth != null) {
- return message
- + ";\nPerhaps linked to system health problems:\n<<<<<<<<<<<<<<<<<<\n"
+ message += ";\nPerhaps linked to system health problems:\n<<<<<<<<<<<<<<<<<<\n"
+ systemHealth + "\n>>>>>>>>>>>>>>>>>>";
}
}
+ Log.d(TAG, "About to throw the error: " + message, new Exception());
return message;
}
@@ -1029,6 +1029,10 @@
waitUntilGoneBySelector(getLauncherObjectSelector(resId));
}
+ void waitUntilOverviewObjectGone(String resId) {
+ waitUntilGoneBySelector(getOverviewObjectSelector(resId));
+ }
+
void waitUntilLauncherObjectGone(BySelector selector) {
waitUntilGoneBySelector(makeLauncherSelector(selector));
}
@@ -1395,14 +1399,15 @@
final Point start = new Point(startX, startY);
final Point end = new Point(endX, endY);
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
- final long endTime = movePointer(start, end, steps, downTime, slowDown, gestureScope);
+ final long endTime = movePointer(
+ start, end, steps, false, downTime, slowDown, gestureScope);
sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
}
- long movePointer(Point start, Point end, int steps, long downTime, boolean slowDown,
- GestureScope gestureScope) {
- long endTime = movePointer(
- downTime, downTime, steps * GESTURE_STEP_MS, start, end, gestureScope);
+ long movePointer(Point start, Point end, int steps, boolean isDecelerating,
+ long downTime, boolean slowDown, GestureScope gestureScope) {
+ long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS,
+ isDecelerating, start, end, gestureScope);
if (slowDown) {
endTime = movePointer(downTime, endTime + GESTURE_STEP_MS, 5 * GESTURE_STEP_MS, end,
end, gestureScope);
@@ -1481,21 +1486,55 @@
public long movePointer(long downTime, long startTime, long duration, Point from, Point to,
GestureScope gestureScope) {
+ return movePointer(
+ downTime, startTime, duration, false, from, to, gestureScope);
+ }
+
+ public long movePointer(long downTime, long startTime, long duration, boolean isDecelerating,
+ Point from, Point to, GestureScope gestureScope) {
log("movePointer: " + from + " to " + to);
final Point point = new Point();
long steps = duration / GESTURE_STEP_MS;
+
long currentTime = startTime;
- for (long i = 0; i < steps; ++i) {
- sleep(GESTURE_STEP_MS);
- currentTime += GESTURE_STEP_MS;
- final float progress = (currentTime - startTime) / (float) duration;
+ if (isDecelerating) {
+ // formula: V = V0 - D*T, assuming V = 0 when T = duration
- point.x = from.x + (int) (progress * (to.x - from.x));
- point.y = from.y + (int) (progress * (to.y - from.y));
+ // vx0: initial speed at the x-dimension, set as twice the avg speed
+ // dx: the constant deceleration at the x-dimension
+ double vx0 = 2 * (to.x - from.x) / duration;
+ double dx = vx0 / duration;
+ // vy0: initial speed at the y-dimension, set as twice the avg speed
+ // dy: the constant deceleration at the y-dimension
+ double vy0 = 2 * (to.y - from.y) / duration;
+ double dy = vy0 / duration;
- sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point, gestureScope);
+ for (long i = 0; i < steps; ++i) {
+ sleep(GESTURE_STEP_MS);
+ currentTime += GESTURE_STEP_MS;
+
+ // formula: P = P0 + V0*T - (D*T^2/2)
+ final double t = (i + 1) * GESTURE_STEP_MS;
+ point.x = from.x + (int) (vx0 * t - 0.5 * dx * t * t);
+ point.y = from.y + (int) (vy0 * t - 0.5 * dy * t * t);
+
+ sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point, gestureScope);
+ }
+ } else {
+ for (long i = 0; i < steps; ++i) {
+ sleep(GESTURE_STEP_MS);
+ currentTime += GESTURE_STEP_MS;
+
+ final float progress = (currentTime - startTime) / (float) duration;
+ point.x = from.x + (int) (progress * (to.x - from.x));
+ point.y = from.y + (int) (progress * (to.y - from.y));
+
+ sendPointer(downTime, currentTime, MotionEvent.ACTION_MOVE, point, gestureScope);
+
+ }
}
+
return currentTime;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 6e7264a..0bac2ca 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -77,7 +77,8 @@
mLauncher.scroll(
widgetsContainer,
Direction.UP,
- new Rect(0, 0, mLauncher.getVisibleBounds(widgetsContainer).width(), 0),
+ new Rect(0, 0, mLauncher.getRightGestureMarginInContainer(widgetsContainer) + 1,
+ 0),
FLING_STEPS, false);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
verifyActiveContainer();
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 0145690..3f0d7fd 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -46,6 +46,9 @@
*/
public final class Workspace extends Home {
private static final int FLING_STEPS = 10;
+ private static final int DEFAULT_DRAG_STEPS = 10;
+ private static final String DROP_BAR_RES_ID = "drop_target_bar";
+ private static final String DELETE_TARGET_TEXT_ID = "delete_target_text";
static final Pattern EVENT_CTRL_W_DOWN = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_W"
@@ -145,16 +148,7 @@
if (!isWorkspaceScrollable(workspace)) {
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"dragging icon to a second page of workspace to make it scrollable")) {
- dragIconToWorkspace(
- mLauncher,
- getHotseatAppIcon("Chrome"),
- new Point(mLauncher.getDevice().getDisplayWidth(),
- mLauncher.getVisibleBounds(workspace).centerY()),
- "popup_container",
- false,
- false,
- () -> mLauncher.expectEvent(
- TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT));
+ dragIcon(workspace, getHotseatAppIcon("Chrome"), pagesPerScreen());
verifyActiveContainer();
}
}
@@ -163,6 +157,48 @@
}
}
+ /**
+ * Returns the number of pages that are visible on the screen simultaneously.
+ */
+ public int pagesPerScreen() {
+ return mLauncher.isTwoPanels() ? 2 : 1;
+ }
+
+ /**
+ * Drags an icon to the (currentPage + pageDelta) page if the page already exists.
+ * If the target page doesn't exist, the icon will be put onto an existing page that is the
+ * closest to the target page.
+ *
+ * @param appIcon - icon to drag.
+ * @param pageDelta - how many pages should the icon be dragged from the current page.
+ * It can be a negative value.
+ */
+ public void dragIcon(AppIcon appIcon, int pageDelta) {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+ final UiObject2 workspace = verifyActiveContainer();
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "dragging icon to page with delta: " + pageDelta)) {
+ dragIcon(workspace, appIcon, pageDelta);
+ verifyActiveContainer();
+ }
+ }
+ }
+
+ private void dragIcon(UiObject2 workspace, AppIcon appIcon, int pageDelta) {
+ int pageWidth = mLauncher.getDevice().getDisplayWidth() / pagesPerScreen();
+ int targetX = (pageWidth / 2) + pageWidth * pageDelta;
+ dragIconToWorkspace(
+ mLauncher,
+ appIcon,
+ new Point(targetX, mLauncher.getVisibleBounds(workspace).centerY()),
+ "popup_container",
+ false,
+ false,
+ () -> mLauncher.expectEvent(
+ TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT));
+ verifyActiveContainer();
+ }
+
private boolean isWorkspaceScrollable(UiObject2 workspace) {
return workspace.getChildCount() > (mLauncher.isTwoPanels() ? 2 : 1);
}
@@ -178,6 +214,40 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ /*
+ * Get the center point of the delete icon in the drop target bar.
+ */
+ private Point getDeleteDropPoint() {
+ return mLauncher.waitForObjectInContainer(
+ mLauncher.waitForLauncherObject(DROP_BAR_RES_ID),
+ DELETE_TARGET_TEXT_ID).getVisibleCenter();
+ }
+
+ /**
+ * Delete the appIcon from the workspace.
+ *
+ * @param appIcon to be deleted.
+ * @return validated workspace after the existing appIcon being deleted.
+ */
+ public Workspace deleteAppIcon(AppIcon appIcon) {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "removing app icon from workspace")) {
+ dragIconToWorkspace(
+ mLauncher, appIcon,
+ () -> getDeleteDropPoint(),
+ true, /* decelerating */
+ appIcon.getLongPressIndicator(),
+ () -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
+ null);
+
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+ "dragged the app to the drop bar")) {
+ return new Workspace(mLauncher);
+ }
+ }
+ }
+
/**
* Finds folder icons in the current workspace.
*
@@ -208,8 +278,8 @@
expectLongClickEvents.run();
launcher.waitForLauncherObject(longPressIndicator);
LauncherInstrumentation.log("dragIconToSpringLoaded: indicator");
- launcher.movePointer(iconCenter, dragStartCenter, 10, downTime, true,
- LauncherInstrumentation.GestureScope.INSIDE);
+ launcher.movePointer(iconCenter, dragStartCenter, DEFAULT_DRAG_STEPS, false,
+ downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
}, SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start");
return dragStartCenter;
}
@@ -237,7 +307,7 @@
expectDropEvents = () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN,
LauncherInstrumentation.EVENT_START);
}
- dragIconToWorkspace(launcher, launchable, () -> dest, longPressIndicator,
+ dragIconToWorkspace(launcher, launchable, () -> dest, false, longPressIndicator,
expectLongClickEvents, expectDropEvents);
}
@@ -247,22 +317,38 @@
*/
static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
Supplier<Point> destSupplier, String longPressIndicator) {
- dragIconToWorkspace(launcher, launchable, destSupplier, longPressIndicator,
+ dragIconToWorkspace(launcher, launchable, destSupplier, false, longPressIndicator,
() -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null);
}
static void dragIconToWorkspace(
LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> dest,
- String longPressIndicator, Runnable expectLongClickEvents,
+ boolean isDecelerating, String longPressIndicator, Runnable expectLongClickEvents,
@Nullable Runnable expectDropEvents) {
try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
"want to drag icon to workspace")) {
final long downTime = SystemClock.uptimeMillis();
- final Point dragStartCenter = dragIconToSpringLoaded(launcher, downTime,
+ Point dragStart = dragIconToSpringLoaded(launcher, downTime,
launchable.getObject(), longPressIndicator, expectLongClickEvents);
- final Point targetDest = dest.get();
- launcher.movePointer(dragStartCenter, targetDest, 10, downTime, true,
- LauncherInstrumentation.GestureScope.INSIDE);
+ Point targetDest = dest.get();
+ int displayX = launcher.getRealDisplaySize().x;
+
+ // Since the destination can be on another page, we need to drag to the edge first
+ // until we reach the target page
+ while (targetDest.x > displayX || targetDest.x < 0) {
+ int edgeX = targetDest.x > 0 ? displayX : 0;
+ Point screenEdge = new Point(edgeX, targetDest.y);
+ launcher.movePointer(dragStart, screenEdge, DEFAULT_DRAG_STEPS, isDecelerating,
+ downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
+ launcher.waitForIdle(); // Wait for the page change to happen
+ targetDest.x += displayX * (targetDest.x > 0 ? -1 : 1);
+ dragStart = screenEdge;
+ }
+
+ // targetDest.x is now between 0 and displayX so we found the target page,
+ // we just have to put move the icon to the destination and drop it
+ launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
+ downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
}
}