Merge "NIU Actions: Handle null default assistant"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8066816..f793131 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,7 +20,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher3">
- <uses-sdk android:targetSdkVersion="29" android:minSdkVersion="26"/>
+ <uses-sdk android:targetSdkVersion="30" android:minSdkVersion="26"/>
<!--
Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
Refer comments around specific entries on how to extend individual components.
diff --git a/build.gradle b/build.gradle
index a7eef13..0622d87 100644
--- a/build.gradle
+++ b/build.gradle
@@ -21,8 +21,8 @@
buildToolsVersion BUILD_TOOLS_VERSION
defaultConfig {
- minSdkVersion 25
- targetSdkVersion 28
+ minSdkVersion 26
+ targetSdkVersion 30
versionCode 1
versionName "1.0"
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
index 72b8d3f..dacd8a2 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -80,7 +80,7 @@
}
@Override
- public Bundle call(String method) {
+ public Bundle call(String method, String arg) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
@@ -161,7 +161,7 @@
}
default:
- return super.call(method);
+ return super.call(method, arg);
}
}
}
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index 0e718ca..cc65cbf 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -14,12 +14,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
- loaded at runtime. -->
<com.android.quickstep.views.GoOverviewActionsView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom">
<LinearLayout
android:id="@+id/action_buttons"
diff --git a/go/quickstep/res/values/styles.xml b/go/quickstep/res/values/styles.xml
index 561531b..442c413 100644
--- a/go/quickstep/res/values/styles.xml
+++ b/go/quickstep/res/values/styles.xml
@@ -16,14 +16,14 @@
-->
<resources>
<!-- App themes -->
- <style name="AppTheme" parent="@style/LauncherTheme">
+ <style name="LauncherTheme" parent="@style/BaseLauncherTheme">
<item name="overviewButtonTextColor">@color/go_overview_text_color</item>
<item name="overviewButtonIconColor">@color/go_overview_text_color</item>
<item name="overviewButtonBackgroundColor">@color/go_overview_button_color</item>
<item name="modalDialogBackground">@color/go_modal_dialog_background</item>
</style>
- <style name="AppTheme.Dark" parent="@style/LauncherTheme.Dark">
+ <style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
<item name="overviewButtonTextColor">@color/go_overview_text_color_dark</item>
<item name="overviewButtonIconColor">@color/go_overview_text_color_dark</item>
<item name="overviewButtonBackgroundColor">@color/go_overview_button_color_dark</item>
diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
index 99238f0..6502526 100644
--- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
+++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java
@@ -53,6 +53,7 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.views.ArrowTipView;
import com.android.quickstep.util.AssistContentRequester;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.views.GoOverviewActionsView;
@@ -117,6 +118,7 @@
private AssistContentRequester mFactoryContentRequester;
private SharedPreferences mSharedPreferences;
private OverlayDialogGo mDialog;
+ private ArrowTipView mArrowTipView;
private TaskOverlayGo(TaskThumbnailView taskThumbnailView,
AssistContentRequester assistContentRequester) {
@@ -386,11 +388,14 @@
* Order of tooltips are translate and then listen
*/
private void showTooltipsIfUnseen() {
+ if (mArrowTipView != null && mArrowTipView.isOpen()) {
+ return;
+ }
if (!mSharedPreferences.getBoolean(TRANSLATE_TOOL_TIP_SEEN, false)) {
- ((GoOverviewActionsView) getActionsView()).showTranslateToolTip();
+ mArrowTipView = ((GoOverviewActionsView) getActionsView()).showTranslateToolTip();
mSharedPreferences.edit().putBoolean(TRANSLATE_TOOL_TIP_SEEN, true).apply();
} else if (!mSharedPreferences.getBoolean(LISTEN_TOOL_TIP_SEEN, false)) {
- ((GoOverviewActionsView) getActionsView()).showListenToolTip();
+ mArrowTipView = ((GoOverviewActionsView) getActionsView()).showListenToolTip();
mSharedPreferences.edit().putBoolean(LISTEN_TOOL_TIP_SEEN, true).apply();
}
}
diff --git a/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java b/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
index 97ba590..8d7aac6 100644
--- a/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
@@ -84,31 +84,33 @@
/**
* Shows Tooltip for action icons
*/
- private void showToolTip(int viewId, int textResourceId) {
+ private ArrowTipView showToolTip(int viewId, int textResourceId) {
int[] location = new int[2];
@Px int topMargin = getResources().getDimensionPixelSize(R.dimen.tooltip_top_margin);
findViewById(viewId).getLocationOnScreen(location);
mArrowTipView = new ArrowTipView(getContext(), /* isPointingUp= */ false)
.showAtLocation(getResources().getString(textResourceId),
/* arrowXCoord= */ location[0] + findViewById(viewId).getWidth() / 2,
- /* yCoord= */ location[1] - topMargin);
+ /* yCoord= */ location[1] - topMargin,
+ /* shouldAutoClose= */ false);
mArrowTipView.bringToFront();
+ return mArrowTipView;
}
/**
* Shows Tooltip for listen action icon
*/
- public void showListenToolTip() {
- showToolTip(/* viewId= */ R.id.action_listen,
+ public ArrowTipView showListenToolTip() {
+ return showToolTip(/* viewId= */ R.id.action_listen,
/* textResourceId= */ R.string.tooltip_listen);
}
/**
* Shows Tooltip for translate action icon
*/
- public void showTranslateToolTip() {
- showToolTip(/* viewId= */ R.id.action_translate,
+ public ArrowTipView showTranslateToolTip() {
+ return showToolTip(/* viewId= */ R.id.action_translate,
/* textResourceId= */ R.string.tooltip_translate);
}
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 68680d3..0c2a28c 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -14,11 +14,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- NOTE! don't add dimensions for margins / gravity to root view in this file, they need to be
- loaded at runtime. -->
<com.android.quickstep.views.OverviewActionsView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom">
<LinearLayout
android:id="@+id/action_buttons"
diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml
index dfa17d6..c0e0862 100644
--- a/quickstep/res/layout/taskbar.xml
+++ b/quickstep/res/layout/taskbar.xml
@@ -36,18 +36,27 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom" >
+ <FrameLayout
+ android:id="@+id/start_contextual_buttons"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
+ android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
+ android:gravity="center_vertical"
+ android:layout_gravity="start"/>
+
<LinearLayout
- android:id="@+id/start_nav_buttons"
+ android:id="@+id/end_nav_buttons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
android:gravity="center_vertical"
- android:layout_gravity="start"/>
+ android:layout_gravity="end"/>
<FrameLayout
- android:id="@+id/end_nav_buttons"
+ android:id="@+id/end_contextual_buttons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 05f7607..3f26977 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -56,14 +56,14 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"تأكّد من التمرير سريعًا من الحافة السفلى للشاشة إلى أعلاها."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"تأكّد من عدم التوقّف قليلاً قبل رفع إصبعك."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"تأكّد من التمرير إلى الأعلى مباشرةً."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"أكملت التدريب على إيماءة الانتقال إلى الشاشة الرئيسية. تعرّف بعد ذلك على كيفية الرجوع."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"لقد أكملت التدريب على إيماءة الانتقال إلى الشاشة الرئيسية. تعرّف بعد ذلك على كيفية الرجوع."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"أكملت التدريب على إيماءة الانتقال إلى الشاشة الرئيسية."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"مرِّر سريعًا للانتقال إلى الشاشة الرئيسية"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"مرِّر سريعًا من أسفل الشاشة إلى أعلاها. تنقلك هذه الإيماءة دائمًا إلى الشاشة الرئيسية."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"تأكّد من التمرير سريعًا من الحافة السفلى للشاشة إلى أعلاها."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"حاوِل إبقاء إصبعك على النافذة لمدة أطول قبل رفعه."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"تأكّد من التمرير سريعًا للأعلى مباشرةً ثم التوقّف قليلاً."</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"تعرّفت على كيفية استخدام الإيماءات. لإيقاف الإيماءات، انتقِل إلى \"الإعدادات\"."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"لقد تعرّفت على كيفية استخدام الإيماءات. لإيقاف الإيماءات، انتقِل إلى \"الإعدادات\"."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"أكملت التدريب على إيماءة التبديل بين التطبيقات."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"مرِّر سريعًا للتبديل بين التطبيقات"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"للتبديل بين التطبيقات، مرِّر سريعًا من أسفل الشاشة لأعلاها مع تثبيت إصبعك ثم ارفعه."</string>
@@ -73,7 +73,7 @@
<string name="gesture_tutorial_try_again" msgid="65962545858556697">"إعادة المحاولة"</string>
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"أحسنت"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"الدليل التوجيهي <xliff:g id="CURRENT">%1$d</xliff:g> من إجمالي <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
- <string name="allset_title" msgid="5021126669778966707">"اكتمال الإعداد"</string>
+ <string name="allset_title" msgid="5021126669778966707">"اكتملت عملية الإعداد"</string>
<string name="allset_hint" msgid="2384632994739392447">"مرِّر سريعًا للأعلى للانتقال إلى الشاشة الرئيسية."</string>
<string name="allset_description" msgid="6350320429953234580">"يمكنك الآن بدء استخدام هاتفك."</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"إعدادات التنقّل داخل النظام"</annotation></string>
@@ -81,7 +81,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"هل تريد تخطي الدليل التوجيهي؟"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"يمكنك العثور على هذا الدليل التوجيهي لاحقًا في التطبيق <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"يمكنك العثور على هذا الدليل التوجيهي لاحقًا في التطبيق \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"إلغاء"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"التخطي"</string>
</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 63de0e1..bde409f 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -47,11 +47,11 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđamo aplikaciju: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Obavezno prevucite od same desne ili leve ivice."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Obavezno prevucite od desne ili leve ivice do sredine ekrana i otpustite."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako da prevlačite zdesna da biste se vratili. Sada naučite da menjate aplikacije."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako da prevlačite zdesna da biste se vratili unazad. Sada naučite da zamenite aplikacije."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Dovršili ste pokret za povratak."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Nikako ne prevlačite previše blizu dna ekrana."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Osetljivost pok. za nazad možete da promenite u Podešavanjima"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Prevucite da biste se vratili"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Prevucite da biste se vratili unazad"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Da biste se vratili na poslednji ekran, prevucite od leve ili desne ivice do sredine ekrana."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Obavezno prevucite nagore od donje ivice ekrana."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Nikako ne stajte pre otpuštanja."</string>
@@ -65,7 +65,7 @@
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Obavezno prevucite pravo nagore, pa zastanite."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste kako da koristite pokrete. Da biste isključili pokrete, idite na podešavanja."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Dovršili ste pokret za promenu aplikacija."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prevucite da biste promenili aplikacije"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prevucite da biste zamenili aplikacije"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Za prelazak sa jedne aplikacije na drugu prevucite nagore od dna ekrana, zadržite, pa pustite."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"To je to"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Gotovo"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 3151c27..8e57bd8 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -58,14 +58,14 @@
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Пераканайцеся, што праводзіце пальцам вертыкальна."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Вы навучыліся рабіць жэст пераходу на галоўны экран. А зараз даведайцеся, як вярнуцца назад."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Вы навучыліся рабіць жэст пераходу на галоўны экран."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Правесці пальцам для пераходу на галоўны экран"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Правядзіце пальцам для пераходу на галоўны экран"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Правядзіце пальцам па экране знізу ўверх. Гэты жэст дазваляе вярнуцца на Галоўны экран."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Пераканайцеся, што праводзіце пальцам па экране знізу ўверх."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Перш чым адпусціць палец, паспрабуйце даўжэй утрымліваць акно націснутым."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Пераканайцеся, што праводзіце пальцам вертыкальна, а потым затрымліваеце яго."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Вы навучыліся выкарыстоўваць жэсты. Каб выключыць жэсты, адкрыйце Налады."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Вы навучыліся рабіць жэст пераключэння паміж праграмамі."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Правесці пальцам для пераключэння паміж праграмамі"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Правядзіце пальцам для пераключэння паміж праграмамі"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Каб пераключыцца на іншую праграму, правядзіце па экране знізу ўверх, патрымайце палец і адпусціце."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Гатова"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Гатова"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 37a2e57..7305d9d 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -51,22 +51,22 @@
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Изпълнихте жеста за връщане назад."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Не прекарвайте пръст твърде близо до долната част на екрана."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Променете чувств. на жеста за връщане назад от настройките"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Прекарване на пръст за връщане назад"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Жест за връщане назад"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"За да се върнете на предишния екран, прекарайте пръст от левия или десния край на екрана до средата."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Трябва да прекарате пръст нагоре от долния край на екрана."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Не задържайте, преди да вдигнете пръста си."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Трябва да прекарате пръст право нагоре."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Изпълнихте жеста за преминаване към началния екран. В следващия урок ще научите как се връща назад."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Изпълнихте жеста за преминаване към началния екран. В следващия урок ще научите как да се върнете назад."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Изпълнихте жеста за преминаване към началния екран."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Прекарване на пръст за преминаване към началния екран"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Жест за преминаване към началния екран"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Прекарайте пръст нагоре от долната част на екрана. Този жест винаги ще ви отвежда до началния екран."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Трябва да прекарате пръст нагоре от долния край на екрана."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Задръжте прозореца по-дълго, преди да вдигнете пръста си."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Прекарайте пръст право нагоре, след което задръжте."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Научихте как да използвате жестовете. За да ги изключите, отворете настройките."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Изпълнихте жеста за превключване между приложения."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Прекарване на пръст за превключване между приложенията"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"За да превкл. между прил., прекарайте пръст нагоре от долната част на екрана, задръжте и освободете"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Жест за превключване между приложенията"</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"За превключване прекарайте пръст нагоре от долната част на екрана, задръжте и освободете"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Готово"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Готово"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Настройки"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 90545e1..1d0b45f 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -47,7 +47,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"স্ক্রিনের একেবারে ডান বা বাঁদিকের প্রান্ত থেকে সোয়াইপ করেছেন কিনা তা দেখে নিন।"</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"স্ক্রিনের ডান বা বাঁদিকের প্রান্ত থেকে মাঝখান পর্যন্ত সোয়াইপ করে আঙুল তুলে নিয়েছেন কিনা তা দেখে নিন।"</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ফিরে যেতে, কীভাবে ডান দিক থেকে সোয়াইপ করতে হয় তা আপনি শিখেছেন। এরপর, একটি অ্যাপ থেকে অন্য অ্যাপে কীভাবে যাবেন জেনে নিন।"</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ফিরে যেতে, কীভাবে ডানদিক থেকে সোয়াইপ করতে হয় তা আপনি শিখেছেন। এরপর, একটি অ্যাপ থেকে অন্য অ্যাপে কীভাবে যাবেন জেনে নিন।"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"আপনি ফিরে যাওয়ার জেসচার সম্পর্কে জেনেছেন।"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"স্ক্রিনের নিচের প্রান্তের খুব কাছে পর্যন্ত যাতে সোয়াইপ না করেন সেটি ভাল করে দেখে নিন।"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ফিরে যাওয়ার জেসচারের সেন্সিটিভিটি পরিবর্তন করতে, সেটিংসে যান"</string>
@@ -63,7 +63,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"স্ক্রিনের নিচের প্রান্ত থেকে আপনি সোয়াইপ করেছেন কিনা ভাল করে দেখে নিন।"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"চেষ্টা করুন যাতে আঙুল সরিয়ে নেওয়ার আগে উইন্ডো কিছুক্ষণ প্রেস করে রাখা যায়।"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"আপনি উপরের দিকে সোজাসুজি সোয়াইপ করেছেন কিনা ভাল করে দেখে নিয়ে তারপর পজ করুন।"</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"ইঙ্গিত কীভাবে ব্যবহার করতে হয় আপনি তা শিখে ফেলেছেন। ইঙ্গিত বন্ধ করতে, সেটিংসে যান।"</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"জেসচার কীভাবে ব্যবহার করতে হয় আপনি তা শিখে ফেলেছেন। জেসচার বন্ধ করতে, সেটিংসে যান।"</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"আপনি একটি অ্যাপ থেকে অন্য অ্যাপে যাওয়ার জেসচার সম্পর্কে জেনেছেন।"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"একটি অ্যাপ থেকে অন্য অ্যাপে যেতে সোয়াইপ করুন"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"একটি অ্যাপ থেকে অন্যটিতে পাল্টাতে, স্ক্রিনের নিচ থেকে উপরে সোয়াইপ করে ধরে রাখুন, তারপরে ছেড়ে দিন।"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 7e63a67..acd7b10 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -56,10 +56,10 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Trebate prevući prema gore s donjeg ruba ekrana."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Obratite pažnju da ne zastanete prije puštanja."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Trebate prevući ravno prema gore."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Završili ste pokret za otvaranje Početnog ekrana. Sljedeće naučite kako se vratiti."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Završili ste pokret za otvaranje Početnog ekrana."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Završili ste pokret za otvaranje početnog ekrana. Sljedeće naučite kako se vratiti."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Završili ste pokret za otvaranje početnog ekrana."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Prevucite da odete na početni ekran"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Prevucite s dna ekrana prema gore. Tim pokretom uvijek idete na Početni ekran."</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Prevucite s dna ekrana prema gore. Tim pokretom uvijek idete na početni ekran."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Trebate prevući prema gore s donjeg ruba ekrana."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Pokušajte zadržati prozor duže prije puštanja."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Trebate prevući ravno prema gore, a zatim zastati."</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 9fe61c7..a0d6aee 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -81,7 +81,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"L\'aplicació o la teva organització no permeten aquesta acció"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vols ometre el tutorial de navegació?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Pots trobar-ho més tard a l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Pots trobar-lo més tard a l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel·la"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omet"</string>
</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index aa3df34..f2e2df0 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -56,7 +56,7 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Stryg opad fra bunden af skærmen."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Undlad at holde fingeren stille, indtil du løfter fingeren."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Stryg lige opad."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Du har fuldført bevægelsen for Gå til startskærmen. Som det næste kan du se, hvordan du går til startskærmen."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Du har fuldført bevægelsen for Gå til startskærmen. Som det næste kan du se, hvordan du går tilbage."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Du har fuldført bevægelsen for Gå til startskærmen."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Stryg for at gå til startskærmen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Stryg opad fra bunden af skærmen. Denne bevægelse åbner altid startskærmen."</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 483f362..4a023e3 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -56,7 +56,7 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Wische vom unteren Displayrand nach oben."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Achte darauf, nicht innezuhalten, bevor du loslässt."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Wische gerade nach oben."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Du hast die „Startbildschirm“-Touch-Geste abgeschlossen. Gleich lernst du, wie du zurückgelangst."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Du hast die „Startbildschirm“-Touch-Geste abgeschlossen. Gleich erfährst du, wie du zurückgelangst."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Du hast die „Startbildschirm“-Touch-Geste abgeschlossen."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Zum Startbildschirm gehen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Wenn du zum Startbildschirm gehen möchtest, wische einfach vom unteren Displayrand nach oben."</string>
@@ -81,7 +81,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigationstutorial überspringen?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Das findest du später in der <xliff:g id="NAME">%1$s</xliff:g> App"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du findest es später auch in der <xliff:g id="NAME">%1$s</xliff:g> App"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Abbrechen"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Überspringen"</string>
</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 352d10e..7243e03 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -75,7 +75,7 @@
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Οδηγός <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Όλα έτοιμα!"</string>
<string name="allset_hint" msgid="2384632994739392447">"Σύρετε προς τα πάνω για μετάβαση στην αρχική οθόνη."</string>
- <string name="allset_description" msgid="6350320429953234580">"Είστε έτοιμοι να ξεκινήστε να χρησιμοποιείτε το τηλέφωνό σας"</string>
+ <string name="allset_description" msgid="6350320429953234580">"Είστε έτοιμοι να ξεκινήσετε να χρησιμοποιείτε το τηλέφωνό σας"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Ρυθμίσεις πλοήγησης συστήματος"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Κοινοποίηση"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index ed7debc..7b42aac 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -63,7 +63,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure that you swipe up from the bottom edge of the screen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Try holding the window for longer before releasing."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure that you swipe straight up, then pause."</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to settings."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to Settings."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"You completed the switch apps gesture."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Swipe to switch apps"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"To switch between apps, swipe up from the bottom of your screen, hold, then release."</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index ed7debc..7b42aac 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -63,7 +63,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure that you swipe up from the bottom edge of the screen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Try holding the window for longer before releasing."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure that you swipe straight up, then pause."</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to settings."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to Settings."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"You completed the switch apps gesture."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Swipe to switch apps"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"To switch between apps, swipe up from the bottom of your screen, hold, then release."</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index ed7debc..7b42aac 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -63,7 +63,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure that you swipe up from the bottom edge of the screen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Try holding the window for longer before releasing."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure that you swipe straight up, then pause."</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to settings."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to Settings."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"You completed the switch apps gesture."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Swipe to switch apps"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"To switch between apps, swipe up from the bottom of your screen, hold, then release."</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index ed7debc..7b42aac 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -63,7 +63,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Make sure that you swipe up from the bottom edge of the screen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Try holding the window for longer before releasing."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Make sure that you swipe straight up, then pause."</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to settings."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"You learned how to use gestures. To turn off gestures, go to Settings."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"You completed the switch apps gesture."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Swipe to switch apps"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"To switch between apps, swipe up from the bottom of your screen, hold, then release."</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index a4e5778..e61fd91 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -53,16 +53,16 @@
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Cambia sensibilidad de gesto \"Atrás\" en Configuración"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Desliza el dedo para volver"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Desliza el dedo desde el borde derecho o izquierdo para volver a la última pantalla."</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Asegúrate de deslizar el dedo hacia arriba desde la borde inferior de la pantalla."</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Desliza el dedo hacia arriba desde el borde inferior de la pantalla."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Asegúrate de no detenerte antes de soltarlo."</string>
- <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Asegúrate de deslizar el dedo derecho hacia arriba."</string>
+ <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Desliza el dedo directamente hacia arriba."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Completaste el gesto para ir a la página principal. A continuación, obtén información para volver."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Completaste el gesto para ir a la página principal."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Desliza el dedo para ir a la página principal"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Desliza el dedo hacia arriba desde la parte inferior de la pantalla. Este gesto te llevará siempre a la pantalla principal."</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Asegúrate de deslizar el dedo hacia arriba desde la borde inferior de la pantalla."</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Desliza el dedo hacia arriba desde el borde inferior de la pantalla."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prueba mantener presionada la ventana más tiempo antes de soltarla."</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Asegúrate de deslizar el dedo derecho hacia arriba y, luego, detente."</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Desliza el dedo directamente hacia arriba y luego detente."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Ya sabes cómo usar los gestos. Para desactivarlos, ve a Configuración."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Completaste el gesto para cambiar de app."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Desliza el dedo para cambiar de app"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 6145562..74b7528 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -58,14 +58,14 @@
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Pühkige kindlasti otse üles."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Tegite avakuvale minemise liigutuse. Järgmisena vaadake, kuidas minna tagasi."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Tegite avakuvale minemise liigutuse."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Pühkimine avakuvale minemiseks"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Pühkige avakuvale minemiseks"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pühkige ekraani alaosast üles. See liigutus viib teid alati tagasi avakuvale."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pühkige kindlasti ekraanikuva alumisest servast üles."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Hoidke sõrme aknal pisut kauem, enne kui vabastate."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pühkige kindlasti otse üles, seejärel peatuge."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Õppisite liigutusi kasutama. Liigutuste väljalülitamiseks avage seaded."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Tegite rakenduste vahel vahetamise liigutuse."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Rakenduste vahel vahetamiseks pühkimine"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Pühkige rakenduste vahetamiseks"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Rakenduste vahel vahetamiseks pühkige ekraanikuva alaosast üles, hoidke ja seejärel vabastage."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Valmis"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Valmis"</string>
@@ -75,7 +75,7 @@
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Õpetus <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Valmis!"</string>
<string name="allset_hint" msgid="2384632994739392447">"Avakuvale liikumiseks pühkige üles"</string>
- <string name="allset_description" msgid="6350320429953234580">"Olete valmis oma telefoni kasutama"</string>
+ <string name="allset_description" msgid="6350320429953234580">"Olete valmis oma telefoni kasutama."</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Süsteemi navigeerimisseaded"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Jaga"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 3b7d367..bd016e9 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -81,7 +81,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Nabigazio-tutoriala saltatu nahi duzu?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Tutorial hau <xliff:g id="NAME">%1$s</xliff:g> aplikazioan aurki dezakezu geroago"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioan dago eskuragarri tutoriala"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Utzi"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Saltatu"</string>
</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index d1e849f..ae260ed 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -65,7 +65,7 @@
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"دقت کنید که مستقیماً تند به بالا بکشید و سپس توقف کنید."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"با نحوه استفاده از اشارهها آشنا شدید. برای خاموش کردن اشارهها، به «تنظیمات» بروید."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"اشاره جابهجا شدن بین برنامهها را تکمیل کردید."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"تند کشیدن برای جابهجا شدن بین برنامهها"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"برای جابهجا شدن بین برنامهها، تند بهبالا بکشید"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"برای جابهجا شدن بین برنامهها، از پایین صفحه تند بهبالا بکشید، نگه دارید، و سپس رها کنید."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"همه چیز آماده است"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"تمام"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index f7b0605..a3c9393 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -51,7 +51,7 @@
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Vous avez appris le geste de retour en arrière."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Assurez-vous de ne pas balayer trop près du bas de l\'écran."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Modifiez la sensibilité du geste de retour dans Paramètres"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Balayez l\'écran pour revenir en arrière"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Balayer l\'écran pour revenir en arrière"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Pour revenir à l\'écran précédent, balayez l\'écran de l\'extrémité gauche ou droite vers le centre."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Assurez-vous de balayer l\'écran à partir de l\'extrémité inférieure vers le haut."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Assurez-vous de ne pas interrompre le geste avant de lever le doigt."</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index dca9705..5164792 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -47,26 +47,26 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Application prédite : <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Veillez à bien balayer l\'écran depuis le bord gauche ou droit."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Balayez bien l\'écran depuis le bord gauche ou droit jusqu\'au centre avant de relever le doigt."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Vous avez appris à balayer depuis droite pour revenir en arrière. Apprenez à passer d\'une appli à l\'autre."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Vous savez revenir en arrière en balayant depuis la droite. Apprenez à passer d\'une appli à l\'autre."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Vous avez appris le geste pour revenir en arrière."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Veillez à ne pas balayer l\'écran trop près du bas."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Modifiez la sensibilité du geste retour dans les paramètres"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Balayez l\'écran pour revenir en arrière"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Pour revenir à l\'écran précédent, balayez l\'écran depuis le bord droit ou gauche jusqu\'au centre."</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Veillez à balayer l\'écran du bas vers le haut."</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Veillez à balayer l\'écran de bas en haut."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Veillez à ne pas marquer de pause dans votre geste avant de relever le doigt."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Veillez à balayer l\'écran vers le haut."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Vous avez appris le geste pour revenir à l\'écran d\'accueil. Apprenez ensuite à revenir en arrière."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Vous savez désormais revenir à l\'écran d\'accueil. Apprenez maintenant à revenir en arrière."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Vous avez appris le geste pour revenir à l\'écran d\'accueil."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Balayer pour revenir à l\'écran d\'accueil"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Balayez pour revenir à l\'écran d\'accueil"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Balayez l\'écran de bas en haut. Ce geste vous ramènera toujours à l\'écran d\'accueil."</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Veillez à balayer l\'écran du bas vers le haut."</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Veillez à balayer l\'écran de bas en haut."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Essayez d\'appuyer plus longtemps sur la fenêtre avant de relever le doigt."</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Veillez à balayer l\'écran vers le haut et à marquer une pause dans votre geste."</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Veillez à balayer l\'écran vers le haut, puis à marquer une pause."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Vous avez appris à utiliser les gestes. Pour les désactiver, accédez aux paramètres."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Vous avez appris le geste pour passer d\'une appli à l\'autre."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Balayer pour passer d\'une appli à l\'autre"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Pour changer d\'appli, balayez l\'écran du bas vers le haut, appuyez de manière prolongée et relâchez."</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Balayez pour passer d\'une appli à l\'autre"</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Pour changer d\'appli, balayez l\'écran de bas en haut, appuyez de manière prolongée et relâchez."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Vous avez terminé"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"OK"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Paramètres"</string>
@@ -75,7 +75,7 @@
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriel <xliff:g id="CURRENT">%1$d</xliff:g> sur <xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Tout est prêt !"</string>
<string name="allset_hint" msgid="2384632994739392447">"Balayez l\'écran vers le haut pour revenir à l\'accueil"</string>
- <string name="allset_description" msgid="6350320429953234580">"Vous êtes prêt à utiliser votre téléphone"</string>
+ <string name="allset_description" msgid="6350320429953234580">"Vous pouvez maintenant utiliser votre téléphone"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Paramètres de navigation système"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Partager"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 86f9017..50ebb27 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -46,10 +46,10 @@
<string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"सुझाए गए ऐप्लिकेशन की सुविधा बंद है"</string>
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"सुझाया गया ऐप्लिकेशन: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"पक्का करें कि आप स्क्रीन की दाईं या बाईं ओर के बिल्कुल किनारे से स्वाइप कर रहे हों."</string>
- <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"पक्का करें कि आप स्क्रीन के दाएं या बाएं किनारे से, स्क्रीन के बीच तक स्वाइप करें और फिर अपनी उंगली उठा लें."</string>
+ <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"स्क्रीन के दाएं या बाएं किनारे से स्क्रीन के बीच तक स्वाइप करें और अपनी उंगली उठा लें."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"आपने स्क्रीन के दाएं किनारे से स्वाइप करके, पिछली स्क्रीन पर वापस जाने का तरीका सीख लिया है. अब, एक ऐप से दूसरे ऐप पर जाने का तरीका सीखें."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"आपने पेज पर पीछे ले जाने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है."</string>
- <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"देखे लें कि आप स्क्रीन पर बिल्कुल नीचे तक स्वाइप न कर रहे हों."</string>
+ <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"देख लें कि आप स्क्रीन पर बिल्कुल नीचे तक स्वाइप न कर रहे हों."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\'सेटिंग\' में जाकर, पीछे जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर (हाव-भाव) की संवेदनशीलता बदलें"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"पिछली स्क्रीन पर वापस जाने के लिए स्वाइप करें"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"पिछली स्क्रीन पर वापस जाने के लिए, स्क्रीन के बाएं या दाएं किनारे से बीचों-बीच तक स्वाइप करें."</string>
@@ -81,7 +81,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेविगेशन ट्यूटोरियल छोड़ना चाहते हैं?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"आप बाद में, <xliff:g id="NAME">%1$s</xliff:g> ऐप्लिकेशन पर इसे देख सकते हैं"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"आप बाद में <xliff:g id="NAME">%1$s</xliff:g> ऐप्लिकेशन पर इसे देख सकते हैं"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"अभी नहीं"</string>
- <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"छोड़ें"</string>
+ <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"अभी नहीं"</string>
</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 5ab1a87..50efb74 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -65,7 +65,7 @@
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pazite da prijeđete prstom ravno prema gore, a zatim zastanete."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste koristiti pokrete. Pokrete možete isključiti u postavkama."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Izvršili ste pokret za promjenu aplikacije."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prijeđite prstom da biste promijenili aplikaciju"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Povlačenje prstom za promjenu aplikacije"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Za promjenu aplikacije prijeđite prstom od dna zaslona prema gore, zadržite pritisak pa pustite."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Sve je spremno"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Gotovo"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 43a210b..5a33a38 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -56,10 +56,10 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Assicurati di scorrere verso l\'alto dal bordo inferiore dello schermo."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Assicurati di non fare pause prima di sollevare il dito."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Assicurati di scorrere verso l\'alto senza fermarti."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Hai completato il gesto Vai alla schermata Home. Ora, impara come tornare indietro."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Hai completato il gesto per andare alla schermata Home. Ora, impara come tornare indietro."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Hai completato il gesto Vai alla schermata Home."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Scorri per andare alla schermata Home"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Scorri verso l\'alto dalla parte inferiore dello schermo; così arrivi sempre alla schermata Home."</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Scorri verso l\'alto dalla parte inferiore dello schermo. Questo gesto ti porta sempre alla schermata Home."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Assicurati di scorrere verso l\'alto dal bordo inferiore dello schermo."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Prova a tenere premuta la finestra più a lungo prima di rilasciarla."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Assicurati di scorrere verso l\'alto senza fermarti, poi fai una pausa."</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 3ee1b99..9c2adef 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -48,16 +48,16 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"右端または左端からスワイプしてください。"</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"画面の右端または左端から中央に向かってスワイプし、指を離してください。"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"右側からスワイプして前の画面に戻る方法を学習しました。次は、アプリを切り替える方法を覚えましょう。"</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"「戻る」操作を完了しました。"</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"「戻る」操作を学習しました。"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"スワイプする際は画面の下部に近づきすぎないようにしましょう。"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"「戻る」操作の感度を変更するには [設定] に移動します"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"スワイプで戻りましょう"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"スワイプで戻る"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"直前の画面に戻るには、画面の左端または右端から中央に向かってスワイプします。"</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"画面の下端から上にスワイプしてください。"</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"指を離す前にいったん止めないでください。"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"まっすぐ上にスワイプしてください。"</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"「ホームに戻る」操作を完了しました。次は、前の画面に戻る方法を覚えましょう。"</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"「ホームに戻る」操作を完了しました。"</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"「ホームに戻る」操作を学習しました。次は、前の画面に戻る方法を覚えましょう。"</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"「ホームに戻る」操作を学習しました。"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"スワイプでホームに戻る"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"画面を下から上にスワイプします。この操作でいつでもホーム画面に戻れます。"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"画面の下端から上にスワイプしてください。"</string>
@@ -65,7 +65,7 @@
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"まっすぐ上にスワイプしてから、いったん指を止めてください。"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"主な操作方法を覚えました。操作を OFF にするには、設定に移動してください。"</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"「アプリを切り替える」操作を完了しました。"</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"スワイプでアプリを切り替え"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"スワイプでアプリを切り替える"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"アプリを切り替えるには、画面を下から上にスワイプして長押しし、指を離します。"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"設定完了"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"完了"</string>
@@ -81,7 +81,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"操作チュートリアルをスキップしますか?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"これは後から <xliff:g id="NAME">%1$s</xliff:g> アプリで確認できます"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"チュートリアルは後から <xliff:g id="NAME">%1$s</xliff:g> アプリで確認できます"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"キャンセル"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"スキップ"</string>
</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index e0297ce..9b981c2 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -63,10 +63,10 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನ ಅಂಚಿನಿಂದ ನೀವು ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ಬೆರಳನ್ನು ಮೇಲೆತ್ತುವ ಮೊದಲು ವಿಂಡೋವನ್ನು ಹೆಚ್ಚು ಸಮಯ ಹಿಡಿದಿಡಲು ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ನೀವು ನೇರವಾಗಿ ಸ್ವೈಪ್ ಮಾಡಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ, ನಂತರ ವಿರಾಮಗೊಳಿಸಿ."</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"ಗೆಸ್ಚರ್ಗಳನ್ನು ಬಳಕೆಯನ್ನು ನೀವು ತಿಳಿದುಕೊಂಡಿರುವಿರಿ. ಗೆಸ್ಚರ್ಗಳನ್ನು ಆಫ್ ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"ಗೆಶ್ಚರ್ಗಳನ್ನು ಬಳಸುವುದು ಹೇಗೆಂದು ನೀವು ತಿಳಿದುಕೊಂಡಿರುವಿರಿ. ಗೆಶ್ಚರ್ಗಳನ್ನು ಆಫ್ ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"ನೀವು ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸುವ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಿಸಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹೋಲ್ಡ್ ಮಾಡಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ."</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ಆ್ಯಪ್ಗಳ ನಡುವೆ ಬದಲಿಸಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"ಸಂಪೂರ್ಣ ಸಿದ್ಧವಾಗಿದೆ"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"ಮುಗಿದಿದೆ"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 9ec5295..ba564a7 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -52,14 +52,14 @@
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"화면 하단에 지나치게 가까운 곳에서 스와이프하면 안 됩니다."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"돌아가기 동작의 민감도를 변경하려면 설정으로 이동하세요"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"스와이프하여 돌아가기"</string>
- <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"마지막 화면으로 돌아가려면 왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요"</string>
+ <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"마지막 화면으로 돌아가려면 왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"화면 하단 가장자리에서 위로 스와이프하세요."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"손가락을 떼기 전에 멈추지 않아야 합니다."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"위로 똑바르게 스와이프하세요."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"홈으로 이동 동작을 완료했습니다. 이번에는 뒤로 돌아가는 방법을 알아보겠습니다."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"홈으로 이동 동작을 완료했습니다."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"스와이프하여 홈으로 이동"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"화면 하단에서 위로 스와이프합니다. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다"</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"화면 하단에서 위로 스와이프합니다. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"화면 하단 가장자리에서 위로 스와이프하세요."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"창을 더 오래 누르고 있다가 손가락을 떼 보세요."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"위로 똑바르게 스와이프한 후 잠깐 멈추세요."</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 2205592..8be5c53 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -48,23 +48,23 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Экранды эң четинен оңдон солго же солдон оңго карай сүрүңүз."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Экранды оң же сол жагынан ортосуна карай сүрүп, манжаңызды алыңыз."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Артка кайтуу үчүн экранды оңдон солго карай сүрүүнү үйрөндүңүз. Эми колдонмолорду которуштурганды үйрөнүп алыңыз."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"\"Артка\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз."</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"\"Артка\" жаңсоосун үйрөндүңүз."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Манжаңызды экрандын ылдый жагына өтө жакындатпай сүрүңүз."</string>
- <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\"Артка\" жаң-нун сезгичтигин өзгөртүү үчүн Жөндөөлөргө өтүңүз"</string>
+ <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\"Артка\" жаң-нун сезгичтигин өзгөртүү үчүн жөндөөлөргө өтүңүз"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Артка кайтуу үчүн сүрүңүз"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Акыркы экранга кайтуу үчүн экранды сол же оң жагынан ортосуна карай сүрүңүз."</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Экранды ылдыйдан өйдө карай сүрүңүз."</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Экранды ылдыйдан өйдө сүрүңүз."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Манжаңызды алганга чейин токтотпоңуз."</string>
- <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Экранды өйдө карай сүрүңүз."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"\"Башкы бетке өтүү\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз. Эми артка кайтууну үйрөнүп алыңыз."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"\"Башкы бетке өтүү\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз."</string>
+ <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Экранды өйдө сүрүңүз."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"\"Башкы бетке өтүү\" жаңсоосун үйрөндүңүз. Эми артка кайтууну үйрөнүп алыңыз."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"\"Башкы бетке өтүү\" жаңсоосун үйрөндүңүз."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Башкы бетке өтүү үчүн сүрүп коюңуз"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Экранды ылдый жагынан өйдө карай сүрүңүз. Бул жаңсоо сизди ар дайым Башкы экранга алып барат."</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Экранды ылдыйдан өйдө карай сүрүңүз."</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Экранды ылдый жагынан өйдө сүрүңүз. Бул жаңсоо сизди ар дайым Башкы экранга алып барат."</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Экранды ылдыйдан өйдө сүрүңүз."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Манжаңызды алуудан мурун экранда узагыраак кармаңыз."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Экранды өйдө карай сүрүп, токтоп туруңуз."</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Жаңсоолорду колдонгонду үйрөндүңүз. Жаңсоолорду өчүрүү үчүн Жөндөөлөргө өтүңүз."</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"\"Колдонмолорду которуштуруу\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Жаңсоолорду колдонгонду үйрөндүңүз. Жаңсоолорду өчүрүү үчүн жөндөөлөргө өтүңүз."</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"\"Колдонмолорду которуштуруу\" жаңсоосун үйрөндүңүз."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Колдонмолорду которуштуруу үчүн сүрүңүз"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Бир колдонмодон экинчисине өтүү үчүн экранды ылдыйдан өйдө карай сүрүп, бир аз коё бербей туруңуз."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Дапдаяр!"</string>
@@ -75,12 +75,12 @@
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Үйрөткүч: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Бүттү!"</string>
<string name="allset_hint" msgid="2384632994739392447">"Башкы бетке өтүү үчүн экранды өйдө сүрүңүз"</string>
- <string name="allset_description" msgid="6350320429953234580">"Телефонуңузду колдонуп баштоого даярсыз"</string>
+ <string name="allset_description" msgid="6350320429953234580">"Телефонуңузду колдоно берсеңиз болот"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Өтүү аракетинин тутумдук жөндөөлөрү"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"</string>
- <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Жаңсап өтүү үйрөткүчүн өт-рүп жибер-би?"</string>
+ <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Жаңсоолор үйрөткүчүн өткөрүп жибересизби?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Аны кийин <xliff:g id="NAME">%1$s</xliff:g> колдонмосунан табасыз"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Жокко чыгаруу"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Өткрп жиберүү"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 6124b1d..52be3ac 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -56,7 +56,7 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"സ്ക്രീനിന്റെ താഴത്തെ അരികിൽ നിന്ന് മുകളിലേക്ക് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"വിടുന്നതിന് മുമ്പ് നിങ്ങൾ താൽക്കാലികമായി നിർത്തുന്നില്ലെന്ന് ഉറപ്പാക്കുക."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"നേരെ മുകളിലേക്ക് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പിക്കുക."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ പൂർത്തിയാക്കി. അടുത്തത്, ഹോമിലേക്ക് എങ്ങനെ പോകാമെന്ന് മനസ്സിലാക്കുക."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ പൂർത്തിയാക്കി. അടുത്തത്, എങ്ങനെ മടങ്ങാമെന്ന് അറിയുക."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"ഹോമിലേക്ക് പോകാൻ സ്വെെപ്പ് ചെയ്യുക"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യൂ. ഈ ജെസ്ച്ചർ എപ്പോഴും ഹോം സ്ക്രീനിലേക്ക് നയിക്കുന്നു."</string>
@@ -66,7 +66,7 @@
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"ജെസ്ച്ചറുകൾ ഉപയോഗിക്കുന്ന രീതി നിങ്ങൾ മനസ്സിലാക്കി. ജെസ്ച്ചറുകൾ ഓഫാക്കാൻ ക്രമീകരണത്തിലേക്ക് പോകുക."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"ആപ്പുകൾ തമ്മിൽ മാറുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"ആപ്പുകൾ മാറാൻ സ്വെെപ്പ് ചെയ്യുക"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ആപ്പുകൾക്കിടയിൽ മാറാറാൻ സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിച്ച ശേഷം വിടുക."</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ആപ്പുകൾക്കിടയിൽ മാറാൻ സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിച്ച ശേഷം വിടുക."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"എല്ലാം സജ്ജീകരിച്ചു"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"പൂർത്തിയായി"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"ക്രമീകരണം"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index dfa98e7..79fbca6 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -47,7 +47,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Таамаглаж буй апп: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Та баруун зах эсвэл зүүн захын булангаас шударна уу."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Та баруун эсвэл зүүн булангаас дэлгэцийн дунд хэсэг хүртэл шударч, суллана уу."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа Дараа нь аппыг хэрхэн сэлгэхийг мэдэж аваарай."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа. Дараа нь аппууд хооронд хэрхэн сэлгэхийг мэдэж аваарай."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Та буцах зангааг гүйцэтгэлээ."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Та дэлгэцийн доод хэсэгтэй хэт ойр бүү шудраарай."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Буцах зангааны мэдрэгшлийг өөрчлөх бол Тохиргоо руу очно уу"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 874c911..b07bbfa 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -63,7 +63,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ဖန်သားပြင် အောက်ခြေအစွန်မှ အပေါ်သို့ ပွတ်ဆွဲကြောင်း သေချာပါစေ။"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"မလွှတ်ခင် ဝင်းဒိုးကို အချိန်ကြာကြာ ဖိထားကြည့်ပါ။"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"အပေါ်တည့်တည့်သို့ ပွတ်ဆွဲပြီးနောက် ခဏရပ်ကြောင်း သေချာပါစေ။"</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"လက်ဟန်များသုံးနည်းကို သင်သိသွားပါပြီ။ လက်ဟန်များကို ပိတ်ရန် ‘ဆက်တင်များ’ သို့ သွားပါ။"</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"လက်ဟန်များသုံးနည်းကို သင်သိသွားပါပြီ။ လက်ဟန်များကို ပိတ်ရန် ဆက်တင်များသို့ သွားပါ။"</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"အက်ပ်များပြောင်းသည့် လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"အက်ပ်များပြောင်းရန် ပွတ်ဆွဲပါ"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"အက်ပ်တစ်ခုမှတစ်ခုသို့ ပြောင်းရန် စခရင်အောက်ခြေမှ အပေါ်သို့ ပွတ်ဆွဲ၍ ဖိထားပြီးနောက် လွှတ်ပါ။"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 4428cec..91cae47 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -23,7 +23,7 @@
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"एपको उपयोगका सेटिङहरू"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"सबै खाली गर्नुहोस्"</string>
+ <string name="recents_clear_all" msgid="5328176793634888831">"सबै मेटाउनुहोस्"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"हालसालैका एपहरू"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< १ मिनेट"</string>
@@ -81,7 +81,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रिनसट"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेभिगेसन ट्युटोरियल स्किप गर्ने हो?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"तपाईं पछि <xliff:g id="NAME">%1$s</xliff:g> एपमा गई यो ट्युटोरियल भेट्टाउन सक्नुहुन्छ"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"तपाईं पछि <xliff:g id="NAME">%1$s</xliff:g> नामक एपमा गई यो ट्युटोरियल भेट्टाउन सक्नुहुन्छ"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द गर्नुहोस्"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"स्किप गर्नु…"</string>
</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 5651ac2..96da966 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -56,8 +56,8 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Swipe vanaf de onderrand van het scherm omhoog."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Pauzeer niet voordat je loslaat."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Swipe recht omhoog."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Je weet nu hoe je het gebaar Naar startscherm maakt. Ontdek als volgende hoe je kunt teruggaan."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Je weet nu hoe je het gebaar Naar startscherm maakt."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Je weet nu hoe je weer naar het startscherm gaat. Ontdek als volgende hoe je weer teruggaat."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Je weet nu hoe je teruggaat naar het startscherm."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Swipe om naar het startscherm te gaan"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Swipe omhoog vanaf de onderkant van het scherm. Met dit gebaar ga je altijd naar het startscherm."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Swipe vanaf de onderrand van het scherm omhoog."</string>
@@ -66,11 +66,11 @@
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Je weet nu hoe je gebaren gebruikt. Als je gebaren wilt uitzetten, kun je dat via Instellingen doen."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Je weet nu hoe je het gebaar Schakelen tussen apps maakt."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Swipe om tussen apps te schakelen"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Swipe omhoog vanaf de onderkant van het scherm, houd vast en laat los om tussen apps te wisselen."</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Swipe omhoog vanaf de onderkant van het scherm, houd vast en laat los om tussen apps te schakelen."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Klaar"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Klaar"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Instellingen"</string>
- <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Opnieuw"</string>
+ <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Probeer opnieuw"</string>
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Dat gaat lekker."</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Klaar"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index a16638a..9488021 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -47,7 +47,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ପୂର୍ବାନୁମାନ କରାଯାଇଥିବା ଆପ୍: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"ଆପଣ ସ୍କ୍ରିନର ଏକଦମ୍-ଡାହାଣ ବା ବାମ ଧାରରୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"ଆପଣ ସ୍କ୍ରିନର ଡାହାଣ ବା ବାମ ଧାରରୁ ମଝିକୁ ସ୍ୱାଇପ୍ କରି ଛାଡ଼ି ଦେଉଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ଆପଣ ଡାହାଣ ଧାରରୁ ସ୍ୱାଇପ୍ କରି ପଛକୁ ଫେରିବା ଜାଣିଲେ। ତା\'ପରେ, ଆପଗୁଡ଼ିକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ଆପଣ ଡାହାଣରୁ ସ୍ୱାଇପ୍ କରି ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣିଲେ। ତା\'ପରେ, ଆପକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"ଆପଣ ସ୍କ୍ରିନର ତଳଭାଗର ଅତି ନିକଟରୁ ସ୍ୱାଇପ୍ କରୁନଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ପଛକୁ ଫେରିବା ଜେଶ୍ଚରର ସମ୍ବେଦନଶୀଳତା ବଦଳାଇବାକୁ ସେଟିଂସକୁ ଯାଆନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 7fa05d8..89b2119 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -59,7 +59,7 @@
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ। ਅੱਗੇ, ਜਾਣੋ ਕਿ ਪਿੱਛੇ ਕਿਵੇਂ ਜਾਣਾ ਹੈ।"</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"ਹੋਮ \'ਤੇ ਜਾਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ। ਇਹ ਸੰਕੇਤ ਹਮੇਸ਼ਾਂ ਤੁਹਾਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲੈ ਜਾਂਦਾ ਹੈ।"</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ। ਇਹ ਇਸ਼ਾਰਾ ਹਮੇਸ਼ਾਂ ਤੁਹਾਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲੈ ਜਾਂਦਾ ਹੈ।"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਕਿਨਾਰੇ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਦੇ ਹੋ।"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"ਛੱਡਣ ਤੋਂ ਪਹਿਲਾਂ ਵਿੰਡੋ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਿੱਧੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਦੇ ਹੋ, ਫਿਰ ਰੋਕੋ।"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index b63d063..893db91 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -47,25 +47,25 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Przewidywana aplikacja: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Pamiętaj, aby przesuwać palcem od samej prawej lub lewej krawędzi."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Pamiętaj, aby przesuwać palcem od prawej lub lewej krawędzi do środka ekranu i podnieść palec."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Wiesz już, jak przesuwać palcem od prawej strony, aby wrócić. Poćwicz teraz przełączanie aplikacji."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Wiesz już, jak przesuwać palcem, aby przejść wstecz. Poćwicz teraz przełączanie aplikacji."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Gest przejścia wstecz został opanowany."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Pamiętaj, aby nie przesuwać palcem zbyt blisko dolnej części ekranu."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Czułość gestu cofania możesz zmienić w Ustawieniach"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Przesuwanie palcem, aby przejść wstecz"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Przesuń palcem, aby przejść wstecz"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Aby wrócić do ostatniego ekranu, przesuń palcem od lewej lub prawej krawędzi do środka ekranu."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Pamiętaj, aby przesuwać palcem od dolnej krawędzi ekranu."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Pamiętaj, aby przed podniesieniem palca nie było przerwy."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Pamiętaj, aby przesuwać palcem prosto do góry."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Gest przechodzenia na ekran główny został opanowany. Poćwicz teraz przechodzenie na ekran główny."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Potrafisz już przejść na ekran główny. Poćwicz teraz powrót do wcześniejszego ekranu."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Gest przechodzenia na ekran główny został opanowany."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Przesuwanie palcem, aby przejść na ekran główny"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Przesuń palcem, aby przejść na ekran główny"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Przesuń palcem z dołu ekranu. Ten gest zawsze powoduje przejście na ekran główny."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pamiętaj, aby przesuwać palcem od dolnej krawędzi ekranu."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Przytrzymaj okno dłużej, zanim podniesiesz palec."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pamiętaj, aby przesuwać palcem prosto do góry, a potem przerwać ruch."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Wiesz już, jak używać gestów. Aby wyłączyć gesty, przejdź do Ustawień."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Gest przełączania aplikacji został opanowany."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Przesuwanie palcem, aby przełączać aplikacje"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Przesuń palcem, aby przełączać aplikacje"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Aby przełączać się między aplikacjami, przesuń palcem od dołu ekranu, przytrzymaj i puść."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Wszystko gotowe"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Gotowe"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 7fe20bb..c1cd2bb 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -56,9 +56,9 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Garanta que desliza rapidamente com o dedo a partir do limite inferior do ecrã."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Garanta que não faz uma pausa antes de soltar."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Garanta que desliza rapidamente com o dedo para cima."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Concluiu o gesto para aceder à Página inicial. A seguir, saiba como retroceder."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Concluiu o gesto para aceder à Página inicial."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Deslize rapidamente com o dedo para aceder à Página inicial"</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Concluiu o gesto para aceder ao ecrã principal. A seguir, saiba como retroceder."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Concluiu o gesto para aceder ao ecrã principal."</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Deslize rapidamente com o dedo para aceder ao ecrã principal"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Deslize rapidamente para cima a partir da parte inferior. Este gesto abre sempre o ecrã principal."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Deslize rapidamente com o dedo a partir do limite inferior do ecrã."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Experimente premir a janela durante mais tempo antes de soltar."</string>
@@ -66,7 +66,7 @@
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Aprendeu a utilizar gestos. Para desativar os gestos, aceda às Definições."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Concluiu o gesto para alternar entre apps."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Deslize rapidamente com o dedo para alternar entre apps"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"P/ alternar entre apps, deslize p/ cima a partir da parte inf. do ecrã sem soltar e, depois, solte."</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Para alternar entre apps, deslize para cima sem soltar a partir da parte inferior do ecrã e solte."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Está tudo pronto"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Concluído"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Definições"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 89db8fc..a5e97e0 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -56,9 +56,9 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Glisați în sus dinspre marginea de jos a ecranului."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Nu întrerupeți gestul înainte de a elibera."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Glisați direct în sus."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Ați finalizat gestul „înapoi la pagina de pornire”. În continuare, aflați cum să reveniți."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Ați finalizat gestul „înapoi la pagina de pornire”."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Glisați pentru a accesa pagina de pornire"</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Ați finalizat gestul „accesați ecranul de pornire”. În continuare, aflați cum să reveniți."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Ați finalizat gestul „accesați ecranul de pornire”."</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Glisați pentru a accesa ecranul de pornire"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Glisați în sus din partea de jos a ecranului. Cu acest gest accesați întotdeauna ecranul de pornire."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Glisați în sus dinspre marginea de jos a ecranului."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Încercați să țineți fereastra mai mult înainte s-o eliberați."</string>
@@ -66,7 +66,7 @@
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Ați învățat cum să folosiți gesturi. Pentru a dezactiva gesturile, accesați Setările."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Ați finalizat gestul „comutați între aplicații”."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Glisați pentru a comuta între aplicații"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Pentru a comuta între aplicații, glisați în sus din partea de jos a ecranului, așteptați și eliberați"</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Ca să comutați între aplicații, glisați în sus din partea de jos a ecranului, așteptați și eliberați."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Gata"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Gata"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Setări"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 44c3c54..799e941 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -59,14 +59,14 @@
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Dokončili ste gesto na prechod na plochu. V ďalšom kroku sa naučíte, ako sa vrátiť späť."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Dokončili ste gesto na prechod na plochu."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Prechod na plochu potiahnutím"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Potiahnite nahor z dolného okraja obrazovky. Týmto gestom sa vždy vrátite na plochu."</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Potiahnite nahor zdola obrazovky. Týmto gestom sa vždy vrátite na plochu."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Musíte potiahnuť nahor z dolného okraja obrazovky."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Skúste okno pred uvoľnením podržať dlhšie."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Musite potiahnuť priamo hore a potom zastať."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste sa používať gestá. Ak ich chcete vypnúť, prejdite do Nastavení."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Dokončili ste gesto na prepnutie aplikácií."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prepínanie aplikácií potiahnutím"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Prepínať medzi aplik. môžete potiahnutím nahor z dolnej časti obraz., pridržaním a násl. uvoľnením."</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Aplikácie môžete prepínať potiahnutím obrazovky zdola nahor, pridržaním a následným uvoľnením."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Hotovo"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Hotovo"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Nastavenia"</string>
@@ -76,7 +76,7 @@
<string name="allset_title" msgid="5021126669778966707">"Hotovo"</string>
<string name="allset_hint" msgid="2384632994739392447">"Potiahnutím nahor prejdete na plochu"</string>
<string name="allset_description" msgid="6350320429953234580">"Telefón môžete začať používať"</string>
- <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavenia navigácie v systéme"</annotation></string>
+ <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Nastavenia navigácie systémom"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikácia alebo vaša organizácia túto akciu nepovoľuje"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 8aab5b1..7e40277 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -51,21 +51,21 @@
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Izvedli ste potezo za pomik nazaj."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Pazite, da ne povlečete preblizu dna zaslona."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Občutljivost poteze za nazaj lahko spremenite v nastavitvah."</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Povlecite za vrnitev."</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Povlecite za vrnitev"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Če se želite vrniti na zadnji zaslon, povlecite z levega ali desnega roba do sredine zaslona."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Pazite, da povlečete s spodnjega roba zaslona navzgor."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Pazite, da ne zaustavite prsta, preden ga dvignete."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Pazite, da povlečete naravnost navzgor."</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Izvedli ste potezo za pomik na začetni zaslon. Zdaj se naučite, kako se pomaknete nazaj."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Izvedli ste potezo za pomik na začetni zaslon."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"Vlečenje za pomik na začetni zaslon"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"Povlecite za pomik na začetni zaslon"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Z dna zaslona s prstom povlecite navzgor. S to potezo lahko vedno odprete začetni zaslon."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Pazite, da povlečete s spodnjega roba zaslona navzgor."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Poskusite okno pridržati dalj časa, preden ga izpustite."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Pazite, da povlečete naravnost navzgor in nato zaustavite prst."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste se uporabljati poteze. Poteze lahko izklopite v nastavitvah."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Izvedli ste potezo za preklapljanje med aplikacijami."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Vlečenje za preklapljanje med aplikacijami"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Povlecite za preklapljanje med aplikacijami"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Za preklapljanje med aplikacijami povlecite navzgor z dna zaslona, pridržite in nato izpustite."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Zdaj znate"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Končano"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 98fe69f..f2ffa0a 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -47,11 +47,11 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Предвиђамо апликацију: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Обавезно превуците од саме десне или леве ивице."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Обавезно превуците од десне или леве ивице до средине екрана и отпустите."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научили сте како да превлачите здесна да бисте се вратили. Сада научите да мењате апликације."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научили сте како да превлачите здесна да бисте се вратили уназад. Сада научите да замените апликације."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Довршили сте покрет за повратак."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Никако не превлачите превише близу дна екрана."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Осетљивост пок. за назад можете да промените у Подешавањима"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Превуците да бисте се вратили"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Превуците да бисте се вратили уназад"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Да бисте се вратили на последњи екран, превуците од леве или десне ивице до средине екрана."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Обавезно превуците нагоре од доње ивице екрана."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Никако не стајте пре отпуштања."</string>
@@ -65,7 +65,7 @@
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Обавезно превуците право нагоре, па застаните."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Научили сте како да користите покрете. Да бисте искључили покрете, идите на подешавања."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Довршили сте покрет за промену апликација."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Превуците да бисте променили апликације"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Превуците да бисте заменили апликације"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"За прелазак са једне апликације на другу превуците нагоре од дна екрана, задржите, па пустите."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"То је то"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Готово"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index b412418..931e458 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -59,7 +59,7 @@
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Du är klar med rörelsen för att öppna startskärmen. Nu ska du få lära dig hur du går tillbaka."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Du är klar med rörelsen för att öppna startskärmen."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Svep för att öppna startskärmen"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Svep uppåt från skärmens nederkant. Du kan alltid återgå startskärmen med den här rörelsen."</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Svep uppåt från skärmens nederkant. Du kan alltid återgå till startskärmen med den här rörelsen."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Se till att du sveper från nederkanten på skärmen."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Testa att trycka längre på fönstret innan du släpper."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Se till att du sveper rakt uppåt och sedan pausar."</string>
@@ -76,12 +76,12 @@
<string name="allset_title" msgid="5021126669778966707">"Klart!"</string>
<string name="allset_hint" msgid="2384632994739392447">"Svep uppåt för att öppna startskärmen"</string>
<string name="allset_description" msgid="6350320429953234580">"Nu kan du börja använda telefonen"</string>
- <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Systemnavigeringsinställningarna"</annotation></string>
+ <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Systemnavigeringsinställningar"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Dela"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisationen tillåter inte den här åtgärden"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vill du hoppa över självstudierna?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du kan hitta det här igen i <xliff:g id="NAME">%1$s</xliff:g>-appen"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du hittar det här igen i <xliff:g id="NAME">%1$s</xliff:g>-appen"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Avbryt"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Hoppa över"</string>
</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 093cbb8..22aa3ef 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -47,7 +47,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Programu iliyotabiriwa: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Hakikisha unatelezesha kidole kuanzia ukingo wa kulia kabisa au ukingo wa kushoto kabisa."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Hakikisha unatelezesha kidole kuanzia ukingo wa kulia au kushoto kuelekea katikati ya skrini na uachilie."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Umejifunza jinsi ya kutelezesha kidole kuanzia kulia ili kurudi nyuma. Hatua inayofuata, jifunze jinsi ya kubadilisha programu."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Umejifunza jinsi ya kutelezesha kidole kuanzia kulia ili kurudi nyuma. Sasa jifunze jinsi ya kubadilisha programu."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Umekamilisha ishara ya kurudi nyuma."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Hakikisha hutelezeshi kidole karibu sana na sehemu ya chini ya skrini."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Kubadilisha hisi ya ishara ya nyuma, nenda kwenye Mipangilio"</string>
@@ -56,7 +56,7 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Hakikisha unatelezesha kidole juu kuanzia ukingo wa chini wa skrini."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Hakikisha kuwa husimamishi kabla ya kuachilia."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Hakikisha unatelezesha kidole kuelekea juu."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Umekamilisha ishara ya kwenda kwenye Skrini ya kwanza. Inayofuata, jifunze jinsi ya kurudi nyuma."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Umekamilisha ishara ya kwenda kwenye Skrini ya kwanza. Sasa jifunze jinsi ya kurudi nyuma."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Umekamilisha ishara ya kwenda kwenye Skrini ya kwanza."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Telezesha kidole ili uende kwenye skrini ya kwanza"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Telezesha kidole juu kuanzia chini ya skrini yako. Ishara hii kila wakati hukupeleka kwenye Skrini ya kwanza."</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index be2ffbd..73e4e0c 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -56,10 +56,10 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"మీరు స్క్రీన్ దిగువ అంచు నుండి పైకి స్వయిప్ చేస్తున్నారని నిర్ధారించుకోండి."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"బయలుదేరే ముందు మీరు పాజ్ చేయకుండా చూసుకోండి."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"మీరు నేరుగా పైకి స్వైప్ చేశారని నిర్ధారించుకోండి."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"మీరు మొదటి ట్యాబ్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు. తర్వాత, వెనుకకు ఎలా వెళ్లాలో తెలుసుకోండి."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"మీరు మొదటి స్క్రీన్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు. తర్వాత, వెనుకకు ఎలా వెళ్లాలో తెలుసుకోండి."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"మీరు మొదటి ట్యాబ్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు."</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"వర్చువల్ హోమ్కి వెళ్లడానికి స్వైప్ చేయండి"</string>
- <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"మీ స్క్రీన్ కింది నుండి పైకి స్వైప్ చేయి. ఈ సంజ్ఞ ఎప్పుడూ మిమ్మల్ని మొదటి స్క్రీన్కు తీసుకెళ్తుంది."</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"మొదటి స్క్రీన్కు వెళ్లడానికి స్వైప్ చేయండి"</string>
+ <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"స్క్రీన్ కింది నుండి పైకి స్వైప్ చేయండి. ఈ సంజ్ఞ ఎప్పుడూ మిమ్మల్ని మొదటి స్క్రీన్కు తీసుకెళ్తుంది."</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"మీరు స్క్రీన్ దిగువ అంచు నుండి పైకి స్వయిప్ చేస్తున్నారని నిర్ధారించుకోండి."</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"రిలీజ్ చేయడానికి ముందు విండోను ఎక్కువసేపు పట్టుకోడానికి ట్రై చేయండి."</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"మీరు నేరుగా స్వైప్ చేశారని నిర్ధారించుకోండి, ఆపై పాజ్ చేయండి."</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 96e9060..52b2878 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -81,7 +81,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"ภาพหน้าจอ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ข้ามบทแนะนำการนำทางไหม"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"คุณดูบทแนะนำนี้ได้ภายหลังในแอป <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"คุณดูบทแนะนำนี้ได้ภายหลังในแอป \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ยกเลิก"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ข้าม"</string>
</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index b1ed104..412449b 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -73,7 +73,7 @@
<string name="gesture_tutorial_try_again" msgid="65962545858556697">"Subukan ulit"</string>
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"Magaling!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
- <string name="allset_title" msgid="5021126669778966707">"Handa na lahat!"</string>
+ <string name="allset_title" msgid="5021126669778966707">"Handa na ang lahat!"</string>
<string name="allset_hint" msgid="2384632994739392447">"Mag-swipe pataas para pumunta sa Home"</string>
<string name="allset_description" msgid="6350320429953234580">"Handa mo nang simulan ang paggamit sa iyong telepono"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Mga setting ng navigation ng system"</annotation></string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 8155498..58d78e0 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -51,12 +51,12 @@
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Geri dön hareketini tamamladınız."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Ekranın alt kısmına çok yakın bir şekilde kaydırmadığınızdan emin olun."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Geri hareketinin hassasiyetini değiştirmek için Ayarlar\'a gidin"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Geri dönmek için kaydırın"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Geri dönmek için kaydırma"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Son ekrana geri gitmek için sol veya sağ kenardan ekranın ortasına doğru kaydırın."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Ekranın alt kenarından yukarı kaydırdığınızdan emin olun."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Bırakmadan önce parmağınızı duraklatmadığınızdan emin olun."</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Düz bir şekilde yukarı kaydırdığınızdan emin olun."</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Ana ekrana git hareketini tamamladınız. Şimdi ana ekrana nasıl gideceğinizi öğreneceksiniz."</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Ana ekrana git hareketini tamamladınız. Şimdi nasıl geri döneceğinizi öğreneceksiniz."</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Ana ekrana git hareketini tamamladınız."</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Ana ekrana gitmek için kaydırma"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Ekranın alt kısmından yukarıya doğru kaydırın. Bu hareket sizi her zaman Ana ekrana götürür."</string>
@@ -66,7 +66,7 @@
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Hareketleri nasıl kullanacağınızı öğrendiniz. Hareketleri kapatmak için Ayarlar\'a gidin."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Uygulamalar arasında geçiş yapma hareketini tamamladınız."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Uygulamalar arasında geçiş yapmak için kaydırma"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Uygulama değiştirmek için ekranınızın altından yukarı kaydırıp basılı tutun ve sonra bırakın."</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Uygulamalar arasında geçiş yapmak için ekranınızın altından yukarı kaydırıp basılı tutun ve sonra bırakın."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Hepsi bu kadar"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Bitti"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Ayarlar"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 9acbf61..544cec7 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -47,7 +47,7 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Передбачений додаток: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Проведіть пальцем саме від правого або лівого краю екрана."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Проведіть пальцем від правого або лівого краю до середини екрана й підніміть палець."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ви вмієте проводити пальцем справа наліво, щоб повертатися. Дізнайтеся, як переходити між додатками."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Тепер ви знаєте, як повернутися на попередній екран, провівши пальцем справа наліво. Дізнайтеся, як переключатися між додатками."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Ви виконали жест \"Назад\"."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Не проводьте пальцем надто близько до нижнього краю екрана."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Щоб змінити чутливість жесту \"Назад\", відкрийте налаштування"</string>
@@ -66,7 +66,7 @@
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Ви вивчили жести. Щоб вимкнути їх, перейдіть у налаштування."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Ви виконали жест переходу в інший додаток."</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Проведіть пальцем, щоб перейти в інший додаток"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Щоб переключитися між додатками, проведіть знизу вгору по екрані, утримуйте палець і відпустіть."</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Щоб переключатися між додатками, проведіть знизу вгору по екрану, утримуйте палець, а потім відпустіть."</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Усе готово!"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Готово"</string>
<string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Налаштування"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index cd34aac..8b194de 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -51,7 +51,7 @@
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Ortga qaytish ishorasi darsini tamomladingiz."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Barmoqni ekran pastiga yaqin surmaslikka harakat qiling."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Orqaga ishorasi sezuvchanligi Sozlamalardan oʻzgartiriladi"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Ortga qaytish uchun suring"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Orqaga qaytish"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Ortga qaytish uchun barmoqni ekranning yon chekkalaridan oʻrtasigacha suring."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Barmoqni ekranning pastki chetidan yuqoriga suring."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Barmoqni ekrandan pauzasiz qoʻyib uzing."</string>
@@ -65,7 +65,7 @@
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Avval tik tepaga surib, keyin pauza qiling."</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Ishoralardan qanday foydalanishni oʻrganib oldingiz. Ishoralarni oʻchirish uchun Sozlamalarga kiring."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Ilovalarni almashtirish darsini tamomladingiz."</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Svayp bilan ilovalarni almashtirish"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Ilovalar orasida almashish"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Ilovalarni ochish uchun ekranning pastidan tepaga qarab suring, biroz ushlab turing va qoʻyib yuboring"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Tayyor"</string>
<string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Tayyor"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 6c192b2..7bd0c70 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -47,11 +47,11 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Ứng dụng dự đoán: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Hãy vuốt từ mép ngoài cùng bên phải hoặc ngoài cùng bên trái."</string>
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Hãy vuốt từ mép phải hoặc mép trái tới giữa màn hình rồi thả tay ra."</string>
- <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Bạn đã tìm hiểu cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
+ <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Bạn đã học được cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Bạn đã thực hiện xong cử chỉ quay lại."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Hãy nhớ không được vuốt quá gần phần cuối màn hình."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Để thay đổi độ nhạy của cử chỉ quay lại, hãy vào mục Cài đặt"</string>
- <string name="back_gesture_intro_title" msgid="19551256430224428">"Hãy vuốt để quay lại"</string>
+ <string name="back_gesture_intro_title" msgid="19551256430224428">"Vuốt để quay lại"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Để quay lại màn hình gần đây nhất, hãy vuốt từ mép trái hoặc mép phải tới chính giữa màn hình."</string>
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Hãy vuốt lên từ mép dưới cùng của màn hình."</string>
<string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Hãy nhớ không được tạm dừng trước khi nhấc ngón tay."</string>
@@ -75,7 +75,7 @@
<string name="gesture_tutorial_step" msgid="1279786122817620968">"Hướng dẫn <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
<string name="allset_title" msgid="5021126669778966707">"Đã hoàn tất!"</string>
<string name="allset_hint" msgid="2384632994739392447">"Vuốt lên để chuyển đến Màn hình chính"</string>
- <string name="allset_description" msgid="6350320429953234580">"Hiện giờ, bạn đã có thể sử dụng điện thoại"</string>
+ <string name="allset_description" msgid="6350320429953234580">"Vậy là bạn đã sẵn sàng sử dụng điện thoại của mình"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Chế độ cài đặt di chuyển trên hệ thống"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index dbadfd0..9e641de 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -49,20 +49,20 @@
<string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"请从右侧或左侧边缘滑动到屏幕中间位置后再松开手指。"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"您已了解如何使用“从右侧向左滑动”手势返回。接下来了解如何切换应用。"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"您完成了“返回”手势教程。"</string>
- <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"滑动时,手的位置不要太靠近屏幕底部。"</string>
+ <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"请确保滑动时手的位置不要太靠近屏幕底部。"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"如要调节“返回”手势的灵敏度,请转到“设置”"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"滑动即可返回"</string>
<string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"如要返回上一个屏幕,请从左侧或右侧边缘滑动到屏幕中间位置。"</string>
- <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"请从屏幕底部边缘向上滑动。"</string>
- <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"在松开手指前请勿停下来。"</string>
- <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"请向上滑动。"</string>
+ <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"请确保从屏幕底部边缘向上滑动。"</string>
+ <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"松开手指前,请确保不要停下来。"</string>
+ <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"请确保直接向上滑动。"</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"您完成了“转到主屏幕”手势教程。接下来了解如何返回。"</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"您完成了“转到主屏幕”手势教程。"</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"滑动即可转到主屏幕"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"上滑可转到主屏幕"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"从屏幕底部向上滑动。这个手势会一律将您转到主屏幕。"</string>
- <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"请从屏幕底部边缘向上滑动。"</string>
+ <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"请确保从屏幕底部边缘向上滑动。"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"请尝试按住窗口较长时间,然后再松开手指。"</string>
- <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"请向上滑动,然后停住。"</string>
+ <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"请确保直接向上滑动,然后停住。"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"您已了解如何使用手势了。如要关闭手势,请转到“设置”。"</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"您完成了“切换应用”手势教程。"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"滑动即可切换应用"</string>
@@ -73,7 +73,7 @@
<string name="gesture_tutorial_try_again" msgid="65962545858556697">"重试"</string>
<string name="gesture_tutorial_nice" msgid="2936275692616928280">"很好!"</string>
<string name="gesture_tutorial_step" msgid="1279786122817620968">"教程 <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
- <string name="allset_title" msgid="5021126669778966707">"设置完毕!"</string>
+ <string name="allset_title" msgid="5021126669778966707">"大功告成!"</string>
<string name="allset_hint" msgid="2384632994739392447">"向上滑动即可转到主屏幕"</string>
<string name="allset_description" msgid="6350320429953234580">"您可以开始使用手机了"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"系统导航设置"</annotation></string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 88a3613..d1e8392 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -58,7 +58,7 @@
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"請向上滑動。"</string>
<string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"您已完成「返回主畫面」手勢的教學課程。接著,一起來瞭解如何返回上一個畫面。"</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"您已完成「返回主畫面」手勢的教學課程。"</string>
- <string name="home_gesture_intro_title" msgid="836590312858441830">"向上滑動即可返回主畫面。"</string>
+ <string name="home_gesture_intro_title" msgid="836590312858441830">"向上滑動即可返回主畫面"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"從螢幕底部向上滑動。這個手勢在所有畫面下都可讓您返回主畫面。"</string>
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"請從螢幕底部邊緣向上滑動。"</string>
<string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"請嘗試按住視窗更長時間,然後再放開。"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 167c7c3..2f24441 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -26,6 +26,6 @@
<color name="all_apps_prediction_row_separator_dark">#3cffffff</color>
<!-- Taskbar -->
- <color name="taskbar_background">#101010</color>
+ <color name="taskbar_background">@color/overview_scrim_dark</color>
<color name="taskbar_icon_selection_ripple">#E0E0E0</color>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 1febc88..659ff9a 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -16,7 +16,8 @@
<resources>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
- <dimen name="task_thumbnail_icon_size_grid">40dp</dimen>
+ <dimen name="task_thumbnail_icon_drawable_size">48dp</dimen>
+ <dimen name="task_thumbnail_icon_drawable_size_grid">32dp</dimen>
<!-- For screens without rounded corners -->
<dimen name="task_corner_radius_small">2dp</dimen>
<!-- For Launchers that want to override the default dialog corner radius -->
@@ -31,19 +32,22 @@
<dimen name="overview_minimum_next_prev_size">50dp</dimen>
<dimen name="overview_task_margin">16dp</dimen>
+ <dimen name="overview_task_margin_grid">12dp</dimen>
<!-- Overrideable in overlay that provides the Overview Actions. -->
<dimen name="overview_actions_height">48dp</dimen>
- <dimen name="overview_actions_bottom_margin_gesture">28dp</dimen>
- <dimen name="overview_actions_bottom_margin_three_button">8dp</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>
+ <dimen name="overview_actions_top_margin_gesture_grid_landscape">19.1dp</dimen>
+ <dimen name="overview_actions_bottom_margin_gesture_grid_landscape">10dp</dimen>
+ <dimen name="overview_actions_margin_three_button">8dp</dimen>
<dimen name="overview_actions_horizontal_margin">16dp</dimen>
- <dimen name="overview_grid_top_margin">77dp</dimen>
- <dimen name="overview_grid_bottom_margin">70dp</dimen>
- <dimen name="overview_grid_side_margin">54dp</dimen>
- <dimen name="overview_grid_row_spacing">42dp</dimen>
- <dimen name="overview_grid_focus_vertical_margin">40dp</dimen>
- <dimen name="split_placeholder_size">110dp</dimen>
+ <dimen name="overview_grid_side_margin">50dp</dimen>
+ <dimen name="overview_grid_row_spacing_portrait">37.13dp</dimen>
+ <dimen name="overview_grid_row_spacing_landscape">33.38dp</dimen>
+ <dimen name="overview_grid_focus_vertical_margin">0dp</dimen>
<!-- These speeds are in dp/s -->
<dimen name="max_task_dismiss_drag_velocity">2.25dp</dimen>
@@ -52,6 +56,7 @@
<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
@@ -70,6 +75,8 @@
<item name="content_scale" format="float" type="dimen">0.97</item>
<dimen name="closing_window_trans_y">115dp</dimen>
+ <dimen name="quick_switch_scaling_scroll_threshold">100dp</dimen>
+
<dimen name="recents_empty_message_text_size">16sp</dimen>
<dimen name="recents_empty_message_text_padding">16dp</dimen>
diff --git a/quickstep/robolectric_tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java b/quickstep/robolectric_tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
index 1386ac0..f82fbcc 100644
--- a/quickstep/robolectric_tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
+++ b/quickstep/robolectric_tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
@@ -34,7 +34,6 @@
import android.os.Process;
import android.os.UserHandle;
-import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.ComponentWithLabel;
@@ -42,7 +41,6 @@
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
import com.android.launcher3.shadows.ShadowDeviceFlag;
-import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -76,7 +74,6 @@
private Context mContext;
private LauncherModelHelper mModelHelper;
private UserHandle mUserHandle;
- private InvariantDeviceProfile mTestProfile;
@Mock
private IconCache mIconCache;
@@ -92,7 +89,6 @@
mContext = RuntimeEnvironment.application;
mModelHelper = new LauncherModelHelper();
mUserHandle = Process.myUserHandle();
- mTestProfile = new InvariantDeviceProfile();
// 2 widgets, app4/provider1 & app5/provider1, have already been added to the workspace.
mModelHelper.initializeData("/widgets_predication_update_task_data.txt");
@@ -226,10 +222,5 @@
public void bindExtraContainerItems(FixedContainerItems item) {
mRecommendedWidgets = item;
}
-
- @Override
- public IntSet getPagesToBindSynchronously() {
- return IntSet.wrap(0);
- }
}
}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index ecd38b4..b4b29aa 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -64,6 +64,7 @@
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.UiThreadHelper;
+import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
@@ -109,6 +110,7 @@
private OverviewActionsView mActionsView;
private @Nullable TaskbarManager mTaskbarManager;
+ private @Nullable OverviewCommandHelper mOverviewCommandHelper;
private @Nullable LauncherTaskbarUIController mTaskbarUIController;
private final ServiceConnection mTisBinderConnection = new ServiceConnection() {
@Override
@@ -117,6 +119,8 @@
mTaskbarManager.setLauncher(BaseQuickstepLauncher.this);
Log.d(TAG, "TIS service connected");
resetServiceBindRetryState();
+
+ mOverviewCommandHelper = ((TISBinder) iBinder).getOverviewCommandHelper();
}
@Override
@@ -159,6 +163,15 @@
super.onDestroy();
}
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ if (mOverviewCommandHelper != null) {
+ mOverviewCommandHelper.clearPendingCommands();
+ }
+ }
+
public QuickstepTransitionManager getAppTransitionManager() {
return mAppTransitionManager;
}
@@ -210,6 +223,17 @@
}
}
+ /**
+ * {@code LauncherOverlayCallbacks} scroll amount.
+ * Indicates transition progress to -1 screen.
+ * @param progress From 0 to 1.
+ */
+ @Override
+ public void onScrollChanged(float progress) {
+ super.onScrollChanged(progress);
+ mDepthController.onOverlayScrollChanged(progress);
+ }
+
@Override
public void startIntentSenderForResult(IntentSender intent, int requestCode,
Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
@@ -271,12 +295,10 @@
SysUINavigationMode.INSTANCE.get(this).updateMode();
mActionsView = findViewById(R.id.overview_actions_view);
- mSplitPlaceholderView = findViewById(R.id.split_placeholder);
RecentsView overviewPanel = (RecentsView) getOverviewPanel();
- mSplitPlaceholderView.init(
- new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this))
- );
- overviewPanel.init(mActionsView, mSplitPlaceholderView);
+ SplitSelectStateController controller =
+ new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this));
+ overviewPanel.init(mActionsView, controller);
mActionsView.setDp(getDeviceProfile());
mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index ebf8fb7..2da8a45 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -40,7 +40,6 @@
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
-import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
@@ -1047,7 +1046,7 @@
mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition(
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
false /* startAtFrontOfQueue */));
- mLauncherOpenTransition.addHomeOpenCheck();
+ mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName());
SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
}
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 82582ee..aba16c2 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -100,9 +100,12 @@
}
};
- private final Consumer<Boolean> mCrossWindowBlurListener = (enabled) -> {
- mCrossWindowBlursEnabled = enabled;
- dispatchTransactionSurface();
+ private final Consumer<Boolean> mCrossWindowBlurListener = new Consumer<Boolean>() {
+ @Override
+ public void accept(Boolean enabled) {
+ mCrossWindowBlursEnabled = enabled;
+ dispatchTransactionSurface(mDepth);
+ }
};
private final Launcher mLauncher;
@@ -114,6 +117,10 @@
private WallpaperManagerCompat mWallpaperManager;
private SurfaceControl mSurface;
/**
+ * How visible the -1 overlay is, from 0 to 1.
+ */
+ private float mOverlayScrollProgress;
+ /**
* Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in.
* @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
*/
@@ -122,6 +129,10 @@
* If we're launching and app and should not be blurring the screen for performance reasons.
*/
private boolean mBlurDisabledForAppLaunch;
+ /**
+ * If we requested early wake-up offsets to SurfaceFlinger.
+ */
+ private boolean mInEarlyWakeUp;
// Workaround for animating the depth when multiwindow mode changes.
private boolean mIgnoreStateChangesDuringMultiWindowAnimation = false;
@@ -189,14 +200,14 @@
if (mSurface != surface) {
mSurface = surface;
if (surface != null) {
- dispatchTransactionSurface();
+ dispatchTransactionSurface(mDepth);
}
}
}
@Override
public void setState(LauncherState toState) {
- if (mIgnoreStateChangesDuringMultiWindowAnimation) {
+ if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) {
return;
}
@@ -204,7 +215,7 @@
if (Float.compare(mDepth, toDepth) != 0) {
setDepth(toDepth);
} else if (toState == LauncherState.OVERVIEW) {
- dispatchTransactionSurface();
+ dispatchTransactionSurface(mDepth);
}
}
@@ -243,31 +254,59 @@
if (Float.compare(mDepth, depthF) == 0) {
return;
}
- mDepth = depthF;
- dispatchTransactionSurface();
+ if (dispatchTransactionSurface(depthF)) {
+ mDepth = depthF;
+ }
}
- private void dispatchTransactionSurface() {
+ public void onOverlayScrollChanged(float progress) {
+ // Round out the progress to dedupe frequent, non-perceptable updates
+ int progressI = (int) (progress * 256);
+ float progressF = progressI / 256f;
+ if (Float.compare(mOverlayScrollProgress, progressF) == 0) {
+ return;
+ }
+ mOverlayScrollProgress = progressF;
+ dispatchTransactionSurface(mDepth);
+ }
+
+ private boolean dispatchTransactionSurface(float depth) {
boolean supportsBlur = BlurUtils.supportsBlursOnWindows();
+ if (supportsBlur && (mSurface == null || !mSurface.isValid())) {
+ return false;
+ }
ensureDependencies();
+ depth = Math.max(depth, mOverlayScrollProgress);
IBinder windowToken = mLauncher.getRootView().getWindowToken();
if (windowToken != null) {
- mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
+ mWallpaperManager.setWallpaperZoomOut(windowToken, depth);
}
- if (supportsBlur && (mSurface != null && mSurface.isValid())) {
+ if (supportsBlur) {
// We cannot mark the window as opaque in overview because there will be an app window
// below the launcher layer, and we need to draw it -- without blurs.
boolean isOverview = mLauncher.isInState(LauncherState.OVERVIEW);
boolean opaque = mLauncher.getScrimView().isFullyOpaque() && !isOverview;
int blur = opaque || isOverview || !mCrossWindowBlursEnabled
- || mBlurDisabledForAppLaunch ? 0 : (int) (mDepth * mMaxBlurRadius);
- new SurfaceControl.Transaction()
+ || mBlurDisabledForAppLaunch ? 0 : (int) (depth * mMaxBlurRadius);
+ SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
.setBackgroundBlurRadius(mSurface, blur)
- .setOpaque(mSurface, opaque)
- .apply();
+ .setOpaque(mSurface, opaque);
+
+ // 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.
+ boolean wantsEarlyWakeUp = depth > 0 && depth < 1;
+ if (wantsEarlyWakeUp && !mInEarlyWakeUp) {
+ transaction.setEarlyWakeupStart();
+ mInEarlyWakeUp = true;
+ } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) {
+ transaction.setEarlyWakeupEnd();
+ mInEarlyWakeUp = false;
+ }
+ transaction.apply();
}
+ return true;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 1edeba0..08300e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -79,8 +79,10 @@
private final TaskbarActivityContext mContext;
private final FrameLayout mNavButtonsView;
- private final ViewGroup mStartContainer;
- private final ViewGroup mEndContainer;
+ private final ViewGroup mNavButtonContainer;
+ // Used for IME+A11Y buttons
+ private final ViewGroup mEndContextualContainer;
+ private final ViewGroup mStartContextualContainer;
// Initialized in init.
private TaskbarControllers mControllers;
@@ -91,8 +93,9 @@
public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
mContext = context;
mNavButtonsView = navButtonsView;
- mStartContainer = mNavButtonsView.findViewById(R.id.start_nav_buttons);
- mEndContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
+ mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
+ mEndContextualContainer = mNavButtonsView.findViewById(R.id.end_contextual_buttons);
+ mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
}
/**
@@ -114,64 +117,72 @@
// IME switcher
View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
- mEndContainer, mControllers.navButtonController, R.id.ime_switcher);
+ mEndContextualContainer, mControllers.navButtonController, R.id.ime_switcher);
mPropertyHolders.add(new StatePropertyHolder(imeSwitcherButton,
flags -> ((flags & MASK_IME_SWITCHER_VISIBLE) == MASK_IME_SWITCHER_VISIBLE)
&& ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)
&& ((flags & FLAG_A11Y_VISIBLE) == 0)));
- mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
- mStartContainer, mControllers.navButtonController, R.id.back);
+ View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
+ mStartContextualContainer, mControllers.navButtonController, R.id.back);
+ imeDownButton.setRotation(Utilities.isRtl(mContext.getResources()) ? 90 : -90);
// Rotate when Ime visible
- mPropertyHolders.add(new StatePropertyHolder(mBackButton,
- flags -> (flags & FLAG_IME_VISIBLE) == 0, View.ROTATION, 0,
- Utilities.isRtl(mContext.getResources()) ? 90 : -90));
+ mPropertyHolders.add(new StatePropertyHolder(imeDownButton,
+ flags -> (flags & FLAG_IME_VISIBLE) != 0));
+
+ mPropertyHolders.add(new StatePropertyHolder(
+ mControllers.taskbarViewController.getTaskbarIconAlpha()
+ .getProperty(ALPHA_INDEX_KEYGUARD),
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
+
+ mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
+ .getKeyguardBgTaskbar(),
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, AnimatedFloat.VALUE, 1, 0));
if (mContext.isThreeButtonNav()) {
- initButtons(mStartContainer, mEndContainer, mControllers.navButtonController);
+ initButtons(mNavButtonContainer, mEndContextualContainer,
+ mControllers.navButtonController);
// Animate taskbar background when IME shows
mPropertyHolders.add(new StatePropertyHolder(
mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
- flags -> (flags & FLAG_IME_VISIBLE) == 0,
- AnimatedFloat.VALUE, 0, 1));
- mPropertyHolders.add(new StatePropertyHolder(
- mControllers.taskbarViewController.getTaskbarIconAlpha()
- .getProperty(ALPHA_INDEX_KEYGUARD),
- flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
+ flags -> (flags & FLAG_IME_VISIBLE) != 0 ||
+ (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0,
+ AnimatedFloat.VALUE, 1, 0));
// Rotation button
RotationButton rotationButton = new RotationButtonImpl(
- addButton(mEndContainer, R.id.rotate_suggestion));
+ addButton(mEndContextualContainer, R.id.rotate_suggestion));
rotationButton.hide();
mControllers.rotationButtonController.setRotationButton(rotationButton);
} else {
mControllers.rotationButtonController.setRotationButton(new RotationButton() {});
- // Show when IME is visible
- mPropertyHolders.add(new StatePropertyHolder(mBackButton,
- flags -> (flags & FLAG_IME_VISIBLE) != 0));
}
applyState();
mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
}
- private void initButtons(ViewGroup startContainer, ViewGroup endContainer,
+ private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
TaskbarNavButtonController navButtonController) {
+ mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
+ mNavButtonContainer, mControllers.navButtonController, R.id.back);
+ mPropertyHolders.add(new StatePropertyHolder(mBackButton,
+ flags -> (flags & FLAG_IME_VISIBLE) == 0));
// Hide when keyguard is showing, show when bouncer is showing
mPropertyHolders.add(new StatePropertyHolder(mBackButton,
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
(flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
// home and recents buttons
- View homeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, startContainer,
+ View homeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer,
navButtonController, R.id.home);
mPropertyHolders.add(new StatePropertyHolder(homeButton,
flags -> (flags & FLAG_IME_VISIBLE) == 0 &&
(flags & FLAG_KEYGUARD_VISIBLE) == 0));
View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
- startContainer, navButtonController, R.id.recent_apps);
+ navContainer, navButtonController, R.id.recent_apps);
mPropertyHolders.add(new StatePropertyHolder(recentsButton,
flags -> (flags & FLAG_IME_VISIBLE) == 0 &&
(flags & FLAG_KEYGUARD_VISIBLE) == 0));
@@ -216,7 +227,7 @@
}
/**
- * Slightly misnamed, but should be called when only keyguard OR AOD is showing
+ * Slightly misnamed, but should be called when keyguard OR AOD is showing
*/
public void setKeyguardVisible(boolean isKeyguardVisible) {
updateStateForFlag(FLAG_KEYGUARD_VISIBLE, isKeyguardVisible);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 67ebc02..b89032e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -117,6 +117,24 @@
dragLayerY += dragRect.top;
DragOptions dragOptions = new DragOptions();
+ dragOptions.preDragCondition = new DragOptions.PreDragCondition() {
+ private DragView mDragView;
+
+ @Override
+ public boolean shouldStartDrag(double distanceDragged) {
+ return mDragView != null && mDragView.isAnimationFinished();
+ }
+
+ @Override
+ public void onPreDragStart(DropTarget.DragObject dragObject) {
+ mDragView = dragObject.dragView;
+ }
+
+ @Override
+ public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
+ mDragView = null;
+ }
+ };
// TODO: open popup/pre-drag
// PopupContainerWithArrow popupContainer = PopupContainerWithArrow.showForIcon(view);
// if (popupContainer != null) {
@@ -155,6 +173,7 @@
mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext());
mDragObject.originalView = originalView;
+ mDragObject.deferDragViewCleanupPostAnimation = false;
mIsInPreDrag = mOptions.preDragCondition != null
&& !mOptions.preDragCondition.shouldStartDrag(0);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index e15e9ff..df89285 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -39,6 +39,7 @@
// Alpha properties for taskbar background.
private final AnimatedFloat mBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
private final AnimatedFloat mBgNavbar = new AnimatedFloat(this::updateBackgroundAlpha);
+ private final AnimatedFloat mKeyguardBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
// Translation property for taskbar background.
private final AnimatedFloat mBgOffset = new AnimatedFloat(this::updateBackgroundOffset);
@@ -56,6 +57,7 @@
public void init(TaskbarControllers controllers) {
mControllers = controllers;
mTaskbarDragLayer.init(new TaskbarDragLayerCallbacks());
+ mKeyguardBgTaskbar.value = 1;
}
public void onDestroy() {
@@ -80,12 +82,18 @@
return mBgNavbar;
}
+ public AnimatedFloat getKeyguardBgTaskbar() {
+ return mKeyguardBgTaskbar;
+ }
+
public AnimatedFloat getTaskbarBackgroundOffset() {
return mBgOffset;
}
private void updateBackgroundAlpha() {
- mTaskbarDragLayer.setTaskbarBackgroundAlpha(Math.max(mBgNavbar.value, mBgTaskbar.value));
+ mTaskbarDragLayer.setTaskbarBackgroundAlpha(
+ Math.max(mBgNavbar.value, mBgTaskbar.value * mKeyguardBgTaskbar.value)
+ );
}
private void updateBackgroundOffset() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index 2936bd2..a2039b6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -57,10 +57,6 @@
mKeyguardSysuiFlags = interestingKeyguardFlags;
mBouncerShowing = bouncerShowing;
- if (!mContext.isThreeButtonNav()) {
- // For gesture nav we don't need to deal with bouncer or showing taskbar when locked
- return;
- }
mNavbarButtonsViewController.setKeyguardVisible(keyguardShowing || dozing);
updateIconsForBouncer();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 6f53f2b..a4a92f7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -194,24 +194,30 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int count = getChildCount();
int spaceNeeded = count * (mItemMarginLeftRight * 2 + mIconTouchSize);
- int iconStart = (right - left - spaceNeeded) / 2;
- int startOffset = ApiWrapper.getHotseatStartOffset(getContext());
- if (startOffset > iconStart) {
- int diff = startOffset - iconStart;
- iconStart = isLayoutRtl() ? (iconStart - diff) : iconStart + diff;
+ int navSpaceNeeded = ApiWrapper.getHotseatEndOffset(getContext());
+ boolean layoutRtl = isLayoutRtl();
+ int iconEnd = right - (right - left - spaceNeeded) / 2;
+ boolean needMoreSpaceForNav = layoutRtl ?
+ navSpaceNeeded > (iconEnd - spaceNeeded) :
+ iconEnd > (right - navSpaceNeeded);
+ if (needMoreSpaceForNav) {
+ int offset = layoutRtl ?
+ navSpaceNeeded - (iconEnd - spaceNeeded) :
+ (right - navSpaceNeeded) - iconEnd;
+ iconEnd += offset;
}
// Layout the children
- mIconLayoutBounds.left = iconStart;
+ mIconLayoutBounds.right = iconEnd;
mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2;
mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize;
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- iconStart += mItemMarginLeftRight;
- int iconEnd = iconStart + mIconTouchSize;
+ for (int i = count; i > 0; i--) {
+ View child = getChildAt(i - 1);
+ iconEnd -= mItemMarginLeftRight;
+ int iconStart = iconEnd - mIconTouchSize;
child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom);
- iconStart = iconEnd + mItemMarginLeftRight;
+ iconEnd = iconStart - mItemMarginLeftRight;
}
- mIconLayoutBounds.right = iconStart;
+ mIconLayoutBounds.left = iconEnd;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index a595f54..85943b6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -44,9 +44,9 @@
}
/**
- * Returns the minimum space that should be left empty at the start of hotseat
+ * Returns the minimum space that should be left empty at the end of hotseat
*/
- public static int getHotseatStartOffset(Context context) {
+ public static int getHotseatEndOffset(Context context) {
if (SysUINavigationMode.INSTANCE.get(context).getMode() == Mode.THREE_BUTTONS) {
Resources res = context.getResources();
return 2 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_spacing)
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 6cad3dd..1f744e1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -18,13 +18,11 @@
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
-import static com.android.launcher3.LauncherState.SPLIT_PLACHOLDER_VIEW;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
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.SplitPlaceholderView.ALPHA_FLOAT;
import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;
import android.annotation.TargetApi;
@@ -110,11 +108,6 @@
propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
MultiValueAlpha.VALUE, overviewButtonAlpha, config.getInterpolator(
ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
-
- float splitPlaceholderAlpha = state.areElementsVisible(mLauncher, SPLIT_PLACHOLDER_VIEW) ?
- 0.85f : 0;
- propertySetter.setFloat(mRecentsView.getSplitPlaceholder(), ALPHA_FLOAT,
- splitPlaceholderAlpha, LINEAR);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 90e17c0..1302ac0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -28,7 +28,6 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Workspace;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Themes;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.util.LayoutUtils;
@@ -104,7 +103,7 @@
@Override
public boolean displayOverviewTasksAsGrid(DeviceProfile deviceProfile) {
- return deviceProfile.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get();
+ return deviceProfile.overviewShowAsGrid;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
index 6968494..1882a0c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
@@ -43,7 +43,7 @@
@Override
public float getSplitSelectTranslation(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
- int splitPosition = recentsView.getSplitPlaceholder().getSplitController()
+ int splitPosition = recentsView.getSplitPlaceholder()
.getActiveSplitPositionOption().mStagePosition;
if (!recentsView.shouldShiftThumbnailsForSplitSelect(splitPosition)) {
return 0f;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 051485a..0603ba5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -227,7 +227,8 @@
if (goingUp) {
currentInterpolator = Interpolators.LINEAR;
pa = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
- true /* animateTaskView */, true /* removeTask */, maxDuration);
+ true /* animateTaskView */, true /* removeTask */, maxDuration,
+ false /* dismissingForSplitSelection*/);
mEndDisplacement = -secondaryTaskDimension;
} else {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9180bd0..6249e6a 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -212,6 +212,8 @@
public static final long RECENTS_ATTACH_DURATION = 300;
+ private static final float MAX_QUICK_SWITCH_RECENTS_SCALE_PROGRESS = 0.07f;
+
/**
* Used as the page index for logging when we return to the last task at the end of the gesture.
*/
@@ -252,6 +254,9 @@
private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
protected boolean mIsSwipingPipToHome;
+ // Interpolate RecentsView scale from start of quick switch scroll until this scroll threshold
+ private final float mQuickSwitchScaleScrollThreshold;
+
public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
@@ -267,6 +272,8 @@
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
+ mQuickSwitchScaleScrollThreshold = context.getResources().getDimension(
+ R.dimen.quick_switch_scaling_scroll_threshold);
initAfterSubclassConstructor();
initStateCallbacks();
@@ -539,7 +546,7 @@
@Override
public void onMotionPauseDetected() {
mHasMotionEverBeenPaused = true;
- maybeUpdateRecentsAttachedState();
+ maybeUpdateRecentsAttachedState(true/* animate */, true/* moveFocusedTask */);
performHapticFeedback();
}
@@ -550,18 +557,24 @@
};
}
- public void maybeUpdateRecentsAttachedState() {
+ private void maybeUpdateRecentsAttachedState() {
maybeUpdateRecentsAttachedState(true /* animate */);
}
+ private void maybeUpdateRecentsAttachedState(boolean animate) {
+ maybeUpdateRecentsAttachedState(animate, false /* moveFocusedTask */);
+ }
+
/**
* Determines whether to show or hide RecentsView. The window is always
* synchronized with its corresponding TaskView in RecentsView, so if
* RecentsView is shown, it will appear to be attached to the window.
*
* Note this method has no effect unless the navigation mode is NO_BUTTON.
+ * @param animate whether to animate when attaching RecentsView
+ * @param moveFocusedTask whether to move focused task to front when attaching
*/
- private void maybeUpdateRecentsAttachedState(boolean animate) {
+ private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveFocusedTask) {
if (!mDeviceState.isFullyGesturalNavMode() || mRecentsView == null) {
return;
}
@@ -580,6 +593,12 @@
} else {
recentsAttachedToAppWindow = mHasMotionEverBeenPaused || mIsLikelyToStartNewTask;
}
+ if (moveFocusedTask && !mAnimationFactory.hasRecentsEverAttachedToAppWindow()
+ && recentsAttachedToAppWindow) {
+ // Only move focused task if RecentsView has never been attached before, to avoid
+ // TaskView jumping to new position as we move the tasks.
+ mRecentsView.moveFocusedTaskToFront();
+ }
mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
// Reapply window transform throughout the attach animation, as the animation affects how
@@ -669,7 +688,8 @@
|| !canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
}
- mLauncherTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
+ mLauncherTransitionController.setProgress(
+ Math.max(mCurrentShift.value, getScaleProgressDueToScroll()), mDragLengthFactor);
}
/**
@@ -1133,6 +1153,12 @@
mGestureState.getEndTarget(), duration,
mTaskAnimationManager.getCurrentCallbacks());
if (mParallelRunningAnim != null) {
+ mParallelRunningAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mParallelRunningAnim = null;
+ }
+ });
mParallelRunningAnim.start();
}
}
@@ -1148,6 +1174,7 @@
boolean isTranslucent = runningTaskTarget != null && runningTaskTarget.isTranslucent;
boolean appCanEnterPip = !mDeviceState.isPipActive()
&& runningTaskTarget != null
+ && runningTaskTarget.allowEnterPip
&& runningTaskTarget.taskInfo.pictureInPictureParams != null
&& runningTaskTarget.taskInfo.pictureInPictureParams.isAutoEnterEnabled();
HomeAnimationFactory homeAnimFactory =
@@ -1234,12 +1261,23 @@
}
}
+ private int calculateWindowRotation(RemoteAnimationTargetCompat runningTaskTarget,
+ RecentsOrientedState orientationState) {
+ if (runningTaskTarget.rotationChange != 0
+ && TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ return Math.abs(runningTaskTarget.rotationChange) == ROTATION_90
+ ? ROTATION_270 : ROTATION_90;
+ } else {
+ return orientationState.getDisplayRotation();
+ }
+ }
+
private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory,
RemoteAnimationTargetCompat runningTaskTarget, float startProgress) {
// Directly animate the app to PiP (picture-in-picture) mode
final ActivityManager.RunningTaskInfo taskInfo = mGestureState.getRunningTask();
final RecentsOrientedState orientationState = mTaskViewSimulator.getOrientationState();
- final int windowRotation = orientationState.getDisplayRotation();
+ final int windowRotation = calculateWindowRotation(runningTaskTarget, orientationState);
final int homeRotation = orientationState.getRecentsActivityRotation();
final Matrix homeToWindowPositionMap = new Matrix();
@@ -1496,6 +1534,8 @@
boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
+ TaskViewUtils.setDividerBarShown(mRecentsAnimationTargets.nonApps, true);
+
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
if (mActivity != null) {
mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
@@ -1784,7 +1824,9 @@
*/
protected void applyWindowTransform() {
if (mWindowTransitionController != null) {
- mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
+ mWindowTransitionController.setProgress(
+ Math.max(mCurrentShift.value, getScaleProgressDueToScroll()),
+ mDragLengthFactor);
}
// No need to apply any transform if there is ongoing swipe-pip-to-home animator since
// that animator handles the leash solely.
@@ -1797,6 +1839,35 @@
ProtoTracer.INSTANCE.get(mContext).scheduleFrameUpdate();
}
+ // Scaling of RecentsView during quick switch based on amount of recents scroll
+ private float getScaleProgressDueToScroll() {
+ if (mActivity == null || !mActivity.getDeviceProfile().isTablet || mRecentsView == null
+ || !mRecentsViewScrollLinked) {
+ return 0;
+ }
+
+ float scrollOffset = Math.abs(mRecentsView.getScrollOffset(mRecentsView.getCurrentPage()));
+ int maxScrollOffset = mRecentsView.getPagedOrientationHandler().getPrimaryValue(
+ mRecentsView.getLastComputedTaskSize().width(),
+ mRecentsView.getLastComputedTaskSize().height());
+ maxScrollOffset += mRecentsView.getPageSpacing();
+
+ float maxScaleProgress =
+ MAX_QUICK_SWITCH_RECENTS_SCALE_PROGRESS * mRecentsView.getMaxScaleForFullScreen();
+ float scaleProgress = maxScaleProgress;
+
+ if (scrollOffset < mQuickSwitchScaleScrollThreshold) {
+ scaleProgress = Utilities.mapToRange(scrollOffset, 0, mQuickSwitchScaleScrollThreshold,
+ 0, maxScaleProgress, ACCEL_DEACCEL);
+ } else if (scrollOffset > (maxScrollOffset - mQuickSwitchScaleScrollThreshold)) {
+ scaleProgress = Utilities.mapToRange(scrollOffset,
+ (maxScrollOffset - mQuickSwitchScaleScrollThreshold), maxScrollOffset,
+ maxScaleProgress, 0, ACCEL_DEACCEL);
+ }
+
+ return scaleProgress;
+ }
+
/**
* Used for winscope tracing, see launcher_trace.proto
* @see com.android.systemui.shared.tracing.ProtoTraceable#writeToProto
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 615a510..624ade2 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -48,7 +48,6 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -207,18 +206,12 @@
public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
PagedOrientationHandler orientedState) {
Resources res = context.getResources();
- if (dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+ if (dp.overviewShowAsGrid) {
Rect gridRect = new Rect();
calculateGridSize(context, dp, gridRect);
- int verticalMargin = Math.max(
- res.getDimensionPixelSize(R.dimen.overview_grid_focus_vertical_margin),
- res.getDimensionPixelSize(R.dimen.overview_actions_height));
- float taskHeight =
- gridRect.height() - verticalMargin * 2 - dp.overviewTaskThumbnailTopMarginPx;
-
PointF taskDimension = getTaskDimension(context, dp);
- float scale = taskHeight / taskDimension.y;
+ float scale = gridRect.height() / taskDimension.y;
int outWidth = Math.round(scale * taskDimension.x);
int outHeight = Math.round(scale * taskDimension.y);
@@ -226,19 +219,9 @@
Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
} else {
int taskMargin = dp.overviewTaskMarginPx;
- int proactiveRowAndMargin;
- if (!TaskView.SHOW_PROACTIVE_ACTIONS || dp.isVerticalBarLayout()) {
- // In Vertical Bar Layout the proactive row doesn't have its own space, it's inside
- // the actions row.
- proactiveRowAndMargin = 0;
- } else {
- proactiveRowAndMargin = res.getDimensionPixelSize(
- R.dimen.overview_proactive_row_height)
- + res.getDimensionPixelSize(R.dimen.overview_proactive_row_bottom_margin);
- }
calculateTaskSizeInternal(context, dp,
dp.overviewTaskThumbnailTopMarginPx,
- proactiveRowAndMargin + getOverviewActionsHeight(context, dp),
+ getProactiveRowAndMargin(context, dp) + getOverviewActionsHeight(context, dp),
res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
outRect);
}
@@ -300,13 +283,14 @@
*/
public final void calculateGridSize(Context context, DeviceProfile dp, Rect outRect) {
Resources res = context.getResources();
- int topMargin = res.getDimensionPixelSize(R.dimen.overview_grid_top_margin);
- int bottomMargin = res.getDimensionPixelSize(R.dimen.overview_grid_bottom_margin);
+ Rect insets = dp.getInsets();
+ int topMargin = dp.overviewTaskThumbnailTopMarginPx;
+ int bottomMargin =
+ getProactiveRowAndMargin(context, dp) + getOverviewActionsHeight(context, dp);
int sideMargin = res.getDimensionPixelSize(R.dimen.overview_grid_side_margin);
- Rect insets = dp.getInsets();
outRect.set(0, 0, dp.widthPx, dp.heightPx);
- outRect.inset(Math.max(insets.left, sideMargin), Math.max(insets.top, topMargin),
+ outRect.inset(Math.max(insets.left, sideMargin), insets.top + topMargin,
Math.max(insets.right, sideMargin), Math.max(insets.bottom, bottomMargin));
}
@@ -319,8 +303,9 @@
Rect gridRect = new Rect();
calculateGridSize(context, dp, gridRect);
- int rowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
- float rowHeight = (gridRect.height() - rowSpacing) / 2f;
+ float rowHeight =
+ (gridRect.height() + dp.overviewTaskThumbnailTopMarginPx - dp.overviewRowSpacing)
+ / 2f;
PointF taskDimension = getTaskDimension(context, dp);
float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / taskDimension.y;
@@ -329,7 +314,6 @@
int gravity = Gravity.TOP;
gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
- gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);
Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
}
@@ -345,6 +329,21 @@
outRect);
}
+ private int getProactiveRowAndMargin(Context context, DeviceProfile dp) {
+ Resources res = context.getResources();
+ int proactiveRowAndMargin;
+ if (!TaskView.SHOW_PROACTIVE_ACTIONS || dp.isVerticalBarLayout()) {
+ // In Vertical Bar Layout the proactive row doesn't have its own space, it's inside
+ // the actions row.
+ proactiveRowAndMargin = 0;
+ } else {
+ proactiveRowAndMargin = res.getDimensionPixelSize(
+ R.dimen.overview_proactive_row_height)
+ + res.getDimensionPixelSize(R.dimen.overview_proactive_row_bottom_margin);
+ }
+ return proactiveRowAndMargin;
+ }
+
/** Gets the space that the overview actions will take, including bottom margin. */
private int getOverviewActionsHeight(Context context, DeviceProfile dp) {
Resources res = context.getResources();
@@ -400,6 +399,10 @@
default boolean isRecentsAttachedToAppWindow() {
return false;
}
+
+ default boolean hasRecentsEverAttachedToAppWindow() {
+ return false;
+ }
}
class DefaultAnimationFactory implements AnimationFactory {
@@ -409,6 +412,7 @@
private final Consumer<AnimatorControllerWithResistance> mCallback;
private boolean mIsAttachedToWindow;
+ private boolean mHasEverAttachedToWindow;
DefaultAnimationFactory(Consumer<AnimatorControllerWithResistance> callback) {
mCallback = callback;
@@ -462,6 +466,9 @@
}
mIsAttachedToWindow = attached;
RecentsView recentsView = mActivity.getOverviewPanel();
+ if (attached) {
+ mHasEverAttachedToWindow = true;
+ }
Animator fadeAnim = mActivity.getStateManager()
.createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
@@ -491,6 +498,11 @@
return mIsAttachedToWindow;
}
+ @Override
+ public boolean hasRecentsEverAttachedToAppWindow() {
+ return mHasEverAttachedToWindow;
+ }
+
protected void createBackgroundToOverviewAnim(ACTIVITY_TYPE activity, PendingAnimation pa) {
// Scale down recents from being full screen to being in overview.
RecentsView recentsView = activity.getOverviewPanel();
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index f29d68a..7fb8e16 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -107,10 +107,9 @@
public RecentsView getVisibleRecentsView() {
RecentsActivity activity = getCreatedActivity();
if (activity != null) {
- RecentsView recentsView = activity.getOverviewPanel();
- if (activity.hasBeenResumed() || (ENABLE_QUICKSTEP_LIVE_TILE.get() && isInLiveTileMode()
- && recentsView.getRunningTaskId() == -1)) {
- return recentsView;
+ if (activity.hasBeenResumed()
+ || (ENABLE_QUICKSTEP_LIVE_TILE.get() && isInLiveTileMode())) {
+ return activity.getOverviewPanel();
}
}
return null;
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index fd44e02..e2f198c 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -173,7 +173,9 @@
@Override
protected void notifyGestureAnimationStartToRecents() {
if (mRunningOverHome) {
- mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
+ if (SysUINavigationMode.getMode(mContext).hasGestures) {
+ mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
+ }
} else {
super.notifyGestureAnimationStartToRecents();
}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 5deb75e..d91d5b0 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -189,7 +189,7 @@
launcher != null && launcher.getStateManager().getState().overviewUi
? launcher.getOverviewPanel() : null;
if (recentsView == null || (!launcher.hasBeenResumed()
- && recentsView.getRunningTaskId() == -1)) {
+ && recentsView.getRunningTaskViewId() == -1)) {
// If live tile has ended, return null.
return null;
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 742d02d..5d1f908 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
@@ -110,6 +109,11 @@
MAIN_EXECUTOR.execute(() -> addCommand(cmd));
}
+ @UiThread
+ public void clearPendingCommands() {
+ mPendingCommands.clear();
+ }
+
private TaskView getNextTask(RecentsView view) {
final TaskView runningTaskView = view.getRunningTaskView();
@@ -199,6 +203,12 @@
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
interactionHandler.onGestureCancelled();
cmd.removeListener(this);
+
+ RecentsView createdRecents =
+ activityInterface.getCreatedActivity().getOverviewPanel();
+ if (createdRecents != null) {
+ createdRecents.onRecentsAnimationComplete();
+ }
}
};
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 0efe666..780032e 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -33,8 +33,11 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.SystemClock;
+import android.util.Log;
import android.util.SparseIntArray;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.tracing.OverviewComponentObserverProto;
import com.android.launcher3.tracing.TouchInteractionServiceProto;
import com.android.launcher3.util.SimpleBroadcastReceiver;
@@ -129,6 +132,16 @@
private void updateOverviewTargets() {
ComponentName defaultHome = PackageManagerWrapper.getInstance()
.getHomeActivities(new ArrayList<>());
+ if (TestProtocol.sDebugTracing && defaultHome == null) {
+ Log.d(TestProtocol.THIRD_PARTY_LAUNCHER_NOT_SET, "getHomeActivities returned null");
+ while ((defaultHome =
+ PackageManagerWrapper.getInstance().getHomeActivities(new ArrayList<>()))
+ == null) {
+ SystemClock.sleep(10);
+ }
+ Log.d(TestProtocol.THIRD_PARTY_LAUNCHER_NOT_SET,
+ "getHomeActivities returned non-null: " + defaultHome);
+ }
mIsHomeDisabled = mDeviceState.isHomeDisabled();
mIsDefaultHome = Objects.equals(mMyHomeIntent.getComponent(), defaultHome);
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 39af0db..d531339 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -21,7 +21,7 @@
}
@Override
- public Bundle call(String method) {
+ public Bundle call(String method, String arg) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT: {
@@ -66,7 +66,7 @@
}
}
- return super.call(method);
+ return super.call(method, arg);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 9dfcd12..03e2395 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -22,8 +22,8 @@
import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY;
import static com.android.launcher3.Utilities.createHomeIntent;
-import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
@@ -75,7 +75,6 @@
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.SplitPlaceholderView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -122,13 +121,10 @@
mActionsView = findViewById(R.id.overview_actions_view);
SYSUI_PROGRESS.set(getRootView().getSysUiScrim(), 0f);
- SplitPlaceholderView splitPlaceholderView = findViewById(R.id.split_placeholder);
- splitPlaceholderView.init(
- new SplitSelectStateController(mUiHandler, SystemUiProxy.INSTANCE.get(this))
- );
-
+ SplitSelectStateController controller =
+ new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this));
mDragLayer.recreateControllers();
- mFallbackRecentsView.init(mActionsView, splitPlaceholderView);
+ mFallbackRecentsView.init(mActionsView, controller);
}
@Override
@@ -290,7 +286,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mStateManager = new StateManager<>(this, RecentsState.DEFAULT);
+ mStateManager = new StateManager<>(this, RecentsState.BG_LAUNCHER);
mOldConfig = new Configuration(getResources().getConfiguration());
initDeviceProfile();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index dac6981..11ca4b1 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -358,7 +358,7 @@
try {
mSystemUiProxy.setSplitScreenMinimized(minimized);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call stopScreenPinning", e);
+ Log.w(TAG, "Failed call setSplitScreenMinimized", e);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index f292f1a..b5da097 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -63,7 +63,6 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
@@ -140,7 +139,7 @@
// If the opening task id is not currently visible in overview, then fall back to normal app
// icon launch animation
- TaskView taskView = recentsView.getTaskView(openingTaskId);
+ TaskView taskView = recentsView.getTaskViewByTaskId(openingTaskId);
if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
return null;
}
@@ -196,7 +195,7 @@
int taskIndex = recentsView.indexOfChild(v);
Context context = v.getContext();
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
- boolean showAsGrid = dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get();
+ boolean showAsGrid = dp.overviewShowAsGrid;
boolean parallaxCenterAndAdjacentTask =
taskIndex != recentsView.getCurrentPage() && !showAsGrid;
float gridTranslationSecondary = recentsView.getGridTranslationSecondary(taskIndex);
@@ -465,7 +464,7 @@
if (launcherClosing) {
Context context = v.getContext();
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
- launcherAnim = dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()
+ launcherAnim = dp.overviewShowAsGrid
? ObjectAnimator.ofFloat(recentsView, RecentsView.CONTENT_ALPHA, 0)
: recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 20d7eb1..61622ee 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -297,6 +297,10 @@
public TaskbarManager getTaskbarManager() {
return mTaskbarManager;
}
+
+ public OverviewCommandHelper getOverviewCommandHelper() {
+ return mOverviewCommandHelper;
+ }
}
private static boolean sConnected = false;
@@ -307,7 +311,6 @@
return sConnected;
}
-
public static boolean isInitialized() {
return sIsInitialized;
}
@@ -584,8 +587,7 @@
} else {
mUncheckedConsumer = InputConsumer.NO_OP;
}
- } else if (mDeviceState.canTriggerOneHandedAction(event)
- && !mDeviceState.isOneHandedModeActive()) {
+ } else if (mDeviceState.canTriggerOneHandedAction(event)) {
// Consume gesture event for triggering one handed feature.
mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
InputConsumer.NO_OP, mInputMonitorCompat);
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 3bf79f1..64a428f 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -24,6 +24,7 @@
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;
@@ -36,10 +37,10 @@
import com.android.quickstep.FallbackActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsActivity;
+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.SplitPlaceholderView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -62,8 +63,8 @@
}
@Override
- public void init(OverviewActionsView actionsView, SplitPlaceholderView splitPlaceholderView) {
- super.init(actionsView, splitPlaceholderView);
+ public void init(OverviewActionsView actionsView, SplitSelectStateController splitController) {
+ super.init(actionsView, splitController);
setOverviewStateEnabled(true);
setOverlayEnabled(true);
}
@@ -94,9 +95,10 @@
TaskViewSimulator taskViewSimulator) {
super.onPrepareGestureEndAnimation(animatorSet, endTarget, taskViewSimulator);
if (mHomeTaskInfo != null && endTarget == RECENTS && animatorSet != null) {
- TaskView tv = getTaskView(mHomeTaskInfo.taskId);
+ TaskView tv = getTaskViewByTaskId(mHomeTaskInfo.taskId);
if (tv != null) {
- PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150);
+ PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150,
+ false /* dismissingForSplitSelection*/);
pa.addEndListener(e -> setCurrentTask(-1));
AnimatorPlaybackController controller = pa.createPlaybackController();
controller.dispatchOnStart();
@@ -115,8 +117,9 @@
}
@Override
- public void setCurrentTask(int runningTaskId) {
- super.setCurrentTask(runningTaskId);
+ public void setCurrentTask(int runningTaskViewId) {
+ super.setCurrentTask(runningTaskViewId);
+ int runningTaskId = getTaskIdsForRunningTaskView()[0];
if (mHomeTaskInfo != null && mHomeTaskInfo.taskId != runningTaskId) {
mHomeTaskInfo = null;
setRunningTaskHidden(false);
@@ -126,7 +129,7 @@
@Nullable
@Override
protected TaskView getHomeTaskView() {
- return mHomeTaskInfo != null ? getTaskView(mHomeTaskInfo.taskId) : null;
+ return mHomeTaskInfo != null ? getTaskViewByTaskId(mHomeTaskInfo.taskId) : null;
}
@Override
@@ -146,11 +149,12 @@
// When quick-switching on 3p-launcher, we add a "stub" tile corresponding to Launcher
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
// track the index of the next task appropriately, as if we are switching on any other app.
- if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == mRunningTaskId && !tasks.isEmpty()) {
+ int runningTaskId = getTaskIdsForRunningTaskView()[0];
+ if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == runningTaskId && !tasks.isEmpty()) {
// Check if the task list has running task
boolean found = false;
for (Task t : tasks) {
- if (t.key.id == mRunningTaskId) {
+ if (t.key.id == runningTaskId) {
found = true;
break;
}
@@ -182,6 +186,7 @@
} else {
if (mActivity.isInState(RecentsState.MODAL_TASK)) {
mActivity.getStateManager().goToState(DEFAULT);
+ resetModalVisuals();
}
}
}
@@ -219,4 +224,12 @@
// 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 111a940..917b58a 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -23,7 +23,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.util.Themes;
import com.android.quickstep.RecentsActivity;
@@ -43,8 +42,8 @@
private static final int FLAG_OVERVIEW_UI = BaseState.getFlag(7);
public static final RecentsState DEFAULT = new RecentsState(0,
- FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID | FLAG_SCRIM
- | FLAG_LIVE_TILE | FLAG_OVERVIEW_UI);
+ FLAG_DISABLE_RESTORE | FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_SHOW_AS_GRID
+ | FLAG_SCRIM | FLAG_LIVE_TILE | FLAG_OVERVIEW_UI);
public static final RecentsState MODAL_TASK = new ModalState(1,
FLAG_DISABLE_RESTORE | FLAG_CLEAR_ALL_BUTTON | FLAG_OVERVIEW_ACTIONS | FLAG_MODAL
| FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_LIVE_TILE | FLAG_OVERVIEW_UI);
@@ -134,11 +133,7 @@
* For this state, whether tasks should layout as a grid rather than a list.
*/
public boolean displayOverviewTasksAsGrid(DeviceProfile deviceProfile) {
- return hasFlag(FLAG_SHOW_AS_GRID) && showAsGrid(deviceProfile);
- }
-
- private boolean showAsGrid(DeviceProfile deviceProfile) {
- return deviceProfile.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get();
+ return hasFlag(FLAG_SHOW_AS_GRID) && deviceProfile.overviewShowAsGrid;
}
/**
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index 6bdc284..7ae0fc8 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -16,19 +16,15 @@
package com.android.quickstep.logging;
-import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_WORKSPACE_SIZE;
import static com.android.launcher3.Utilities.getDevicePrefs;
import static com.android.launcher3.Utilities.getPrefs;
-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;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_5;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_DISABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_ENABLED;
+import static com.android.launcher3.model.DeviceGridState.KEY_WORKSPACE_SIZE;
import static com.android.launcher3.model.QuickstepModelDelegate.LAST_PREDICTION_ENABLED_STATE;
import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
import static com.android.launcher3.util.Themes.KEY_THEMED_ICONS;
@@ -43,11 +39,11 @@
import com.android.launcher3.AutoInstallsLayout;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
+import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.util.SettingsCache;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
@@ -135,7 +131,8 @@
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (LAST_PREDICTION_ENABLED_STATE.equals(key)
- || KEY_MIGRATION_SRC_WORKSPACE_SIZE.equals(key)
+ || KEY_WORKSPACE_SIZE.equals(key)
+ || KEY_THEMED_ICONS.equals(key)
|| mLoggablePrefs.containsKey(key)) {
dispatchUserEvent();
}
@@ -153,32 +150,13 @@
? LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED
: LAUNCHER_HOME_SCREEN_SUGGESTIONS_DISABLED);
- SharedPreferences prefs = getPrefs(mContext);
- StatsLogManager.LauncherEvent gridSizeChangedEvent = null;
- String workspaceSize = prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, null);
- if (workspaceSize != null) {
- switch (Utilities.parsePoint(workspaceSize).x) {
- case 5:
- gridSizeChangedEvent = LAUNCHER_GRID_SIZE_5;
- break;
- case 4:
- gridSizeChangedEvent = LAUNCHER_GRID_SIZE_4;
- break;
- case 3:
- gridSizeChangedEvent = LAUNCHER_GRID_SIZE_3;
- break;
- case 2:
- gridSizeChangedEvent = LAUNCHER_GRID_SIZE_2;
- break;
- default:
- // Ignore illegal input.
- break;
- }
- }
+ StatsLogManager.LauncherEvent gridSizeChangedEvent =
+ new DeviceGridState(mContext).getWorkspaceSizeEvent();
if (gridSizeChangedEvent != null) {
logger.log(gridSizeChangedEvent);
}
+ SharedPreferences prefs = getPrefs(mContext);
if (FeatureFlags.ENABLE_THEMED_ICONS.get()) {
logger.log(prefs.getBoolean(KEY_THEMED_ICONS, false)
? LAUNCHER_THEMED_ICON_ENABLED
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index 1ed2da3..ac2534e 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -23,6 +23,7 @@
import com.android.launcher3.Alarm;
import com.android.launcher3.R;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.testing.TestProtocol;
/**
* Given positions along x- or y-axis, tracks velocity and acceleration and determines when there is
@@ -118,9 +119,9 @@
* @param pointerIndex Index for the pointer being tracked in the motion event
*/
public void addPosition(MotionEvent ev, int pointerIndex) {
- mForcePauseTimeout.setAlarm(mMakePauseHarderToTrigger
- ? HARDER_TRIGGER_TIMEOUT
- : FORCE_PAUSE_TIMEOUT);
+ mForcePauseTimeout.setAlarm(TestProtocol.sForcePauseTimeout != null
+ ? TestProtocol.sForcePauseTimeout
+ : mMakePauseHarderToTrigger ? HARDER_TRIGGER_TIMEOUT : FORCE_PAUSE_TIMEOUT);
float newVelocity = mVelocityProvider.addMotionEvent(ev, ev.getPointerId(pointerIndex));
if (mPreviousVelocity != null) {
checkMotionPaused(newVelocity, mPreviousVelocity, ev.getEventTime());
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 2351a4e..16c925a 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -56,6 +56,7 @@
private final SystemUiProxy mSystemUiProxy;
private TaskView mInitialTaskView;
+ private TaskView mSecondTaskView;
private SplitPositionOption mInitialPosition;
private Rect mInitialBounds;
private final Handler mHandler;
@@ -79,23 +80,19 @@
* To be called after second task selected
*/
public void setSecondTaskId(TaskView taskView) {
- if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
- // Assume initial task is for top/left part of screen
- final int[] taskIds = mInitialPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT
- ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
- : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
+ mSecondTaskView = taskView;
+ // Assume initial task is for top/left part of screen
+ final int[] taskIds = mInitialPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT
+ ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
+ : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
+ if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
RemoteSplitLaunchTransitionRunner animationRunner =
new RemoteSplitLaunchTransitionRunner(mInitialTaskView, taskView);
mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
} else {
- // Assume initial task is for top/left part of screen
- final int[] taskIds = mInitialPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT
- ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
- : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
-
RemoteSplitLaunchAnimationRunner animationRunner =
new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
@@ -191,12 +188,17 @@
*/
public void resetState() {
mInitialTaskView = null;
+ mSecondTaskView = null;
mInitialPosition = null;
mInitialBounds = null;
}
+ /**
+ * @return {@code true} if first task has been selected and waiting for the second task to be
+ * chosen
+ */
public boolean isSplitSelectActive() {
- return mInitialTaskView != null;
+ return mInitialTaskView != null && mSecondTaskView == null;
}
public Rect getInitialBounds() {
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index c0f5c14..d4191fe 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -40,6 +40,7 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.util.Themes;
+import com.android.quickstep.TaskAnimationManager;
import com.android.systemui.shared.pip.PipSurfaceTransactionHelper;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -278,19 +279,36 @@
private RotatedPosition getRotatedPosition(float progress) {
final float degree, positionX, positionY;
- if (mFromRotation == Surface.ROTATION_90) {
- degree = -90 * progress;
- positionX = progress * (mDestinationBoundsTransformed.left - mStartBounds.left)
- + mStartBounds.left;
- positionY = progress * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
- + mStartBounds.top;
+ if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ if (mFromRotation == Surface.ROTATION_90) {
+ degree = -90 * (1 - progress);
+ positionX = progress * (mDestinationBoundsTransformed.left - mStartBounds.left)
+ + mStartBounds.left;
+ positionY = progress * (mDestinationBoundsTransformed.top - mStartBounds.top)
+ + mStartBounds.top + mStartBounds.bottom * (1 - progress);
+ } else {
+ degree = 90 * (1 - progress);
+ positionX = progress * (mDestinationBoundsTransformed.left - mStartBounds.left)
+ + mStartBounds.left + mStartBounds.right * (1 - progress);
+ positionY = progress * (mDestinationBoundsTransformed.top - mStartBounds.top)
+ + mStartBounds.top;
+ }
} else {
- degree = 90 * progress;
- positionX = progress * (mDestinationBoundsTransformed.right - mStartBounds.left)
- + mStartBounds.left;
- positionY = progress * (mDestinationBoundsTransformed.top - mStartBounds.top)
- + mStartBounds.top;
+ if (mFromRotation == Surface.ROTATION_90) {
+ degree = -90 * progress;
+ positionX = progress * (mDestinationBoundsTransformed.left - mStartBounds.left)
+ + mStartBounds.left;
+ positionY = progress * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
+ + mStartBounds.top;
+ } else {
+ degree = 90 * progress;
+ positionX = progress * (mDestinationBoundsTransformed.right - mStartBounds.left)
+ + mStartBounds.left;
+ positionY = progress * (mDestinationBoundsTransformed.top - mStartBounds.top)
+ + mStartBounds.top;
+ }
}
+
return new RotatedPosition(degree, positionX, positionY);
}
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
index f67940a..e9d7c3c 100644
--- a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
+++ b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
@@ -17,13 +17,11 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_EDU_SHOWN;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -35,7 +33,7 @@
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
-import android.view.ViewGroup;
+import android.view.View;
import androidx.core.graphics.ColorUtils;
@@ -44,25 +42,21 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.launcher3.util.Themes;
import com.android.quickstep.util.MultiValueUpdateListener;
/**
* View used to educate the user on how to access All Apps when in No Nav Button navigation mode.
- * Consumes all touches until after the animation is completed and the view is removed.
+ * If the user drags on the view, the animation is overridden so the user can swipe to All Apps or
+ * Home.
*/
public class AllAppsEduView extends AbstractFloatingView {
- private static final float HINT_PROG_SCRIM_THRESHOLD = 0.06f;
- private static final float HINT_PROG_CONTENT_THRESHOLD = 0.08f;
-
private Launcher mLauncher;
+ private AllAppsEduTouchController mTouchController;
private AnimatorSet mAnimation;
@@ -74,6 +68,8 @@
private int mWidthPx;
private int mMaxHeightPx;
+ private boolean mCanInterceptTouch;
+
public AllAppsEduView(Context context, AttributeSet attrs) {
super(context, attrs);
mCircle = (GradientDrawable) context.getDrawable(R.drawable.all_apps_edu_circle);
@@ -123,8 +119,49 @@
return true;
}
+
+ private boolean shouldInterceptTouch(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mCanInterceptTouch = (ev.getEdgeFlags() & EDGE_NAV_BAR) == 0;
+ }
+ return mCanInterceptTouch;
+ }
+
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ if (shouldInterceptTouch(ev)) {
+ mTouchController.onControllerTouchEvent(ev);
+ updateAnimationOnTouchEvent(ev);
+ }
+ return true;
+ }
+
+ private void updateAnimationOnTouchEvent(MotionEvent ev) {
+ if (mAnimation == null) {
+ return;
+ }
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mAnimation.pause();
+ return;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mAnimation.resume();
+ return;
+ }
+
+ if (mTouchController.isDraggingOrSettling()) {
+ mAnimation = null;
+ handleClose(false);
+ }
+ }
+
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (shouldInterceptTouch(ev)) {
+ mTouchController.onControllerInterceptTouchEvent(ev);
+ updateAnimationOnTouchEvent(ev);
+ }
return true;
}
@@ -145,23 +182,9 @@
int secondPart = 1200;
int introDuration = firstPart + secondPart;
- StateAnimationConfig config = new StateAnimationConfig();
- config.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
- HINT_PROG_SCRIM_THRESHOLD, HINT_PROG_CONTENT_THRESHOLD));
- config.setInterpolator(ANIM_SCRIM_FADE,
- Interpolators.clampToProgress(ACCEL, 0, HINT_PROG_CONTENT_THRESHOLD));
- config.duration = secondPart;
- config.userControlled = false;
AnimatorPlaybackController stateAnimationController =
- mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, config);
- float maxAllAppsProgress = mLauncher.getDeviceProfile().isLandscape ? 0.35f : 0.15f;
-
- AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
- PendingAnimation allAppsAlpha = new PendingAnimation(config.duration);
- allAppsController.setAlphas(ALL_APPS, config, allAppsAlpha);
- mLauncher.getWorkspace().getStateTransitionAnimation().setScrim(allAppsAlpha, ALL_APPS,
- config);
- mAnimation.play(allAppsAlpha.buildAnim());
+ mTouchController.initAllAppsAnimation();
+ float maxAllAppsProgress = 0.75f;
ValueAnimator intro = ValueAnimator.ofFloat(0, 1f);
intro.setInterpolator(LINEAR);
@@ -198,6 +221,7 @@
mGradient.setAlpha(0);
}
});
+ mLauncher.getAppsView().setVisibility(View.VISIBLE);
mAnimation.play(intro);
ValueAnimator closeAllApps = ValueAnimator.ofFloat(maxAllAppsProgress, 0f);
@@ -223,6 +247,7 @@
private void init(Launcher launcher) {
mLauncher = launcher;
+ mTouchController = new AllAppsEduTouchController(mLauncher);
int accentColor = Themes.getColorAccent(launcher);
mGradient = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,
@@ -250,9 +275,8 @@
*/
public static void show(Launcher launcher) {
final DragLayer dragLayer = launcher.getDragLayer();
- ViewGroup parent = (ViewGroup) dragLayer.getParent();
- AllAppsEduView view = launcher.getViewCache().getView(R.layout.all_apps_edu_view,
- launcher, parent);
+ AllAppsEduView view = (AllAppsEduView) launcher.getLayoutInflater().inflate(
+ R.layout.all_apps_edu_view, dragLayer, false);
view.init(launcher);
launcher.getDragLayer().addView(view);
launcher.getStatsLogManager().logger().log(LAUNCHER_ALL_APPS_EDU_SHOWN);
@@ -260,4 +284,27 @@
view.requestLayout();
view.playAnimation();
}
+
+ private static class AllAppsEduTouchController extends PortraitStatesTouchController {
+
+ private AllAppsEduTouchController(Launcher l) {
+ super(l);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ return true;
+ }
+
+ private AnimatorPlaybackController initAllAppsAnimation() {
+ mFromState = NORMAL;
+ mToState = ALL_APPS;
+ mProgressMultiplier = initCurrentAnimation();
+ return mCurrentAnimation;
+ }
+
+ private boolean isDraggingOrSettling() {
+ return mDetector.isDraggingOrSettling();
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
new file mode 100644
index 0000000..a1befc5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -0,0 +1,241 @@
+package com.android.quickstep.views;
+
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+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;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.util.MultiValueUpdateListener;
+
+/**
+ * Create an instance via {@link #getFloatingTaskView(StatefulActivity, TaskView, RectF)} to
+ * which will have the thumbnail from the provided existing TaskView overlaying the taskview itself.
+ *
+ * Can then animate the taskview using
+ * {@link #addAnimation(PendingAnimation, RectF, Rect, View, boolean)}
+ * giving a starting and ending bounds. Currently this is set to use the split placeholder view,
+ * but it could be generified.
+ *
+ * TODO: Figure out how to copy thumbnail data from existing TaskView to this view.
+ */
+public class FloatingTaskView extends FrameLayout {
+
+ private SplitPlaceholderView mSplitPlaceholderView;
+ private RectF mStartingPosition;
+ private final Launcher mLauncher;
+ private final boolean mIsRtl;
+ private final Rect mOutline = new Rect();
+ private PagedOrientationHandler mOrientationHandler;
+ private ImageView mImageView;
+
+ public FloatingTaskView(Context context) {
+ this(context, null);
+ }
+
+ public FloatingTaskView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FloatingTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+ mIsRtl = Utilities.isRtl(getResources());
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mImageView = findViewById(R.id.thumbnail);
+ mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ mImageView.setLayerType(LAYER_TYPE_HARDWARE, null);
+ mSplitPlaceholderView = findViewById(R.id.split_placeholder);
+ mSplitPlaceholderView.setAlpha(0);
+ mSplitPlaceholderView.setBackgroundColor(getResources().getColor(android.R.color.white));
+ }
+
+ public static FloatingTaskView getFloatingTaskView(StatefulActivity launcher,
+ TaskView originalView, RectF positionOut) {
+ final BaseDragLayer dragLayer = launcher.getDragLayer();
+ ViewGroup parent = (ViewGroup) dragLayer.getParent();
+ final FloatingTaskView floatingView = (FloatingTaskView) launcher.getLayoutInflater()
+ .inflate(R.layout.floating_split_select_view, parent, false);
+
+ floatingView.mStartingPosition = positionOut;
+ floatingView.updateInitialPositionForView(originalView);
+ final InsettableFrameLayout.LayoutParams lp =
+ (InsettableFrameLayout.LayoutParams) floatingView.getLayoutParams();
+
+ floatingView.mSplitPlaceholderView.setLayoutParams(
+ new FrameLayout.LayoutParams(lp.width, lp.height));
+ positionOut.round(floatingView.mOutline);
+ floatingView.setPivotX(0);
+ floatingView.setPivotY(0);
+
+ // Copy bounds of exiting thumbnail into ImageView
+ TaskThumbnailView thumbnail = originalView.getThumbnail();
+ floatingView.mImageView.setImageBitmap(thumbnail.getThumbnail());
+ floatingView.mImageView.setVisibility(VISIBLE);
+
+ floatingView.mOrientationHandler =
+ originalView.getRecentsView().getPagedOrientationHandler();
+ floatingView.mSplitPlaceholderView.setIcon(originalView.getIconView());
+ floatingView.mSplitPlaceholderView.getIcon()
+ .setRotation(floatingView.mOrientationHandler.getDegreesRotated());
+ parent.addView(floatingView);
+ return floatingView;
+ }
+
+ 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,
+ true /* ignoreTransform */, null /* recycle */,
+ mStartingPosition);
+ mStartingPosition.offset(originalView.getTranslationX(), originalView.getTranslationY());
+ final InsettableFrameLayout.LayoutParams lp = new InsettableFrameLayout.LayoutParams(
+ Math.round(mStartingPosition.width()),
+ Math.round(mStartingPosition.height()));
+ initPosition(mStartingPosition, lp);
+ setLayoutParams(lp);
+ }
+
+ // TODO(194414938) set correct corner radii
+ 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 dY = position.top - lp.topMargin;
+
+ setTranslationX(dX);
+ setTranslationY(dY);
+
+ float scaleX = position.width() / lp.width;
+ float scaleY = position.height() / lp.height;
+ setScaleX(scaleX);
+ setScaleY(scaleY);
+ float childScaleX = 1f / scaleX;
+ float childScaleY = 1f / scaleY;
+
+ invalidate();
+ // TODO(194414938) seems like this scale value could be fine tuned, some stretchiness
+ mImageView.setScaleX(1f / scaleX + scaleX * progress);
+ mImageView.setScaleY(1f / scaleY + scaleY * progress);
+ mOrientationHandler.setPrimaryScale(mSplitPlaceholderView.getIcon(), childScaleX);
+ mOrientationHandler.setSecondaryScale(mSplitPlaceholderView.getIcon(), childScaleY);
+ }
+
+ 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));
+ } 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;
+ 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();
+ int[] dragLayerBounds = new int[2];
+ dragLayer.getLocationOnScreen(dragLayerBounds);
+ SplitOverlayProperties prop = new SplitOverlayProperties(endBounds,
+ startingBounds, viewToCover, dragLayerBounds[0],
+ dragLayerBounds[1]);
+
+ ValueAnimator transitionAnimator = ValueAnimator.ofFloat(0, 1);
+ animation.add(transitionAnimator);
+ long animDuration = animation.getDuration();
+ Rect crop = new Rect();
+ RectF floatingTaskViewBounds = new RectF();
+ final float initialWindowRadius = supportsRoundedCornersOnWindows(getResources())
+ ? Math.max(crop.width(), crop.height()) / 2f
+ : 0f;
+
+ if (fadeWithThumbnail) {
+ animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
+ 0, 1, ACCEL);
+ animation.addFloat(mImageView, LauncherAnimUtils.VIEW_ALPHA,
+ 1, 0, DEACCEL_3);
+ }
+
+ MultiValueUpdateListener listener = new MultiValueUpdateListener() {
+ final FloatProp mWindowRadius = new FloatProp(initialWindowRadius,
+ initialWindowRadius, 0, animDuration, LINEAR);
+ final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration, LINEAR);
+ final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration, LINEAR);
+ final FloatProp mTaskViewScaleX = new FloatProp(prop.initialTaskViewScaleX,
+ prop.finalTaskViewScaleX, 0, animDuration, LINEAR);
+ final FloatProp mTaskViewScaleY = new FloatProp(prop.initialTaskViewScaleY,
+ prop.finalTaskViewScaleY, 0, animDuration, LINEAR);
+ @Override
+ public void onUpdate(float percent, boolean initOnly) {
+ // Calculate the icon position.
+ floatingTaskViewBounds.set(startingBounds);
+ floatingTaskViewBounds.offset(mDx.value, mDy.value);
+ Utilities.scaleRectFAboutCenter(floatingTaskViewBounds, mTaskViewScaleX.value,
+ mTaskViewScaleY.value);
+
+ update(floatingTaskViewBounds, percent, mWindowRadius.value * 1);
+ }
+ };
+ transitionAnimator.addUpdateListener(listener);
+ }
+
+ private static class SplitOverlayProperties {
+
+ private final float initialTaskViewScaleX;
+ private final float initialTaskViewScaleY;
+ private final float finalTaskViewScaleX;
+ private final float finalTaskViewScaleY;
+ private final float dX;
+ private final float dY;
+
+ SplitOverlayProperties(Rect endBounds, RectF startTaskViewBounds, View view,
+ int dragLayerLeft, int dragLayerTop) {
+ float maxScaleX = endBounds.width() / startTaskViewBounds.width();
+ float maxScaleY = endBounds.height() / startTaskViewBounds.height();
+
+ initialTaskViewScaleX = view.getScaleX();
+ initialTaskViewScaleY = view.getScaleY();
+ finalTaskViewScaleX = maxScaleX;
+ finalTaskViewScaleY = maxScaleY;
+
+ // Animate the app icon to the center of the window bounds in screen coordinates.
+ float centerX = endBounds.centerX() - dragLayerLeft;
+ float centerY = endBounds.centerY() - dragLayerTop;
+
+ dX = centerX - startTaskViewBounds.centerX();
+ dY = centerY - startTaskViewBounds.centerY();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index 5b0ade0..813e653 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -17,8 +17,10 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.view.View;
import com.android.launcher3.Utilities;
@@ -30,6 +32,7 @@
public class IconView extends View {
private Drawable mDrawable;
+ private int mDrawableWidth, mDrawableHeight;
public IconView(Context context) {
super(context);
@@ -50,11 +53,29 @@
mDrawable = d;
if (mDrawable != null) {
mDrawable.setCallback(this);
- mDrawable.setBounds(0, 0, getWidth(), getHeight());
+ setDrawableSizeInternal(getWidth(), getHeight());
}
invalidate();
}
+ /**
+ * Sets the size of the icon drawable.
+ */
+ public void setDrawableSize(int iconWidth, int iconHeight) {
+ mDrawableWidth = iconWidth;
+ mDrawableHeight = iconHeight;
+ if (mDrawable != null) {
+ setDrawableSizeInternal(getWidth(), getHeight());
+ }
+ }
+
+ private void setDrawableSizeInternal(int selfWidth, int selfHeight) {
+ Rect selfRect = new Rect(0, 0, selfWidth, selfHeight);
+ Rect drawableRect = new Rect();
+ Gravity.apply(Gravity.CENTER, mDrawableWidth, mDrawableHeight, selfRect, drawableRect);
+ mDrawable.setBounds(drawableRect);
+ }
+
public Drawable getDrawable() {
return mDrawable;
}
@@ -63,7 +84,7 @@
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (mDrawable != null) {
- mDrawable.setBounds(0, 0, w, h);
+ setDrawableSizeInternal(w, h);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 65956d5..6b2d19c 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -38,6 +38,7 @@
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.LauncherActivityInterface;
+import com.android.quickstep.util.SplitSelectStateController;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.RecentsExtraCard;
@@ -81,7 +82,8 @@
}
@Override
- public void init(OverviewActionsView actionsView, SplitPlaceholderView splitPlaceholderView) {
+ public void init(OverviewActionsView actionsView,
+ SplitSelectStateController splitPlaceholderView) {
super.init(actionsView, splitPlaceholderView);
setContentAlpha(0);
}
@@ -225,6 +227,7 @@
} else {
if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
mActivity.getStateManager().goToState(LauncherState.OVERVIEW);
+ resetModalVisuals();
}
}
}
@@ -252,9 +255,6 @@
super.onConfigurationChanged(newConfig);
// If overview is in modal state when rotate, reset it to overview state without running
// animation.
- if (mActivity.isInState(OVERVIEW_MODAL_TASK)) {
- mActivity.getStateManager().goToState(LauncherState.OVERVIEW, false);
- resetModalVisuals();
- }
+ setModalStateEnabled(false);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 563bb53..a2d2179 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -16,7 +16,6 @@
package com.android.quickstep.views;
-import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
import android.content.Context;
@@ -33,7 +32,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.SysUINavigationMode;
@@ -90,9 +88,6 @@
protected T mCallbacks;
- private float mModalness;
- private float mModalTransformY;
-
protected DeviceProfile mDp;
public OverviewActionsView(Context context) {
@@ -225,29 +220,6 @@
requestLayout();
}
- /**
- * The current task is fully modal (modalness = 1) when it is shown on its own in a modal
- * way. Modalness 0 means the task is shown in context with all the other tasks.
- */
- public void setTaskModalness(float modalness) {
- mModalness = modalness;
- applyTranslationY();
- }
-
- public void setModalTransformY(float modalTransformY) {
- mModalTransformY = modalTransformY;
- applyTranslationY();
- }
-
- private void applyTranslationY() {
- setTranslationY(getModalTrans(mModalTransformY));
- }
-
- private float getModalTrans(float endTranslation) {
- float progress = ACCEL_DEACCEL.getInterpolation(mModalness);
- return Utilities.mapRange(progress, 0, endTranslation);
- }
-
/** Get the top margin associated with the action buttons in Overview. */
public static int getOverviewActionsTopMarginPx(
SysUINavigationMode.Mode mode, DeviceProfile dp) {
@@ -260,7 +232,7 @@
return dp.overviewActionsMarginThreeButtonPx;
}
- return dp.overviewActionsMarginGesturePx;
+ return dp.overviewActionsTopMarginGesturePx;
}
/** Get the bottom margin associated with the action buttons in Overview. */
@@ -276,6 +248,6 @@
return dp.overviewActionsMarginThreeButtonPx + inset;
}
- return dp.overviewActionsMarginGesturePx + inset;
+ return dp.overviewActionsBottomMarginGesturePx + inset;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index e128942..b077ca6 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -83,7 +83,6 @@
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.SparseBooleanArray;
-import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -95,7 +94,6 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.OverScroller;
@@ -386,7 +384,6 @@
protected final ACTIVITY_TYPE mActivity;
private final float mFastFlingVelocity;
private final RecentsModel mModel;
- private final int mRowSpacing;
private final int mGridSideMargin;
private final ClearAllButton mClearAllButton;
private final Rect mClearAllButtonDeadZoneRect = new Rect();
@@ -401,6 +398,9 @@
private final InvariantDeviceProfile mIdp;
+ /**
+ * Getting views should be done via {@link #getTaskViewFromPool()}
+ */
private final ViewPool<TaskView> mTaskViewPool;
private final TaskOverlayFactory mTaskOverlayFactory;
@@ -444,7 +444,7 @@
}
// Remove the task immediately from the task list
- TaskView taskView = getTaskView(taskId);
+ TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
removeView(taskView);
}
@@ -466,7 +466,7 @@
return;
}
- TaskView taskView = getTaskView(taskId);
+ TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView == null) {
return;
}
@@ -499,10 +499,16 @@
private int mTaskListChangeId = -1;
// Only valid until the launcher state changes to NORMAL
- protected int mRunningTaskId = -1;
+ /**
+ * ID for the current running TaskView view, unique amongst TaskView instances. ID's are set
+ * through {@link #getTaskViewFromPool()} and incremented by {@link #mTaskViewIdCount}
+ */
+ protected int mRunningTaskViewId = -1;
+ private int mTaskViewIdCount;
+ private final int[] INVALID_TASK_IDS = new int[]{-1, -1};
protected boolean mRunningTaskTileHidden;
private Task mTmpRunningTask;
- protected int mFocusedTaskId = -1;
+ protected int mFocusedTaskViewId = -1;
private boolean mTaskIconScaledDown = false;
private boolean mRunningTaskShowScreenshot = false;
@@ -545,15 +551,18 @@
/**
* Placeholder view indicating where the first split screen selected app will be placed
*/
- private SplitPlaceholderView mSplitPlaceholderView;
+ private SplitSelectStateController mSplitSelectStateController;
/**
* The first task that split screen selection was initiated with. When split select state is
* initialized, we create a
- * {@link #createTaskDismissAnimation(TaskView, boolean, boolean, long)} for this TaskView but
- * don't actually remove the task since the user might back out. As such, we also ensure this
- * View doesn't go back into the {@link #mTaskViewPool}, see {@link #onViewRemoved(View)}
+ * {@link #createTaskDismissAnimation(TaskView, boolean, boolean, long, boolean)} for this
+ * TaskView but don't actually remove the task since the user might back out. As such, we also
+ * ensure this View doesn't go back into the {@link #mTaskViewPool},
+ * see {@link #onViewRemoved(View)}
*/
private TaskView mSplitHiddenTaskView;
+ private TaskView mSecondSplitHiddenTaskView;
+
/**
* Keeps track of the index of the TaskView that split screen was initialized with so we know
* where to insert it back into list of taskViews in case user backs out of entering split
@@ -563,6 +572,13 @@
* removed from recentsView
*/
private int mSplitHiddenTaskViewIndex;
+ private FloatingTaskView mFirstFloatingTaskView;
+ private FloatingTaskView mSecondFloatingTaskView;
+
+ /**
+ * The task to be removed and immediately re-added. Should not be added to task pool.
+ */
+ private TaskView mMovingTaskView;
// Keeps track of the index where the first TaskView should be
private int mTaskViewStartIndex = 0;
@@ -588,7 +604,6 @@
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
BaseActivityInterface sizeStrategy) {
super(context, attrs, defStyleAttr);
- setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
setEnableFreeScroll(true);
mSizeStrategy = sizeStrategy;
mActivity = BaseActivity.fromContext(context);
@@ -610,7 +625,6 @@
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
- mRowSpacing = getResources().getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
mGridSideMargin = getResources().getDimensionPixelSize(R.dimen.overview_grid_side_margin);
mSquaredTouchSlop = squaredTouchSlop(context);
@@ -729,7 +743,7 @@
@Override
public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
if (mHandleTaskStackChanges) {
- TaskView taskView = getTaskView(taskId);
+ TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
Task task = taskView.getTask();
taskView.getThumbnail().setThumbnail(task, thumbnailData);
@@ -759,7 +773,7 @@
* @param refreshNow Refresh immediately if it's true.
*/
public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData, boolean refreshNow) {
- TaskView taskView = getTaskView(taskId);
+ TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData, refreshNow);
}
@@ -772,18 +786,18 @@
updateTaskStackListenerState();
}
- public void init(OverviewActionsView actionsView, SplitPlaceholderView splitPlaceholderView) {
+ public void init(OverviewActionsView actionsView, SplitSelectStateController splitController) {
mActionsView = actionsView;
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
- mSplitPlaceholderView = splitPlaceholderView;
+ mSplitSelectStateController = splitController;
}
- public SplitPlaceholderView getSplitPlaceholder() {
- return mSplitPlaceholderView;
+ public SplitSelectStateController getSplitPlaceholder() {
+ return mSplitSelectStateController;
}
public boolean isSplitSelectionActive() {
- return mSplitPlaceholderView.getSplitController().isSplitSelectActive();
+ return mSplitSelectStateController.isSplitSelectActive();
}
@Override
@@ -826,11 +840,15 @@
public void onViewRemoved(View child) {
super.onViewRemoved(child);
- // Clear the task data for the removed child if it was visible unless it's the initial
- // taskview for entering split screen, we only pretend to dismiss the task
- if (child instanceof TaskView && child != mSplitHiddenTaskView) {
+ // Clear the task data for the removed child if it was visible unless:
+ // - It's the initial taskview for entering split screen, we only pretend to dismiss the
+ // task
+ // - It's the focused task to be moved to the front, we immediately re-add the task
+ if (child instanceof TaskView && child != mSplitHiddenTaskView
+ && child != mMovingTaskView) {
TaskView taskView = (TaskView) child;
- mHasVisibleTaskData.delete(taskView.getTaskId());
+ mHasVisibleTaskData.delete(taskView.getTaskIds()[0]);
+ taskView.setTaskViewId(-1);
mTaskViewPool.recycle(taskView);
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
}
@@ -870,7 +888,8 @@
}
public void launchSideTaskInLiveTileModeForRestartedApp(int taskId) {
- if (mRunningTaskId != -1 && mRunningTaskId == taskId) {
+ int runningTaskViewId = getTaskViewIdFromTaskId(taskId);
+ if (mRunningTaskViewId != -1 && mRunningTaskViewId == runningTaskViewId) {
RemoteAnimationTargets targets = getLiveTileParams().getTargetSet();
if (targets != null && targets.findTask(taskId) != null) {
launchSideTaskInLiveTileMode(taskId, targets.apps, targets.wallpapers,
@@ -882,7 +901,7 @@
public void launchSideTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps,
RemoteAnimationTargetCompat[] wallpaper, RemoteAnimationTargetCompat[] nonApps) {
AnimatorSet anim = new AnimatorSet();
- TaskView taskView = getTaskView(taskId);
+ TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView == null || !isTaskViewVisible(taskView)) {
// TODO: Refine this animation.
SurfaceTransactionApplier surfaceApplier =
@@ -959,10 +978,11 @@
== getPagedOrientationHandler().getPrimaryScroll(this);
}
- public TaskView getTaskView(int taskId) {
+ public TaskView getTaskViewByTaskId(int taskId) {
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = getTaskViewAt(i);
- if (taskView.getTaskId() == taskId) {
+ int[] taskIds = taskView.getTaskIds();
+ if (taskIds[0] == taskId || taskIds[1] == taskId) {
return taskView;
}
}
@@ -977,7 +997,7 @@
// Reset the running task when leaving overview since it can still have a reference to
// its thumbnail
mTmpRunningTask = null;
- if (mSplitPlaceholderView.getSplitController().isSplitSelectActive()) {
+ if (mSplitSelectStateController.isSplitSelectActive()) {
cancelSplitSelect(false);
}
}
@@ -1121,6 +1141,42 @@
}
}
+ /**
+ * Moves the focused task to the front of the carousel in tablets, to minimize animation
+ * required to focus the task in grid.
+ */
+ public void moveFocusedTaskToFront() {
+ if (!mActivity.getDeviceProfile().overviewShowAsGrid) {
+ return;
+ }
+
+ TaskView focusedTaskView = getFocusedTaskView();
+ if (focusedTaskView == null) {
+ return;
+ }
+
+ if (indexOfChild(focusedTaskView) != mCurrentPage) {
+ return;
+ }
+
+ if (mCurrentPage == mTaskViewStartIndex) {
+ return;
+ }
+
+ int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+ int currentPageScroll = getScrollForPage(mCurrentPage);
+ mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
+
+ mMovingTaskView = focusedTaskView;
+ removeView(focusedTaskView);
+ mMovingTaskView = null;
+ focusedTaskView.onRecycle();
+ addView(focusedTaskView, mTaskViewStartIndex);
+ setCurrentPage(mTaskViewStartIndex);
+
+ updateGridProperties();
+ }
+
protected void applyLoadPlan(ArrayList<Task> tasks) {
if (mPendingAnimation != null) {
mPendingAnimation.addEndListener(success -> applyLoadPlan(tasks));
@@ -1143,7 +1199,7 @@
unloadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
TaskView ignoreResetTaskView =
- mIgnoreResetTaskId == -1 ? null : getTaskView(mIgnoreResetTaskId);
+ mIgnoreResetTaskId == -1 ? null : getTaskViewByTaskId(mIgnoreResetTaskId);
final int requiredTaskCount = tasks.size();
if (getTaskViewCount() != requiredTaskCount) {
@@ -1151,7 +1207,7 @@
removeView(mClearAllButton);
}
for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
- addView(mTaskViewPool.getView());
+ addView(getTaskViewFromPool());
}
while (getTaskViewCount() > requiredTaskCount) {
removeView(getChildAt(getChildCount() - 1));
@@ -1161,6 +1217,12 @@
}
}
+ // Save running task ID if it exists before rebinding all taskViews, otherwise the task from
+ // the runningTaskView currently bound could get assigned to another TaskView
+ // TODO set these type to array and check all taskIDs? Maybe we can get away w/ only one
+ int runningTaskId = getTaskIdsForTaskViewId(mRunningTaskViewId)[0];
+ int focusedTaskId = getTaskIdsForTaskViewId(mFocusedTaskViewId)[0];
+
// Rebind and reset all task views
for (int i = requiredTaskCount - 1; i >= 0; i--) {
final int pageIndex = requiredTaskCount - i - 1 + mTaskViewStartIndex;
@@ -1169,28 +1231,40 @@
taskView.bind(task, mOrientationState);
}
+ // Keep same previous focused task
+ TaskView newFocusedTaskView = getTaskViewByTaskId(focusedTaskId);
// If the list changed, maybe the focused task doesn't exist anymore
- if (getFocusedTaskView() == null && getTaskViewCount() > 0) {
- mFocusedTaskId = getTaskViewAt(0).getTaskId();
+ if (newFocusedTaskView == null && getTaskViewCount() > 0) {
+ newFocusedTaskView = getTaskViewAt(0);
}
+ mFocusedTaskViewId = newFocusedTaskView != null ?
+ newFocusedTaskView.getTaskViewId() : -1;
updateTaskSize();
+ TaskView newRunningTaskView = null;
+ if (runningTaskId != -1) {
+ // Update mRunningTaskViewId to be the new TaskView that was assigned by binding
+ // the full list of tasks to taskViews
+ newRunningTaskView = getTaskViewByTaskId(runningTaskId);
+ mRunningTaskViewId = newRunningTaskView.getTaskViewId();
+ }
+
if (mNextPage == INVALID_PAGE) {
// Set the current page to the running task, but not if settling on new task.
- TaskView runningTaskView = getRunningTaskView();
- if (runningTaskView != null) {
- setCurrentPage(indexOfChild(runningTaskView));
+ if (runningTaskId != -1) {
+ setCurrentPage(indexOfChild(newRunningTaskView));
} else if (getTaskViewCount() > 0) {
setCurrentPage(indexOfChild(getTaskViewAt(0)));
}
} else if (currentTaskId != -1) {
- currentTaskView = getTaskView(currentTaskId);
+ currentTaskView = getTaskViewByTaskId(currentTaskId);
if (currentTaskView != null) {
setCurrentPage(indexOfChild(currentTaskView));
}
}
- if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreResetTaskView) {
+ if (mIgnoreResetTaskId != -1 &&
+ getTaskViewByTaskId(mIgnoreResetTaskId) != ignoreResetTaskView) {
// If the taskView mapping is changing, do not preserve the visuals. Since we are
// mostly preserving the first task, and new taskViews are added to the end, it should
// generally map to the same task.
@@ -1234,7 +1308,7 @@
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
TaskView taskView = getTaskViewAt(i);
- if (mIgnoreResetTaskId != taskView.getTaskId()) {
+ if (mIgnoreResetTaskId != taskView.getTaskIds()[0]) {
taskView.resetViewTransforms();
taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1);
taskView.setStableAlpha(mContentAlpha);
@@ -1302,6 +1376,7 @@
DeviceProfile dp = mActivity.getDeviceProfile();
setOverviewGridEnabled(
mActivity.getStateManager().getState().displayOverviewTasksAsGrid(dp));
+ setPageSpacing(dp.overviewPageSpacing);
// Propagate DeviceProfile change event.
mLiveTileTaskViewSimulator.setDp(dp);
@@ -1334,6 +1409,7 @@
|| !mOrientationHandler.equals(oldOrientationHandler)) {
// Changed orientations, update controllers so they intercept accordingly.
mActivity.getDragLayer().recreateControllers();
+ setModalStateEnabled(false);
}
boolean isInLandscape = mOrientationState.getTouchRotation() != ROTATION_0
@@ -1372,32 +1448,10 @@
mTaskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
mTopBottomRowHeightDiff =
mLastComputedGridTaskSize.height() + dp.overviewTaskThumbnailTopMarginPx
- + mRowSpacing;
+ + dp.overviewRowSpacing;
// Force TaskView to update size from thumbnail
updateTaskSize();
-
- // Update ActionsView position
- if (mActionsView != null) {
- FrameLayout.LayoutParams layoutParams =
- (FrameLayout.LayoutParams) mActionsView.getLayoutParams();
- if (dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
- layoutParams.gravity = Gravity.BOTTOM;
- layoutParams.bottomMargin =
- dp.heightPx - mInsets.bottom - mLastComputedGridSize.bottom;
- layoutParams.leftMargin = mLastComputedTaskSize.left;
- layoutParams.rightMargin = dp.widthPx - mLastComputedTaskSize.right;
- // When in modal state, remove bottom margin to avoid covering content.
- mActionsView.setModalTransformY(layoutParams.bottomMargin);
- } else {
- layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- layoutParams.bottomMargin = 0;
- layoutParams.leftMargin = 0;
- layoutParams.rightMargin = 0;
- mActionsView.setModalTransformY(0);
- }
- mActionsView.setLayoutParams(layoutParams);
- }
}
/**
@@ -1514,7 +1568,7 @@
@Override
protected int getDestinationPage(int scaledScroll) {
- if (!(mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get())) {
+ if (!mActivity.getDeviceProfile().overviewShowAsGrid) {
return super.getDestinationPage(scaledScroll);
}
@@ -1608,7 +1662,7 @@
private void unloadVisibleTaskData(@TaskView.TaskDataChanges int dataChanges) {
for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
if (mHasVisibleTaskData.valueAt(i)) {
- TaskView taskView = getTaskView(mHasVisibleTaskData.keyAt(i));
+ TaskView taskView = getTaskViewByTaskId(mHasVisibleTaskData.keyAt(i));
if (taskView != null) {
taskView.onTaskListVisibilityChanged(false /* visible */, dataChanges);
}
@@ -1623,7 +1677,7 @@
// they want to updated their thumbnail state
for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
if (mHasVisibleTaskData.valueAt(i)) {
- TaskView taskView = getTaskView(mHasVisibleTaskData.keyAt(i));
+ TaskView taskView = getTaskViewByTaskId(mHasVisibleTaskData.keyAt(i));
if (taskView != null) {
// Poke the view again, which will trigger it to load high res if the state
// is enabled
@@ -1644,7 +1698,7 @@
setCurrentTask(-1);
mIgnoreResetTaskId = -1;
mTaskListChangeId = -1;
- mFocusedTaskId = getTaskViewCount() > 0 ? getTaskViewAt(0).getTaskId() : -1;
+ mFocusedTaskViewId = getTaskViewCount() > 0 ? getTaskViewAt(0).getTaskViewId() : -1;
if (mRecentsAnimationController != null) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile) {
@@ -1669,20 +1723,49 @@
});
}
- public int getRunningTaskId() {
- return mRunningTaskId;
+ public int getRunningTaskViewId() {
+ return mRunningTaskViewId;
+ }
+
+ protected int[] getTaskIdsForRunningTaskView() {
+ return getTaskIdsForTaskViewId(mRunningTaskViewId);
+ }
+
+ private int[] getTaskIdsForTaskViewId(int taskViewId) {
+ // For now 2 distinct task IDs is max for split screen
+ TaskView runningTaskView = getTaskViewFromTaskViewId(taskViewId);
+ if (runningTaskView == null) {
+ return INVALID_TASK_IDS;
+ }
+
+ return runningTaskView.getTaskIds();
}
public @Nullable TaskView getRunningTaskView() {
- return getTaskView(mRunningTaskId);
- }
-
- public int getRunningTaskIndex() {
- return getTaskIndexForId(mRunningTaskId);
+ return getTaskViewFromTaskViewId(mRunningTaskViewId);
}
public @Nullable TaskView getFocusedTaskView() {
- return getTaskView(mFocusedTaskId);
+ return getTaskViewFromTaskViewId(mFocusedTaskViewId);
+ }
+
+ private TaskView getTaskViewFromTaskViewId(int taskViewId) {
+ if (taskViewId == -1) {
+ return null;
+ }
+
+ for (int i = 0; i < getTaskViewCount(); i++) {
+ TaskView taskView = getTaskViewAt(i);
+ if (taskView.getTaskViewId() == taskViewId) {
+ return taskView;
+ }
+ }
+ return null;
+ }
+
+ public int getRunningTaskIndex() {
+ TaskView taskView = getRunningTaskView();
+ return taskView == null ? -1 : indexOfChild(taskView);
}
protected @Nullable TaskView getHomeTaskView() {
@@ -1690,11 +1773,27 @@
}
/**
+ * Handle the edge case where Recents could increment task count very high over long
+ * period of device usage. Probably will never happen, but meh.
+ */
+ private TaskView getTaskViewFromPool() {
+ TaskView taskView = mTaskViewPool.getView();
+ taskView.setTaskViewId(mTaskViewIdCount);
+ if (mTaskViewIdCount == Integer.MAX_VALUE) {
+ mTaskViewIdCount = 0;
+ } else {
+ mTaskViewIdCount++;
+ }
+
+ return taskView;
+ }
+
+ /**
* Get the index of the task view whose id matches {@param taskId}.
* @return -1 if there is no task view for the task id, else the index of the task view.
*/
public int getTaskIndexForId(int taskId) {
- TaskView tv = getTaskView(taskId);
+ TaskView tv = getTaskViewByTaskId(taskId);
return tv == null ? -1 : indexOfChild(tv);
}
@@ -1815,7 +1914,7 @@
public void onGestureAnimationEnd() {
mGestureActive = false;
if (mOrientationState.setGestureActive(false)) {
- updateOrientationHandler();
+ updateOrientationHandler(/* forceRecreateDragLayerControllers = */ false);
}
setEnableFreeScroll(true);
@@ -1834,7 +1933,7 @@
* Returns true if we should add a stub taskView for the running task id
*/
protected boolean shouldAddStubTaskView(RunningTaskInfo runningTaskInfo) {
- return runningTaskInfo != null && getTaskView(runningTaskInfo.taskId) == null;
+ return runningTaskInfo != null && getTaskViewByTaskId(runningTaskInfo.taskId) == null;
}
/**
@@ -1844,10 +1943,12 @@
* is called. Also scrolls the view to this task.
*/
public void showCurrentTask(RunningTaskInfo runningTaskInfo) {
+ int runningTaskViewId = -1;
if (shouldAddStubTaskView(runningTaskInfo)) {
boolean wasEmpty = getChildCount() == 0;
// Add an empty view for now until the task plan is loaded and applied
- final TaskView taskView = mTaskViewPool.getView();
+ final TaskView taskView = getTaskViewFromPool();
+ runningTaskViewId = taskView.getTaskViewId();
addView(taskView, mTaskViewStartIndex);
if (wasEmpty) {
addView(mClearAllButton);
@@ -1862,12 +1963,13 @@
measure(makeMeasureSpec(getMeasuredWidth(), EXACTLY),
makeMeasureSpec(getMeasuredHeight(), EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
+ } else if (getTaskViewByTaskId(runningTaskInfo.taskId) != null) {
+ runningTaskViewId = getTaskViewByTaskId(runningTaskInfo.taskId).getTaskViewId();
}
boolean runningTaskTileHidden = mRunningTaskTileHidden;
- int runningTaskId = runningTaskInfo == null ? -1 : runningTaskInfo.taskId;
- setCurrentTask(runningTaskId);
- mFocusedTaskId = runningTaskId;
+ setCurrentTask(runningTaskViewId);
+ mFocusedTaskViewId = runningTaskViewId;
setCurrentPage(getRunningTaskIndex());
setRunningTaskViewShowScreenshot(false);
setRunningTaskHidden(runningTaskTileHidden);
@@ -1881,22 +1983,27 @@
/**
* Sets the running task id, cleaning up the old running task if necessary.
*/
- public void setCurrentTask(int runningTaskId) {
- if (mRunningTaskId == runningTaskId) {
+ public void setCurrentTask(int runningTaskViewId) {
+ if (mRunningTaskViewId == runningTaskViewId) {
return;
}
- if (mRunningTaskId != -1) {
+ if (mRunningTaskViewId != -1) {
// Reset the state on the old running task view
setTaskIconScaledDown(false);
setRunningTaskViewShowScreenshot(true);
setRunningTaskHidden(false);
}
- mRunningTaskId = runningTaskId;
+ mRunningTaskViewId = runningTaskViewId;
+ }
+
+ private int getTaskViewIdFromTaskId(int taskId) {
+ TaskView taskView = getTaskViewByTaskId(taskId);
+ return taskView != null ? taskView.getTaskViewId() : -1;
}
/**
- * Hides the tile associated with {@link #mRunningTaskId}
+ * Hides the tile associated with {@link #mRunningTaskViewId}
*/
public void setRunningTaskHidden(boolean isHidden) {
mRunningTaskTileHidden = isHidden;
@@ -1977,7 +2084,7 @@
float bottomAccumulatedTranslationX = 0;
// Contains whether the child index is in top or bottom of grid (for non-focused task)
- // Different from mTopRowIdSet, which contains the taskId of what task is in top row
+ // Different from mTopRowIdSet, which contains the taskViewId of what task is in top row
IntSet topSet = new IntSet();
IntSet bottomSet = new IntSet();
@@ -2029,8 +2136,8 @@
// calculate the distance focused task need to shift.
focusedTaskShift += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
}
- int taskId = taskView.getTaskId();
- boolean isTopRow = isTaskDismissal ? mTopRowIdSet.contains(taskId)
+ int taskViewId = taskView.getTaskViewId();
+ boolean isTopRow = isTaskDismissal ? mTopRowIdSet.contains(taskViewId)
: topRowWidth <= bottomRowWidth;
if (isTopRow) {
if (homeTaskView != null && nextFocusedTaskView == null) {
@@ -2040,7 +2147,7 @@
topRowWidth += taskWidthAndSpacing;
}
topSet.add(i);
- mTopRowIdSet.add(taskId);
+ mTopRowIdSet.add(taskViewId);
taskView.setGridTranslationY(mTaskGridVerticalDiff);
@@ -2165,13 +2272,13 @@
if (taskView1 == null || taskView2 == null) {
return false;
}
- int taskId1 = taskView1.getTaskId();
- int taskId2 = taskView2.getTaskId();
- if (taskId1 == mFocusedTaskId || taskId2 == mFocusedTaskId) {
+ int taskViewId1 = taskView1.getTaskViewId();
+ int taskViewId2 = taskView2.getTaskViewId();
+ if (taskViewId1 == mFocusedTaskViewId || taskViewId2 == mFocusedTaskViewId) {
return false;
}
- return (mTopRowIdSet.contains(taskId1) && mTopRowIdSet.contains(taskId2)) || (
- !mTopRowIdSet.contains(taskId1) && !mTopRowIdSet.contains(taskId2));
+ return (mTopRowIdSet.contains(taskViewId1) && mTopRowIdSet.contains(taskViewId2)) || (
+ !mTopRowIdSet.contains(taskViewId1) && !mTopRowIdSet.contains(taskViewId2));
}
/**
@@ -2243,50 +2350,23 @@
PendingAnimation anim) {
// Use setFloat instead of setViewAlpha as we want to keep the view visible even when it's
// alpha is set to 0 so that it can be recycled in the view pool properly
- anim.setFloat(taskView, VIEW_ALPHA, 0, clampToProgress(ACCEL, 0, 0.5f));
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && taskView.isRunningTask()) {
anim.setFloat(mLiveTileParams, TransformParams.TARGET_ALPHA, 0,
clampToProgress(ACCEL, 0, 0.5f));
}
- SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
+ anim.setFloat(taskView, VIEW_ALPHA, 0, clampToProgress(ACCEL, 0, 0.5f));
+ FloatProperty<TaskView> secondaryViewTranslate =
+ taskView.getSecondaryDissmissTranslationProperty();
+ int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
+ int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
ResourceProvider rp = DynamicResource.provider(mActivity);
SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START)
.setDampingRatio(rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio))
.setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness));
- FloatProperty<TaskView> dismissingTaskViewTranslate =
- taskView.getSecondaryDissmissTranslationProperty();
- // TODO(b/186800707) translate entire grid size distance
- int translateDistance = mOrientationHandler.getSecondaryDimension(taskView);
- int positiveNegativeFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
- if (splitController.isSplitSelectActive()) {
- // Have the task translate towards whatever side was just pinned
- int dir = mOrientationHandler.getSplitTaskViewDismissDirection(splitController
- .getActiveSplitPositionOption(), mActivity.getDeviceProfile());
- switch (dir) {
- case PagedOrientationHandler.SPLIT_TRANSLATE_SECONDARY_NEGATIVE:
- dismissingTaskViewTranslate = taskView
- .getSecondaryDissmissTranslationProperty();
- positiveNegativeFactor = -1;
- break;
- case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_POSITIVE:
- dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty();
- positiveNegativeFactor = 1;
- break;
-
- case PagedOrientationHandler.SPLIT_TRANSLATE_PRIMARY_NEGATIVE:
- dismissingTaskViewTranslate = taskView.getPrimaryDismissTranslationProperty();
- positiveNegativeFactor = -1;
- break;
- default:
- throw new IllegalStateException("Invalid split task translation: " + dir);
- }
- }
- // Double translation distance so dismissal drag is the full height, as we only animate
- // the drag for the first half of the progress.
- anim.add(ObjectAnimator.ofFloat(taskView, dismissingTaskViewTranslate,
- positiveNegativeFactor * translateDistance * 2).setDuration(duration), LINEAR, sp);
+ anim.add(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate,
+ verticalFactor * secondaryTaskDimension * 2).setDuration(duration), LINEAR, sp);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile
&& taskView.isRunningTask()) {
@@ -2301,15 +2381,37 @@
}
/**
+ * Places an {@link FloatingTaskView} on top of the thumbnail for {@link #mSplitHiddenTaskView}
+ * and then animates it into the split position that was desired
+ */
+ private void createInitialSplitSelectAnimation(PendingAnimation anim) {
+ float placeholderHeight = getResources().getDimension(R.dimen.split_placeholder_size);
+ mOrientationHandler.getInitialSplitPlaceholderBounds((int) placeholderHeight,
+ mActivity.getDeviceProfile(),
+ mSplitSelectStateController.getActiveSplitPositionOption(), mTempRect);
+
+ RectF startingTaskRect = new RectF();
+ mSplitHiddenTaskView.setVisibility(INVISIBLE);
+ mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
+ mSplitHiddenTaskView, startingTaskRect);
+ mFirstFloatingTaskView.setAlpha(1);
+ mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
+ mTempRect, mSplitHiddenTaskView, true /*fadeWithThumbnail*/);
+ }
+
+ /**
* Creates a {@link PendingAnimation} for dismissing the specified {@link TaskView}.
* @param dismissedTaskView the {@link TaskView} to be dismissed
* @param animateTaskView whether the {@link TaskView} to be dismissed should be animated
* @param shouldRemoveTask whether the associated {@link Task} should be removed from
* ActivityManager after dismissal
* @param duration duration of the animation
+ * @param dismissingForSplitSelection task dismiss animation is used for entering split
+ * selection state from app icon
*/
public PendingAnimation createTaskDismissAnimation(TaskView dismissedTaskView,
- boolean animateTaskView, boolean shouldRemoveTask, long duration) {
+ boolean animateTaskView, boolean shouldRemoveTask, long duration,
+ boolean dismissingForSplitSelection) {
if (mPendingAnimation != null) {
mPendingAnimation.createPlaybackController().dispatchOnCancel().dispatchOnEnd();
}
@@ -2323,7 +2425,8 @@
boolean showAsGrid = showAsGrid();
int taskCount = getTaskViewCount();
int dismissedIndex = indexOfChild(dismissedTaskView);
- int dismissedTaskId = dismissedTaskView.getTaskId();
+ int dismissedTaskId = dismissedTaskView.getTaskIds()[0];
+ int dismissedTaskViewId = dismissedTaskView.getTaskViewId();
// Grid specific properties.
boolean isFocusedTaskDismissed = false;
@@ -2340,7 +2443,7 @@
if (showAsGrid) {
dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
- isFocusedTaskDismissed = dismissedTaskId == mFocusedTaskId;
+ isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
if (isFocusedTaskDismissed) {
nextFocusedTaskFromTop =
mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
@@ -2350,7 +2453,7 @@
if (taskView == dismissedTaskView) {
continue;
}
- boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskId());
+ boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
if ((nextFocusedTaskFromTop && isTopRow
|| (!nextFocusedTaskFromTop && !isTopRow))) {
nextFocusedTaskView = taskView;
@@ -2376,7 +2479,11 @@
View child = getChildAt(i);
if (child == dismissedTaskView) {
if (animateTaskView) {
- addDismissedTaskAnimations(dismissedTaskView, duration, anim);
+ if (dismissingForSplitSelection) {
+ createInitialSplitSelectAnimation(anim);
+ } else {
+ addDismissedTaskAnimations(dismissedTaskView, duration, anim);
+ }
}
} else if (!showAsGrid) {
// Compute scroll offsets from task dismissal for animation.
@@ -2525,7 +2632,7 @@
mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
}
removeViewInLayout(dismissedTaskView);
- mTopRowIdSet.remove(dismissedTaskId);
+ mTopRowIdSet.remove(dismissedTaskViewId);
if (taskCount == 1) {
removeViewInLayout(mClearAllButton);
@@ -2533,8 +2640,8 @@
} else {
// Update focus task and its size.
if (finalNextFocusedTaskView != null) {
- mFocusedTaskId = finalNextFocusedTaskView.getTaskId();
- mTopRowIdSet.remove(mFocusedTaskId);
+ mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
+ mTopRowIdSet.remove(mFocusedTaskViewId);
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
updateTaskSize(true);
@@ -2559,7 +2666,7 @@
/**
* @return {@code true} if one of the task thumbnails would intersect/overlap with the
- * {@link #mSplitPlaceholderView}
+ * {@link #mFirstFloatingTaskView}
*/
public boolean shouldShiftThumbnailsForSplitSelect(@SplitConfigurationOptions.StagePosition
int stagePosition) {
@@ -2653,7 +2760,7 @@
@UiThread
private void dismissTask(int taskId) {
- TaskView taskView = getTaskView(taskId);
+ TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView == null) {
return;
}
@@ -2662,7 +2769,7 @@
public void dismissTask(TaskView taskView, boolean animateTaskView, boolean removeTask) {
runDismissAnimation(createTaskDismissAnimation(taskView, animateTaskView, removeTask,
- DISMISS_TASK_DURATION));
+ DISMISS_TASK_DURATION, false /* dismissingForSplitSelection*/));
}
@SuppressWarnings("unused")
@@ -2732,9 +2839,12 @@
}
alpha = Utilities.boundToRange(alpha, 0, 1);
mContentAlpha = alpha;
+ int runningTaskId = getTaskIdsForRunningTaskView()[0];
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
TaskView child = getTaskViewAt(i);
- if (!mRunningTaskTileHidden || child.getTaskId() != mRunningTaskId) {
+ int[] childTaskIds = child.getTaskIds();
+ if (!mRunningTaskTileHidden ||
+ (childTaskIds[0] != runningTaskId && childTaskIds[1] != runningTaskId)) {
child.setStableAlpha(alpha);
}
}
@@ -2893,8 +3003,8 @@
float modalOffset = ACCEL_0_75.getInterpolation(mTaskModalness);
int count = getChildCount();
- TaskView runningTask = mRunningTaskId == -1 || !mRunningTaskTileHidden
- ? null : getTaskView(mRunningTaskId);
+ TaskView runningTask = mRunningTaskViewId == -1 || !mRunningTaskTileHidden
+ ? null : getRunningTaskView();
int midpoint = runningTask == null ? -1 : indexOfChild(runningTask);
int modalMidpoint = getCurrentPage();
@@ -3064,8 +3174,11 @@
protected void setTaskViewsSecondarySplitTranslation(float translation) {
mTaskViewsSecondarySplitTranslation = translation;
for (int i = 0; i < getTaskViewCount(); i++) {
- TaskView task = getTaskViewAt(i);
- task.getSecondarySplitTranslationProperty().set(task, translation);
+ TaskView taskView = getTaskViewAt(i);
+ if (taskView == mSplitHiddenTaskView) {
+ continue;
+ }
+ taskView.getSecondarySplitTranslationProperty().set(taskView, translation);
}
}
@@ -3081,30 +3194,60 @@
public void initiateSplitSelect(TaskView taskView, SplitPositionOption splitPositionOption) {
mSplitHiddenTaskView = taskView;
- SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
Rect initialBounds = new Rect(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
taskView.getBottom());
- splitController.setInitialTaskSelect(taskView, splitPositionOption, initialBounds);
+ mSplitSelectStateController.setInitialTaskSelect(taskView,
+ splitPositionOption, initialBounds);
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
- mSplitPlaceholderView.setLayoutParams(
- splitController.getLayoutParamsForActivePosition(getResources(),
- mActivity.getDeviceProfile()));
- mSplitPlaceholderView.setIcon(taskView.getIconView());
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ finishRecentsAnimation(true, null);
+ }
}
public PendingAnimation createSplitSelectInitAnimation() {
int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
- return createTaskDismissAnimation(mSplitHiddenTaskView, true, false, duration);
+ return createTaskDismissAnimation(mSplitHiddenTaskView, true, false, duration,
+ true /* dismissingForSplitSelection*/);
}
public void confirmSplitSelect(TaskView taskView) {
- mSplitPlaceholderView.getSplitController().setSecondTaskId(taskView);
- resetTaskVisuals();
- setTranslationY(0);
+ RectF secondTaskStartingBounds = new RectF();
+ Rect secondTaskEndingBounds = new Rect();
+ // TODO(194414938) starting bounds seem slightly off, investigate
+ Rect firstTaskStartingBounds = new Rect();
+ Rect firstTaskEndingBounds = mTempRect;
+ int duration = mActivity.getStateManager().getState().getTransitionDuration(getContext());
+ PendingAnimation pendingAnimation = new PendingAnimation(duration);
+
+ int halfDividerSize = getResources()
+ .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
+ mOrientationHandler.getFinalSplitPlaceholderBounds(halfDividerSize,
+ mActivity.getDeviceProfile(),
+ mSplitSelectStateController.getActiveSplitPositionOption(), firstTaskEndingBounds,
+ secondTaskEndingBounds);
+
+ mFirstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
+ mFirstFloatingTaskView.addAnimation(pendingAnimation,
+ new RectF(firstTaskStartingBounds), firstTaskEndingBounds, mFirstFloatingTaskView,
+ false /*fadeWithThumbnail*/);
+
+ mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
+ taskView, secondTaskStartingBounds);
+ mSecondFloatingTaskView.setAlpha(1);
+ mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
+ secondTaskEndingBounds, taskView.getThumbnail(),
+ true /*fadeWithThumbnail*/);
+ pendingAnimation.addEndListener(aBoolean -> {
+ mSplitSelectStateController.setSecondTaskId(taskView);
+ resetFromSplitSelectionState();
+ });
+ mSecondSplitHiddenTaskView = taskView;
+ taskView.setVisibility(INVISIBLE);
+ pendingAnimation.buildAnim().start();
}
public PendingAnimation cancelSplitSelect(boolean animate) {
- SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
+ SplitSelectStateController splitController = mSplitSelectStateController;
SplitPositionOption splitOption = splitController.getActiveSplitPositionOption();
Rect initialBounds = splitController.getInitialBounds();
splitController.resetState();
@@ -3217,8 +3360,19 @@
}
onLayout(false /* changed */, getLeft(), getTop(), getRight(), getBottom());
resetTaskVisuals();
+ mSplitHiddenTaskView.setVisibility(VISIBLE);
mSplitHiddenTaskView = null;
+ mSecondSplitHiddenTaskView.setVisibility(VISIBLE);
+ mSecondSplitHiddenTaskView = null;
mSplitHiddenTaskViewIndex = -1;
+ if (mFirstFloatingTaskView != null) {
+ mActivity.getRootView().removeView(mFirstFloatingTaskView);
+ mFirstFloatingTaskView = null;
+ }
+ if (mSecondFloatingTaskView != null) {
+ mActivity.getRootView().removeView(mSecondFloatingTaskView);
+ mSecondFloatingTaskView = null;
+ }
}
private void updateDeadZoneRects() {
@@ -3664,8 +3818,8 @@
TaskView taskView = getTaskViewAt(i);
float scrollDiff = taskView.getScrollAdjustment(showAsFullscreen, showAsGrid);
int pageScroll = newPageScrolls[i + mTaskViewStartIndex] + (int) scrollDiff;
- if ((mIsRtl && pageScroll < clearAllScroll)
- || (!mIsRtl && pageScroll > clearAllScroll)) {
+ if ((mIsRtl && pageScroll < clearAllScroll + clearAllWidth)
+ || (!mIsRtl && pageScroll > clearAllScroll - clearAllWidth)) {
pageScroll = clearAllScroll + (mIsRtl ? clearAllWidth : -clearAllWidth);
}
if (outPageScrolls[i] != pageScroll) {
@@ -3817,8 +3971,9 @@
}
return;
}
- switchToScreenshot(mRunningTaskId == -1 ? null
- : mRecentsAnimationController.screenshotTask(mRunningTaskId), onFinishRunnable);
+ int runningTaskId = getTaskIdsForRunningTaskView()[0];
+ switchToScreenshot(mRunningTaskViewId == -1 ? null
+ : mRecentsAnimationController.screenshotTask(runningTaskId), onFinishRunnable);
}
/**
@@ -3854,7 +4009,6 @@
boolean inPlaceLandscape = !mOrientationState.canRecentsActivityRotate()
&& mOrientationState.getTouchRotation() != ROTATION_0;
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION, modalness < 1 && inPlaceLandscape);
- mActionsView.setTaskModalness(modalness);
}
@Nullable
diff --git a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
index bb8bc11..a712d1a 100644
--- a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
@@ -22,6 +22,8 @@
import android.view.Gravity;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
+
import com.android.quickstep.util.SplitSelectStateController;
public class SplitPlaceholderView extends FrameLayout {
@@ -55,6 +57,11 @@
return mSplitController;
}
+ @Nullable
+ public IconView getIcon() {
+ return mIcon;
+ }
+
public void setIcon(IconView icon) {
if (mIcon == null) {
mIcon = new IconView(getContext());
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 1345a94..bfc7eea 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -43,7 +43,6 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.views.BaseDragLayer;
@@ -138,7 +137,7 @@
// NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
// which would render the X and Y position set here incorrect
setPivotX(0);
- if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+ if (mActivity.getDeviceProfile().overviewShowAsGrid) {
// In tablet, set pivotY to original position without mThumbnailTopMargin adjustment.
setPivotY(-taskTopMargin);
} else {
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 1ced86b..320ea09 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -47,7 +47,6 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SystemUiController;
@@ -449,7 +448,7 @@
// Note: Disable rotation in grid layout.
boolean windowingModeSupportsRotation = !dp.isMultiWindowMode
&& thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN
- && !(dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get());
+ && !dp.overviewShowAsGrid;
isOrientationDifferent = isOrientationChange(deltaRotate)
&& windowingModeSupportsRotation;
if (canvasWidth == 0 || canvasHeight == 0 || scale == 0) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 2e154f6..02c5d84 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -77,7 +77,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -367,6 +366,9 @@
private float mModalness = 0;
private float mStableAlpha = 1;
+ private int mTaskViewId = -1;
+ private final int[] mTaskIdContainer = new int[]{-1, -1};
+
private boolean mShowScreenshot;
// The current background requests to load the task thumbnail and icon
@@ -402,6 +404,14 @@
setOutlineProvider(mOutlineProvider);
}
+ public void setTaskViewId(int id) {
+ this.mTaskViewId = id;
+ }
+
+ public int getTaskViewId() {
+ return mTaskViewId;
+ }
+
/**
* Builds proto for logging
*/
@@ -507,6 +517,7 @@
public void bind(Task task, RecentsOrientedState orientedState) {
cancelPendingLoadTasks();
mTask = task;
+ mTaskIdContainer[0] = mTask.key.id;
mSnapshotView.bind(task);
setOrientationState(orientedState);
}
@@ -515,8 +526,12 @@
return mTask;
}
- public int getTaskId() {
- return mTask != null && mTask.key != null ? mTask.key.id : -1;
+ /**
+ * @return integer array of two elements to be size consistent with max number of tasks possible
+ * index 0 will contain the taskId, index 1 will be -1 indicating a null taskID value
+ */
+ public int[] getTaskIds() {
+ return mTaskIdContainer;
}
public TaskThumbnailView getThumbnail() {
@@ -531,6 +546,9 @@
if (getTask() == null) {
return;
}
+ if (confirmSecondSplitSelectApp()) {
+ return;
+ }
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
if (!mIsClickableAsLiveTile) {
return;
@@ -549,7 +567,7 @@
if (targets == null) {
// If the recents animation is cancelled somehow between the parent if block and
// here, try to launch the task as a non live tile task.
- launcherNonLiveTileTask();
+ launchTaskAnimated();
return;
}
@@ -567,19 +585,22 @@
});
anim.start();
} else {
- launcherNonLiveTileTask();
+ launchTaskAnimated();
}
mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
.log(LAUNCHER_TASK_LAUNCH_TAP);
}
- private void launcherNonLiveTileTask() {
- if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
- // User tapped to select second split screen app
+ /**
+ * @return {@code true} if user is already in split select mode and this tap was to choose the
+ * second app. {@code false} otherwise
+ */
+ private boolean confirmSecondSplitSelectApp() {
+ boolean isSelectingSecondSplitApp = mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+ if (isSelectingSecondSplitApp) {
getRecentsView().confirmSplitSelect(this);
- } else {
- launchTaskAnimated();
}
+ return isSelectingSecondSplitApp;
}
/**
@@ -593,7 +614,8 @@
ActivityOptionsWrapper opts = mActivity.getActivityLaunchOptions(this, null);
if (ActivityManagerWrapper.getInstance()
.startActivityFromRecents(mTask.key, opts.options)) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && getRecentsView().getRunningTaskId() != -1) {
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() &&
+ getRecentsView().getRunningTaskViewId() != -1) {
// Return a fresh callback in the live tile case, so that it's not accidentally
// triggered by QuickstepTransitionManager.AppLaunchAnimationRunner.
RunnableList callbackList = new RunnableList();
@@ -932,7 +954,7 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+ if (mActivity.getDeviceProfile().overviewShowAsGrid) {
setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
setPivotY(mSnapshotView.getTop());
} else {
@@ -949,11 +971,8 @@
* How much to scale down pages near the edge of the screen.
*/
public static float getEdgeScaleDownFactor(DeviceProfile deviceProfile) {
- if (deviceProfile.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
- return EDGE_SCALE_DOWN_FACTOR_GRID;
- } else {
- return EDGE_SCALE_DOWN_FACTOR_CAROUSEL;
- }
+ return deviceProfile.overviewShowAsGrid ? EDGE_SCALE_DOWN_FACTOR_GRID
+ : EDGE_SCALE_DOWN_FACTOR_CAROUSEL;
}
private void setNonGridScale(float nonGridScale) {
@@ -1334,9 +1353,10 @@
float boxTranslationY;
int expectedWidth;
int expectedHeight;
- if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
- final int thumbnailPadding =
- mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+ int iconDrawableSize;
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ if (deviceProfile.overviewShowAsGrid) {
+ final int thumbnailPadding = deviceProfile.overviewTaskThumbnailTopMarginPx;
final Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
final int taskWidth = lastComputedTaskSize.width();
final int taskHeight = lastComputedTaskSize.height();
@@ -1349,11 +1369,13 @@
// that is associated with the original orientation of the focused task.
boxWidth = taskWidth;
boxHeight = taskHeight;
+ iconDrawableSize = deviceProfile.overviewTaskIconDrawableSizePx;
} else {
// Otherwise task is in grid, and should use lastComputedGridTaskSize.
Rect lastComputedGridTaskSize = getRecentsView().getLastComputedGridTaskSize();
boxWidth = lastComputedGridTaskSize.width();
boxHeight = lastComputedGridTaskSize.height();
+ iconDrawableSize = deviceProfile.overviewTaskIconDrawableSizeGridPx;
}
// Bound width/height to the box size.
@@ -1370,6 +1392,7 @@
boxTranslationY = 0f;
expectedWidth = ViewGroup.LayoutParams.MATCH_PARENT;
expectedHeight = ViewGroup.LayoutParams.MATCH_PARENT;
+ iconDrawableSize = deviceProfile.overviewTaskIconDrawableSizePx;
}
setNonGridScale(nonGridScale);
@@ -1379,6 +1402,7 @@
params.height = expectedHeight;
setLayoutParams(params);
}
+ mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
}
private float getGridTrans(float endTranslation) {
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index dc73a9a..ca47de3 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -82,6 +82,6 @@
RecentsView recentsView = launcher.getOverviewPanel();
return recentsView.getSizeStrategy().isInLiveTileMode()
- && recentsView.getRunningTaskId() != -1;
+ && recentsView.getRunningTaskViewId() != -1;
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index a683d01..e4f5a19 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -59,6 +59,7 @@
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.quickstep.views.RecentsView;
import org.junit.After;
@@ -98,6 +99,7 @@
mDevice = UiDevice.getInstance(instrumentation);
mDevice.setOrientationNatural();
mLauncher = new LauncherInstrumentation();
+ mLauncher.enableDebugTracing();
// b/143488140
//mLauncher.enableCheckEventsForSuccessfulGestures();
@@ -213,6 +215,7 @@
// b/143488140
//@NavigationModeSwitch
@Test
+ @ScreenRecord // b/187080582
public void testOverview() {
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index c14a590..164e755 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -93,7 +93,6 @@
@Test
@PortraitLandscape
- @ScreenRecord //b/191344757
public void testOverview() throws Exception {
startTestAppsWithCheck();
// mLauncher.pressHome() also tests an important case of pressing home while in background.
@@ -159,7 +158,7 @@
@Test
@NavigationModeSwitch
@PortraitLandscape
- @ScreenRecord //b/191344757
+ @ScreenRecord //b/193125090
public void testOverviewActions() throws Exception {
// Experimenting for b/165029151:
final Overview overview = mLauncher.pressHome().switchToOverview();
@@ -185,7 +184,6 @@
@Test
@NavigationModeSwitch
@PortraitLandscape
- @ScreenRecord //b/191344757
public void testSwitchToOverview() throws Exception {
assertNotNull("Workspace.switchToOverview() returned null",
mLauncher.pressHome().switchToOverview());
@@ -196,7 +194,6 @@
@Test
@NavigationModeSwitch
@PortraitLandscape
- @ScreenRecord //b/191344757
public void testBackground() throws Exception {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
final Background background = getAndAssertBackground();
@@ -218,7 +215,6 @@
@Test
@PortraitLandscape
- @ScreenRecord //b/191344757
public void testAllAppsFromHome() throws Exception {
// Test opening all apps
assertNotNull("switchToAllApps() returned null",
diff --git a/res/drawable-v31/bg_deferred_app_widget.xml b/res/drawable-v31/bg_deferred_app_widget.xml
new file mode 100644
index 0000000..a08998d
--- /dev/null
+++ b/res/drawable-v31/bg_deferred_app_widget.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="8dp">
+ <shape android:shape="rectangle">
+ <corners android:radius="@android:dimen/system_app_widget_background_radius" />
+ <solid android:color="#77000000" />
+ </shape>
+</inset>
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index c57b75a..e29e1b1 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -37,7 +37,7 @@
android:id="@+id/add_item_bottom_sheet_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="24dp"
+ android:paddingVertical="24dp"
android:background="@drawable/add_item_dialog_background"
android:orientation="vertical" >
@@ -46,6 +46,7 @@
android:id="@+id/widget_appName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:gravity="center_horizontal"
android:textColor="?android:attr/textColorPrimary"
android:textSize="24sp"
@@ -55,8 +56,10 @@
android:maxLines="1" />
<TextView
+ android:id="@+id/widget_drag_instruction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:gravity="center_horizontal"
android:paddingTop="8dp"
android:text="@string/add_item_request_drag_hint"
@@ -75,12 +78,15 @@
android:id="@+id/widget_cell"
layout="@layout/widget_cell"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin" />
</ScrollView>
<LinearLayout
+ android:id="@+id/actions_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:gravity="center_vertical|end"
android:paddingVertical="8dp"
android:orientation="horizontal">
diff --git a/res/layout/floating_split_select_view.xml b/res/layout/floating_split_select_view.xml
new file mode 100644
index 0000000..e184b91
--- /dev/null
+++ b/res/layout/floating_split_select_view.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.quickstep.views.FloatingTaskView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/thumbnail"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" />
+
+ <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/white"
+ android:visibility="gone" />
+
+</com.android.quickstep.views.FloatingTaskView>
\ No newline at end of file
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index de091c5..89895e5 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -16,36 +16,12 @@
<com.android.launcher3.shortcuts.DeepShortcutView
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="@dimen/bg_popup_item_width"
android:layout_height="@dimen/bg_popup_item_height"
android:elevation="@dimen/deep_shortcuts_elevation"
android:background="@drawable/middle_item_primary"
android:theme="@style/PopupItem" >
- <com.android.launcher3.BubbleTextView
- style="@style/BaseIconUnBounded"
- android:id="@+id/bubble_text"
- android:background="?android:attr/selectableItemBackground"
- android:gravity="start|center_vertical"
- android:textAlignment="viewStart"
- android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
- android:paddingEnd="@dimen/popup_padding_end"
- android:textSize="14sp"
- android:minLines="1"
- android:maxLines="2"
- android:ellipsize="end"
- android:textColor="?android:attr/textColorPrimary"
- launcher:iconDisplay="shortcut_popup"
- launcher:layoutHorizontal="true"
- android:focusable="false" />
-
- <View
- android:id="@+id/icon"
- android:layout_width="@dimen/system_shortcut_icon_size"
- android:layout_height="@dimen/system_shortcut_icon_size"
- android:layout_marginStart="@dimen/system_shortcut_margin_start"
- android:layout_gravity="start|center_vertical"
- android:backgroundTint="?android:attr/textColorPrimary"/>
+ <include layout="@layout/system_shortcut_content" />
</com.android.launcher3.shortcuts.DeepShortcutView>
diff --git a/res/layout/system_shortcut_content.xml b/res/layout/system_shortcut_content.xml
new file mode 100644
index 0000000..8b39202
--- /dev/null
+++ b/res/layout/system_shortcut_content.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<merge
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto" >
+
+ <com.android.launcher3.BubbleTextView
+ style="@style/BaseIconUnBounded"
+ android:id="@+id/bubble_text"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="start|center_vertical"
+ android:textAlignment="viewStart"
+ android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
+ android:paddingEnd="@dimen/popup_padding_end"
+ android:textSize="14sp"
+ android:minLines="1"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:textColor="?android:attr/textColorPrimary"
+ launcher:iconDisplay="shortcut_popup"
+ launcher:layoutHorizontal="true"
+ android:focusable="false" />
+
+ <View
+ android:id="@+id/icon"
+ android:layout_width="@dimen/system_shortcut_icon_size"
+ android:layout_height="@dimen/system_shortcut_icon_size"
+ android:layout_marginStart="@dimen/system_shortcut_margin_start"
+ android:layout_gravity="start|center_vertical"
+ android:backgroundTint="?android:attr/textColorPrimary"/>
+</merge>
\ No newline at end of file
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index 15131f1..11eea60 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -44,7 +44,6 @@
style="@style/TextHeadline"
android:layout_weight="1"
android:background="@android:color/transparent"
- android:textStyle="bold"
android:gravity="center_horizontal"
android:hint="@string/folder_hint_text"
android:imeOptions="flagNoExtractUi"
diff --git a/res/layout/widgets_bottom_sheet_content.xml b/res/layout/widgets_bottom_sheet_content.xml
index 3b3ff8b..3d330dc 100644
--- a/res/layout/widgets_bottom_sheet_content.xml
+++ b/res/layout/widgets_bottom_sheet_content.xml
@@ -47,6 +47,7 @@
<include layout="@layout/widgets_table_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:layout_gravity="center_horizontal" />
</ScrollView>
</LinearLayout>
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 1b4f3b9..96b73c2 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -57,6 +57,7 @@
android:id="@+id/search_widgets_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:visibility="gone"
android:clipToPadding="false" />
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index f0ddc2b..fefad19 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -20,6 +20,7 @@
android:id="@+id/widgets_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToPadding="false"
android:paddingTop="@dimen/widget_picker_view_pager_top_padding"
android:descendantFocusability="afterDescendants"
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
index fbe559c..0f7e020 100644
--- a/res/layout/widgets_full_sheet_recyclerview.xml
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -18,4 +18,5 @@
android:id="@+id/primary_widgets_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToPadding="false" />
\ No newline at end of file
diff --git a/res/layout/widgets_full_sheet_search_and_recommendations.xml b/res/layout/widgets_full_sheet_search_and_recommendations.xml
index 4a3e20d..938c8ed 100644
--- a/res/layout/widgets_full_sheet_search_and_recommendations.xml
+++ b/res/layout/widgets_full_sheet_search_and_recommendations.xml
@@ -18,6 +18,7 @@
android:id="@+id/search_and_recommendations_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:layout_marginBottom="16dp"
android:orientation="vertical">
@@ -53,7 +54,6 @@
android:id="@+id/recommended_widget_table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:layout_marginTop="8dp"
android:background="@drawable/widgets_recommendation_background"
android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index 7f84050..8f0eae7 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -19,7 +19,6 @@
android:id="@+id/widgets_list_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:paddingVertical="@dimen/widget_list_header_view_vertical_padding"
android:orientation="horizontal"
launcher:appIconSize="48dp">
diff --git a/res/layout/widgets_search_bar.xml b/res/layout/widgets_search_bar.xml
index cb27f4f..9178a75 100644
--- a/res/layout/widgets_search_bar.xml
+++ b/res/layout/widgets_search_bar.xml
@@ -6,7 +6,6 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="24dp"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:background="@drawable/bg_widgets_searchbox">
<com.android.launcher3.ExtendedEditText
diff --git a/res/layout/widgets_table_container.xml b/res/layout/widgets_table_container.xml
index ab470d8..ab96b1343 100644
--- a/res/layout/widgets_table_container.xml
+++ b/res/layout/widgets_table_container.xml
@@ -17,5 +17,4 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widgets_table"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin" />
+ android:layout_height="wrap_content" />
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index b828e1d..2b8b9fa 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -28,7 +28,7 @@
<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="long_press_widget_to_add" msgid="3587712543577675817">"انقر مرتين مع تثبيت إصبعك لنقل أداة."</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>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"العرض %1$d الطول %2$d"</string>
@@ -72,7 +72,7 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"البحث عن مزيد من التطبيقات"</string>
<string name="label_application" msgid="8531721983832654978">"تطبيق"</string>
<string name="notifications_header" msgid="1404149926117359025">"الإشعارات"</string>
- <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"انقر مرتين مع تثبيت إصبعك لنقل اختصار."</string>
+ <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"انقر مع الاستمرار لنقل اختصار"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"انقر مرتين مع تثبيت إصبعك لنقل اختصار أو استخدام الإجراءات المخصّصة."</string>
<string name="out_of_space" msgid="6692471482459245734">"ما مِن مساحة على هذه الشاشة الرئيسية."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"لا يوجد المزيد من الحقول في علبة المفضلة"</string>
@@ -122,7 +122,7 @@
<string name="allow_rotation_title" msgid="7728578836261442095">"السماح بتدوير الشاشة الرئيسية"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"عند تدوير الهاتف"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"نقاط الإشعارات"</string>
- <string name="notification_dots_desc_on" msgid="1679848116452218908">"مفعّل"</string>
+ <string name="notification_dots_desc_on" msgid="1679848116452218908">"مفعّلة"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"غير مفعّل"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"يلزم تمكين الوصول إلى الإشعارات"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"لعرض نقاط الإشعارات، يجب تفعيل إشعارات التطبيق في <xliff:g id="NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 521ade4..d83776c 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -48,7 +48,7 @@
<string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
<string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Suche"</string>
<string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Text aus dem Suchfeld löschen"</string>
- <string name="no_widgets_available" msgid="4337693382501046170">"Widgets und Shortcuts nicht verfügbar"</string>
+ <string name="no_widgets_available" msgid="4337693382501046170">"Widgets und Verknüpfungen nicht verfügbar"</string>
<string name="no_search_results" msgid="3787956167293097509">"Keine Widgets oder Verknüpfungen gefunden"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Privat"</string>
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Geschäftlich"</string>
@@ -64,7 +64,7 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Weitere Apps suchen"</string>
<string name="label_application" msgid="8531721983832654978">"App"</string>
<string name="notifications_header" msgid="1404149926117359025">"Benachrichtigungen"</string>
- <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Tippen und halten, um eine Verknüpfung zu bewegen."</string>
+ <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Zum Verschieben einer Verknüpfung berühren und halten"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Doppeltippen und halten, um eine Verknüpfung zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
<string name="out_of_space" msgid="6692471482459245734">"Auf diesem Startbildschirm ist kein Platz mehr vorhanden"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Ablage \"Favoriten\" ist voll."</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 36387ac..eca881f1f 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -158,12 +158,12 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personales"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"De trabajo"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
- <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Las apps de trabajo tienen una insignia y el administrador de IT las puede ver"</string>
+ <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Las apps de trabajo tienen una insignia y el administrador de TI las puede ver"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Entendido"</string>
<string name="work_apps_paused_title" msgid="3040901117349444598">"Las apps de trabajo están detenidas"</string>
<string name="work_apps_paused_body" msgid="261634750995824906">"Las apps de trabajo no pueden enviarte notificaciones, usar la batería ni acceder a tu ubicación"</string>
<string name="work_apps_paused_content_description" msgid="5149623040804051095">"Las apps de trabajo están desactivadas y, por ende, no pueden enviarte notificaciones, usar la batería ni acceder a tu ubicación"</string>
- <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Las apps de trabajo tienen una insignia y el administrador de IT las puede ver"</string>
+ <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Las apps de trabajo tienen una insignia y el administrador de TI las puede ver"</string>
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Entendido"</string>
<string name="work_apps_pause_btn_text" msgid="1921059713673767460">"Desactivar las apps de trabajo"</string>
<string name="work_apps_enable_btn_text" msgid="1156432622148413741">"Activar las apps de trabajo"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index c061796..633ca2d 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -64,7 +64,7 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Rechercher plus d\'applications"</string>
<string name="label_application" msgid="8531721983832654978">"Application"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
- <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Appuyez de manière prolongée pour déplacer raccourci."</string>
+ <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Appuyez de manière prolongée pour déplacer un raccourci."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Appuyez deux fois et maintenez la pression pour déplacer un raccourci ou utiliser les actions personnalisées."</string>
<string name="out_of_space" msgid="6692471482459245734">"Espace insuffisant sur cet écran d\'accueil"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Plus d\'espace disponible dans la zone de favoris."</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 695b128..2a154bf 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -79,10 +79,10 @@
<string name="pin_prediction" msgid="4196423321649756498">"પૂર્વાનુમાનને પિન કરો"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"શૉર્ટકટ ઇન્સ્ટૉલ કરો"</string>
<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="permdesc_write_settings" msgid="5440712911516509985">"એપ્લિકેશનને હોમમાં સેટિંગ્સ અને શોર્ટકટ્સ બદલવાની મંજૂરી આપે છે."</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="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>
<string name="gadget_setup_text" msgid="1745356155479272374">"સેટઅપ પૂર્ણ કરવા માટે ટૅપ કરો"</string>
@@ -114,7 +114,7 @@
<string name="notification_dots_desc_off" msgid="1760796511504341095">"બંધ છે"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"નોટિફિકેશનનો ઍક્સેસની જરૂરી છે"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"નોટિફિકેશન માટેનું ચિહ્ન બતાવવા હેતુ, <xliff:g id="NAME">%1$s</xliff:g> માટેની ઍપ્લિકેશન નોટિફિકેશન ચાલુ કરો"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"સેટિંગ્સ બદલો"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"સેટિંગ બદલો"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"નોટિફિકેશન માટેના ચિહ્ન બતાવો"</string>
<string name="auto_add_shortcuts_label" msgid="3698776050751790653">"ઍપના આઇકન હોમ સ્ક્રીન પર ઉમેરો"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"નવી ઍપ માટે"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index e231074..53640fe 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -71,7 +71,7 @@
<string name="all_apps_button_label" msgid="8130441508702294465">"ऐप्लिकेशन सूची"</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-in/strings.xml b/res/values-in/strings.xml
index a7f67bc..673a446 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
- <string name="work_folder_name" msgid="3753320833950115786">"Kantor"</string>
+ <string name="work_folder_name" msgid="3753320833950115786">"Kerja"</string>
<string name="activity_not_found" msgid="8071924732094499514">"Aplikasi tidak dipasang."</string>
<string name="activity_not_available" msgid="7456344436509528827">"Aplikasi tidak tersedia"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplikasi yang didownload dinonaktifkan dalam mode Aman"</string>
@@ -51,7 +51,7 @@
<string name="no_widgets_available" msgid="4337693382501046170">"Widget dan pintasan tidak tersedia"</string>
<string name="no_search_results" msgid="3787956167293097509">"Tidak ada widget atau pintasan yang ditemukan"</string>
<string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Pribadi"</string>
- <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kantor"</string>
+ <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kerja"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Percakapan"</string>
<string name="widget_education_header" msgid="4874760613775913787">"Info bermanfaat mudah dilihat"</string>
<string name="widget_education_content" msgid="745542879510751525">"Untuk mendapatkan info tanpa membuka aplikasi, Anda dapat menambahkan widget ke Layar utama"</string>
@@ -105,7 +105,7 @@
<string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> item atau lebih"</string>
<string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpaper"</string>
<string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Wallpaper & gaya"</string>
- <string name="settings_button_text" msgid="8873672322605444408">"Setelan layar utama"</string>
+ <string name="settings_button_text" msgid="8873672322605444408">"Setelan Layar utama"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dinonaktifkan oleh admin"</string>
<string name="allow_rotation_title" msgid="7728578836261442095">"Izinkan Layar utama diputar"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Saat ponsel diputar"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index aee2c73..71a3403 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -85,7 +85,7 @@
<string name="permdesc_write_settings" msgid="5440712911516509985">"Consente all\'app di modificare le impostazioni e le scorciatoie in Home."</string>
<string name="msg_no_phone_permission" msgid="9208659281529857371">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è autorizzata a effettuare telefonate"</string>
<string name="gadget_error_text" msgid="740356548025791839">"Impossibile caricare il widget"</string>
- <string name="gadget_setup_text" msgid="1745356155479272374">"Tocca per completare la configurazione"</string>
+ <string name="gadget_setup_text" msgid="1745356155479272374">"Tocca e completa configurazione"</string>
<string name="uninstall_system_app_text" msgid="4172046090762920660">"Questa è un\'app di sistema e non può essere disinstallata."</string>
<string name="folder_hint_text" msgid="5174843001373488816">"Modifica nome"</string>
<string name="disabled_app_label" msgid="6673129024321402780">"App <xliff:g id="APP_NAME">%1$s</xliff:g> disattivata"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index ae0416d..c21a941 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -154,7 +154,7 @@
<string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Кыска жолдор жана билдирмелер"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"Этибарга албоо"</string>
<string name="accessibility_close" msgid="2277148124685870734">"Жабуу"</string>
- <string name="notification_dismissed" msgid="6002233469409822874">"Эскертме көз жаздымда калтырылды"</string>
+ <string name="notification_dismissed" msgid="6002233469409822874">"Билдирме жабылды"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Жеке колдонмолор"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Жумуш колдонмолору"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Жумуш профили"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 1df4726..1d5321b 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -68,7 +68,7 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Wyszukaj więcej aplikacji"</string>
<string name="label_application" msgid="8531721983832654978">"Aplikacja"</string>
<string name="notifications_header" msgid="1404149926117359025">"Powiadomienia"</string>
- <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Naciśnij i przytrzymaj, aby wybrać skrót."</string>
+ <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Naciśnij i przytrzymaj, aby przenieść skrót."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Naciśnij dwukrotnie i przytrzymaj, aby przenieść skrót lub użyć działań niestandardowych."</string>
<string name="out_of_space" msgid="6692471482459245734">"Brak miejsca na tym ekranie głównym"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Brak miejsca w Ulubionych"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 85d7db6..2415542 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -75,7 +75,7 @@
<string name="all_apps_button_label" msgid="8130441508702294465">"Список приложений"</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-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 47a88f2..3727932 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -17,4 +17,7 @@
<resources>
<!-- DragController -->
<dimen name="drag_flingToDeleteMinVelocity">-1000dp</dimen>
+
+<!-- Widgets pickers -->
+ <dimen name="widget_list_horizontal_margin">32dp</dimen>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 46570f0..da37250 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -29,7 +29,8 @@
<dimen name="dynamic_grid_cell_layout_padding">5.5dp</dimen>
<dimen name="dynamic_grid_cell_padding_x">8dp</dimen>
- <dimen name="two_panel_home_side_padding">18dp</dimen>
+ <dimen name="two_panels_home_side_padding_landscape">36dp</dimen>
+ <dimen name="two_panels_home_side_padding_portrait">9dp</dimen>
<!-- Hotseat -->
<dimen name="dynamic_grid_hotseat_top_padding">8dp</dimen>
@@ -196,6 +197,7 @@
<dimen name="drop_target_text_size">16sp</dimen>
<dimen name="drop_target_shadow_elevation">2dp</dimen>
<dimen name="drop_target_bar_margin_horizontal">4dp</dimen>
+ <dimen name="drop_target_button_drawable_padding">8dp</dimen>
<!-- the distance an icon must be dragged before button drop targets accept it -->
<dimen name="drag_distanceThreshold">30dp</dimen>
@@ -322,10 +324,21 @@
<!-- Overview placeholder to compile in Launcer3 without Quickstep -->
<dimen name="task_thumbnail_icon_size">0dp</dimen>
- <dimen name="task_thumbnail_icon_size_grid">0dp</dimen>
+ <dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
+ <dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
<dimen name="overview_task_margin">0dp</dimen>
- <dimen name="overview_actions_bottom_margin_gesture">0dp</dimen>
- <dimen name="overview_actions_bottom_margin_three_button">0dp</dimen>
+ <dimen name="overview_task_margin_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>
+ <dimen name="overview_actions_top_margin_gesture_grid_landscape">0dp</dimen>
+ <dimen name="overview_actions_bottom_margin_gesture_grid_landscape">0dp</dimen>
+ <dimen name="overview_actions_margin_three_button">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="split_placeholder_size">110dp</dimen>
<!-- Workspace grid visualization parameters -->
<dimen name="grid_visualization_rounding_radius">22dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index e4a245a..b7661b9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -259,7 +259,7 @@
<!-- Drop targets -->
<style name="DropTargetButtonBase" parent="@android:style/TextAppearance.DeviceDefault">
- <item name="android:drawablePadding">8dp</item>
+ <item name="android:drawablePadding">@dimen/drop_target_button_drawable_padding</item>
<item name="android:padding">14dp</item>
<item name="android:textColor">@color/drop_target_text</item>
<item name="android:textSize">@dimen/drop_target_text_size</item>
diff --git a/res/xml/size_limits_80x104.xml b/res/xml/size_limits_80x104.xml
index f5ca757..4178664 100644
--- a/res/xml/size_limits_80x104.xml
+++ b/res/xml/size_limits_80x104.xml
@@ -31,32 +31,72 @@
</device-padding>
<device-padding
- launcher:maxEmptySpace="97dp">
+ launcher:maxEmptySpace="100dp">
<workspaceTopPadding
launcher:a="0"
- launcher:b="16dp"/>
+ launcher:b="9dp"/>
<workspaceBottomPadding
- launcher:a="0.56"
+ launcher:a="0.40"
launcher:b="0"
- launcher:c="16dp"/>
+ launcher:c="9dp"/>
<hotseatBottomPadding
- launcher:a="0.44"
+ launcher:a="0.60"
launcher:b="0"
- launcher:c="16dp"/>
+ launcher:c="9dp"/>
+ </device-padding>
+
+ <device-padding
+ launcher:maxEmptySpace="103dp">
+ <workspaceTopPadding
+ launcher:a="0"
+ launcher:b="26dp"/>
+ <workspaceBottomPadding
+ launcher:a="0"
+ launcher:b="20dp"/>
+ <hotseatBottomPadding
+ launcher:a="1"
+ launcher:b="0"
+ launcher:c="46dp"/>
</device-padding>
<device-padding
launcher:maxEmptySpace="107dp">
<workspaceTopPadding
launcher:a="0"
- launcher:b="16dp"/>
+ launcher:b="9dp"/>
<workspaceBottomPadding
launcher:a="0"
- launcher:b="36dp"/>
+ launcher:b="34dp"/>
<hotseatBottomPadding
launcher:a="1"
launcher:b="0"
- launcher:c="52dp"/>
+ launcher:c="43dp"/>
+ </device-padding>
+
+ <device-padding
+ launcher:maxEmptySpace="120dp">
+ <workspaceTopPadding
+ launcher:a="0"
+ launcher:b="16dp"/>
+ <workspaceBottomPadding
+ launcher:a="1"
+ launcher:c="72dp"/>
+ <hotseatBottomPadding
+ launcher:a="0"
+ launcher:b="56dp"/>
+ </device-padding>
+
+ <device-padding
+ launcher:maxEmptySpace="135dp">
+ <workspaceTopPadding
+ launcher:a="0"
+ launcher:b="39dp"/>
+ <workspaceBottomPadding
+ launcher:a="1"
+ launcher:c="95dp"/>
+ <hotseatBottomPadding
+ launcher:a="0"
+ launcher:b="56dp"/>
</device-padding>
<device-padding
@@ -71,5 +111,4 @@
launcher:a="0"
launcher:b="36dp"/>
</device-padding>
-
</device-paddings>
\ No newline at end of file
diff --git a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
index 34a8025..a397db5 100644
--- a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
@@ -76,7 +76,7 @@
setupUserManager();
setupBackupManager();
mModelHelper = new LauncherModelHelper();
- RestoreDbTask.setPending(RuntimeEnvironment.application, true);
+ RestoreDbTask.setPending(RuntimeEnvironment.application);
mDb = mModelHelper.provider.getDb();
mIdp = InvariantDeviceProfile.INSTANCE.get(RuntimeEnvironment.application);
}
diff --git a/robolectric_tests/src/com/android/launcher3/model/GridBackupTableTest.java b/robolectric_tests/src/com/android/launcher3/model/GridBackupTableTest.java
deleted file mode 100644
index 56ce215..0000000
--- a/robolectric_tests/src/com/android/launcher3/model/GridBackupTableTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package com.android.launcher3.model;
-
-
-import static android.database.DatabaseUtils.queryNumEntries;
-
-import static com.android.launcher3.LauncherSettings.Favorites.BACKUP_TABLE_NAME;
-import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
-import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
-import static com.android.launcher3.util.LauncherModelHelper.APP_ICON;
-import static com.android.launcher3.util.LauncherModelHelper.DESKTOP;
-import static com.android.launcher3.util.LauncherModelHelper.NO__ICON;
-import static com.android.launcher3.util.LauncherModelHelper.SHORTCUT;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Point;
-
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.LauncherSettings.Settings;
-import com.android.launcher3.util.LauncherModelHelper;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-/**
- * Unit tests for {@link GridBackupTable}
- */
-@RunWith(RobolectricTestRunner.class)
-public class GridBackupTableTest {
-
- private static final int BACKUP_ITEM_COUNT = 12;
-
- private LauncherModelHelper mModelHelper;
- private Context mContext;
- private SQLiteDatabase mDb;
-
- @Before
- public void setUp() {
- mModelHelper = new LauncherModelHelper();
- mContext = RuntimeEnvironment.application;
- mDb = mModelHelper.provider.getDb();
-
- setupGridData();
- }
-
- private void setupGridData() {
- mModelHelper.createGrid(new int[][][]{{
- { APP_ICON, APP_ICON, SHORTCUT, SHORTCUT},
- { SHORTCUT, SHORTCUT, NO__ICON, NO__ICON},
- { NO__ICON, NO__ICON, SHORTCUT, SHORTCUT},
- { APP_ICON, SHORTCUT, SHORTCUT, APP_ICON},
- }});
- assertEquals(BACKUP_ITEM_COUNT, queryNumEntries(mDb, TABLE_NAME));
- }
-
- @Test
- public void backupTableCreated() {
- GridBackupTable backupTable = new GridBackupTable(mContext, mDb, 4, 4, 4);
- assertFalse(backupTable.backupOrRestoreAsNeeded());
- Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE);
-
- assertTrue(tableExists(mDb, BACKUP_TABLE_NAME));
-
- // One extra entry for properties
- assertEquals(BACKUP_ITEM_COUNT + 1, queryNumEntries(mDb, BACKUP_TABLE_NAME));
- }
-
- @Test
- public void backupTableRestored() {
- assertFalse(new GridBackupTable(mContext, mDb, 4, 4, 4).backupOrRestoreAsNeeded());
- Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE);
-
- // Delete entries
- mDb.delete(TABLE_NAME, null, null);
- assertEquals(0, queryNumEntries(mDb, TABLE_NAME));
-
- GridBackupTable backupTable = new GridBackupTable(mContext, mDb, 3, 3, 3);
- assertTrue(backupTable.backupOrRestoreAsNeeded());
-
- // Items have been restored
- assertEquals(BACKUP_ITEM_COUNT, queryNumEntries(mDb, TABLE_NAME));
-
- Point outSize = new Point();
- assertEquals(4, backupTable.getRestoreHotseatAndGridSize(outSize));
- assertEquals(4, outSize.x);
- assertEquals(4, outSize.y);
- }
-
- @Test
- public void backupTableRemovedOnAdd() {
- assertFalse(new GridBackupTable(mContext, mDb, 4, 4, 4).backupOrRestoreAsNeeded());
- Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE);
-
- assertTrue(tableExists(mDb, BACKUP_TABLE_NAME));
-
- mModelHelper.addItem(1, 2, DESKTOP, 1, 1);
- assertFalse(tableExists(mDb, BACKUP_TABLE_NAME));
- }
-
- @Test
- public void backupTableRemovedOnDelete() {
- assertFalse(new GridBackupTable(mContext, mDb, 4, 4, 4).backupOrRestoreAsNeeded());
- Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE);
-
- assertTrue(tableExists(mDb, BACKUP_TABLE_NAME));
-
- mContext.getContentResolver().delete(Favorites.CONTENT_URI, null, null);
- assertFalse(tableExists(mDb, BACKUP_TABLE_NAME));
- }
-
- @Test
- public void backupTableRetainedOnUpdate() {
- assertFalse(new GridBackupTable(mContext, mDb, 4, 4, 4).backupOrRestoreAsNeeded());
- Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE);
-
- assertTrue(tableExists(mDb, BACKUP_TABLE_NAME));
-
- ContentValues values = new ContentValues();
- values.put(Favorites.RANK, 4);
- // Something was updated
- assertTrue(mContext.getContentResolver()
- .update(Favorites.CONTENT_URI, values, null, null) > 0);
-
- // Backup table remains
- assertTrue(tableExists(mDb, BACKUP_TABLE_NAME));
- }
-}
diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
deleted file mode 100644
index d544a0b..0000000
--- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java
+++ /dev/null
@@ -1,373 +0,0 @@
-package com.android.launcher3.model;
-
-import static com.android.launcher3.model.GridSizeMigrationTask.getWorkspaceScreenIds;
-import static com.android.launcher3.util.LauncherModelHelper.APP_ICON;
-import static com.android.launcher3.util.LauncherModelHelper.HOTSEAT;
-import static com.android.launcher3.util.LauncherModelHelper.SHORTCUT;
-import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Point;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.model.GridSizeMigrationTask.MultiStepMigrationTask;
-import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.LauncherModelHelper;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.HashSet;
-import java.util.LinkedList;
-
-/**
- * Unit tests for {@link GridSizeMigrationTask}
- */
-@RunWith(RobolectricTestRunner.class)
-public class GridSizeMigrationTaskTest {
-
- private LauncherModelHelper mModelHelper;
- private Context mContext;
- private SQLiteDatabase mDb;
-
- private HashSet<String> mValidPackages;
- private InvariantDeviceProfile mIdp;
-
- @Before
- public void setUp() {
- mModelHelper = new LauncherModelHelper();
- mContext = RuntimeEnvironment.application;
- mDb = mModelHelper.provider.getDb();
-
- mValidPackages = new HashSet<>();
- mValidPackages.add(TEST_PACKAGE);
- mIdp = InvariantDeviceProfile.INSTANCE.get(mContext);
- }
-
- @Test
- public void testHotseatMigration_apps_dropped() throws Exception {
- int[] hotseatItems = {
- mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0),
- mModelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0),
- -1,
- mModelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0),
- mModelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0),
- };
-
- mIdp.numDatabaseHotseatIcons = 3;
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3)
- .migrateHotseat();
- // First item is dropped as it has the least weight.
- verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
- }
-
- @Test
- public void testHotseatMigration_shortcuts_dropped() throws Exception {
- int[] hotseatItems = {
- mModelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0),
- mModelHelper.addItem(30, 1, HOTSEAT, 0, 0),
- -1,
- mModelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0),
- mModelHelper.addItem(10, 4, HOTSEAT, 0, 0),
- };
-
- mIdp.numDatabaseHotseatIcons = 3;
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, false, 5, 3)
- .migrateHotseat();
- // First item is dropped as it has the least weight.
- verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]);
- }
-
- private void verifyHotseat(int... sortedIds) {
- int screenId = 0;
- int total = 0;
-
- for (int id : sortedIds) {
- Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
- new String[]{LauncherSettings.Favorites._ID},
- "container=-101 and screen=" + screenId, null, null, null);
-
- if (id == -1) {
- assertEquals(0, c.getCount());
- } else {
- assertEquals(1, c.getCount());
- c.moveToNext();
- assertEquals(id, c.getLong(0));
- total ++;
- }
- c.close();
-
- screenId++;
- }
-
- // Verify that not other entry exist in the DB.
- Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
- new String[]{LauncherSettings.Favorites._ID},
- "container=-101", null, null, null);
- assertEquals(total, c.getCount());
- c.close();
- }
-
- @Test
- public void testWorkspace_empty_row_column_removed() throws Exception {
- int[][][] ids = mModelHelper.createGrid(new int[][][]{{
- { 0, 0, -1, 1},
- { 3, 1, -1, 4},
- { -1, -1, -1, -1},
- { 5, 2, -1, 6},
- }});
-
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
- new Point(4, 4), new Point(3, 3)).migrateWorkspace();
-
- // Column 2 and row 2 got removed.
- verifyWorkspace(new int[][][] {{
- {ids[0][0][0], ids[0][0][1], ids[0][0][3]},
- {ids[0][1][0], ids[0][1][1], ids[0][1][3]},
- {ids[0][3][0], ids[0][3][1], ids[0][3][3]},
- }});
- }
-
- @Test
- public void testWorkspace_new_screen_created() throws Exception {
- int[][][] ids = mModelHelper.createGrid(new int[][][]{{
- { 0, 0, 0, 1},
- { 3, 1, 0, 4},
- { -1, -1, -1, -1},
- { 5, 2, -1, 6},
- }});
-
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
- new Point(4, 4), new Point(3, 3)).migrateWorkspace();
-
- // Items in the second column get moved to new screen
- verifyWorkspace(new int[][][] {{
- {ids[0][0][0], ids[0][0][1], ids[0][0][3]},
- {ids[0][1][0], ids[0][1][1], ids[0][1][3]},
- {ids[0][3][0], ids[0][3][1], ids[0][3][3]},
- }, {
- {ids[0][0][2], ids[0][1][2], -1},
- }});
- }
-
- @Test
- public void testWorkspace_items_merged_in_next_screen() throws Exception {
- int[][][] ids = mModelHelper.createGrid(new int[][][]{{
- { 0, 0, 0, 1},
- { 3, 1, 0, 4},
- { -1, -1, -1, -1},
- { 5, 2, -1, 6},
- },{
- { 0, 0, -1, 1},
- { 3, 1, -1, 4},
- }});
-
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
- new Point(4, 4), new Point(3, 3)).migrateWorkspace();
-
- // Items in the second column of the first screen should get placed on the 3rd
- // row of the second screen
- verifyWorkspace(new int[][][] {{
- {ids[0][0][0], ids[0][0][1], ids[0][0][3]},
- {ids[0][1][0], ids[0][1][1], ids[0][1][3]},
- {ids[0][3][0], ids[0][3][1], ids[0][3][3]},
- }, {
- {ids[1][0][0], ids[1][0][1], ids[1][0][3]},
- {ids[1][1][0], ids[1][1][1], ids[1][1][3]},
- {ids[0][0][2], ids[0][1][2], -1},
- }});
- }
-
- @Test
- public void testWorkspace_items_not_merged_in_next_screen() throws Exception {
- // First screen has 2 mItems that need to be moved, but second screen has only one
- // empty space after migration (top-left corner)
- int[][][] ids = mModelHelper.createGrid(new int[][][]{{
- { 0, 0, 0, 1},
- { 3, 1, 0, 4},
- { -1, -1, -1, -1},
- { 5, 2, -1, 6},
- },{
- { -1, 0, -1, 1},
- { 3, 1, -1, 4},
- { -1, -1, -1, -1},
- { 5, 2, -1, 6},
- }});
-
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
- new Point(4, 4), new Point(3, 3)).migrateWorkspace();
-
- // Items in the second column of the first screen should get placed on a new screen.
- verifyWorkspace(new int[][][] {{
- {ids[0][0][0], ids[0][0][1], ids[0][0][3]},
- {ids[0][1][0], ids[0][1][1], ids[0][1][3]},
- {ids[0][3][0], ids[0][3][1], ids[0][3][3]},
- }, {
- { -1, ids[1][0][1], ids[1][0][3]},
- {ids[1][1][0], ids[1][1][1], ids[1][1][3]},
- {ids[1][3][0], ids[1][3][1], ids[1][3][3]},
- }, {
- {ids[0][0][2], ids[0][1][2], -1},
- }});
- }
-
- @Test
- public void testWorkspace_first_row_blocked() throws Exception {
- if (!FeatureFlags.QSB_ON_FIRST_SCREEN) {
- return;
- }
- // The first screen has one item on the 4th column which needs moving, as the first row
- // will be kept empty.
- int[][][] ids = mModelHelper.createGrid(new int[][][]{{
- { -1, -1, -1, -1},
- { 3, 1, 7, 0},
- { 8, 7, 7, -1},
- { 5, 2, 7, -1},
- }}, 0);
-
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
- new Point(4, 4), new Point(3, 4)).migrateWorkspace();
-
- // Items in the second column of the first screen should get placed on a new screen.
- verifyWorkspace(new int[][][] {{
- { -1, -1, -1},
- {ids[0][1][0], ids[0][1][1], ids[0][1][2]},
- {ids[0][2][0], ids[0][2][1], ids[0][2][2]},
- {ids[0][3][0], ids[0][3][1], ids[0][3][2]},
- }, {
- {ids[0][1][3]},
- }});
- }
-
- @Test
- public void testWorkspace_items_moved_to_empty_first_row() throws Exception {
- if (!FeatureFlags.QSB_ON_FIRST_SCREEN) {
- return;
- }
- // Items will get moved to the next screen to keep the first screen empty.
- int[][][] ids = mModelHelper.createGrid(new int[][][]{{
- { -1, -1, -1, -1},
- { 0, 1, 0, 0},
- { 8, 7, 7, -1},
- { 5, 6, 7, -1},
- }}, 0);
-
- new GridSizeMigrationTask(mContext, mDb, mValidPackages, false,
- new Point(4, 4), new Point(3, 3)).migrateWorkspace();
-
- // Items in the second column of the first screen should get placed on a new screen.
- verifyWorkspace(new int[][][] {{
- { -1, -1, -1},
- {ids[0][2][0], ids[0][2][1], ids[0][2][2]},
- {ids[0][3][0], ids[0][3][1], ids[0][3][2]},
- }, {
- {ids[0][1][1], ids[0][1][0], ids[0][1][2]},
- {ids[0][1][3]},
- }});
- }
-
- /**
- * Verifies that the workspace mItems are arranged in the provided order.
- * @param ids A 3d array where the first dimension represents the screen, and the rest two
- * represent the workspace grid.
- */
- private void verifyWorkspace(int[][][] ids) {
- IntArray allScreens = getWorkspaceScreenIds(mDb, LauncherSettings.Favorites.TABLE_NAME);
- assertEquals(ids.length, allScreens.size());
- int total = 0;
-
- for (int i = 0; i < ids.length; i++) {
- int screenId = allScreens.get(i);
- for (int y = 0; y < ids[i].length; y++) {
- for (int x = 0; x < ids[i][y].length; x++) {
- int id = ids[i][y][x];
-
- Cursor c = mContext.getContentResolver().query(
- LauncherSettings.Favorites.CONTENT_URI,
- new String[]{LauncherSettings.Favorites._ID},
- "container=-100 and screen=" + screenId +
- " and cellX=" + x + " and cellY=" + y, null, null, null);
- if (id == -1) {
- assertEquals(0, c.getCount());
- } else {
- assertEquals(1, c.getCount());
- c.moveToNext();
- assertEquals(String.format("Failed to verify item at %d %d, %d", i, y, x),
- id, c.getLong(0));
- total++;
- }
- c.close();
- }
- }
- }
-
- // Verify that not other entry exist in the DB.
- Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI,
- new String[]{LauncherSettings.Favorites._ID},
- "container=-100", null, null, null);
- assertEquals(total, c.getCount());
- c.close();
- }
-
- @Test
- public void testMultiStepMigration_small_to_large() throws Exception {
- MultiStepMigrationTaskVerifier verifier = new MultiStepMigrationTaskVerifier();
- verifier.migrate(new Point(3, 3), new Point(5, 5));
- verifier.assertCompleted();
- }
-
- @Test
- public void testMultiStepMigration_large_to_small() throws Exception {
- MultiStepMigrationTaskVerifier verifier = new MultiStepMigrationTaskVerifier(
- 5, 5, 4, 4,
- 4, 4, 3, 4
- );
- verifier.migrate(new Point(5, 5), new Point(3, 4));
- verifier.assertCompleted();
- }
-
- @Test
- public void testMultiStepMigration_zig_zag() throws Exception {
- MultiStepMigrationTaskVerifier verifier = new MultiStepMigrationTaskVerifier(
- 5, 7, 4, 7,
- 4, 7, 3, 7
- );
- verifier.migrate(new Point(5, 5), new Point(3, 7));
- verifier.assertCompleted();
- }
-
- private static class MultiStepMigrationTaskVerifier extends MultiStepMigrationTask {
-
- private final LinkedList<Point> mPoints;
-
- public MultiStepMigrationTaskVerifier(int... points) {
- super(null, null, null, false);
-
- mPoints = new LinkedList<>();
- for (int i = 0; i < points.length; i += 2) {
- mPoints.add(new Point(points[i], points[i + 1]));
- }
- }
-
- @Override
- protected boolean runStepTask(Point sourceSize, Point nextSize) throws Exception {
- assertEquals(sourceSize, mPoints.poll());
- assertEquals(nextSize, mPoints.poll());
- return false;
- }
-
- public void assertCompleted() {
- assertTrue(mPoints.isEmpty());
- }
- }
-}
diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
index d2051e0..87b0887 100644
--- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
+++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskV2Test.java
@@ -124,11 +124,9 @@
mIdp.numColumns = 4;
mIdp.numRows = 4;
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
- srcHotseatItems.length);
+ LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
- mIdp.numDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
task.migrate(mIdp);
@@ -204,11 +202,9 @@
mIdp.numColumns = 4;
mIdp.numRows = 4;
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
- numSrcDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
- mIdp.numDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
task.migrate(mIdp);
@@ -247,16 +243,13 @@
mModelHelper.addItem(APP_ICON, 5, HOTSEAT, 0, 0, testPackage5, 5, TMP_CONTENT_URI),
};
- int numSrcDatabaseHotseatIcons = srcHotseatItems.length;
mIdp.numDatabaseHotseatIcons = 4;
mIdp.numColumns = 4;
mIdp.numRows = 4;
GridSizeMigrationTaskV2.DbReader srcReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages,
- numSrcDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TMP_TABLE, mContext, mValidPackages);
GridSizeMigrationTaskV2.DbReader destReader = new GridSizeMigrationTaskV2.DbReader(mDb,
- LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages,
- mIdp.numDatabaseHotseatIcons);
+ LauncherSettings.Favorites.TABLE_NAME, mContext, mValidPackages);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(mContext, mDb, srcReader,
destReader, mIdp.numDatabaseHotseatIcons, new Point(mIdp.numColumns, mIdp.numRows));
task.migrate(mIdp);
diff --git a/robolectric_tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java b/robolectric_tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
index 07351fe..4319355 100644
--- a/robolectric_tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
@@ -31,6 +31,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.shadows.ShadowLooperExecutor;
import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper;
@@ -202,7 +203,7 @@
}
@Override
- public IntSet getPagesToBindSynchronously() {
+ public IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
return mPageToBindSync;
}
diff --git a/robolectric_tests/src/com/android/launcher3/util/LauncherPageRestoreHelperTest.java b/robolectric_tests/src/com/android/launcher3/util/LauncherPageRestoreHelperTest.java
deleted file mode 100644
index 51f5851..0000000
--- a/robolectric_tests/src/com/android/launcher3/util/LauncherPageRestoreHelperTest.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/**
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util;
-
-import android.os.Bundle;
-
-import com.android.launcher3.LauncherPageRestoreHelper;
-import com.android.launcher3.Workspace;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-@RunWith(RobolectricTestRunner.class)
-public class LauncherPageRestoreHelperTest {
-
- // Type: int
- private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
- // Type: int
- private static final String RUNTIME_STATE_CURRENT_SCREEN_COUNT =
- "launcher.current_screen_count";
-
- private LauncherPageRestoreHelper mPageRestoreHelper;
- private Bundle mState;
-
- @Mock
- private Workspace mWorkspace;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mPageRestoreHelper = new LauncherPageRestoreHelper(mWorkspace);
- mState = new Bundle();
- }
-
- @Test
- public void givenNoChildrenInWorkspace_whenSavePages_thenNothingSaved() {
- when(mWorkspace.getChildCount()).thenReturn(0);
-
- mPageRestoreHelper.savePagesToRestore(mState);
-
- assertFalse(mState.containsKey(RUNTIME_STATE_CURRENT_SCREEN_COUNT));
- assertFalse(mState.containsKey(RUNTIME_STATE_CURRENT_SCREEN));
- }
-
- @Test
- public void givenMultipleCurrentPages_whenSavePages_thenSavedCorrectly() {
- when(mWorkspace.getChildCount()).thenReturn(5);
- when(mWorkspace.getCurrentPage()).thenReturn(2);
- givenPanelCount(2);
-
- mPageRestoreHelper.savePagesToRestore(mState);
-
- assertEquals(5, mState.getInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT));
- assertEquals(2, mState.getInt(RUNTIME_STATE_CURRENT_SCREEN));
- }
-
- @Test
- public void givenNullSavedState_whenRestorePages_thenReturnEmptyIntSet() {
- IntSet result = mPageRestoreHelper.getPagesToRestore(null);
-
- assertTrue(result.isEmpty());
- }
-
- @Test
- public void givenTotalPageCountMissing_whenRestorePages_thenReturnEmptyIntSet() {
- givenSavedCurrentPage(1);
- givenPanelCount(1);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertTrue(result.isEmpty());
- }
-
- @Test
- public void givenCurrentPageMissing_whenRestorePages_thenReturnEmptyIntSet() {
- givenSavedPageCount(3);
- givenPanelCount(2);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertTrue(result.isEmpty());
- }
-
- @Test
- public void givenOnePanel_whenRestorePages_thenReturnThatPage() {
- givenSavedCurrentPage(2);
- givenSavedPageCount(5);
- givenPanelCount(1);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(1, result.size());
- assertEquals(2, result.getArray().get(0));
- }
-
- @Test
- public void givenTwoPanelOnFirstPages_whenRestorePages_thenReturnThosePages() {
- givenSavedCurrentPage(0, 1);
- givenSavedPageCount(2);
- givenPanelCount(2);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(IntSet.wrap(0, 1), result);
- }
-
- @Test
- public void givenTwoPanelOnMiddlePages_whenRestorePages_thenReturnThosePages() {
- givenSavedCurrentPage(2, 3);
- givenSavedPageCount(5);
- givenPanelCount(2);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(IntSet.wrap(2, 3), result);
- }
-
- @Test
- public void givenTwoPanelOnLastPage_whenRestorePages_thenReturnOnlyLastPage() {
- // The device has two panel home but the current page is the last page, so we don't have
- // a right panel, only the left one.
- givenSavedCurrentPage(2);
- givenSavedPageCount(3);
- givenPanelCount(2);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(IntSet.wrap(2), result);
- }
-
- @Test
- public void givenOnlyOnePageAndPhoneFolding_whenRestorePages_thenReturnOnlyOnePage() {
- givenSavedCurrentPage(0);
- givenSavedPageCount(1);
- givenPanelCount(1);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(IntSet.wrap(0), result);
- }
-
- @Test
- public void givenPhoneFolding_whenRestorePages_thenReturnOnlyTheFirstCurrentPage() {
- givenSavedCurrentPage(2, 3);
- givenSavedPageCount(4);
- givenPanelCount(1);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(IntSet.wrap(2), result);
- }
-
- @Test
- public void givenPhoneUnfolding_whenRestorePages_thenReturnCurrentPagePlusTheNextOne() {
- givenSavedCurrentPage(2);
- givenSavedPageCount(4);
- givenPanelCount(2);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(IntSet.wrap(2, 3), result);
- }
-
- @Test
- public void givenPhoneUnfoldingOnLastPage_whenRestorePages_thenReturnOnlyLastPage() {
- givenSavedCurrentPage(4);
- givenSavedPageCount(5);
- givenPanelCount(2);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(IntSet.wrap(4), result);
- }
-
- @Test
- public void givenOnlyOnePageAndPhoneUnfolding_whenRestorePages_thenReturnOnlyOnePage() {
- givenSavedCurrentPage(0);
- givenSavedPageCount(1);
- givenPanelCount(2);
-
- IntSet result = mPageRestoreHelper.getPagesToRestore(mState);
-
- assertEquals(IntSet.wrap(0), result);
- }
-
- private void givenPanelCount(int panelCount) {
- when(mWorkspace.getPanelCount()).thenReturn(panelCount);
- when(mWorkspace.getLeftmostVisiblePageForIndex(anyInt())).thenAnswer(invocation -> {
- int pageIndex = invocation.getArgument(0);
- return pageIndex * panelCount / panelCount;
- });
- }
-
- private void givenSavedPageCount(int pageCount) {
- mState.putInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT, pageCount);
- }
-
- private void givenSavedCurrentPage(int... pages) {
- mState.putInt(RUNTIME_STATE_CURRENT_SCREEN, pages[0]);
- }
-}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index f800cf6..02fe7d9 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -321,7 +321,8 @@
@UiThread
protected void applyIconAndLabel(ItemInfoWithIcon info) {
- boolean useTheme = mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER;
+ boolean useTheme = mDisplay == DISPLAY_WORKSPACE || mDisplay == DISPLAY_FOLDER
+ || mDisplay == DISPLAY_TASKBAR;
FastBitmapDrawable iconDrawable = info.newIcon(getContext(), useTheme);
mDotParams.color = IconPalette.getMutedColor(iconDrawable.getIconColor(), 0.54f);
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 1c3f329..7d0f858 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -66,6 +66,8 @@
private final int mDragDistanceThreshold;
/** The size of the drawable shown in the drop target. */
private final int mDrawableSize;
+ /** The padding, in pixels, between the text and drawable. */
+ private final int mDrawablePadding;
protected CharSequence mText;
protected Drawable mDrawable;
@@ -85,6 +87,8 @@
Resources resources = getResources();
mDragDistanceThreshold = resources.getDimensionPixelSize(R.dimen.drag_distanceThreshold);
mDrawableSize = resources.getDimensionPixelSize(R.dimen.drop_target_text_size);
+ mDrawablePadding = resources.getDimensionPixelSize(
+ R.dimen.drop_target_button_drawable_padding);
}
@Override
@@ -212,8 +216,7 @@
final DragLayer dragLayer = mLauncher.getDragLayer();
final DragView dragView = d.dragView;
final Rect to = getIconRect(d);
- final float scale = (float) to.width() / d.dragView.getMeasuredWidth();
- dragView.disableColorExtraction();
+ final float scale = (float) to.width() / dragView.getMeasuredWidth();
dragView.detachContentView(/* reattachToPreviousParent= */ true);
mDropTargetBar.deferOnDragEnd();
@@ -222,9 +225,6 @@
completeDrop(d);
mDropTargetBar.onDragEnd();
mLauncher.getStateManager().goToState(NORMAL);
- // Only re-enable updates once the workspace is back to normal, which will be after the
- // current frame.
- post(dragView::resumeColorExtraction);
};
dragLayer.animateView(d.dragView, to, scale, 0.1f, 0.1f,
@@ -301,6 +301,8 @@
mTextVisible = isVisible;
setText(newText);
setCompoundDrawablesRelative(mDrawable, null, null, null);
+ int drawablePadding = mTextVisible ? mDrawablePadding : 0;
+ setCompoundDrawablePadding(drawablePadding);
}
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index f4447b1..28e3b9d 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -18,7 +18,6 @@
import static android.animation.ValueAnimator.areAnimatorsEnabled;
-import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
import android.animation.Animator;
@@ -566,9 +565,10 @@
int spanX = mDragOutlines[i].cellHSpan;
int spanY = mDragOutlines[i].cellVSpan;
+ // TODO b/194414754 clean this up, reconcile with cellToRect
mVisualizeGridRect.set(paddingX, paddingY,
- mCellWidth * spanX - paddingX,
- mCellHeight * spanY - paddingY);
+ mCellWidth * spanX + mBorderSpacing * (spanX - 1) - paddingX,
+ mCellHeight * spanY + mBorderSpacing * (spanY - 1) - paddingY);
int transX = x * mCellWidth + (x * mBorderSpacing)
+ getPaddingLeft() + paddingX;
@@ -1070,18 +1070,12 @@
// Apply local extracted color if the DragView is an AppWidgetHostViewDrawable.
View view = dragObject.dragView.getContentView();
if (view instanceof LauncherAppWidgetHostView) {
- Launcher launcher = Launcher.getLauncher(dragObject.dragView.getContext());
+ Launcher launcher = Launcher.getLauncher(getContext());
Workspace workspace = launcher.getWorkspace();
int screenId = workspace.getIdForScreen(this);
- int pageId = workspace.getPageIndexForScreenId(screenId);
cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect);
- // Now get the rect in drag layer coordinates.
- getBoundsForViewInDragLayer(launcher.getDragLayer(), this, mTempRect, true,
- mTmpFloatArray, mTempRectF);
- Utilities.setRect(mTempRectF, mTempRect);
-
- ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, pageId);
+ ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, this, screenId);
}
}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index ba55834..477964a 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -25,6 +25,7 @@
import android.util.AttributeSet;
import android.view.View;
+import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.StatsLogManager;
@@ -128,11 +129,21 @@
public void completeDrop(DragObject d) {
ItemInfo item = d.dragInfo;
if (canRemove(item)) {
- int itemPage = mLauncher.getWorkspace().getCurrentPage();
+ ItemInfo pageItem = item;
+ if (item.container <= 0) {
+ View v = mLauncher.getWorkspace().getHomescreenIconByItemId(item.container);
+ if (v != null) {
+ pageItem = (ItemInfo) v.getTag();
+ }
+ }
+ IntSet pageIds = pageItem.container == Favorites.CONTAINER_DESKTOP
+ ? IntSet.wrap(pageItem.screenId)
+ : mLauncher.getWorkspace().getCurrentPageScreenIds();
+
onAccessibilityDrop(null, item);
ModelWriter modelWriter = mLauncher.getModelWriter();
Runnable onUndoClicked = () -> {
- mLauncher.setPagesToBindSynchronously(IntSet.wrap(itemPage));
+ mLauncher.setPagesToBindSynchronously(pageIds);
modelWriter.abortDelete();
mLauncher.getStatsLogManager().logger().log(LAUNCHER_UNDO);
};
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 624862d..7acec1f 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -22,6 +22,7 @@
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;
@@ -92,6 +93,9 @@
private static final float MAX_HORIZONTAL_PADDING_PERCENT = 0.14f;
private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 2.0f;
+ private static final float TALLER_DEVICE_ASPECT_RATIO_THRESHOLD = 2.15f;
+ private static final float TALL_DEVICE_EXTRA_SPACE_THRESHOLD_DP = 252;
+ private static final float TALL_DEVICE_MORE_EXTRA_SPACE_THRESHOLD_DP = 268;
// To evenly space the icons, increase the left/right margins for tablets in portrait mode.
private static final int PORTRAIT_TABLET_LEFT_RIGHT_PADDING_MULTIPLIER = 4;
@@ -151,12 +155,13 @@
public int folderChildDrawablePaddingPx;
// Hotseat
+ public int hotseatBarSizeExtraSpacePx;
public final int numShownHotseatIcons;
public int hotseatCellHeightPx;
private final int hotseatExtraVerticalSize;
// In portrait: size = height, in landscape: size = width
public int hotseatBarSizePx;
- public final int hotseatBarTopPaddingPx;
+ public int hotseatBarTopPaddingPx;
public final int hotseatBarBottomPaddingPx;
// Start is the side next to the nav bar, end is the side next to the workspace
public final int hotseatBarSidePaddingStartPx;
@@ -176,11 +181,17 @@
public float allAppsIconTextSizePx;
// Overview
+ public final boolean overviewShowAsGrid;
public int overviewTaskMarginPx;
public int overviewTaskIconSizePx;
+ public int overviewTaskIconDrawableSizePx;
+ public int overviewTaskIconDrawableSizeGridPx;
public int overviewTaskThumbnailTopMarginPx;
public final int overviewActionsMarginThreeButtonPx;
- public final int overviewActionsMarginGesturePx;
+ public final int overviewActionsTopMarginGesturePx;
+ public final int overviewActionsBottomMarginGesturePx;
+ public int overviewPageSpacing;
+ public int overviewRowSpacing;
// Widgets
public final PointF appWidgetScale = new PointF(1.0f, 1.0f);
@@ -250,7 +261,8 @@
final Resources res = context.getResources();
hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height);
- isTaskbarPresent = isTablet && FeatureFlags.ENABLE_TASKBAR.get();
+ isTaskbarPresent = isTablet && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS
+ && FeatureFlags.ENABLE_TASKBAR.get();
if (isTaskbarPresent) {
// Taskbar will be added later, but provides bottom insets that we should subtract
// from availableHeightPx.
@@ -295,8 +307,10 @@
: res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
if (isTwoPanels) {
- cellLayoutPaddingLeftRightPx =
- res.getDimensionPixelSize(R.dimen.two_panel_home_side_padding);
+ cellLayoutPaddingLeftRightPx = res.getDimensionPixelSize(
+ isLandscape
+ ? R.dimen.two_panels_home_side_padding_landscape
+ : R.dimen.two_panels_home_side_padding_portrait);
cellLayoutBottomPaddingPx = 0;
} else if (isLandscape) {
cellLayoutPaddingLeftRightPx = 0;
@@ -327,6 +341,7 @@
isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons;
numShownAllAppsColumns =
isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns;
+ hotseatBarSizeExtraSpacePx = 0;
hotseatBarTopPaddingPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
hotseatBarBottomPaddingPx = (isTallDevice ? 0
@@ -344,19 +359,45 @@
? res.getDimensionPixelSize(R.dimen.scalable_grid_qsb_bottom_margin)
: 0;
- overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin);
- overviewTaskIconSizePx =
- isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get() ? res.getDimensionPixelSize(
- R.dimen.task_thumbnail_icon_size_grid) : res.getDimensionPixelSize(
- R.dimen.task_thumbnail_icon_size);
+ overviewShowAsGrid = isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get();
+ overviewTaskMarginPx = overviewShowAsGrid
+ ? res.getDimensionPixelSize(R.dimen.overview_task_margin_grid)
+ : res.getDimensionPixelSize(R.dimen.overview_task_margin);
+ overviewTaskIconSizePx = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
+ overviewTaskIconDrawableSizePx =
+ res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size);
+ overviewTaskIconDrawableSizeGridPx =
+ res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size_grid);
overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx * 2;
- overviewActionsMarginGesturePx = res.getDimensionPixelSize(
- R.dimen.overview_actions_bottom_margin_gesture);
+ if (overviewShowAsGrid) {
+ if (isLandscape) {
+ overviewActionsTopMarginGesturePx = res.getDimensionPixelSize(
+ R.dimen.overview_actions_top_margin_gesture_grid_landscape);
+ overviewActionsBottomMarginGesturePx = res.getDimensionPixelSize(
+ R.dimen.overview_actions_bottom_margin_gesture_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);
+ }
+ } else {
+ overviewActionsTopMarginGesturePx = res.getDimensionPixelSize(
+ R.dimen.overview_actions_margin_gesture);
+ overviewActionsBottomMarginGesturePx = overviewActionsTopMarginGesturePx;
+ }
overviewActionsMarginThreeButtonPx = res.getDimensionPixelSize(
- R.dimen.overview_actions_bottom_margin_three_button);
+ 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);
// Calculate all of the remaining variables.
extraSpace = updateAvailableDimensions(res);
+
// Now that we have all of the variables calculated, we can tune certain sizes.
if (isScalableGrid && inv.devicePaddings != null) {
// Paddings were created assuming no scaling, so we first unscale the extra space.
@@ -376,12 +417,32 @@
qsbBottomMarginPx = Math.round(qsbBottomMarginOriginalPx * cellScaleToFit);
} else if (!isVerticalBarLayout() && isPhone && isTallDevice) {
// We increase the hotseat size when there is extra space.
- // ie. For a display with a large aspect ratio, we can keep the icons on the workspace
- // in portrait mode closer together by adding more height to the hotseat.
- // Note: This calculation was created after noticing a pattern in the design spec.
- int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2
- - workspacePageIndicatorHeight;
- hotseatBarSizePx += extraSpace;
+
+ if (Float.compare(aspectRatio, TALLER_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0
+ && extraSpace >= Utilities.dpToPx(TALL_DEVICE_EXTRA_SPACE_THRESHOLD_DP)) {
+ // For taller devices, we will take a piece of the extra space from each row,
+ // and add it to the space above and below the hotseat.
+
+ // For devices with more extra space, we take a larger piece from each cell.
+ int piece = extraSpace < Utilities.dpToPx(TALL_DEVICE_MORE_EXTRA_SPACE_THRESHOLD_DP)
+ ? 7 : 5;
+
+ int extraSpace = ((getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2)
+ * inv.numRows) / piece;
+
+ workspaceTopPadding = extraSpace / 8;
+ int halfLeftOver = (extraSpace - workspaceTopPadding) / 2;
+ hotseatBarTopPaddingPx += halfLeftOver;
+ hotseatBarSizeExtraSpacePx = halfLeftOver;
+ } else {
+ // ie. For a display with a large aspect ratio, we can keep the icons on the
+ // workspace in portrait mode closer together by adding more height to the hotseat.
+ // Note: This calculation was created after noticing a pattern in the design spec.
+ hotseatBarSizeExtraSpacePx = getCellSize().y - iconSizePx
+ - iconDrawablePaddingPx * 2 - workspacePageIndicatorHeight;
+ }
+
+ updateHotseatIconSize(iconSizePx);
// Recalculate the available dimensions using the new hotseat size.
updateAvailableDimensions(res);
@@ -399,13 +460,15 @@
}
private void updateHotseatIconSize(int hotseatIconSizePx) {
- hotseatCellHeightPx = hotseatIconSizePx;
+ // Ensure there is enough space for folder icons, which have a slightly larger radius.
+ hotseatCellHeightPx = (int) Math.ceil(hotseatIconSizePx * ICON_OVERLAP_FACTOR);
if (isVerticalBarLayout()) {
hotseatBarSizePx = hotseatIconSizePx + hotseatBarSidePaddingStartPx
+ hotseatBarSidePaddingEndPx;
} else {
hotseatBarSizePx = hotseatIconSizePx + hotseatBarTopPaddingPx
- + hotseatBarBottomPaddingPx + (isScalableGrid ? 0 : hotseatExtraVerticalSize);
+ + hotseatBarBottomPaddingPx + (isScalableGrid ? 0 : hotseatExtraVerticalSize)
+ + hotseatBarSizeExtraSpacePx;
}
}
@@ -413,6 +476,10 @@
cellLayoutBorderSpacingPx = isScalableGrid ? borderSpacing : 0;
}
+ public Info getDisplayInfo() {
+ return mInfo;
+ }
+
/**
* We inset the widget padding added by the system and instead rely on the border spacing
* between cells to create reliable consistency between widgets
@@ -478,7 +545,7 @@
if (workspaceCellPaddingY < iconTextHeight) {
iconTextSizePx = 0;
iconDrawablePaddingPx = 0;
- cellHeightPx = iconSizePx;
+ cellHeightPx = (int) Math.ceil(iconSizePx * ICON_OVERLAP_FACTOR);
autoResizeAllAppsCells();
}
}
@@ -565,7 +632,8 @@
desiredWorkspaceLeftRightMarginPx = (int) (desiredWorkspaceLeftRightOriginalPx * scale);
} else {
cellWidthPx = iconSizePx + iconDrawablePaddingPx;
- cellHeightPx = iconSizePx + iconDrawablePaddingPx
+ cellHeightPx = (int) Math.ceil(iconSizePx * ICON_OVERLAP_FACTOR)
+ + iconDrawablePaddingPx
+ Utilities.calculateTextHeight(iconTextSizePx);
int cellPaddingY = (getCellSize().y - cellHeightPx) / 2;
if (iconDrawablePaddingPx > cellPaddingY && !isVerticalLayout
@@ -654,8 +722,11 @@
int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
if (isScalableGrid) {
- folderCellWidthPx = (int) (cellWidthPx * scale);
- folderCellHeightPx = (int) (cellHeightPx * scale);
+ int minWidth = folderChildIconSizePx + iconDrawablePaddingPx * 2;
+ int minHeight = folderChildIconSizePx + iconDrawablePaddingPx * 2 + textHeight;
+
+ folderCellWidthPx = (int) Math.max(minWidth, cellWidthPx * scale);
+ folderCellHeightPx = (int) Math.max(minHeight, cellHeightPx * scale);
int borderSpacing = (int) (cellLayoutBorderSpacingOriginalPx * scale);
folderCellLayoutBorderSpacingPx = borderSpacing;
@@ -699,8 +770,14 @@
// Since we are only concerned with the overall padding, layout direction does
// not matter.
Point padding = getTotalWorkspacePadding();
- result.x = calculateCellWidth(availableWidthPx - padding.x
- - cellLayoutPaddingLeftRightPx * 2, cellLayoutBorderSpacingPx, inv.numColumns);
+ // availableWidthPx is the screen width of the device. In 2 panels mode, each panel should
+ // only have half of the screen width. In addition, there is only cellLayoutPadding in the
+ // left side of the left panel and the right side of the right panel. There is no
+ // cellLayoutPadding in the middle.
+ int screenWidthPx = isTwoPanels
+ ? availableWidthPx / 2 - padding.x - cellLayoutPaddingLeftRightPx
+ : availableWidthPx - padding.x - cellLayoutPaddingLeftRightPx * 2;
+ result.x = calculateCellWidth(screenWidthPx, cellLayoutBorderSpacingPx, inv.numColumns);
result.y = calculateCellHeight(availableHeightPx - padding.y
- cellLayoutBottomPaddingPx, cellLayoutBorderSpacingPx, inv.numRows);
return result;
@@ -777,7 +854,7 @@
int taskbarOffset = getTaskbarOffsetY();
int hotseatTopDiff = hotseatHeight - taskbarSize - taskbarOffset;
- int startOffset = ApiWrapper.getHotseatStartOffset(context);
+ int endOffset = ApiWrapper.getHotseatEndOffset(context);
int requiredWidth = iconSizePx * numShownHotseatIcons;
Resources res = context.getResources();
@@ -785,16 +862,16 @@
float taskbarIconSpacing = 2 * res.getDimension(R.dimen.taskbar_icon_spacing);
int maxSize = (int) (requiredWidth
* (taskbarIconSize + taskbarIconSpacing) / taskbarIconSize);
- int hotseatSize = Math.min(maxSize, availableWidthPx - startOffset);
+ int hotseatSize = Math.min(maxSize, availableWidthPx - endOffset);
int sideSpacing = (availableWidthPx - hotseatSize) / 2;
mHotseatPadding.set(sideSpacing, hotseatTopDiff, sideSpacing, taskbarOffset);
- if (startOffset > sideSpacing) {
+ if (endOffset > sideSpacing) {
int diff = Utilities.isRtl(context.getResources())
- ? sideSpacing - startOffset
- : startOffset - sideSpacing;
- mHotseatPadding.left += diff;
- mHotseatPadding.right -= diff;
+ ? sideSpacing - endOffset
+ : endOffset - sideSpacing;
+ mHotseatPadding.left -= diff;
+ mHotseatPadding.right += diff;
}
} else {
// We want the edges of the hotseat to line up with the edges of the workspace, but the
@@ -824,11 +901,11 @@
? workspacePadding.bottom
: hotseatBarSizePx - hotseatCellHeightPx - hotseatQsbHeight;
- if (isScalableGrid && qsbBottomMarginPx <= freeSpace) {
- return qsbBottomMarginPx;
+ if (isScalableGrid && qsbBottomMarginPx > mInsets.bottom) {
+ return Math.min(qsbBottomMarginPx, freeSpace);
} else {
return (int) (freeSpace * QSB_CENTER_FACTOR)
- + (isTaskbarPresent ? taskbarSize : getInsets().bottom);
+ + (isTaskbarPresent ? taskbarSize : mInsets.bottom);
}
}
@@ -899,14 +976,16 @@
return isVerticalBarLayout();
}
- public int getCellHeight(@ContainerType int containerType) {
+ public int getCellContentHeight(@ContainerType int containerType) {
switch (containerType) {
case CellLayout.WORKSPACE:
return cellHeightPx;
case CellLayout.FOLDER:
return folderCellHeightPx;
case CellLayout.HOTSEAT:
- return hotseatCellHeightPx;
+ // The hotseat is the only container where the cell height is going to be
+ // different from the content within that cell.
+ return iconSizePx;
default:
// ??
return 0;
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index a2bd201..10b3f98 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import static com.android.launcher3.Utilities.dpiFromPx;
-import static com.android.launcher3.Utilities.getPointString;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
@@ -44,6 +43,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.IntArray;
@@ -66,9 +66,6 @@
public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
new MainThreadInitializedObject<>(InvariantDeviceProfile::new);
- public static final String KEY_MIGRATION_SRC_WORKSPACE_SIZE = "migration_src_workspace_size";
- public static final String KEY_MIGRATION_SRC_HOTSEAT_COUNT = "migration_src_hotseat_count";
-
private static final int DEFAULT_TRUE = -1;
private static final int DEFAULT_SPLIT_DISPLAY = 2;
@@ -188,10 +185,7 @@
if (!newGridName.equals(gridName)) {
Utilities.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName).apply();
}
- Utilities.getPrefs(context).edit()
- .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, numDatabaseHotseatIcons)
- .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, getPointString(numColumns, numRows))
- .apply();
+ new DeviceGridState(this).writeToPrefs(context);
DisplayController.INSTANCE.get(context).addChangeListener(
(displayContext, info, flags) -> {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 78a8a97..8249887 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -36,6 +36,7 @@
import static com.android.launcher3.LauncherState.NO_SCALE;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.Utilities.postAsyncCallback;
+import static com.android.launcher3.WorkspaceLayoutManager.LEFT_PANEL_ID;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -79,6 +80,7 @@
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -221,7 +223,8 @@
* Default launcher application.
*/
public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
- Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {
+ Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin>,
+ LauncherOverlayCallbacks {
public static final String TAG = "Launcher";
public static final ActivityTracker<Launcher> ACTIVITY_TRACKER = new ActivityTracker<>();
@@ -259,6 +262,8 @@
private static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result";
// Type: SparseArray<Parcelable>
private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
+ // Type int[]
+ private static final String RUNTIME_STATE_CURRENT_SCREEN_IDS = "launcher.current_screen_ids";
public static final String ON_CREATE_EVT = "Launcher.onCreate";
public static final String ON_START_EVT = "Launcher.onStart";
@@ -287,8 +292,6 @@
private WidgetManagerHelper mAppWidgetManager;
private LauncherAppWidgetHost mAppWidgetHost;
- private LauncherPageRestoreHelper mPageRestoreHelper;
-
private final int[] mTmpAddItemCellCoordinates = new int[2];
@Thunk
@@ -325,7 +328,7 @@
private PopupDataProvider mPopupDataProvider;
private IntSet mSynchronouslyBoundPages = new IntSet();
- private IntSet mPagesToBindSynchronously = new IntSet();
+ @NonNull private IntSet mPagesToBindSynchronously = new IntSet();
// We only want to get the SharedPreferences once since it does an FS stat each time we get
// it from the context.
@@ -460,9 +463,11 @@
restoreState(savedInstanceState);
mStateManager.reapplyState();
- mPageRestoreHelper = new LauncherPageRestoreHelper(mWorkspace);
if (savedInstanceState != null) {
- mPagesToBindSynchronously = mPageRestoreHelper.getPagesToRestore(savedInstanceState);
+ int[] pageIds = savedInstanceState.getIntArray(RUNTIME_STATE_CURRENT_SCREEN_IDS);
+ if (pageIds != null) {
+ mPagesToBindSynchronously = IntSet.wrap(pageIds);
+ }
}
if (!mModel.addCallbacksAndLoad(this)) {
@@ -619,7 +624,7 @@
@Override
public void setLauncherOverlay(LauncherOverlay overlay) {
if (overlay != null) {
- overlay.setOverlayCallbacks(new LauncherOverlayCallbacksImpl());
+ overlay.setOverlayCallbacks(this);
}
mWorkspace.setLauncherOverlay(overlay);
}
@@ -1123,12 +1128,15 @@
mAppWidgetHost.setActivityResumed(false);
}
- class LauncherOverlayCallbacksImpl implements LauncherOverlayCallbacks {
-
- public void onScrollChanged(float progress) {
- if (mWorkspace != null) {
- mWorkspace.onOverlayScrollChanged(progress);
- }
+ /**
+ * {@code LauncherOverlayCallbacks} scroll amount.
+ * Indicates transition progress to -1 screen.
+ * @param progress From 0 to 1.
+ */
+ @Override
+ public void onScrollChanged(float progress) {
+ if (mWorkspace != null) {
+ mWorkspace.onOverlayScrollChanged(progress);
}
}
@@ -1188,7 +1196,6 @@
// Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
// default state, otherwise we will update to the wrong offsets in RTL
mWorkspace.lockWallpaperToDefaultPage();
- mWorkspace.bindAndInitLeftPanel();
mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */);
mDragController.addDragListener(mWorkspace);
@@ -1586,14 +1593,19 @@
public void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
if (mSynchronouslyBoundPages != null) {
- mSynchronouslyBoundPages.forEach(page -> mWorkspace.restoreInstanceStateForChild(page));
+ mSynchronouslyBoundPages.forEach(screenId -> {
+ int pageIndex = mWorkspace.getPageIndexForScreenId(screenId);
+ if (pageIndex != PagedView.INVALID_PAGE) {
+ mWorkspace.restoreInstanceStateForChild(pageIndex);
+ }
+ });
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
- mPageRestoreHelper.savePagesToRestore(outState);
-
+ outState.putIntArray(RUNTIME_STATE_CURRENT_SCREEN_IDS,
+ mWorkspace.getCurrentPageScreenIds().getArray().toArray());
outState.putInt(RUNTIME_STATE, mStateManager.getState().ordinal);
AbstractFloatingView widgets = AbstractFloatingView
@@ -2081,18 +2093,42 @@
mPagesToBindSynchronously = pages;
}
- /**
- * Implementation of the method from LauncherModel.Callbacks.
- */
@Override
- public IntSet getPagesToBindSynchronously() {
- if (mPagesToBindSynchronously != null && !mPagesToBindSynchronously.isEmpty()) {
- return mPagesToBindSynchronously;
- } else if (mWorkspace != null) {
- return mWorkspace.getVisiblePageIndices();
+ public IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
+ IntSet visibleIds = mPagesToBindSynchronously.isEmpty()
+ ? mWorkspace.getCurrentPageScreenIds() : mPagesToBindSynchronously;
+ IntArray actualIds = new IntArray();
+
+ if (mDeviceProfile.isTwoPanels) {
+ actualIds.add(LEFT_PANEL_ID);
} else {
- return new IntSet();
+ visibleIds.remove(LEFT_PANEL_ID);
}
+ IntSet result = new IntSet();
+ if (visibleIds.isEmpty()) {
+ return result;
+ }
+ for (int id : orderedScreenIds.toArray()) {
+ if (id != LEFT_PANEL_ID) {
+ actualIds.add(id);
+ }
+ }
+ int firstId = visibleIds.getArray().get(0);
+ if (actualIds.contains(firstId)) {
+ result.add(firstId);
+
+ if (mDeviceProfile.isTwoPanels) {
+ int index = actualIds.indexOf(firstId);
+ int nextIndex = ((int) (index / 2)) * 2;
+ if (nextIndex == index) {
+ nextIndex++;
+ }
+ if (nextIndex < actualIds.size()) {
+ result.add(actualIds.get(nextIndex));
+ }
+ }
+ }
+ return result;
}
/**
@@ -2143,7 +2179,7 @@
// Make sure the first screen is at the start if there's no widget panel,
// or on the second place if the first is the widget panel
boolean isLeftPanelShown =
- mWorkspace.mWorkspaceScreens.containsKey(Workspace.LEFT_PANEL_ID);
+ mWorkspace.mWorkspaceScreens.containsKey(LEFT_PANEL_ID);
int firstScreenPosition = isLeftPanelShown && orderedScreenIds.size() > 1 ? 1 : 0;
if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
@@ -2171,7 +2207,7 @@
continue;
}
- if (screenId == Workspace.LEFT_PANEL_ID) {
+ if (screenId == LEFT_PANEL_ID) {
// No need to bind the left panel, as its always bound.
continue;
}
@@ -2252,7 +2288,7 @@
}
// Skip if the item is on the left widget panel but the panel is not shown
- if (item.screenId == Workspace.LEFT_PANEL_ID && !getDeviceProfile().isTwoPanels) {
+ if (item.screenId == LEFT_PANEL_ID && !getDeviceProfile().isTwoPanels) {
continue;
}
@@ -2555,9 +2591,6 @@
@Override
public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks) {
mSynchronouslyBoundPages = boundPages;
- if (!boundPages.isEmpty()) {
- mWorkspace.setCurrentPage(boundPages.getArray().get(0));
- }
mPagesToBindSynchronously = new IntSet();
clearPendingBinds();
@@ -2598,7 +2631,8 @@
}
int currentPage = pagesBoundFirst != null && !pagesBoundFirst.isEmpty()
- ? pagesBoundFirst.getArray().get(0) : PagedView.INVALID_PAGE;
+ ? mWorkspace.getPageIndexForScreenId(pagesBoundFirst.getArray().get(0))
+ : PagedView.INVALID_PAGE;
// When undoing the removal of the last item on a page, return to that page.
// Since we are just resetting the current page without user interaction,
// override the previous page so we don't log the page switch.
@@ -2837,13 +2871,26 @@
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
Log.d(TestProtocol.PERMANENT_DIAG_TAG, "Opening options popup on key up");
}
- OptionsPopupView.showDefaultOptions(this, -1, -1);
+ showDefaultOptions(-1, -1);
}
return true;
}
return super.onKeyUp(keyCode, event);
}
+ /**
+ * Shows the default options popup
+ */
+ public void showDefaultOptions(float x, float y) {
+ float halfSize = getResources().getDimension(R.dimen.options_menu_thumb_size) / 2;
+ if (x < 0 || y < 0) {
+ x = mDragLayer.getWidth() / 2;
+ y = mDragLayer.getHeight() / 2;
+ }
+ RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
+ OptionsPopupView.show(this, target, OptionsPopupView.getOptions(this), false);
+ }
+
@Override
protected void collectStateHandlers(List<StateHandler> out) {
out.add(getAllAppsController());
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java
index 140794b..dc533f0 100644
--- a/src/com/android/launcher3/LauncherBackupAgent.java
+++ b/src/com/android/launcher3/LauncherBackupAgent.java
@@ -31,6 +31,6 @@
@Override
public void onRestoreFinished() {
- RestoreDbTask.setPending(this, true);
+ RestoreDbTask.setPending(this);
}
}
diff --git a/src/com/android/launcher3/LauncherPageRestoreHelper.java b/src/com/android/launcher3/LauncherPageRestoreHelper.java
deleted file mode 100644
index e679a12..0000000
--- a/src/com/android/launcher3/LauncherPageRestoreHelper.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3;
-
-import android.os.Bundle;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.launcher3.util.IntSet;
-
-import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
-
-/**
- * There's a logic which prioritizes the binding for the current page and defers the other pages'
- * binding. If two panel home is enabled, we want to bind both pages together.
- * LauncherPageRestoreHelper's purpose is to contain the logic for persisting, restoring and
- * calculating which pages to load immediately.
- */
-public class LauncherPageRestoreHelper {
-
- public static final String TAG = "LauncherPageRestoreHelper";
-
- // Type: int
- private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
- // Type: int
- private static final String RUNTIME_STATE_CURRENT_SCREEN_COUNT =
- "launcher.current_screen_count";
-
- private Workspace mWorkspace;
-
- public LauncherPageRestoreHelper(Workspace workspace) {
- this.mWorkspace = workspace;
- }
-
- /**
- * Some configuration changes trigger Launcher to recreate itself, and we want to give more
- * priority to the currently active pages in the restoration process.
- */
- @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
- public IntSet getPagesToRestore(Bundle savedInstanceState) {
- IntSet pagesToRestore = new IntSet();
-
- if (savedInstanceState == null) {
- return pagesToRestore;
- }
-
- int currentPage = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN, -1);
- int totalPageCount = savedInstanceState.getInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT, -1);
- int panelCount = mWorkspace.getPanelCount();
-
- if (totalPageCount <= 0 || currentPage < 0) {
- Log.e(TAG, "getPagesToRestore: Invalid input: " + totalPageCount + ", " + currentPage);
- return pagesToRestore;
- }
-
- int newCurrentPage = mWorkspace.getLeftmostVisiblePageForIndex(currentPage);
- for (int page = newCurrentPage; page < newCurrentPage + panelCount
- && page < totalPageCount; page++) {
- pagesToRestore.add(page);
- }
-
- return pagesToRestore;
- }
-
- /**
- * This should be called from Launcher's onSaveInstanceState method to persist everything that
- * is necessary to calculate later which pages need to be initialized first after a
- * configuration change.
- */
- @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
- public void savePagesToRestore(Bundle outState) {
- int pageCount = mWorkspace.getChildCount();
- if (pageCount > 0) {
- outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getCurrentPage());
- outState.putInt(RUNTIME_STATE_CURRENT_SCREEN_COUNT, pageCount);
- }
- }
-}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 440e9e3..49f20c6 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -16,7 +16,6 @@
package com.android.launcher3;
-import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
@@ -61,7 +60,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.DbDowngradeHelper;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
@@ -153,15 +151,7 @@
mOpenHelper = DatabaseHelper.createDatabaseHelper(
getContext(), false /* forMigration */);
- if (RestoreDbTask.isPending(getContext())) {
- if (!RestoreDbTask.performRestore(getContext(), mOpenHelper,
- new BackupManager(getContext()))) {
- mOpenHelper.createEmptyDB(mOpenHelper.getWritableDatabase());
- }
- // Set is pending to false irrespective of the result, so that it doesn't get
- // executed again.
- RestoreDbTask.setPending(getContext(), false);
- }
+ RestoreDbTask.restoreIfNeeded(getContext(), mOpenHelper);
}
}
@@ -434,32 +424,26 @@
return null;
}
case LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER: {
- if (MULTI_DB_GRID_MIRATION_ALGO.get()) {
- Bundle result = new Bundle();
- result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
- prepForMigration(
- InvariantDeviceProfile.INSTANCE.get(getContext()).dbFile,
- Favorites.TMP_TABLE,
- () -> mOpenHelper,
- () -> DatabaseHelper.createDatabaseHelper(
- getContext(), true /* forMigration */)));
- return result;
- }
- return null;
+ Bundle result = new Bundle();
+ result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
+ prepForMigration(
+ InvariantDeviceProfile.INSTANCE.get(getContext()).dbFile,
+ Favorites.TMP_TABLE,
+ () -> mOpenHelper,
+ () -> DatabaseHelper.createDatabaseHelper(
+ getContext(), true /* forMigration */)));
+ return result;
}
case LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW: {
- if (MULTI_DB_GRID_MIRATION_ALGO.get()) {
- Bundle result = new Bundle();
- result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
- prepForMigration(
- arg /* dbFile */,
- Favorites.PREVIEW_TABLE_NAME,
- () -> DatabaseHelper.createDatabaseHelper(
- getContext(), arg, true /* forMigration */),
- () -> mOpenHelper));
- return result;
- }
- return null;
+ Bundle result = new Bundle();
+ result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
+ prepForMigration(
+ arg /* dbFile */,
+ Favorites.PREVIEW_TABLE_NAME,
+ () -> DatabaseHelper.createDatabaseHelper(
+ getContext(), arg, true /* forMigration */),
+ () -> mOpenHelper));
+ return result;
}
case LauncherSettings.Settings.METHOD_SWITCH_DATABASE: {
if (TextUtils.equals(arg, mOpenHelper.getDatabaseName())) return null;
@@ -655,8 +639,7 @@
static DatabaseHelper createDatabaseHelper(Context context, String dbName,
boolean forMigration) {
if (dbName == null) {
- dbName = MULTI_DB_GRID_MIRATION_ALGO.get() ? InvariantDeviceProfile.INSTANCE.get(
- context).dbFile : LauncherFiles.LAUNCHER_DB;
+ dbName = InvariantDeviceProfile.INSTANCE.get(context).dbFile;
}
DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName, forMigration);
// Table creation sometimes fails silently, which leads to a crash loop.
@@ -667,10 +650,6 @@
// This operation is a no-op if the table already exists.
databaseHelper.addFavoritesTable(databaseHelper.getWritableDatabase(), true);
}
- if (!MULTI_DB_GRID_MIRATION_ALGO.get()) {
- databaseHelper.mBackupTableExists = tableExists(
- databaseHelper.getReadableDatabase(), Favorites.BACKUP_TABLE_NAME);
- }
databaseHelper.mHotseatRestoreTableExists = tableExists(
databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE);
@@ -852,11 +831,7 @@
case 25:
convertShortcutsToLauncherActivities(db);
case 26:
- // QSB was moved to the grid. Clear the first row on screen 0.
- if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
- !LauncherDbUtils.prepareScreenZeroToHostQsb(mContext, db)) {
- break;
- }
+ // QSB was moved to the grid. Ignore overlapping items
case 27: {
// Update the favorites table so that the screen ids are ordered based on
// workspace page rank.
@@ -1090,7 +1065,7 @@
}
private int initializeMaxScreenId(SQLiteDatabase db) {
- return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d",
+ return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
Favorites.CONTAINER_DESKTOP);
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 20f5f9b..eb3f94c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -238,10 +238,6 @@
return getChildAt(index);
}
- protected int indexToPage(int index) {
- return index;
- }
-
/**
* Updates the scroll of the current page immediately to its final scroll position. We use this
* in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
@@ -322,18 +318,51 @@
*/
@VisibleForTesting(otherwise = PACKAGE_PRIVATE)
public IntSet getVisiblePageIndices() {
- IntSet visiblePageIndices = new IntSet();
+ return getPageIndices(mCurrentPage);
+ }
+
+ /**
+ * In case the panelCount is 1 this just returns the same page index in an IntSet.
+ * But in cases where the panelCount > 1 this will return all the page indices that belong
+ * together, i.e. on the Workspace they are next to each other and shown at the same time.
+ */
+ private IntSet getPageIndices(int pageIndex) {
+ // we want to make sure the pageIndex is the leftmost page
+ pageIndex = getLeftmostVisiblePageForIndex(pageIndex);
+
+ IntSet pageIndices = new IntSet();
int panelCount = getPanelCount();
int pageCount = getPageCount();
-
- // If a device goes from one panel to two panel (i.e. unfolding a foldable device) while
- // an odd indexed page is the current page, then the new leftmost visible page will be
- // different from the old mCurrentPage.
- int currentPage = getLeftmostVisiblePageForIndex(mCurrentPage);
- for (int page = currentPage; page < currentPage + panelCount && page < pageCount; page++) {
- visiblePageIndices.add(page);
+ for (int page = pageIndex; page < pageIndex + panelCount && page < pageCount; page++) {
+ pageIndices.add(page);
}
- return visiblePageIndices;
+ return pageIndices;
+ }
+
+ /**
+ * Returns an IntSet with the indices of the neighbour pages that are in the focus direction.
+ */
+ private IntSet getNeighbourPageIndices(int focus) {
+ int panelCount = getPanelCount();
+ // getNextPage is more reliable than getCurrentPage
+ int currentPage = getNextPage();
+
+ int nextPage;
+ if (focus == View.FOCUS_LEFT) {
+ nextPage = currentPage - panelCount;
+ } else if (focus == View.FOCUS_RIGHT) {
+ nextPage = currentPage + panelCount;
+ } else {
+ // no neighbours to other directions
+ return new IntSet();
+ }
+ nextPage = validateNewPage(nextPage);
+ if (nextPage == currentPage) {
+ // We reached the end of the pages
+ return new IntSet();
+ }
+
+ return getPageIndices(nextPage);
}
/**
@@ -352,7 +381,14 @@
* Returns true if the view is on one of the current pages, false otherwise.
*/
public boolean isVisible(View child) {
- return getLeftmostVisiblePageForIndex(indexOfChild(child)) == mCurrentPage;
+ return isVisible(indexOfChild(child));
+ }
+
+ /**
+ * Returns true if the page with the given index is currently visible, false otherwise.
+ */
+ private boolean isVisible(int pageIndex) {
+ return getLeftmostVisiblePageForIndex(pageIndex) == mCurrentPage;
}
/**
@@ -709,6 +745,7 @@
final int scrollOffsetStart = mOrientationHandler.getScrollOffsetStart(this, mInsets);
final int scrollOffsetEnd = mOrientationHandler.getScrollOffsetEnd(this, mInsets);
boolean pageScrollChanged = false;
+ int panelCount = getPanelCount();
for (int i = startIndex, childStart = scrollOffsetStart; i != endIndex; i += delta) {
final View child = getPageAt(i);
@@ -726,11 +763,15 @@
pageScrollChanged = true;
outPageScrolls[i] = pageScroll;
}
- childStart += primaryDimension + mPageSpacing + getChildGap();
+ childStart += primaryDimension + getChildGap();
+
+ // This makes sure that the space is added after the page, not after each panel
+ if (i % panelCount == panelCount - 1) {
+ childStart += mPageSpacing;
+ }
}
}
- int panelCount = getPanelCount();
if (panelCount > 1) {
for (int i = 0; i < childCount; i++) {
// In case we have multiple panels, always use left panel's page scroll for all
@@ -812,8 +853,8 @@
@Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
- int page = indexToPage(indexOfChild(child));
- if (page != mCurrentPage || !mScroller.isFinished()) {
+ int page = indexOfChild(child);
+ if (!isVisible(page) || !mScroller.isFinished()) {
if (immediate) {
setCurrentPage(page);
} else {
@@ -852,21 +893,25 @@
direction = View.FOCUS_LEFT;
}
}
- if (direction == View.FOCUS_LEFT) {
- if (getCurrentPage() > 0) {
- int nextPage = validateNewPage(getCurrentPage() - 1);
- snapToPage(nextPage);
- getChildAt(nextPage).requestFocus(direction);
- return true;
- }
- } else if (direction == View.FOCUS_RIGHT) {
- if (getCurrentPage() < getPageCount() - 1) {
- int nextPage = validateNewPage(getCurrentPage() + 1);
- snapToPage(nextPage);
- getChildAt(nextPage).requestFocus(direction);
- return true;
+
+ int currentPage = getNextPage();
+ int closestNeighbourIndex = -1;
+ int closestNeighbourDistance = Integer.MAX_VALUE;
+ // Find the closest neighbour page
+ for (int neighbourPageIndex : getNeighbourPageIndices(direction)) {
+ int distance = Math.abs(neighbourPageIndex - currentPage);
+ if (closestNeighbourDistance > distance) {
+ closestNeighbourDistance = distance;
+ closestNeighbourIndex = neighbourPageIndex;
}
}
+ if (closestNeighbourIndex != -1) {
+ View page = getPageAt(closestNeighbourIndex);
+ snapToPage(closestNeighbourIndex);
+ page.requestFocus(direction);
+ return true;
+ }
+
return false;
}
@@ -876,28 +921,12 @@
return;
}
- // Add the current page's views as focusable and the next possible page's too. If the
- // last focus change action was left then the left neighbour's views will be added, and
- // if it was right then the right neighbour's views will be added.
- // Unfortunately mCurrentPage can be outdated if there were multiple control actions in a
- // short period of time, but mNextPage is up to date because it is always updated by
- // method snapToPage.
- int nextPage = getNextPage();
- // XXX-RTL: This will be fixed in a future CL
- if (nextPage >= 0 && nextPage < getPageCount()) {
- getPageAt(nextPage).addFocusables(views, direction, focusableMode);
- }
- if (direction == View.FOCUS_LEFT) {
- if (nextPage > 0) {
- nextPage = validateNewPage(nextPage - 1);
- getPageAt(nextPage).addFocusables(views, direction, focusableMode);
- }
- } else if (direction == View.FOCUS_RIGHT) {
- if (nextPage < getPageCount() - 1) {
- nextPage = validateNewPage(nextPage + 1);
- getPageAt(nextPage).addFocusables(views, direction, focusableMode);
- }
- }
+ // nextPage is more reliable when multiple control movements have been done in a short
+ // period of time
+ getPageIndices(getNextPage())
+ .addAll(getNeighbourPageIndices(direction))
+ .forEach(pageIndex ->
+ getPageAt(pageIndex).addFocusables(views, direction, focusableMode));
}
/**
@@ -1477,8 +1506,8 @@
setCurrentPage(nextPage);
}
- int page = indexToPage(indexOfChild(child));
- if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
+ int page = indexOfChild(child);
+ if (page >= 0 && !isVisible(page) && !isInTouchMode()) {
snapToPage(page);
}
}
@@ -1609,7 +1638,7 @@
return false;
}
- if (FeatureFlags.IS_STUDIO_BUILD) {
+ if (FeatureFlags.IS_STUDIO_BUILD && !Utilities.IS_RUNNING_IN_TEST_HARNESS) {
duration *= Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.WINDOW_ANIMATION_SCALE, 1);
}
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index dff8534..bebbf4f 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -122,7 +122,7 @@
public int getCellContentHeight() {
return Math.min(getMeasuredHeight(),
- mActivity.getDeviceProfile().getCellHeight(mContainerType));
+ mActivity.getDeviceProfile().getCellContentHeight(mContainerType));
}
public void measureChild(View child) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 3cabc87..b92cf09 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -381,6 +381,21 @@
}
/**
+ * Similar to {@link #scaleRectAboutCenter(Rect, float)} except this allows different scales
+ * for X and Y
+ */
+ public static void scaleRectFAboutCenter(RectF r, float scaleX, float scaleY) {
+ float px = r.centerX();
+ float py = r.centerY();
+ r.offset(-px, -py);
+ r.left = r.left * scaleX;
+ r.top = r.top * scaleY;
+ r.right = r.right * scaleX;
+ r.bottom = r.bottom * scaleY;
+ r.offset(px, py);
+ }
+
+ /**
* Maps t from one range to another range.
* @param t The value to map.
* @param fromMin The lower bound of the range that t is being mapped from.
@@ -633,21 +648,6 @@
handler.sendMessage(msg);
}
- /**
- * Parses a string encoded using {@link #getPointString(int, int)}
- */
- public static Point parsePoint(String point) {
- String[] split = point.split(",");
- return new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
- }
-
- /**
- * Encodes a point to string to that it can be persisted atomically.
- */
- public static String getPointString(int x, int y) {
- return String.format(Locale.ENGLISH, "%d,%d", x, y);
- }
-
public static void unregisterReceiverSafely(Context context, BroadcastReceiver receiver) {
try {
context.unregisterReceiver(receiver);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a585be6..83ca08d 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -102,6 +102,7 @@
import com.android.launcher3.util.EdgeEffectCompat;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
@@ -197,7 +198,6 @@
private final int[] mTempXY = new int[2];
private final float[] mTempFXY = new float[2];
@Thunk float[] mDragViewVisualCenter = new float[2];
- private final float[] mTempTouchCoordinates = new float[2];
private SpringLoadedDragController mSpringLoadedDragController;
@@ -207,8 +207,6 @@
private boolean mStripScreensOnPageStopMoving = false;
- private DragPreviewProvider mOutlineProvider = null;
-
private boolean mWorkspaceFadeInAdjacentScreens;
final WallpaperOffsetInterpolator mWallpaperOffset;
@@ -315,40 +313,25 @@
// Increase our bottom insets so we don't overlap with the taskbar.
mInsets.bottom += grid.nonOverlappingTaskbarInset;
- if (grid.isTwoPanels) {
- setPageSpacing(0); // we have two pages and we don't want any spacing
-
- // Add left widget panel if it isn't already there
- if (!mWorkspaceScreens.containsKey(LEFT_PANEL_ID)) {
- int newCurrentPage = mCurrentPage + 1;
- bindAndInitLeftPanel();
- setCurrentPage(newCurrentPage);
- }
+ if (mWorkspaceFadeInAdjacentScreens) {
+ // In landscape mode the page spacing is set to the default.
+ setPageSpacing(grid.edgeMarginPx);
} else {
- if (mWorkspaceFadeInAdjacentScreens) {
- // In landscape mode the page spacing is set to the default.
- setPageSpacing(grid.edgeMarginPx);
- } else {
- // In portrait, we want the pages spaced such that there is no
- // overhang of the previous / next page into the current page viewport.
- // We assume symmetrical padding in portrait mode.
- int maxInsets = Math.max(insets.left, insets.right);
- int maxPadding = Math.max(grid.edgeMarginPx, padding.left + 1);
- setPageSpacing(Math.max(maxInsets, maxPadding));
- }
-
- // Remove left widget panel if it is present
- if (mWorkspaceScreens.containsKey(LEFT_PANEL_ID)) {
- int newCurrentPage = mCurrentPage - 1;
- removeLeftPanel();
- setCurrentPage(newCurrentPage);
- }
+ // In portrait, we want the pages spaced such that there is no
+ // overhang of the previous / next page into the current page viewport.
+ // We assume symmetrical padding in portrait mode.
+ int maxInsets = Math.max(insets.left, insets.right);
+ int maxPadding = Math.max(grid.edgeMarginPx, padding.left + 1);
+ setPageSpacing(Math.max(maxInsets, maxPadding));
}
+ updateWorkspaceScreensPadding();
+ }
+
+ private void updateWorkspaceScreensPadding() {
+ DeviceProfile grid = mLauncher.getDeviceProfile();
int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
int paddingBottom = grid.cellLayoutBottomPaddingPx;
- int twoPanelLandscapeSidePadding = paddingLeftRight * 2;
- int twoPanelPortraitSidePadding = paddingLeftRight / 2;
int panelCount = getPanelCount();
for (int i = mWorkspaceScreens.size() - 1; i >= 0; i--) {
@@ -356,13 +339,11 @@
int paddingRight = paddingLeftRight;
if (panelCount > 1) {
if (i % panelCount == 0) { // left side panel
- paddingLeft = grid.isLandscape ? twoPanelLandscapeSidePadding
- : twoPanelPortraitSidePadding;
+ paddingLeft = paddingLeftRight;
paddingRight = 0;
} else if (i % panelCount == panelCount - 1) { // right side panel
paddingLeft = 0;
- paddingRight = grid.isLandscape ? twoPanelLandscapeSidePadding
- : twoPanelPortraitSidePadding;
+ paddingRight = paddingLeftRight;
} else { // middle panel
paddingLeft = 0;
paddingRight = 0;
@@ -511,7 +492,6 @@
});
mDragInfo = null;
- mOutlineProvider = null;
mDragSourceInternal = null;
}
@@ -572,6 +552,10 @@
if (!FeatureFlags.QSB_ON_FIRST_SCREEN) {
return;
}
+ if (isTwoPanelEnabled()) {
+ insertNewWorkspaceScreen(Workspace.LEFT_PANEL_ID, getChildCount());
+ }
+
// Add the first page
CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, getChildCount());
// Always add a QSB on the first screen.
@@ -592,19 +576,6 @@
}
}
- /**
- * Initializes and binds the left panel
- */
- public void bindAndInitLeftPanel() {
- if (!FeatureFlags.QSB_ON_FIRST_SCREEN || !isTwoPanelEnabled()
- || mWorkspaceScreens.containsKey(Workspace.LEFT_PANEL_ID)) {
- return;
- }
-
- insertNewWorkspaceScreen(Workspace.LEFT_PANEL_ID, getChildCount());
- mLauncher.getModelWriter().setLeftPanelShown(true);
- }
-
public void removeAllWorkspaceScreens() {
// Disable all layout transitions before removing all pages to ensure that we don't get the
// transition animations competing with us changing the scroll when we add pages
@@ -626,7 +597,6 @@
mLauncher.mHandler.removeCallbacksAndMessages(DeferredWidgetRefresh.class);
// Ensure that the first page is always present
- bindAndInitLeftPanel();
bindAndInitFirstWorkspaceScreen(qsb);
// Re-enable the layout transitions
@@ -647,18 +617,6 @@
insertNewWorkspaceScreen(screenId, getChildCount());
}
- private void removeLeftPanel() {
- if (!mWorkspaceScreens.containsKey(LEFT_PANEL_ID)) {
- return;
- }
- mLauncher.getModelWriter().setLeftPanelShown(false);
- CellLayout leftPanel = mWorkspaceScreens.get(LEFT_PANEL_ID);
- mWorkspaceScreens.remove(LEFT_PANEL_ID);
- removeView(leftPanel);
- mScreenOrder.removeValue(LEFT_PANEL_ID);
- updatePageScrollValues();
- }
-
public CellLayout insertNewWorkspaceScreen(int screenId, int insertIndex) {
if (mWorkspaceScreens.containsKey(screenId)) {
throw new RuntimeException("Screen id " + screenId + " already exists!");
@@ -668,10 +626,6 @@
// created CellLayout.
CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
R.layout.workspace_screen, this, false /* attachToRoot */);
- DeviceProfile grid = mLauncher.getDeviceProfile();
- int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx;
- int paddingBottom = grid.cellLayoutBottomPaddingPx;
- newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
mWorkspaceScreens.put(screenId, newScreen);
mScreenOrder.add(insertIndex, screenId);
@@ -680,6 +634,7 @@
mLauncher.getStateManager().getState(), newScreen, insertIndex);
updatePageScrollValues();
+ updateWorkspaceScreensPadding();
return newScreen;
}
@@ -831,6 +786,10 @@
return indexOfChild(mWorkspaceScreens.get(screenId));
}
+ public IntSet getCurrentPageScreenIds() {
+ return IntSet.wrap(getScreenIdForPageIndex(getCurrentPage()));
+ }
+
public int getScreenIdForPageIndex(int index) {
if (0 <= index && index < mScreenOrder.size()) {
return mScreenOrder.get(index);
@@ -1368,11 +1327,7 @@
position[0], position[1], 0, null);
}
- public void prepareDragWithProvider(DragPreviewProvider outlineProvider) {
- mOutlineProvider = outlineProvider;
- }
-
- private void onStartStateTransition(LauncherState state) {
+ private void onStartStateTransition() {
mIsSwitchingState = true;
mTransitionProgress = 0;
@@ -1393,7 +1348,7 @@
*/
@Override
public void setState(LauncherState toState) {
- onStartStateTransition(toState);
+ onStartStateTransition();
mStateTransitionAnimation.setState(toState);
onEndStateTransition();
}
@@ -1404,7 +1359,7 @@
@Override
public void setStateWithAnimation(
LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {
- StateTransitionListener listener = new StateTransitionListener(toState);
+ StateTransitionListener listener = new StateTransitionListener();
mStateTransitionAnimation.setStateWithAnimation(toState, config, animation);
// Invalidate the pages now, so that we have the visible pages before the
@@ -1513,8 +1468,6 @@
icon.clearPressedBackground();
}
- mOutlineProvider = previewProvider;
-
if (draggableView == null && child instanceof DraggableView) {
draggableView = (DraggableView) child;
}
@@ -1824,19 +1777,16 @@
boolean droppedOnOriginalCell = false;
- int snapScreen = -1;
+ boolean snappedToNewPage = false;
boolean resizeOnDrop = false;
+ Runnable onCompleteRunnable = null;
if (d.dragSource != this || mDragInfo == null) {
final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
(int) mDragViewVisualCenter[1] };
onDropExternal(touchXY, dropTargetLayout, d);
} else {
final View cell = mDragInfo.cell;
- final DragView dragView = d.dragView;
boolean droppedOnOriginalCellDuringTransition = false;
- Runnable onCompleteRunnable = dragView::resumeColorExtraction;
-
- dragView.disableColorExtraction();
if (dropTargetLayout != null && !d.cancelled) {
// Move internally
@@ -1909,11 +1859,14 @@
}
if (foundCell) {
- if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) {
- snapScreen = getPageIndexForScreenId(screenId);
+ int targetScreenIndex = getPageIndexForScreenId(screenId);
+ int snapScreen = getLeftmostVisiblePageForIndex(targetScreenIndex);
+ // On large screen devices two pages can be shown at the same time, and snap
+ // isn't needed if the source and target screens appear at the same time
+ if (snapScreen != mCurrentPage && !hasMovedIntoHotseat) {
snapToPage(snapScreen);
+ snappedToNewPage = true;
}
-
final ItemInfo info = (ItemInfo) cell.getTag();
if (hasMovedLayouts) {
// Reparent the view
@@ -1947,9 +1900,7 @@
AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo();
if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE
&& !options.isAccessibleDrag) {
- final Runnable previousRunnable = onCompleteRunnable;
onCompleteRunnable = () -> {
- previousRunnable.run();
if (!isPageInTransition()) {
AppWidgetResizeFrame.showForWidget(hostView, cellLayout);
}
@@ -2007,7 +1958,7 @@
ANIMATE_INTO_POSITION_AND_DISAPPEAR;
animateWidgetDrop(info, parent, d.dragView, null, animationType, cell, false);
} else {
- int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
+ int duration = snappedToNewPage ? ADJACENT_SCREEN_DROP_DURATION : -1;
mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
this);
}
@@ -2018,7 +1969,7 @@
parent.onDropChild(cell);
mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY,
- forSuccessCallback(onCompleteRunnable));
+ onCompleteRunnable == null ? null : forSuccessCallback(onCompleteRunnable));
mStatsLogManager.logger().withItemInfo(d.dragInfo).withInstanceId(d.logInstanceId)
.log(LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED);
}
@@ -2336,25 +2287,16 @@
int nextPage = getNextPage();
if (layout == null && !isPageInTransition()) {
- // Check if the item is dragged over currentPage - 1 page
- mTempTouchCoordinates[0] = Math.min(centerX, d.x);
- mTempTouchCoordinates[1] = d.y;
- layout = verifyInsidePage(nextPage + (mIsRtl ? 1 : -1), mTempTouchCoordinates);
+ layout = verifyInsidePage(nextPage + (mIsRtl ? 1 : -1), Math.min(centerX, d.x), d.y);
}
if (layout == null && !isPageInTransition()) {
- // Check if the item is dragged over currentPage + 1 page
- mTempTouchCoordinates[0] = Math.max(centerX, d.x);
- mTempTouchCoordinates[1] = d.y;
- layout = verifyInsidePage(nextPage + (mIsRtl ? -1 : 1), mTempTouchCoordinates);
+ layout = verifyInsidePage(nextPage + (mIsRtl ? -1 : 1), Math.max(centerX, d.x), d.y);
}
// If two panel is enabled, users can also drag items to currentPage + 2
if (isTwoPanelEnabled() && layout == null && !isPageInTransition()) {
- // Check if the item is dragged over currentPage + 2 page
- mTempTouchCoordinates[0] = Math.max(centerX, d.x);
- mTempTouchCoordinates[1] = d.y;
- layout = verifyInsidePage(nextPage + (mIsRtl ? -2 : 2), mTempTouchCoordinates);
+ layout = verifyInsidePage(nextPage + (mIsRtl ? -2 : 2), Math.max(centerX, d.x), d.y);
}
// Always pick the current page.
@@ -2372,12 +2314,11 @@
/**
* Returns the child CellLayout if the point is inside the page coordinates, null otherwise.
*/
- private CellLayout verifyInsidePage(int pageNo, float[] touchXy) {
+ private CellLayout verifyInsidePage(int pageNo, float x, float y) {
if (pageNo >= 0 && pageNo < getPageCount()) {
CellLayout cl = (CellLayout) getChildAt(pageNo);
- mapPointFromSelfToChild(cl, touchXy);
- if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&
- touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {
+ if (x >= cl.getLeft() && x <= cl.getRight()
+ && y >= cl.getTop() && y <= cl.getBottom()) {
// This point is inside the cell layout
return cl;
}
@@ -3376,12 +3317,6 @@
private class StateTransitionListener extends AnimatorListenerAdapter
implements AnimatorUpdateListener {
- private final LauncherState mToState;
-
- StateTransitionListener(LauncherState toState) {
- mToState = toState;
- }
-
@Override
public void onAnimationUpdate(ValueAnimator anim) {
mTransitionProgress = anim.getAnimatedFraction();
@@ -3389,7 +3324,7 @@
@Override
public void onAnimationStart(Animator animation) {
- onStartStateTransition(mToState);
+ onStartStateTransition();
}
@Override
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 9faac5b..0fb5e77 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -188,7 +188,8 @@
private boolean itemSupportsAccessibleDrag(ItemInfo item) {
if (item instanceof WorkspaceItemInfo) {
// Support the action unless the item is in a context menu.
- return item.screenId >= 0 && item.container != Favorites.CONTAINER_HOTSEAT_PREDICTION;
+ return (item.screenId >= 0 || item.screenId == Workspace.LEFT_PANEL_ID)
+ && item.container != Favorites.CONTAINER_HOTSEAT_PREDICTION;
}
return (item instanceof LauncherAppWidgetInfo)
|| (item instanceof FolderInfo);
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 01f7de6..3ab893b 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -56,6 +56,10 @@
mAnim = new AnimatorSet();
}
+ public long getDuration() {
+ return mDuration;
+ }
+
/**
* Utility method to sent an interpolator on an animation and add it to the list
*/
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 1779ddb..da701a8 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -144,9 +144,6 @@
public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag(
"ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache");
- public static final BooleanFlag MULTI_DB_GRID_MIRATION_ALGO = getDebugFlag(
- "MULTI_DB_GRID_MIRATION_ALGO", true, "Use the multi-db grid migration algorithm");
-
public static final BooleanFlag ENABLE_THEMED_ICONS = getDebugFlag(
"ENABLE_THEMED_ICONS", true, "Enable themed icons on workspace");
@@ -175,8 +172,8 @@
"ENABLE_SMARTSPACE_UNIVERSAL", false,
"Replace Smartspace with a version rendered by System UI.");
- public static final BooleanFlag ENABLE_SMARTSPACE_ENHANCED = new DeviceFlag(
- "ENABLE_SMARTSPACE_ENHANCED", false,
+ public static final BooleanFlag ENABLE_SMARTSPACE_ENHANCED = getDebugFlag(
+ "ENABLE_SMARTSPACE_ENHANCED", true,
"Replace Smartspace with the enhanced version. "
+ "Ignored if ENABLE_SMARTSPACE_UNIVERSAL is enabled.");
@@ -258,6 +255,10 @@
"WIDGETS_IN_LAUNCHER_PREVIEW", true,
"Enables widgets in Launcher preview for the Wallpaper app.");
+ public static final BooleanFlag QUICK_WALLPAPER_PICKER = getDebugFlag(
+ "QUICK_WALLPAPER_PICKER", false,
+ "Shows quick wallpaper picker in long-press menu");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 6bd6261..92ed18a 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -192,15 +192,15 @@
float appWidgetHostViewScale = mWidgetCell.getAppWidgetHostViewScale();
int xOffset =
appWidgetHostView.getLeft() - (int) (mLastTouchPos.x * appWidgetHostViewScale);
- int yOffset = appWidgetHostView.getTop()
- - (int) (mLastTouchPos.y * mWidgetCell.getAppWidgetHostViewScale());
+ int yOffset =
+ appWidgetHostView.getTop() - (int) (mLastTouchPos.y * appWidgetHostViewScale);
bounds.offset(xOffset, yOffset);
listener = new PinItemDragListener(
mRequest,
bounds,
appWidgetHostView.getMeasuredWidth(),
appWidgetHostView.getMeasuredWidth(),
- appWidgetHostView.getScaleX());
+ appWidgetHostViewScale);
} else {
bounds = img.getBitmapBounds();
bounds.offset(img.getLeft() - (int) mLastTouchPos.x,
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index f2ab96c..57d6cc3 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -23,6 +23,8 @@
import static com.android.launcher3.Utilities.getBadge;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -63,7 +65,6 @@
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
/** A custom view for rendering an icon, folder, shortcut or widget during drag-n-drop. */
public abstract class DragView<T extends Context & ActivityContext> extends FrameLayout {
@@ -94,6 +95,8 @@
private boolean mHasDrawn = false;
final ValueAnimator mAnim;
+ // Whether mAnim has started. Unlike mAnim.isStarted(), this is true even after mAnim ends.
+ private boolean mAnimStarted;
private int mLastTouchX;
private int mLastTouchY;
@@ -171,6 +174,12 @@
animation.cancel();
}
});
+ mAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mAnimStarted = true;
+ }
+ });
setDragRegion(new Rect(0, 0, width, height));
@@ -289,16 +298,6 @@
mOnDragStartCallback.executeAllAndDestroy();
}
- // TODO(b/183609936): This is only for LauncherAppWidgetHostView that is rendered in a drawable.
- // Once LauncherAppWidgetHostView is directly rendered in this view, removes this method.
- @Override
- public void invalidate() {
- super.invalidate();
- if (mContent instanceof ImageView) {
- mContent.invalidate();
- }
- }
-
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(makeMeasureSpec(mWidth, EXACTLY), makeMeasureSpec(mHeight, EXACTLY));
@@ -396,6 +395,10 @@
}
}
+ public boolean isAnimationFinished() {
+ return mAnimStarted && !mAnim.isRunning();
+ }
+
/**
* Move the window containing this view.
*
@@ -474,24 +477,6 @@
}
/**
- * If the drag view uses color extraction, block it.
- */
- public void disableColorExtraction() {
- if (mContent instanceof LauncherAppWidgetHostView) {
- ((LauncherAppWidgetHostView) mContent).disableColorExtraction();
- }
- }
-
- /**
- * If the drag view uses color extraction, restores it.
- */
- public void resumeColorExtraction() {
- if (mContent instanceof LauncherAppWidgetHostView) {
- ((LauncherAppWidgetHostView) mContent).enableColorExtraction(/* updateColors= */ false);
- }
- }
-
- /**
* Removes this view from the {@link DragLayer}.
*
* <p>If the drag content is a {@link #mContent}, this call doesn't reattach the
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 6a6603c..74d9a22 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -21,11 +21,11 @@
import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.graphics.Matrix;
+import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.Log;
@@ -129,10 +129,19 @@
canvas.restore();
});
+ Bitmap bgBitmap = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
+ (canvas) -> {
+ Paint p = new Paint();
+ p.setColor(bg.getBgColor());
+
+ canvas.drawCircle(dragViewSize.x / 2f, dragViewSize.y / 2f, bg.getRadius(), p);
+ });
+
ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBmp, 0, 0);
ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap, 0, 0);
+ ShiftedBitmapDrawable background = new ShiftedBitmapDrawable(bgBitmap, 0, 0);
- return new FolderAdaptiveIcon(new ColorDrawable(bg.getBgColor()), foreground, badge, mask);
+ return new FolderAdaptiveIcon(background, foreground, badge, mask);
}
@Override
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index 54967a9..8cd91d3 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -7,7 +7,9 @@
private static final float MIN_SCALE = 0.44f;
private static final float MAX_SCALE = 0.51f;
- private static final float MAX_RADIUS_DILATION = 0.1f;
+ private static final float MAX_RADIUS_DILATION = 0.25f;
+ // The max amount of overlap the preview items can go outside of the background bounds.
+ public static final float ICON_OVERLAP_FACTOR = 1 + (MAX_RADIUS_DILATION / 2f);
private static final float ITEM_RADIUS_SCALE_FACTOR = 1.15f;
public static final int EXIT_INDEX = -2;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index f005b61..60d8cdb 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -16,6 +16,7 @@
package com.android.launcher3.folder;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELED;
@@ -236,6 +237,8 @@
public void getPreviewBounds(Rect outBounds) {
mPreviewItemManager.recomputePreviewDrawingParams();
mBackground.getBounds(outBounds);
+ // The preview items go outside of the bounds of the background.
+ Utilities.scaleRectAboutCenter(outBounds, ICON_OVERLAP_FACTOR);
}
public float getBackgroundStrokeWidth() {
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
index e599e8c..c5b3913 100644
--- a/src/com/android/launcher3/folder/LauncherDelegate.java
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -18,8 +18,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.View;
@@ -38,10 +36,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.launcher3.views.BaseDragLayer.LayoutParams;
-import com.android.launcher3.widget.LocalColorExtractor;
-import java.util.Arrays;
import java.util.Optional;
import java.util.function.Consumer;
@@ -51,8 +46,6 @@
public class LauncherDelegate {
private final Launcher mLauncher;
- private final Rect mTempRect = new Rect();
- private final RectF mTempRectF = new RectF();
private LauncherDelegate(Launcher launcher) {
mLauncher = launcher;
@@ -84,15 +77,6 @@
return mLauncher;
}
- void addRectForColorExtraction(BaseDragLayer.LayoutParams lp, LocalColorExtractor target) {
- mTempRect.set(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
- target.getExtractedRectForViewRect(mLauncher,
- mLauncher.getWorkspace().getCurrentPage(), mTempRect, mTempRectF);
- if (!mTempRectF.isEmpty()) {
- target.addLocation(Arrays.asList(mTempRectF));
- }
- }
-
boolean replaceFolderWithFinalItem(Folder folder) {
// Add the last remaining child to the workspace in place of the folder
Runnable onCompleteRunnable = new Runnable() {
@@ -215,9 +199,6 @@
folder.close(true);
return true;
}
-
- @Override
- void addRectForColorExtraction(LayoutParams lp, LocalColorExtractor target) { }
}
static LauncherDelegate from(ActivityContext context) {
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 460521f..18d0b10 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -16,6 +16,7 @@
package com.android.launcher3.folder;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.graphics.IconShape.getShape;
import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
@@ -186,7 +187,7 @@
outBounds.set(left, top, right, bottom);
}
- int getRadius() {
+ public int getRadius() {
return previewSize / 2;
}
@@ -348,7 +349,12 @@
public Path getClipPath() {
mPath.reset();
- getShape().addToPath(mPath, getOffsetX(), getOffsetY(), getScaledRadius());
+ float radius = getScaledRadius() * ICON_OVERLAP_FACTOR;
+ // Find the difference in radius so that the clip path remains centered.
+ float radiusDifference = radius - getRadius();
+ float offsetX = basePreviewOffsetX - radiusDifference;
+ float offsetY = basePreviewOffsetY - radiusDifference;
+ getShape().addToPath(mPath, offsetX, offsetY, radius);
return mPath;
}
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 94778a2..bb726f8 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -286,8 +286,8 @@
WallpaperColors wallpaperColors = wallpaperColorsOverride != null
? wallpaperColorsOverride
: WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);
- mWallpaperColorResources = LocalColorExtractor.newInstance(context)
- .generateColorsOverride(wallpaperColors);
+ mWallpaperColorResources = wallpaperColors != null ? LocalColorExtractor.newInstance(
+ context).generateColorsOverride(wallpaperColors) : null;
} else {
mWallpaperColorResources = null;
}
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index e45b8f7..24d6fe5 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -142,7 +142,7 @@
mSystemBackgroundColor = preloadColors[PRELOAD_BACKGROUND_COLOR_INDEX];
mIsDarkMode = isDarkMode;
- setInternalProgress(info.getProgressLevel());
+ setLevel(info.getProgressLevel());
setIsStartable(info.isAppStartable());
}
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 13c83be..c7448dc 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -16,7 +16,6 @@
package com.android.launcher3.graphics;
-import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -47,7 +46,6 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext;
import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.GridSizeMigrationTask;
import com.android.launcher3.model.GridSizeMigrationTaskV2;
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDelegate;
@@ -165,7 +163,7 @@
@Override
public void run() {
- DeviceProfile deviceProfile = mIdp.getDeviceProfile(mContext);
+ DeviceProfile deviceProfile = mIdp.getDeviceProfile(previewContext);
String query = (deviceProfile.isTwoPanels ? LauncherSettings.Favorites.SCREEN
+ " = " + Workspace.LEFT_PANEL_ID + " or " : "")
+ LauncherSettings.Favorites.SCREEN + " = " + Workspace.FIRST_SCREEN_ID
@@ -175,7 +173,6 @@
query);
MAIN_EXECUTOR.execute(() -> {
- mBgDataModel.isLeftPanelShown = deviceProfile.isTwoPanels;
renderView(previewContext, mBgDataModel, mWidgetProvidersMap);
mOnDestroyCallbacks.add(previewContext::onDestroy);
});
@@ -199,16 +196,10 @@
@WorkerThread
private boolean doGridMigrationIfNecessary() {
- boolean needsToMigrate =
- MULTI_DB_GRID_MIRATION_ALGO.get()
- ? GridSizeMigrationTaskV2.needsToMigrate(mContext, mIdp)
- : GridSizeMigrationTask.needsToMigrate(mContext, mIdp);
- if (!needsToMigrate) {
+ if (!GridSizeMigrationTaskV2.needsToMigrate(mContext, mIdp)) {
return false;
}
- return MULTI_DB_GRID_MIRATION_ALGO.get()
- ? GridSizeMigrationTaskV2.migrateGridIfNeeded(mContext, mIdp)
- : GridSizeMigrationTask.migrateGridIfNeeded(mContext, mIdp);
+ return GridSizeMigrationTaskV2.migrateGridIfNeeded(mContext, mIdp);
}
@UiThread
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index b2b0010..4f12d0b 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.model;
+import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
+import static com.android.launcher3.WorkspaceLayoutManager.LEFT_PANEL_ID;
+
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
@@ -27,6 +30,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
@@ -38,6 +42,7 @@
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.PackageManagerHelper;
import java.util.ArrayList;
@@ -291,11 +296,15 @@
boolean found = false;
int screenCount = workspaceScreens.size();
- int firstScreenToCheck = dataModel.isLeftPanelShown ? 2 : 1;
- // Search on the screens for empty space
- for (int screen = firstScreenToCheck; screen < screenCount; screen++) {
+ // First check the preferred screen.
+ IntSet screensToExclude = IntSet.wrap(LEFT_PANEL_ID);
+ if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
+ screensToExclude.add(FIRST_SCREEN_ID);
+ }
+
+ for (int screen = 0; screen < screenCount; screen++) {
screenId = workspaceScreens.get(screen);
- if (findNextAvailableIconSpaceInScreen(
+ if (!screensToExclude.contains(screenId) && findNextAvailableIconSpaceInScreen(
app, screenItems.get(screenId), coordinates, spanX, spanY)) {
// We found a space for it
found = true;
diff --git a/src/com/android/launcher3/model/BaseLoaderResults.java b/src/com/android/launcher3/model/BaseLoaderResults.java
index c202d8d..0e132c2 100644
--- a/src/com/android/launcher3/model/BaseLoaderResults.java
+++ b/src/com/android/launcher3/model/BaseLoaderResults.java
@@ -165,25 +165,7 @@
}
private void bind() {
- IntSet currentScreenIndices;
- {
- // Create an anonymous scope to calculate currentScreen as it has to be a
- // final variable.
- IntSet screenIndices = mCallbacks.getPagesToBindSynchronously();
- if (screenIndices == null || screenIndices.isEmpty()
- || screenIndices.getArray().get(screenIndices.size() - 1)
- >= mOrderedScreenIds.size()) {
- // There maybe no workspace screens (just hotseat items and an empty page).
- // Also we want to prevent IndexOutOfBoundsExceptions.
- screenIndices = new IntSet();
- }
- currentScreenIndices = screenIndices;
- }
-
-
- IntSet currentScreenIds = new IntSet();
- currentScreenIndices.forEach(
- index -> currentScreenIds.add(mOrderedScreenIds.get(index)));
+ IntSet currentScreenIds = mCallbacks.getPagesToBindSynchronously(mOrderedScreenIds);
// Separate the items that are on the current screen, and all the other remaining items
ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
@@ -218,7 +200,7 @@
Executor pendingExecutor = pendingTasks::add;
bindWorkspaceItems(otherWorkspaceItems, pendingExecutor);
bindAppWidgets(otherAppWidgets, pendingExecutor);
- executeCallbacksTask(c -> c.finishBindingItems(currentScreenIndices), pendingExecutor);
+ executeCallbacksTask(c -> c.finishBindingItems(currentScreenIds), pendingExecutor);
pendingExecutor.execute(
() -> {
MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
@@ -229,7 +211,7 @@
executeCallbacksTask(
c -> {
MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- c.onInitialBindComplete(currentScreenIndices, pendingTasks);
+ c.onInitialBindComplete(currentScreenIds, pendingTasks);
}, mUiExecutor);
}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index dd4c3c3..13ad90e 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -117,11 +117,6 @@
public int lastBindId = 0;
/**
- * Value that indicates if left widget panel is shown or not.
- */
- public boolean isLeftPanelShown = false;
-
- /**
* Clears all the data
*/
public synchronized void clear() {
@@ -146,14 +141,6 @@
if (FeatureFlags.QSB_ON_FIRST_SCREEN || screenSet.isEmpty()) {
screenSet.add(Workspace.FIRST_SCREEN_ID);
}
-
- if (isLeftPanelShown) {
- // We should add it even though there are no items on it.
- screenSet.add(Workspace.LEFT_PANEL_ID);
- } else {
- // We should NOT add it even though there are items on it.
- screenSet.remove(Workspace.LEFT_PANEL_ID);
- }
return screenSet.getArray();
}
@@ -459,10 +446,11 @@
int FLAG_QUIET_MODE_CHANGE_PERMISSION = 1 << 2;
/**
- * Returns an IntSet of page numbers to bind first, synchronously if possible
+ * Returns an IntSet of page ids to bind first, synchronously if possible
* or an empty IntSet
+ * @param orderedScreenIds All the page ids to be bound
*/
- default IntSet getPagesToBindSynchronously() {
+ default IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
return new IntSet();
}
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
new file mode 100644
index 0000000..761053d
--- /dev/null
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -0,0 +1,115 @@
+/*
+ * 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 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;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_GRID_SIZE_5;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.text.TextUtils;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Utility class representing persisted grid properties.
+ */
+public class DeviceGridState {
+
+ public static final String KEY_WORKSPACE_SIZE = "migration_src_workspace_size";
+ public static final String KEY_HOTSEAT_COUNT = "migration_src_hotseat_count";
+ public static final String KEY_DEVICE_TYPE = "migration_src_device_type";
+
+ public static final int TYPE_PHONE = 0;
+ public static final int TYPE_MULTI_DISPLAY = 1;
+ public static final int TYPE_TABLET = 2;
+
+ private final String mGridSizeString;
+ private final int mNumHotseat;
+ private final int mDeviceType;
+
+ 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;
+ }
+
+ public DeviceGridState(Context context) {
+ SharedPreferences prefs = Utilities.getPrefs(context);
+ mGridSizeString = prefs.getString(KEY_WORKSPACE_SIZE, "");
+ mNumHotseat = prefs.getInt(KEY_HOTSEAT_COUNT, -1);
+ mDeviceType = prefs.getInt(KEY_DEVICE_TYPE, TYPE_PHONE);
+ }
+
+ /**
+ * Returns the device type for the grid
+ */
+ public int getDeviceType() {
+ return mDeviceType;
+ }
+
+ /**
+ * Stores the device state to shared preferences
+ */
+ public void writeToPrefs(Context context) {
+ Utilities.getPrefs(context).edit()
+ .putString(KEY_WORKSPACE_SIZE, mGridSizeString)
+ .putInt(KEY_HOTSEAT_COUNT, mNumHotseat)
+ .putInt(KEY_DEVICE_TYPE, mDeviceType)
+ .apply();
+ }
+
+ /**
+ * Returns the logging event corresponding to the grid state
+ */
+ public LauncherEvent getWorkspaceSizeEvent() {
+ if (!TextUtils.isEmpty(mGridSizeString)) {
+ switch (mGridSizeString.charAt(0)) {
+ case '5':
+ return LAUNCHER_GRID_SIZE_5;
+ case '4':
+ return LAUNCHER_GRID_SIZE_4;
+ case '3':
+ return LAUNCHER_GRID_SIZE_3;
+ case '2':
+ return LAUNCHER_GRID_SIZE_2;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DeviceGridState that = (DeviceGridState) o;
+ return mNumHotseat == that.mNumHotseat
+ && mDeviceType == that.mDeviceType
+ && Objects.equals(mGridSizeString, that.mGridSizeString);
+ }
+}
diff --git a/src/com/android/launcher3/model/GridBackupTable.java b/src/com/android/launcher3/model/GridBackupTable.java
index acfc339..51cbf4b 100644
--- a/src/com/android/launcher3/model/GridBackupTable.java
+++ b/src/com/android/launcher3/model/GridBackupTable.java
@@ -23,14 +23,12 @@
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Point;
import android.os.Process;
import android.util.Log;
import androidx.annotation.IntDef;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.LauncherSettings.Settings;
import com.android.launcher3.pm.UserCache;
/**
@@ -85,49 +83,6 @@
}
/**
- * Create a backup from current workspace layout if one isn't created already (Note backup
- * created this way is always sanitized). Otherwise restore from the backup instead.
- */
- public boolean backupOrRestoreAsNeeded() {
- // Check if backup table exists
- if (!tableExists(mDb, BACKUP_TABLE_NAME)) {
- if (Settings.call(mContext.getContentResolver(), Settings.METHOD_WAS_EMPTY_DB_CREATED)
- .getBoolean(Settings.EXTRA_VALUE, false)) {
- // No need to copy if empty DB was created.
- return false;
- }
- doBackup(UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
- Process.myUserHandle()), 0);
- return false;
- }
- return restoreIfBackupExists(Favorites.TABLE_NAME);
- }
-
- public boolean restoreToPreviewIfBackupExists() {
- if (!tableExists(mDb, BACKUP_TABLE_NAME)) {
- return false;
- }
-
- return restoreIfBackupExists(Favorites.PREVIEW_TABLE_NAME);
- }
-
- private boolean restoreIfBackupExists(String toTableName) {
- if (loadDBProperties() != STATE_SANITIZED) {
- return false;
- }
- long userSerial = UserCache.INSTANCE.get(mContext).getSerialNumberForUser(
- Process.myUserHandle());
- copyTable(mDb, BACKUP_TABLE_NAME, toTableName, userSerial);
- Log.d(TAG, "Backup table found");
- return true;
- }
-
- public int getRestoreHotseatAndGridSize(Point outGridSize) {
- outGridSize.set(mRestoredGridX, mRestoredGridY);
- return mRestoredHotseatSize;
- }
-
- /**
* Creates a new table and populates with copy of Favorites.TABLE_NAME
*/
public void createCustomBackupTable(String tableName) {
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
deleted file mode 100644
index 7b3e509..0000000
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ /dev/null
@@ -1,1098 +0,0 @@
-package com.android.launcher3.model;
-
-import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_HOTSEAT_COUNT;
-import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_WORKSPACE_SIZE;
-import static com.android.launcher3.LauncherSettings.Settings.EXTRA_VALUE;
-import static com.android.launcher3.Utilities.getPointString;
-import static com.android.launcher3.Utilities.parsePoint;
-import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
-
-import android.content.ComponentName;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Point;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.SparseArray;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.LauncherSettings.Settings;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.LauncherPreviewRenderer;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.provider.LauncherDbUtils;
-import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
-import com.android.launcher3.util.GridOccupancy;
-import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.IntSparseArrayMap;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.WidgetManagerHelper;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-
-/**
- * This class takes care of shrinking the workspace (by maximum of one row and one column), as a
- * result of restoring from a larger device or device density change.
- */
-public class GridSizeMigrationTask {
-
- private static final String TAG = "GridSizeMigrationTask";
- private static final boolean DEBUG = false;
-
- // These are carefully selected weights for various item types (Math.random?), to allow for
- // the least absurd migration experience.
- private static final float WT_SHORTCUT = 1;
- private static final float WT_APPLICATION = 0.8f;
- private static final float WT_WIDGET_MIN = 2;
- private static final float WT_WIDGET_FACTOR = 0.6f;
- private static final float WT_FOLDER_FACTOR = 0.5f;
-
- protected final SQLiteDatabase mDb;
- protected final Context mContext;
-
- protected final IntArray mEntryToRemove = new IntArray();
- protected final ArrayList<DbEntry> mCarryOver = new ArrayList<>();
-
- private final SparseArray<ContentValues> mUpdateOperations = new SparseArray<>();
- private final HashSet<String> mValidPackages;
- private final String mTableName;
-
- private final int mSrcX, mSrcY;
- private final int mTrgX, mTrgY;
- private final boolean mShouldRemoveX, mShouldRemoveY;
-
- private final int mSrcHotseatSize;
- private final int mDestHotseatSize;
-
- protected GridSizeMigrationTask(Context context, SQLiteDatabase db,
- HashSet<String> validPackages, boolean usePreviewTable, Point sourceSize,
- Point targetSize) {
- mContext = context;
- mDb = db;
- mValidPackages = validPackages;
- mTableName = usePreviewTable ? Favorites.PREVIEW_TABLE_NAME : Favorites.TABLE_NAME;
-
- mSrcX = sourceSize.x;
- mSrcY = sourceSize.y;
-
- mTrgX = targetSize.x;
- mTrgY = targetSize.y;
-
- mShouldRemoveX = mTrgX < mSrcX;
- mShouldRemoveY = mTrgY < mSrcY;
-
- // Non-used variables
- mSrcHotseatSize = mDestHotseatSize = -1;
- }
-
- protected GridSizeMigrationTask(Context context, SQLiteDatabase db,
- HashSet<String> validPackages, boolean usePreviewTable, int srcHotseatSize,
- int destHotseatSize) {
- mContext = context;
- mDb = db;
- mValidPackages = validPackages;
- mTableName = usePreviewTable ? Favorites.PREVIEW_TABLE_NAME : Favorites.TABLE_NAME;
-
- mSrcHotseatSize = srcHotseatSize;
-
- mDestHotseatSize = destHotseatSize;
-
- // Non-used variables
- mSrcX = mSrcY = mTrgX = mTrgY = -1;
- mShouldRemoveX = mShouldRemoveY = false;
- }
-
- /**
- * Applied all the pending DB operations
- *
- * @return true if any DB operation was commited.
- */
- private boolean applyOperations() throws Exception {
- // Update items
- int updateCount = mUpdateOperations.size();
- for (int i = 0; i < updateCount; i++) {
- mDb.update(mTableName, mUpdateOperations.valueAt(i),
- "_id=" + mUpdateOperations.keyAt(i), null);
- }
-
- if (!mEntryToRemove.isEmpty()) {
- if (DEBUG) {
- Log.d(TAG, "Removing items: " + mEntryToRemove.toConcatString());
- }
- mDb.delete(mTableName, Utilities.createDbSelectionQuery(Favorites._ID, mEntryToRemove),
- null);
- }
-
- return updateCount > 0 || !mEntryToRemove.isEmpty();
- }
-
- /**
- * To migrate hotseat, we load all the entries in order (LTR or RTL) and arrange them
- * in the order in the new hotseat while keeping an empty space for all-apps. If the number of
- * entries is more than what can fit in the new hotseat, we drop the entries with least weight.
- * For weight calculation {@see #WT_SHORTCUT}, {@see #WT_APPLICATION}
- * & {@see #WT_FOLDER_FACTOR}.
- *
- * @return true if any DB change was made
- */
- protected boolean migrateHotseat() throws Exception {
- ArrayList<DbEntry> items = loadHotseatEntries();
- while (items.size() > mDestHotseatSize) {
- // Pick the center item by default.
- DbEntry toRemove = items.get(items.size() / 2);
-
- // Find the item with least weight.
- for (DbEntry entry : items) {
- if (entry.weight < toRemove.weight) {
- toRemove = entry;
- }
- }
-
- mEntryToRemove.add(toRemove.id);
- items.remove(toRemove);
- }
-
- // Update screen IDS
- int newScreenId = 0;
- for (DbEntry entry : items) {
- if (entry.screenId != newScreenId) {
- entry.screenId = newScreenId;
-
- // These values does not affect the item position, but we should set them
- // to something other than -1.
- entry.cellX = newScreenId;
- entry.cellY = 0;
-
- update(entry);
- }
-
- newScreenId++;
- }
-
- return applyOperations();
- }
-
- @VisibleForTesting
- static IntArray getWorkspaceScreenIds(SQLiteDatabase db, String tableName) {
- return LauncherDbUtils.queryIntArray(db, tableName, Favorites.SCREEN,
- Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP,
- Favorites.SCREEN, Favorites.SCREEN);
- }
-
- /**
- * @return true if any DB change was made
- */
- protected boolean migrateWorkspace() throws Exception {
- IntArray allScreens = getWorkspaceScreenIds(mDb, mTableName);
- if (allScreens.isEmpty()) {
- throw new Exception("Unable to get workspace screens");
- }
-
- for (int i = 0; i < allScreens.size(); i++) {
- int screenId = allScreens.get(i);
- if (DEBUG) {
- Log.d(TAG, "Migrating " + screenId);
- }
- migrateScreen(screenId);
- }
-
- if (!mCarryOver.isEmpty()) {
- IntSparseArrayMap<DbEntry> itemMap = new IntSparseArrayMap<>();
- for (DbEntry e : mCarryOver) {
- itemMap.put(e.id, e);
- }
-
- do {
- // Some items are still remaining. Try adding a few new screens.
-
- // At every iteration, make sure that at least one item is removed from
- // {@link #mCarryOver}, to prevent an infinite loop. If no item could be removed,
- // break the loop and abort migration by throwing an exception.
- OptimalPlacementSolution placement = new OptimalPlacementSolution(
- new GridOccupancy(mTrgX, mTrgY), deepCopy(mCarryOver), 0, true);
- placement.find();
- if (placement.finalPlacedItems.size() > 0) {
- int newScreenId = LauncherSettings.Settings.call(
- mContext.getContentResolver(),
- LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
- .getInt(EXTRA_VALUE);
- for (DbEntry item : placement.finalPlacedItems) {
- if (!mCarryOver.remove(itemMap.get(item.id))) {
- throw new Exception("Unable to find matching items");
- }
- item.screenId = newScreenId;
- update(item);
- }
- } else {
- throw new Exception("None of the items can be placed on an empty screen");
- }
-
- } while (!mCarryOver.isEmpty());
- }
- return applyOperations();
- }
-
- /**
- * Migrate a particular screen id.
- * Strategy:
- * 1) For all possible combinations of row and column, pick the one which causes the least
- * data loss: {@link #tryRemove(int, int, int, ArrayList, float[])}
- * 2) Maintain a list of all lost items before this screen, and add any new item lost from
- * this screen to that list as well.
- * 3) If all those items from the above list can be placed on this screen, place them
- * (otherwise they are placed on a new screen).
- */
- protected void migrateScreen(int screenId) {
- // If we are migrating the first screen, do not touch the first row.
- int startY = (FeatureFlags.QSB_ON_FIRST_SCREEN && screenId == Workspace.FIRST_SCREEN_ID)
- ? 1 : 0;
-
- ArrayList<DbEntry> items = loadWorkspaceEntries(screenId);
-
- int removedCol = Integer.MAX_VALUE;
- int removedRow = Integer.MAX_VALUE;
-
- // removeWt represents the cost function for loss of items during migration, and moveWt
- // represents the cost function for repositioning the items. moveWt is only considered if
- // removeWt is same for two different configurations.
- // Start with Float.MAX_VALUE (assuming full data) and pick the configuration with least
- // cost.
- float removeWt = Float.MAX_VALUE;
- float moveWt = Float.MAX_VALUE;
- float[] outLoss = new float[2];
- ArrayList<DbEntry> finalItems = null;
-
- // Try removing all possible combinations
- for (int x = 0; x < mSrcX; x++) {
- // Try removing the rows first from bottom. This keeps the workspace
- // nicely aligned with hotseat.
- for (int y = mSrcY - 1; y >= startY; y--) {
- // Use a deep copy when trying out a particular combination as it can change
- // the underlying object.
- ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items),
- outLoss);
-
- if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1]
- < moveWt))) {
- removeWt = outLoss[0];
- moveWt = outLoss[1];
- removedCol = mShouldRemoveX ? x : removedCol;
- removedRow = mShouldRemoveY ? y : removedRow;
- finalItems = itemsOnScreen;
- }
-
- // No need to loop over all rows, if a row removal is not needed.
- if (!mShouldRemoveY) {
- break;
- }
- }
-
- if (!mShouldRemoveX) {
- break;
- }
- }
-
- if (DEBUG) {
- Log.d(TAG, String.format("Removing row %d, column %d on screen %d",
- removedRow, removedCol, screenId));
- }
-
- IntSparseArrayMap<DbEntry> itemMap = new IntSparseArrayMap<>();
- for (DbEntry e : deepCopy(items)) {
- itemMap.put(e.id, e);
- }
-
- for (DbEntry item : finalItems) {
- DbEntry org = itemMap.get(item.id);
- itemMap.remove(item.id);
-
- // Check if update is required
- if (!item.columnsSame(org)) {
- update(item);
- }
- }
-
- // The remaining items in {@link #itemMap} are those which didn't get placed.
- for (DbEntry item : itemMap) {
- mCarryOver.add(item);
- }
-
- if (!mCarryOver.isEmpty() && removeWt == 0) {
- // No new items were removed in this step. Try placing all the items on this screen.
- GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
- occupied.markCells(0, 0, mTrgX, startY, true);
- for (DbEntry item : finalItems) {
- occupied.markCells(item, true);
- }
-
- OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied,
- deepCopy(mCarryOver), startY, true);
- placement.find();
- if (placement.lowestWeightLoss == 0) {
- // All items got placed
-
- for (DbEntry item : placement.finalPlacedItems) {
- item.screenId = screenId;
- update(item);
- }
-
- mCarryOver.clear();
- }
- }
- }
-
- /**
- * Updates an item in the DB.
- */
- protected void update(DbEntry item) {
- ContentValues values = new ContentValues();
- item.addToContentValues(values);
- mUpdateOperations.put(item.id, values);
- }
-
- /**
- * Tries the remove the provided row and column.
- *
- * @param items all the items on the screen under operation
- * @param outLoss array of size 2. The first entry is filled with weight loss, and the second
- * with the overall item movement.
- */
- private ArrayList<DbEntry> tryRemove(int col, int row, int startY,
- ArrayList<DbEntry> items, float[] outLoss) {
- GridOccupancy occupied = new GridOccupancy(mTrgX, mTrgY);
- occupied.markCells(0, 0, mTrgX, startY, true);
-
- col = mShouldRemoveX ? col : Integer.MAX_VALUE;
- row = mShouldRemoveY ? row : Integer.MAX_VALUE;
-
- ArrayList<DbEntry> finalItems = new ArrayList<>();
- ArrayList<DbEntry> removedItems = new ArrayList<>();
-
- for (DbEntry item : items) {
- if ((item.cellX <= col && (item.spanX + item.cellX) > col)
- || (item.cellY <= row && (item.spanY + item.cellY) > row)) {
- removedItems.add(item);
- if (item.cellX >= col) item.cellX--;
- if (item.cellY >= row) item.cellY--;
- } else {
- if (item.cellX > col) item.cellX--;
- if (item.cellY > row) item.cellY--;
- finalItems.add(item);
- occupied.markCells(item, true);
- }
- }
-
- OptimalPlacementSolution placement =
- new OptimalPlacementSolution(occupied, removedItems, startY);
- placement.find();
- finalItems.addAll(placement.finalPlacedItems);
- outLoss[0] = placement.lowestWeightLoss;
- outLoss[1] = placement.lowestMoveCost;
- return finalItems;
- }
-
- private class OptimalPlacementSolution {
- private final ArrayList<DbEntry> itemsToPlace;
- private final GridOccupancy occupied;
-
- // If set to true, item movement are not considered in move cost, leading to a more
- // linear placement.
- private final boolean ignoreMove;
-
- // The first row in the grid from where the placement should start.
- private final int startY;
-
- float lowestWeightLoss = Float.MAX_VALUE;
- float lowestMoveCost = Float.MAX_VALUE;
- ArrayList<DbEntry> finalPlacedItems;
-
- public OptimalPlacementSolution(
- GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace, int startY) {
- this(occupied, itemsToPlace, startY, false);
- }
-
- public OptimalPlacementSolution(GridOccupancy occupied, ArrayList<DbEntry> itemsToPlace,
- int startY, boolean ignoreMove) {
- this.occupied = occupied;
- this.itemsToPlace = itemsToPlace;
- this.ignoreMove = ignoreMove;
- this.startY = startY;
-
- // Sort the items such that larger widgets appear first followed by 1x1 items
- Collections.sort(this.itemsToPlace);
- }
-
- public void find() {
- find(0, 0, 0, new ArrayList<DbEntry>());
- }
-
- /**
- * Recursively finds a placement for the provided items.
- *
- * @param index the position in {@link #itemsToPlace} to start looking at.
- * @param weightLoss total weight loss upto this point
- * @param moveCost total move cost upto this point
- * @param itemsPlaced all the items already placed upto this point
- */
- public void find(int index, float weightLoss, float moveCost,
- ArrayList<DbEntry> itemsPlaced) {
- if ((weightLoss >= lowestWeightLoss) ||
- ((weightLoss == lowestWeightLoss) && (moveCost >= lowestMoveCost))) {
- // Abort, as we already have a better solution.
- return;
-
- } else if (index >= itemsToPlace.size()) {
- // End loop.
- lowestWeightLoss = weightLoss;
- lowestMoveCost = moveCost;
-
- // Keep a deep copy of current configuration as it can change during recursion.
- finalPlacedItems = deepCopy(itemsPlaced);
- return;
- }
-
- DbEntry me = itemsToPlace.get(index);
- int myX = me.cellX;
- int myY = me.cellY;
-
- // List of items to pass over if this item was placed.
- ArrayList<DbEntry> itemsIncludingMe = new ArrayList<>(itemsPlaced.size() + 1);
- itemsIncludingMe.addAll(itemsPlaced);
- itemsIncludingMe.add(me);
-
- if (me.spanX > 1 || me.spanY > 1) {
- // If the current item is a widget (and it greater than 1x1), try to place it at
- // all possible positions. This is because a widget placed at one position can
- // affect the placement of a different widget.
- int myW = me.spanX;
- int myH = me.spanY;
-
- for (int y = startY; y < mTrgY; y++) {
- for (int x = 0; x < mTrgX; x++) {
- float newMoveCost = moveCost;
- if (x != myX) {
- me.cellX = x;
- newMoveCost++;
- }
- if (y != myY) {
- me.cellY = y;
- newMoveCost++;
- }
- if (ignoreMove) {
- newMoveCost = moveCost;
- }
-
- if (occupied.isRegionVacant(x, y, myW, myH)) {
- // place at this position and continue search.
- occupied.markCells(me, true);
- find(index + 1, weightLoss, newMoveCost, itemsIncludingMe);
- occupied.markCells(me, false);
- }
-
- // Try resizing horizontally
- if (myW > me.minSpanX && occupied.isRegionVacant(x, y, myW - 1, myH)) {
- me.spanX--;
- occupied.markCells(me, true);
- // 1 extra move cost
- find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe);
- occupied.markCells(me, false);
- me.spanX++;
- }
-
- // Try resizing vertically
- if (myH > me.minSpanY && occupied.isRegionVacant(x, y, myW, myH - 1)) {
- me.spanY--;
- occupied.markCells(me, true);
- // 1 extra move cost
- find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe);
- occupied.markCells(me, false);
- me.spanY++;
- }
-
- // Try resizing horizontally & vertically
- if (myH > me.minSpanY && myW > me.minSpanX &&
- occupied.isRegionVacant(x, y, myW - 1, myH - 1)) {
- me.spanX--;
- me.spanY--;
- occupied.markCells(me, true);
- // 2 extra move cost
- find(index + 1, weightLoss, newMoveCost + 2, itemsIncludingMe);
- occupied.markCells(me, false);
- me.spanX++;
- me.spanY++;
- }
- me.cellX = myX;
- me.cellY = myY;
- }
- }
-
- // Finally also try a solution when this item is not included. Trying it in the end
- // causes it to get skipped in most cases due to higher weight loss, and prevents
- // unnecessary deep copies of various configurations.
- find(index + 1, weightLoss + me.weight, moveCost, itemsPlaced);
- } else {
- // Since this is a 1x1 item and all the following items are also 1x1, just place
- // it at 'the most appropriate position' and hope for the best.
- // The most appropriate position: one with lease straight line distance
- int newDistance = Integer.MAX_VALUE;
- int newX = Integer.MAX_VALUE, newY = Integer.MAX_VALUE;
-
- for (int y = startY; y < mTrgY; y++) {
- for (int x = 0; x < mTrgX; x++) {
- if (!occupied.cells[x][y]) {
- int dist = ignoreMove ? 0 :
- ((me.cellX - x) * (me.cellX - x) + (me.cellY - y) * (me.cellY
- - y));
- if (dist < newDistance) {
- newX = x;
- newY = y;
- newDistance = dist;
- }
- }
- }
- }
-
- if (newX < mTrgX && newY < mTrgY) {
- float newMoveCost = moveCost;
- if (newX != myX) {
- me.cellX = newX;
- newMoveCost++;
- }
- if (newY != myY) {
- me.cellY = newY;
- newMoveCost++;
- }
- if (ignoreMove) {
- newMoveCost = moveCost;
- }
- occupied.markCells(me, true);
- find(index + 1, weightLoss, newMoveCost, itemsIncludingMe);
- occupied.markCells(me, false);
- me.cellX = myX;
- me.cellY = myY;
-
- // Try to find a solution without this item, only if
- // 1) there was at least one space, i.e., we were able to place this item
- // 2) if the next item has the same weight (all items are already sorted), as
- // if it has lower weight, that solution will automatically get discarded.
- // 3) ignoreMove false otherwise, move cost is ignored and the weight will
- // anyway be same.
- if (index + 1 < itemsToPlace.size()
- && itemsToPlace.get(index + 1).weight >= me.weight && !ignoreMove) {
- find(index + 1, weightLoss + me.weight, moveCost, itemsPlaced);
- }
- } else {
- // No more space. Jump to the end.
- for (int i = index + 1; i < itemsToPlace.size(); i++) {
- weightLoss += itemsToPlace.get(i).weight;
- }
- find(itemsToPlace.size(), weightLoss + me.weight, moveCost, itemsPlaced);
- }
- }
- }
- }
-
- private ArrayList<DbEntry> loadHotseatEntries() {
- Cursor c = queryWorkspace(
- new String[]{
- Favorites._ID, // 0
- Favorites.ITEM_TYPE, // 1
- Favorites.INTENT, // 2
- Favorites.SCREEN}, // 3
- Favorites.CONTAINER + " = " + Favorites.CONTAINER_HOTSEAT);
-
- final int indexId = c.getColumnIndexOrThrow(Favorites._ID);
- final int indexItemType = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE);
- final int indexIntent = c.getColumnIndexOrThrow(Favorites.INTENT);
- final int indexScreen = c.getColumnIndexOrThrow(Favorites.SCREEN);
-
- ArrayList<DbEntry> entries = new ArrayList<>();
- while (c.moveToNext()) {
- DbEntry entry = new DbEntry();
- entry.id = c.getInt(indexId);
- entry.itemType = c.getInt(indexItemType);
- entry.screenId = c.getInt(indexScreen);
-
- if (entry.screenId >= mSrcHotseatSize) {
- mEntryToRemove.add(entry.id);
- continue;
- }
-
- try {
- // calculate weight
- switch (entry.itemType) {
- case Favorites.ITEM_TYPE_SHORTCUT:
- case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- case Favorites.ITEM_TYPE_APPLICATION: {
- verifyIntent(c.getString(indexIntent));
- entry.weight = entry.itemType == Favorites.ITEM_TYPE_APPLICATION ?
- WT_APPLICATION : WT_SHORTCUT;
- break;
- }
- case Favorites.ITEM_TYPE_FOLDER: {
- int total = getFolderItemsCount(entry.id);
- if (total == 0) {
- throw new Exception("Folder is empty");
- }
- entry.weight = WT_FOLDER_FACTOR * total;
- break;
- }
- default:
- throw new Exception("Invalid item type");
- }
- } catch (Exception e) {
- if (DEBUG) {
- Log.d(TAG, "Removing item " + entry.id, e);
- }
- mEntryToRemove.add(entry.id);
- continue;
- }
- entries.add(entry);
- }
- c.close();
- return entries;
- }
-
-
- /**
- * Loads entries for a particular screen id.
- */
- protected ArrayList<DbEntry> loadWorkspaceEntries(int screen) {
- Cursor c = queryWorkspace(
- new String[]{
- Favorites._ID, // 0
- Favorites.ITEM_TYPE, // 1
- Favorites.CELLX, // 2
- Favorites.CELLY, // 3
- Favorites.SPANX, // 4
- Favorites.SPANY, // 5
- Favorites.INTENT, // 6
- Favorites.APPWIDGET_PROVIDER, // 7
- Favorites.APPWIDGET_ID}, // 8
- Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP
- + " AND " + Favorites.SCREEN + " = " + screen);
-
- final int indexId = c.getColumnIndexOrThrow(Favorites._ID);
- final int indexItemType = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE);
- final int indexCellX = c.getColumnIndexOrThrow(Favorites.CELLX);
- final int indexCellY = c.getColumnIndexOrThrow(Favorites.CELLY);
- final int indexSpanX = c.getColumnIndexOrThrow(Favorites.SPANX);
- final int indexSpanY = c.getColumnIndexOrThrow(Favorites.SPANY);
- final int indexIntent = c.getColumnIndexOrThrow(Favorites.INTENT);
- final int indexAppWidgetProvider = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER);
- final int indexAppWidgetId = c.getColumnIndexOrThrow(Favorites.APPWIDGET_ID);
-
- ArrayList<DbEntry> entries = new ArrayList<>();
- WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(mContext);
- while (c.moveToNext()) {
- DbEntry entry = new DbEntry();
- entry.id = c.getInt(indexId);
- entry.itemType = c.getInt(indexItemType);
- entry.cellX = c.getInt(indexCellX);
- entry.cellY = c.getInt(indexCellY);
- entry.spanX = c.getInt(indexSpanX);
- entry.spanY = c.getInt(indexSpanY);
- entry.screenId = screen;
-
- try {
- // calculate weight
- switch (entry.itemType) {
- case Favorites.ITEM_TYPE_SHORTCUT:
- case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- case Favorites.ITEM_TYPE_APPLICATION: {
- verifyIntent(c.getString(indexIntent));
- entry.weight = entry.itemType == Favorites.ITEM_TYPE_APPLICATION ?
- WT_APPLICATION : WT_SHORTCUT;
- break;
- }
- case Favorites.ITEM_TYPE_APPWIDGET: {
- String provider = c.getString(indexAppWidgetProvider);
- ComponentName cn = ComponentName.unflattenFromString(provider);
- verifyPackage(cn.getPackageName());
- entry.weight = Math.max(WT_WIDGET_MIN, WT_WIDGET_FACTOR
- * entry.spanX * entry.spanY);
-
- int widgetId = c.getInt(indexAppWidgetId);
- LauncherAppWidgetProviderInfo pInfo =
- widgetManagerHelper.getLauncherAppWidgetInfo(widgetId);
- Point spans = null;
- if (pInfo != null) {
- spans = pInfo.getMinSpans();
- }
- if (spans != null) {
- entry.minSpanX = spans.x > 0 ? spans.x : entry.spanX;
- entry.minSpanY = spans.y > 0 ? spans.y : entry.spanY;
- } else {
- // Assume that the widget be resized down to 2x2
- entry.minSpanX = entry.minSpanY = 2;
- }
-
- if (entry.minSpanX > mTrgX || entry.minSpanY > mTrgY) {
- throw new Exception("Widget can't be resized down to fit the grid");
- }
- break;
- }
- case Favorites.ITEM_TYPE_FOLDER: {
- int total = getFolderItemsCount(entry.id);
- if (total == 0) {
- throw new Exception("Folder is empty");
- }
- entry.weight = WT_FOLDER_FACTOR * total;
- break;
- }
- default:
- throw new Exception("Invalid item type");
- }
- } catch (Exception e) {
- if (DEBUG) {
- Log.d(TAG, "Removing item " + entry.id, e);
- }
- mEntryToRemove.add(entry.id);
- continue;
- }
- entries.add(entry);
- }
- c.close();
- return entries;
- }
-
- /**
- * @return the number of valid items in the folder.
- */
- private int getFolderItemsCount(int folderId) {
- Cursor c = queryWorkspace(
- new String[]{Favorites._ID, Favorites.INTENT},
- Favorites.CONTAINER + " = " + folderId);
-
- int total = 0;
- while (c.moveToNext()) {
- try {
- verifyIntent(c.getString(1));
- total++;
- } catch (Exception e) {
- mEntryToRemove.add(c.getInt(0));
- }
- }
- c.close();
- return total;
- }
-
- protected Cursor queryWorkspace(String[] columns, String where) {
- return mDb.query(mTableName, columns, where, null, null, null, null);
- }
-
- /**
- * Verifies if the intent should be restored.
- */
- private void verifyIntent(String intentStr) throws Exception {
- Intent intent = Intent.parseUri(intentStr, 0);
- if (intent.getComponent() != null) {
- verifyPackage(intent.getComponent().getPackageName());
- } else if (intent.getPackage() != null) {
- // Only verify package if the component was null.
- verifyPackage(intent.getPackage());
- }
- }
-
- /**
- * Verifies if the package should be restored
- */
- private void verifyPackage(String packageName) throws Exception {
- if (!mValidPackages.contains(packageName)) {
- throw new Exception("Package not available");
- }
- }
-
- protected static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
-
- public float weight;
-
- public DbEntry() {
- }
-
- public DbEntry copy() {
- DbEntry entry = new DbEntry();
- entry.copyFrom(this);
- entry.weight = weight;
- entry.minSpanX = minSpanX;
- entry.minSpanY = minSpanY;
- return entry;
- }
-
- /**
- * Comparator such that larger widgets come first, followed by all 1x1 items
- * based on their weights.
- */
- @Override
- public int compareTo(DbEntry another) {
- if (itemType == Favorites.ITEM_TYPE_APPWIDGET) {
- if (another.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
- return another.spanY * another.spanX - spanX * spanY;
- } else {
- return -1;
- }
- } else if (another.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
- return 1;
- } else {
- // Place higher weight before lower weight.
- return Float.compare(another.weight, weight);
- }
- }
-
- public boolean columnsSame(DbEntry org) {
- return org.cellX == cellX && org.cellY == cellY && org.spanX == spanX &&
- org.spanY == spanY && org.screenId == screenId;
- }
-
- public void addToContentValues(ContentValues values) {
- values.put(Favorites.SCREEN, screenId);
- values.put(Favorites.CELLX, cellX);
- values.put(Favorites.CELLY, cellY);
- values.put(Favorites.SPANX, spanX);
- values.put(Favorites.SPANY, spanY);
- }
- }
-
- private static ArrayList<DbEntry> deepCopy(ArrayList<DbEntry> src) {
- ArrayList<DbEntry> dup = new ArrayList<>(src.size());
- for (DbEntry e : src) {
- dup.add(e.copy());
- }
- return dup;
- }
-
- public static void markForMigration(
- Context context, int gridX, int gridY, int hotseatSize) {
- Utilities.getPrefs(context).edit()
- .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, getPointString(gridX, gridY))
- .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, hotseatSize)
- .apply();
- }
-
- /**
- * Check given a new IDP, if migration is necessary.
- */
- public static boolean needsToMigrate(Context context, InvariantDeviceProfile idp) {
- SharedPreferences prefs = Utilities.getPrefs(context);
- String gridSizeString = getPointString(idp.numColumns, idp.numRows);
-
- return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, ""))
- || idp.numDatabaseHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1);
- }
-
- /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
- public static boolean migrateGridIfNeeded(Context context) {
- if (context instanceof LauncherPreviewRenderer.PreviewContext) {
- return true;
- }
- return migrateGridIfNeeded(context, null);
- }
-
- /**
- * Run the migration algorithm if needed. For preview, we provide the intended idp because it
- * has not been changed. If idp is null, we read it from the context, for actual grid migration.
- *
- * @return false if the migration failed.
- */
- public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) {
- boolean migrateForPreview = idp != null;
- if (!migrateForPreview) {
- idp = LauncherAppState.getIDP(context);
- }
-
- if (!needsToMigrate(context, idp)) {
- return true;
- }
-
- SharedPreferences prefs = Utilities.getPrefs(context);
- String gridSizeString = getPointString(idp.numColumns, idp.numRows);
- long migrationStartTime = SystemClock.elapsedRealtime();
- try (SQLiteTransaction transaction = (SQLiteTransaction) Settings.call(
- context.getContentResolver(), Settings.METHOD_NEW_TRANSACTION)
- .getBinder(Settings.EXTRA_VALUE)) {
-
- int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
- idp.numDatabaseHotseatIcons);
- Point sourceSize = parsePoint(prefs.getString(
- KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString));
-
- boolean dbChanged = false;
- if (migrateForPreview) {
- copyTable(transaction.getDb(), Favorites.TABLE_NAME, transaction.getDb(),
- Favorites.PREVIEW_TABLE_NAME, context);
- }
-
- GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb(),
- srcHotseatCount, sourceSize.x, sourceSize.y);
- if (migrateForPreview ? backupTable.restoreToPreviewIfBackupExists()
- : backupTable.backupOrRestoreAsNeeded()) {
- dbChanged = true;
- srcHotseatCount = backupTable.getRestoreHotseatAndGridSize(sourceSize);
- }
-
- HashSet<String> validPackages = getValidPackages(context);
- // Hotseat.
- if (srcHotseatCount != idp.numDatabaseHotseatIcons
- && new GridSizeMigrationTask(context, transaction.getDb(), validPackages,
- migrateForPreview, srcHotseatCount,
- idp.numDatabaseHotseatIcons).migrateHotseat()) {
- dbChanged = true;
- }
-
- // Grid size
- Point targetSize = new Point(idp.numColumns, idp.numRows);
- if (new MultiStepMigrationTask(validPackages, context, transaction.getDb(),
- migrateForPreview).migrate(sourceSize, targetSize)) {
- dbChanged = true;
- }
-
- if (dbChanged) {
- // Make sure we haven't removed everything.
- final Cursor c = context.getContentResolver().query(
- migrateForPreview ? Favorites.PREVIEW_CONTENT_URI : Favorites.CONTENT_URI,
- null, null, null, null);
- boolean hasData = c.moveToNext();
- c.close();
- if (!hasData) {
- throw new Exception("Removed every thing during grid resize");
- }
- }
-
- transaction.commit();
- if (!migrateForPreview) {
- Settings.call(context.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE);
- }
- return true;
- } catch (Exception e) {
- Log.e(TAG, "Error during preview grid migration", e);
-
- return false;
- } finally {
- Log.v(TAG, "Preview workspace migration completed in "
- + (SystemClock.elapsedRealtime() - migrationStartTime));
-
- if (!migrateForPreview) {
- // Save current configuration, so that the migration does not run again.
- prefs.edit()
- .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
- .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numDatabaseHotseatIcons)
- .apply();
- }
- }
- }
-
- protected static HashSet<String> getValidPackages(Context context) {
- // Initialize list of valid packages. This contain all the packages which are already on
- // the device and packages which are being installed. Any item which doesn't belong to
- // this set is removed.
- // Since the loader removes such items anyway, removing these items here doesn't cause
- // any extra data loss and gives us more free space on the grid for better migration.
- HashSet<String> validPackages = new HashSet<>();
- for (PackageInfo info : context.getPackageManager()
- .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
- validPackages.add(info.packageName);
- }
- InstallSessionHelper.INSTANCE.get(context)
- .getActiveSessions().keySet()
- .forEach(packageUserKey -> validPackages.add(packageUserKey.mPackageName));
- return validPackages;
- }
-
- /**
- * Removes any broken item from the hotseat.
- *
- * @return a map with occupied hotseat position set to non-null value.
- */
- public static IntSparseArrayMap<Object> removeBrokenHotseatItems(Context context)
- throws Exception {
- try (SQLiteTransaction transaction = (SQLiteTransaction) Settings.call(
- context.getContentResolver(), Settings.METHOD_NEW_TRANSACTION)
- .getBinder(Settings.EXTRA_VALUE)) {
- GridSizeMigrationTask task = new GridSizeMigrationTask(
- context, transaction.getDb(), getValidPackages(context),
- false /* usePreviewTable */, Integer.MAX_VALUE, Integer.MAX_VALUE);
-
- // Load all the valid entries
- ArrayList<DbEntry> items = task.loadHotseatEntries();
- // Delete any entry marked for deletion by above load.
- task.applyOperations();
- IntSparseArrayMap<Object> positions = new IntSparseArrayMap<>();
- for (DbEntry item : items) {
- positions.put(item.screenId, item);
- }
- transaction.commit();
- return positions;
- }
- }
-
- /**
- * Task to run grid migration in multiple steps when the size difference is more than 1.
- */
- protected static class MultiStepMigrationTask {
- private final HashSet<String> mValidPackages;
- private final Context mContext;
- private final SQLiteDatabase mDb;
- private final boolean mUsePreviewTable;
-
- public MultiStepMigrationTask(HashSet<String> validPackages, Context context,
- SQLiteDatabase db, boolean usePreviewTable) {
- mValidPackages = validPackages;
- mContext = context;
- mDb = db;
- mUsePreviewTable = usePreviewTable;
- }
-
- public boolean migrate(Point sourceSize, Point targetSize) throws Exception {
- boolean dbChanged = false;
- if (!targetSize.equals(sourceSize)) {
- if (sourceSize.x < targetSize.x) {
- // Source is smaller that target, just expand the grid without actual migration.
- sourceSize.x = targetSize.x;
- }
- if (sourceSize.y < targetSize.y) {
- // Source is smaller that target, just expand the grid without actual migration.
- sourceSize.y = targetSize.y;
- }
-
- // Migrate the workspace grid, such that the points differ by max 1 in x and y
- // each on every step.
- while (!targetSize.equals(sourceSize)) {
- // Get the next size, such that the points differ by max 1 in x and y each
- Point nextSize = new Point(sourceSize);
- if (targetSize.x < nextSize.x) {
- nextSize.x--;
- }
- if (targetSize.y < nextSize.y) {
- nextSize.y--;
- }
- if (runStepTask(sourceSize, nextSize)) {
- dbChanged = true;
- }
- sourceSize.set(nextSize.x, nextSize.y);
- }
- }
- return dbChanged;
- }
-
- protected boolean runStepTask(Point sourceSize, Point nextSize) throws Exception {
- return new GridSizeMigrationTask(mContext, mDb, mValidPackages, mUsePreviewTable,
- sourceSize, nextSize).migrateWorkspace();
- }
- }
-}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index 3935bcf..e64b25c 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -16,9 +16,6 @@
package com.android.launcher3.model;
-import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_HOTSEAT_COUNT;
-import static com.android.launcher3.InvariantDeviceProfile.KEY_MIGRATION_SRC_WORKSPACE_SIZE;
-import static com.android.launcher3.Utilities.getPointString;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.content.ComponentName;
@@ -107,11 +104,7 @@
* Check given a new IDP, if migration is necessary.
*/
public static boolean needsToMigrate(Context context, InvariantDeviceProfile idp) {
- SharedPreferences prefs = Utilities.getPrefs(context);
- String gridSizeString = getPointString(idp.numColumns, idp.numRows);
-
- return !gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, ""))
- || idp.numDatabaseHotseatIcons != prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, -1);
+ return !new DeviceGridState(idp).equals(new DeviceGridState(context));
}
/** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */
@@ -124,15 +117,15 @@
/**
* When migrating the grid for preview, we copy the table
- * {@link LauncherSettings.Favorites.TABLE_NAME} into
- * {@link LauncherSettings.Favorites.PREVIEW_TABLE_NAME}, run grid size migration from the
+ * {@link LauncherSettings.Favorites#TABLE_NAME} into
+ * {@link LauncherSettings.Favorites#PREVIEW_TABLE_NAME}, run grid size migration from the
* former to the later, then use the later table for preview.
*
* Similarly when doing the actual grid migration, the former grid option's table
- * {@link LauncherSettings.Favorites.TABLE_NAME} is copied into the new grid option's
- * {@link LauncherSettings.Favorites.TMP_TABLE}, we then run the grid size migration algorithm
+ * {@link LauncherSettings.Favorites#TABLE_NAME} is copied into the new grid option's
+ * {@link LauncherSettings.Favorites#TMP_TABLE}, we then run the grid size migration algorithm
* to migrate the later to the former, and load the workspace from the default
- * {@link LauncherSettings.Favorites.TABLE_NAME}.
+ * {@link LauncherSettings.Favorites#TABLE_NAME}.
*
* @return false if the migration failed.
*/
@@ -147,10 +140,7 @@
}
SharedPreferences prefs = Utilities.getPrefs(context);
- String gridSizeString = getPointString(idp.numColumns, idp.numRows);
HashSet<String> validPackages = getValidPackages(context);
- int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
- idp.numDatabaseHotseatIcons);
if (migrateForPreview) {
if (!LauncherSettings.Settings.call(
@@ -175,11 +165,11 @@
DbReader srcReader = new DbReader(t.getDb(),
migrateForPreview ? LauncherSettings.Favorites.TABLE_NAME
: LauncherSettings.Favorites.TMP_TABLE,
- context, validPackages, srcHotseatCount);
+ context, validPackages);
DbReader destReader = new DbReader(t.getDb(),
migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME
: LauncherSettings.Favorites.TABLE_NAME,
- context, validPackages, idp.numDatabaseHotseatIcons);
+ context, validPackages);
Point targetSize = new Point(idp.numColumns, idp.numRows);
GridSizeMigrationTaskV2 task = new GridSizeMigrationTaskV2(context, t.getDb(),
@@ -202,10 +192,7 @@
if (!migrateForPreview) {
// Save current configuration, so that the migration does not run again.
- prefs.edit()
- .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
- .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numDatabaseHotseatIcons)
- .apply();
+ new DeviceGridState(idp).writeToPrefs(context);
}
}
}
@@ -504,7 +491,6 @@
private final String mTableName;
private final Context mContext;
private final HashSet<String> mValidPackages;
- private final int mHotseatSize;
private int mLastScreenId = -1;
private final ArrayList<DbEntry> mHotseatEntries = new ArrayList<>();
@@ -513,12 +499,11 @@
new ArrayMap<>();
DbReader(SQLiteDatabase db, String tableName, Context context,
- HashSet<String> validPackages, int hotseatSize) {
+ HashSet<String> validPackages) {
mDb = db;
mTableName = tableName;
mContext = context;
mValidPackages = validPackages;
- mHotseatSize = hotseatSize;
}
protected ArrayList<DbEntry> loadHotseatEntries() {
@@ -543,11 +528,6 @@
entry.itemType = c.getInt(indexItemType);
entry.screenId = c.getInt(indexScreen);
- if (entry.screenId >= mHotseatSize) {
- entriesToRemove.add(entry.id);
- continue;
- }
-
try {
// calculate weight
switch (entry.itemType) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 31ca6e7..41a760b 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -16,7 +16,7 @@
package com.android.launcher3.model;
-import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
+import static com.android.launcher3.WorkspaceLayoutManager.LEFT_PANEL_ID;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
@@ -79,13 +79,13 @@
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.provider.ImportDataTask;
import com.android.launcher3.qsb.QsbContainerView;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IOUtils;
+import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.LooperIdleLock;
import com.android.launcher3.util.PackageManagerHelper;
@@ -175,11 +175,17 @@
private void sendFirstScreenActiveInstallsBroadcast() {
ArrayList<ItemInfo> firstScreenItems = new ArrayList<>();
ArrayList<ItemInfo> allItems = mBgDataModel.getAllWorkspaceItems();
- // Screen set is never empty
- final int firstScreen = mBgDataModel.collectWorkspaceScreens().get(0);
- // TODO(b/185515153): support two panel home.
- filterCurrentWorkspaceItems(IntSet.wrap(firstScreen), allItems, firstScreenItems,
+ // Screen set is never empty
+ IntArray allScreens = mBgDataModel.collectWorkspaceScreens();
+ final int firstScreen = allScreens.get(0);
+
+ IntSet firstScreens = IntSet.wrap(firstScreen);
+ if (firstScreen == LEFT_PANEL_ID && allScreens.size() >= 2) {
+ firstScreens.add(allScreens.get(1));
+ }
+
+ filterCurrentWorkspaceItems(firstScreens, allItems, firstScreenItems,
new ArrayList<>() /* otherScreenItems are ignored */);
mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
}
@@ -326,16 +332,7 @@
final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context);
boolean clearDb = false;
- try {
- ImportDataTask.performImportIfPossible(context);
- } catch (Exception e) {
- // Migration failed. Clear workspace.
- clearDb = true;
- }
-
- if (!clearDb && (MULTI_DB_GRID_MIRATION_ALGO.get()
- ? !GridSizeMigrationTaskV2.migrateGridIfNeeded(context)
- : !GridSizeMigrationTask.migrateGridIfNeeded(context))) {
+ if (!GridSizeMigrationTaskV2.migrateGridIfNeeded(context)) {
// Migration failed. Clear workspace.
clearDb = true;
}
@@ -762,16 +759,13 @@
if (widgetProviderInfo != null
&& (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
|| appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
- logDeleteWidgetInfo(mApp.getInvariantDeviceProfile(),
- widgetProviderInfo);
-
- // This can happen when display size changes.
- c.markDeleted("Widget removed, min sizes not met: "
- + "span=" + appWidgetInfo.spanX + "x"
- + appWidgetInfo.spanY + " minSpan="
+ FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
+ + " minSizes not meet: span=" + appWidgetInfo.spanX
+ + "x" + appWidgetInfo.spanY + " minSpan="
+ widgetProviderInfo.minSpanX + "x"
+ widgetProviderInfo.minSpanY);
- continue;
+ logWidgetInfo(mApp.getInvariantDeviceProfile(),
+ widgetProviderInfo);
}
if (!c.isOnWorkspaceOrHotseat()) {
c.markDeleted("Widget found where container != " +
@@ -992,10 +986,8 @@
}
@SuppressLint("NewApi") // Already added API check.
- private static void logDeleteWidgetInfo(InvariantDeviceProfile idp,
+ private static void logWidgetInfo(InvariantDeviceProfile idp,
LauncherAppWidgetProviderInfo widgetProviderInfo) {
- FileLog.d(TAG, "Deleting " + widgetProviderInfo.getComponent()
- + " due to min size constraint");
Point cellSize = new Point();
for (DeviceProfile deviceProfile : idp.supportedProfiles) {
deviceProfile.getCellSize(cellSize);
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 55edfd4..0439e75 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -121,13 +121,6 @@
}
}
- /**
- * Sets the value that indicates if left widget panel is shown or not.
- */
- public void setLeftPanelShown(boolean value) {
- mBgDataModel.isLeftPanelShown = value;
- }
-
private void checkItemInfoLocked(int itemId, ItemInfo item, StackTraceElement[] stackTrace) {
ItemInfo modelItem = mBgDataModel.itemsIdMap.get(itemId);
if (modelItem != null && item != modelItem) {
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index a534ee3..3bb49f5 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -33,7 +33,6 @@
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
@@ -50,7 +49,6 @@
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
@@ -69,7 +67,6 @@
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
/**
@@ -126,11 +123,8 @@
private Runnable mOnCloseCallback = () -> { };
// The rect string of the view that the arrow is attached to, in screen reference frame.
- protected String mArrowColorRectString;
private int mArrowColor;
- protected final HashMap<String, View> mViewForRect = new HashMap<>();
-
- @Nullable protected LocalColorExtractor mColorExtractor;
+ protected final List<LocalColorExtractor> mColorExtractors;
private final float mElevation;
private final int mBackgroundColor;
@@ -178,7 +172,9 @@
boolean isAboveAnotherSurface = getTopOpenViewWithType(mLauncher, TYPE_FOLDER) != null
|| mLauncher.getStateManager().getState() == LauncherState.ALL_APPS;
if (!isAboveAnotherSurface && Utilities.ATLEAST_S && ENABLE_LOCAL_COLOR_POPUPS.get()) {
- setupColorExtraction();
+ mColorExtractors = new ArrayList<>();
+ } else {
+ mColorExtractors = null;
}
if (isAboveAnotherSurface) {
@@ -323,37 +319,6 @@
return colors.get(index, mBackgroundColor);
}
- @TargetApi(Build.VERSION_CODES.S)
- private void setupColorExtraction() {
- Workspace workspace = mLauncher.findViewById(R.id.workspace);
- if (workspace == null) {
- return;
- }
-
- mColorExtractor = LocalColorExtractor.newInstance(mLauncher);
- mColorExtractor.setListener((rect, extractedColors) -> {
- String rectString = rect.toShortString();
- View v = mViewForRect.get(rectString);
- AnimatorSet colors = new AnimatorSet();
- if (v != null) {
- int newColor = getExtractedColor(extractedColors);
- setChildColor(v, newColor, colors);
- int numChildren = v instanceof ViewGroup ? ((ViewGroup) v).getChildCount() : 0;
- for (int i = 0; i < numChildren; ++i) {
- View childView = ((ViewGroup) v).getChildAt(i);
- setChildColor(childView, newColor, colors);
-
- }
- if (rectString.equals(mArrowColorRectString)) {
- mArrowColor = newColor;
- updateArrowColor();
- }
- }
- colors.setDuration(150);
- v.post(colors::start);
- });
- }
-
protected void addPreDrawForColorExtraction(Launcher launcher) {
getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
@@ -374,40 +339,55 @@
}
private void initColorExtractionLocations(Launcher launcher) {
- if (mColorExtractor == null) {
+ if (mColorExtractors == null) {
return;
}
- ArrayList<RectF> locations = new ArrayList<>();
+ Workspace workspace = launcher.getWorkspace();
+ if (workspace == null) {
+ return;
+ }
boolean firstVisibleChild = true;
+ int screenId = workspace.getScreenIdForPageIndex(workspace.getCurrentPage());
+ DragLayer dragLayer = launcher.getDragLayer();
+
+ final View[] viewAlignedWithArrow = new View[1];
+
// Order matters here, since we need the arrow to match the color of its adjacent view.
- for (View view : getChildrenForColorExtraction()) {
+ for (final View view : getChildrenForColorExtraction()) {
if (view != null && view.getVisibility() == VISIBLE) {
- RectF rf = new RectF();
- mColorExtractor.getExtractedRectForView(launcher,
- launcher.getWorkspace().getCurrentPage(), view, rf);
- if (!rf.isEmpty()) {
- locations.add(rf);
- String rectString = rf.toShortString();
- mViewForRect.put(rectString, view);
- if (mIsAboveIcon) {
- mArrowColorRectString = rectString;
- } else {
- if (firstVisibleChild) {
- mArrowColorRectString = rectString;
+ Rect pos = new Rect();
+ dragLayer.getDescendantRectRelativeToSelf(view, pos);
+ if (!pos.isEmpty()) {
+ LocalColorExtractor extractor = LocalColorExtractor.newInstance(launcher);
+ extractor.setWorkspaceLocation(pos, dragLayer, screenId);
+ extractor.setListener(extractedColors -> {
+ AnimatorSet colors = new AnimatorSet();
+ int newColor = getExtractedColor(extractedColors);
+ setChildColor(view, newColor, colors);
+ int numChildren = view instanceof ViewGroup
+ ? ((ViewGroup) view).getChildCount() : 0;
+ for (int i = 0; i < numChildren; ++i) {
+ View childView = ((ViewGroup) view).getChildAt(i);
+ setChildColor(childView, newColor, colors);
}
- }
+ if (viewAlignedWithArrow[0] == view) {
+ mArrowColor = newColor;
+ updateArrowColor();
+ }
+ colors.setDuration(150);
+ view.post(colors::start);
+ });
+ mColorExtractors.add(extractor);
- if (firstVisibleChild) {
- firstVisibleChild = false;
+ if (mIsAboveIcon || firstVisibleChild) {
+ viewAlignedWithArrow[0] = view;
}
-
+ firstVisibleChild = false;
}
}
}
- if (!locations.isEmpty()) {
- mColorExtractor.addLocation(locations);
- }
+
}
/**
@@ -807,11 +787,8 @@
getPopupContainer().removeView(this);
getPopupContainer().removeView(mArrow);
mOnCloseCallback.run();
- mArrowColorRectString = null;
- mViewForRect.clear();
- if (mColorExtractor != null) {
- mColorExtractor.removeLocations();
- mColorExtractor.setListener(null);
+ if (mColorExtractors != null) {
+ mColorExtractors.forEach(e -> e.setListener(null));
}
}
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java
deleted file mode 100644
index c9af2fe..0000000
--- a/src/com/android/launcher3/provider/ImportDataTask.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.provider;
-
-import static com.android.launcher3.Utilities.getDevicePrefs;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-import android.os.Process;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.SparseBooleanArray;
-
-import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
-import com.android.launcher3.DefaultLayoutParser;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherProvider;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.LauncherSettings.Settings;
-import com.android.launcher3.Workspace;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logging.FileLog;
-import com.android.launcher3.model.GridSizeMigrationTask;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.IntSparseArrayMap;
-import com.android.launcher3.util.PackageManagerHelper;
-
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashSet;
-
-/**
- * Utility class to import data from another Launcher which is based on Launcher3 schema.
- */
-public class ImportDataTask {
-
- public static final String KEY_DATA_IMPORT_SRC_PKG = "data_import_src_pkg";
- public static final String KEY_DATA_IMPORT_SRC_AUTHORITY = "data_import_src_authority";
-
- private static final String TAG = "ImportDataTask";
- private static final int MIN_ITEM_COUNT_FOR_SUCCESSFUL_MIGRATION = 6;
- // Insert items progressively to avoid OOM exception when loading icons.
- private static final int BATCH_INSERT_SIZE = 15;
-
- private final Context mContext;
-
- private final Uri mOtherFavoritesUri;
-
- private int mHotseatSize;
- private int mMaxGridSizeX;
- private int mMaxGridSizeY;
-
- private ImportDataTask(Context context, String sourceAuthority) {
- mContext = context;
- mOtherFavoritesUri = Uri.parse("content://" + sourceAuthority + "/" + Favorites.TABLE_NAME);
- }
-
- public boolean importWorkspace() throws Exception {
- FileLog.d(TAG, "Importing DB from " + mOtherFavoritesUri);
-
- mHotseatSize = mMaxGridSizeX = mMaxGridSizeY = 0;
- importWorkspaceItems();
- GridSizeMigrationTask.markForMigration(mContext, mMaxGridSizeX, mMaxGridSizeY, mHotseatSize);
-
- // Create empty DB flag.
- LauncherSettings.Settings.call(mContext.getContentResolver(),
- LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
- return true;
- }
-
- /**
- * 1) Imports all the workspace entries from the source provider.
- * 2) For home screen entries, maps the screen id based on {@param screenIdMap}
- * 3) In the end fills any holes in hotseat with items from default hotseat layout.
- */
- private void importWorkspaceItems() throws Exception {
- String profileId = Long.toString(UserCache.INSTANCE.get(mContext)
- .getSerialNumberForUser(Process.myUserHandle()));
-
- boolean createEmptyRowOnFirstScreen;
- if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
- try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null,
- // get items on the first row of the first screen (min screen id)
- "profileId = ? AND container = -100 AND cellY = 0 AND screen = " +
- "(SELECT MIN(screen) FROM favorites WHERE container = -100)",
- new String[]{profileId},
- null)) {
- // First row of first screen is not empty
- createEmptyRowOnFirstScreen = c.moveToNext();
- }
- } else {
- createEmptyRowOnFirstScreen = false;
- }
-
- ArrayList<ContentProviderOperation> insertOperations = new ArrayList<>(BATCH_INSERT_SIZE);
-
- // Set of package names present in hotseat
- final HashSet<String> hotseatTargetApps = new HashSet<>();
- int maxId = 0;
-
- // Number of imported items on workspace and hotseat
- int totalItemsOnWorkspace = 0;
-
- try (Cursor c = mContext.getContentResolver()
- .query(mOtherFavoritesUri, null,
- // Only migrate the primary user
- Favorites.PROFILE_ID + " = ?", new String[]{profileId},
- // Get the items sorted by container, so that the folders are loaded
- // before the corresponding items.
- Favorites.CONTAINER + " , " + Favorites.SCREEN)) {
-
- // various columns we expect to exist.
- final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
- final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT);
- final int titleIndex = c.getColumnIndexOrThrow(Favorites.TITLE);
- final int containerIndex = c.getColumnIndexOrThrow(Favorites.CONTAINER);
- final int itemTypeIndex = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE);
- final int widgetProviderIndex = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER);
- final int screenIndex = c.getColumnIndexOrThrow(Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow(Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow(Favorites.CELLY);
- final int spanXIndex = c.getColumnIndexOrThrow(Favorites.SPANX);
- final int spanYIndex = c.getColumnIndexOrThrow(Favorites.SPANY);
- final int rankIndex = c.getColumnIndexOrThrow(Favorites.RANK);
- final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
- final int iconPackageIndex = c.getColumnIndexOrThrow(Favorites.ICON_PACKAGE);
- final int iconResourceIndex = c.getColumnIndexOrThrow(Favorites.ICON_RESOURCE);
-
- SparseBooleanArray mValidFolders = new SparseBooleanArray();
- ContentValues values = new ContentValues();
-
- Integer firstScreenId = null;
- while (c.moveToNext()) {
- values.clear();
- int id = c.getInt(idIndex);
- maxId = Math.max(maxId, id);
- int type = c.getInt(itemTypeIndex);
- int container = c.getInt(containerIndex);
-
- int screen = c.getInt(screenIndex);
-
- int cellX = c.getInt(cellXIndex);
- int cellY = c.getInt(cellYIndex);
- int spanX = c.getInt(spanXIndex);
- int spanY = c.getInt(spanYIndex);
-
- switch (container) {
- case Favorites.CONTAINER_DESKTOP: {
- if (screen < Workspace.FIRST_SCREEN_ID) {
- FileLog.d(TAG, String.format(
- "Skipping item %d, type %d not on a valid screen %d",
- id, type, screen));
- continue;
- }
- if (firstScreenId == null) {
- firstScreenId = screen;
- }
- // Reset the screen to 0-index value
- if (createEmptyRowOnFirstScreen && firstScreenId.equals(screen)) {
- // Shift items by 1.
- cellY++;
- // Change the screen id to first screen
- screen = Workspace.FIRST_SCREEN_ID;
- }
-
- mMaxGridSizeX = Math.max(mMaxGridSizeX, cellX + spanX);
- mMaxGridSizeY = Math.max(mMaxGridSizeY, cellY + spanY);
- break;
- }
- case Favorites.CONTAINER_HOTSEAT: {
- mHotseatSize = Math.max(mHotseatSize, screen + 1);
- break;
- }
- default:
- if (!mValidFolders.get(container)) {
- FileLog.d(TAG, String.format("Skipping item %d, type %d not in a valid folder %d", id, type, container));
- continue;
- }
- }
-
- Intent intent = null;
- switch (type) {
- case Favorites.ITEM_TYPE_FOLDER: {
- mValidFolders.put(id, true);
- // Use a empty intent to indicate a folder.
- intent = new Intent();
- break;
- }
- case Favorites.ITEM_TYPE_APPWIDGET: {
- values.put(Favorites.RESTORED,
- LauncherAppWidgetInfo.FLAG_ID_NOT_VALID |
- LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY |
- LauncherAppWidgetInfo.FLAG_UI_NOT_READY);
- values.put(Favorites.APPWIDGET_PROVIDER, c.getString(widgetProviderIndex));
- break;
- }
- case Favorites.ITEM_TYPE_SHORTCUT:
- case Favorites.ITEM_TYPE_APPLICATION: {
- intent = Intent.parseUri(c.getString(intentIndex), 0);
- if (PackageManagerHelper.isLauncherAppTarget(intent)) {
- type = Favorites.ITEM_TYPE_APPLICATION;
- } else {
- values.put(Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
- values.put(Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
- }
- values.put(Favorites.ICON, c.getBlob(iconIndex));
- values.put(Favorites.INTENT, intent.toUri(0));
- values.put(Favorites.RANK, c.getInt(rankIndex));
-
- values.put(Favorites.RESTORED, 1);
- break;
- }
- default:
- FileLog.d(TAG, String.format("Skipping item %d, not a valid type %d", id, type));
- continue;
- }
-
- if (container == Favorites.CONTAINER_HOTSEAT) {
- if (intent == null) {
- FileLog.d(TAG, String.format("Skipping item %d, null intent on hotseat", id));
- continue;
- }
- if (intent.getComponent() != null) {
- intent.setPackage(intent.getComponent().getPackageName());
- }
- hotseatTargetApps.add(getPackage(intent));
- }
-
- values.put(Favorites._ID, id);
- values.put(Favorites.ITEM_TYPE, type);
- values.put(Favorites.CONTAINER, container);
- values.put(Favorites.SCREEN, screen);
- values.put(Favorites.CELLX, cellX);
- values.put(Favorites.CELLY, cellY);
- values.put(Favorites.SPANX, spanX);
- values.put(Favorites.SPANY, spanY);
- values.put(Favorites.TITLE, c.getString(titleIndex));
- insertOperations.add(ContentProviderOperation
- .newInsert(Favorites.CONTENT_URI).withValues(values).build());
- if (container < 0) {
- totalItemsOnWorkspace++;
- }
-
- if (insertOperations.size() >= BATCH_INSERT_SIZE) {
- mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY,
- insertOperations);
- insertOperations.clear();
- }
- }
- }
- FileLog.d(TAG, totalItemsOnWorkspace + " items imported from external source");
- if (totalItemsOnWorkspace < MIN_ITEM_COUNT_FOR_SUCCESSFUL_MIGRATION) {
- throw new Exception("Insufficient data");
- }
- if (!insertOperations.isEmpty()) {
- mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY,
- insertOperations);
- insertOperations.clear();
- }
-
- IntSparseArrayMap<Object> hotseatItems = GridSizeMigrationTask
- .removeBrokenHotseatItems(mContext);
- int myHotseatCount = LauncherAppState.getIDP(mContext).numDatabaseHotseatIcons;
- if (hotseatItems.size() < myHotseatCount) {
- // Insufficient hotseat items. Add a few more.
- HotseatParserCallback parserCallback = new HotseatParserCallback(
- hotseatTargetApps, hotseatItems, insertOperations, maxId + 1, myHotseatCount);
- new HotseatLayoutParser(mContext,
- parserCallback).loadLayout(null, new IntArray());
- mHotseatSize = hotseatItems.keyAt(hotseatItems.size() - 1) + 1;
-
- if (!insertOperations.isEmpty()) {
- mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY,
- insertOperations);
- }
- }
- }
-
- private static String getPackage(Intent intent) {
- return intent.getComponent() != null ? intent.getComponent().getPackageName()
- : intent.getPackage();
- }
-
- /**
- * Performs data import if possible.
- * @return true on successful data import, false if it was not available
- * @throws Exception if the import failed
- */
- public static boolean performImportIfPossible(Context context) throws Exception {
- SharedPreferences devicePrefs = getDevicePrefs(context);
- String sourcePackage = devicePrefs.getString(KEY_DATA_IMPORT_SRC_PKG, "");
- String sourceAuthority = devicePrefs.getString(KEY_DATA_IMPORT_SRC_AUTHORITY, "");
-
- if (TextUtils.isEmpty(sourcePackage) || TextUtils.isEmpty(sourceAuthority)) {
- return false;
- }
-
- // Synchronously clear the migration flags. This ensures that we do not try migration
- // again and thus prevents potential crash loops due to migration failure.
- devicePrefs.edit().remove(KEY_DATA_IMPORT_SRC_PKG).remove(KEY_DATA_IMPORT_SRC_AUTHORITY).commit();
-
- if (!Settings.call(context.getContentResolver(), Settings.METHOD_WAS_EMPTY_DB_CREATED)
- .getBoolean(Settings.EXTRA_VALUE, false)) {
- // Only migration if a new DB was created.
- return false;
- }
-
- for (ProviderInfo info : context.getPackageManager().queryContentProviders(
- null, context.getApplicationInfo().uid, 0)) {
-
- if (sourcePackage.equals(info.packageName)) {
- if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- // Only migrate if the source launcher is also on system image.
- return false;
- }
-
- // Wait until we found a provider with matching authority.
- if (sourceAuthority.equals(info.authority)) {
- if (TextUtils.isEmpty(info.readPermission) ||
- context.checkPermission(info.readPermission, Process.myPid(),
- Process.myUid()) == PackageManager.PERMISSION_GRANTED) {
- // All checks passed, run the import task.
- return new ImportDataTask(context, sourceAuthority).importWorkspace();
- }
- }
- }
- }
- return false;
- }
-
- /**
- * Extension of {@link DefaultLayoutParser} which only allows icons and shortcuts.
- */
- private static class HotseatLayoutParser extends DefaultLayoutParser {
- public HotseatLayoutParser(Context context, LayoutParserCallback callback) {
- super(context, null, callback, context.getResources(),
- LauncherAppState.getIDP(context).defaultLayoutId);
- }
-
- @Override
- protected ArrayMap<String, TagParser> getLayoutElementsMap() {
- // Only allow shortcut parsers
- ArrayMap<String, TagParser> parsers = new ArrayMap<>();
- parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
- parsers.put(TAG_SHORTCUT, new UriShortcutParser(mSourceRes));
- parsers.put(TAG_RESOLVE, new ResolveParser());
- return parsers;
- }
- }
-
- /**
- * {@link LayoutParserCallback} which adds items in empty hotseat spots.
- */
- private static class HotseatParserCallback implements LayoutParserCallback {
- private final HashSet<String> mExistingApps;
- private final IntSparseArrayMap<Object> mExistingItems;
- private final ArrayList<ContentProviderOperation> mOutOps;
- private final int mRequiredSize;
- private int mStartItemId;
-
- HotseatParserCallback(
- HashSet<String> existingApps, IntSparseArrayMap<Object> existingItems,
- ArrayList<ContentProviderOperation> outOps, int startItemId, int requiredSize) {
- mExistingApps = existingApps;
- mExistingItems = existingItems;
- mOutOps = outOps;
- mRequiredSize = requiredSize;
- mStartItemId = startItemId;
- }
-
- @Override
- public int generateNewItemId() {
- return mStartItemId++;
- }
-
- @Override
- public int insertAndCheck(SQLiteDatabase db, ContentValues values) {
- if (mExistingItems.size() >= mRequiredSize) {
- // No need to add more items.
- return 0;
- }
- if (!Integer.valueOf(Favorites.CONTAINER_HOTSEAT)
- .equals(values.getAsInteger(Favorites.CONTAINER))) {
- // Ignore items which are not for hotseat.
- return 0;
- }
-
- Intent intent;
- try {
- intent = Intent.parseUri(values.getAsString(Favorites.INTENT), 0);
- } catch (URISyntaxException e) {
- return 0;
- }
- String pkg = getPackage(intent);
- if (pkg == null || mExistingApps.contains(pkg)) {
- // The item does not target an app or is already in hotseat.
- return 0;
- }
- mExistingApps.add(pkg);
-
- // find next vacant spot.
- int screen = 0;
- while (mExistingItems.get(screen) != null) {
- screen++;
- }
- mExistingItems.put(screen, intent);
- values.put(Favorites.SCREEN, screen);
- mOutOps.add(ContentProviderOperation.newInsert(Favorites.CONTENT_URI).withValues(values).build());
- return 0;
- }
- }
-}
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 7e05a5a..6855bb1 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -16,84 +16,21 @@
package com.android.launcher3.provider;
-import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.os.Binder;
import android.os.Process;
-import android.util.Log;
-import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.IntArray;
-import java.util.Locale;
-
/**
* A set of utility methods for Launcher DB used for DB updates and migration.
*/
public class LauncherDbUtils {
- private static final String TAG = "LauncherDbUtils";
-
- /**
- * Makes the first screen as screen 0 (if screen 0 already exists,
- * renames it to some other number).
- * If the first row of screen 0 is non empty, runs a 'lossy' GridMigrationTask to clear
- * the first row. The items in the first screen are moved and resized but the carry-forward
- * items are simply deleted.
- */
- public static boolean prepareScreenZeroToHostQsb(Context context, SQLiteDatabase db) {
- try (SQLiteTransaction t = new SQLiteTransaction(db)) {
- // Get the first screen
- final int firstScreenId;
- try (Cursor c = db.rawQuery(String.format(Locale.ENGLISH,
- "SELECT MIN(%1$s) from %2$s where %3$s = %4$d",
- Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
- Favorites.CONTAINER_DESKTOP), null)) {
-
- if (!c.moveToNext()) {
- // No update needed
- t.commit();
- return true;
- }
-
- firstScreenId = c.getInt(0);
- }
-
- if (firstScreenId != 0) {
- // Rename the first screen to 0.
- renameScreen(db, firstScreenId, 0);
- }
-
- // Check if the first row is empty
- if (DatabaseUtils.queryNumEntries(db, Favorites.TABLE_NAME,
- "container = -100 and screen = 0 and cellY = 0") == 0) {
- // First row is empty, no need to migrate.
- t.commit();
- return true;
- }
-
- new LossyScreenMigrationTask(context, LauncherAppState.getIDP(context), db)
- .migrateScreen0();
- t.commit();
- return true;
- } catch (Exception e) {
- Log.e(TAG, "Failed to update workspace size", e);
- return false;
- }
- }
-
- private static void renameScreen(SQLiteDatabase db, int oldScreen, int newScreen) {
- String[] whereParams = new String[] { Integer.toString(oldScreen) };
- ContentValues values = new ContentValues();
- values.put(Favorites.SCREEN, newScreen);
- db.update(Favorites.TABLE_NAME, values, "container = -100 and screen = ?", whereParams);
- }
-
public static IntArray queryIntArray(SQLiteDatabase db, String tableName, String columnName,
String selection, String groupBy, String orderBy) {
IntArray out = new IntArray();
diff --git a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
deleted file mode 100644
index c0111b9..0000000
--- a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.provider;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Point;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
-import com.android.launcher3.model.GridSizeMigrationTask;
-import com.android.launcher3.util.IntSparseArrayMap;
-
-import java.util.ArrayList;
-
-/**
- * An extension of {@link GridSizeMigrationTask} which migrates only one screen and
- * deletes all carry-forward items.
- */
-public class LossyScreenMigrationTask extends GridSizeMigrationTask {
-
- private final IntSparseArrayMap<DbEntry> mOriginalItems;
- private final IntSparseArrayMap<DbEntry> mUpdates;
-
- protected LossyScreenMigrationTask(
- Context context, InvariantDeviceProfile idp, SQLiteDatabase db) {
- // Decrease the rows count by 1
- super(context, db, getValidPackages(context), false /* usePreviewTable */,
- new Point(idp.numColumns, idp.numRows + 1),
- new Point(idp.numColumns, idp.numRows));
-
- mOriginalItems = new IntSparseArrayMap<>();
- mUpdates = new IntSparseArrayMap<>();
- }
-
- @Override
- protected void update(DbEntry item) {
- mUpdates.put(item.id, item.copy());
- }
-
- @Override
- protected ArrayList<DbEntry> loadWorkspaceEntries(int screen) {
- ArrayList<DbEntry> result = super.loadWorkspaceEntries(screen);
- for (DbEntry entry : result) {
- mOriginalItems.put(entry.id, entry.copy());
-
- // Shift all items by 1 in y direction and mark them for update.
- entry.cellY++;
- mUpdates.put(entry.id, entry.copy());
- }
-
- return result;
- }
-
- public void migrateScreen0() {
- migrateScreen(Workspace.FIRST_SCREEN_ID);
-
- ContentValues tempValues = new ContentValues();
- for (DbEntry update : mUpdates) {
- DbEntry org = mOriginalItems.get(update.id);
-
- if (org.cellX != update.cellX || org.cellY != update.cellY
- || org.spanX != update.spanX || org.spanY != update.spanY) {
- tempValues.clear();
- update.addToContentValues(tempValues);
- mDb.update(Favorites.TABLE_NAME, tempValues, "_id = ?",
- new String[] {Integer.toString(update.id)});
- }
- }
-
- // Delete any carry over items as we are only migration a single screen.
- for (DbEntry entry : mCarryOver) {
- mEntryToRemove.add(entry.id);
- }
-
- if (!mEntryToRemove.isEmpty()) {
- mDb.delete(Favorites.TABLE_NAME,
- Utilities.createDbSelectionQuery(Favorites._ID, mEntryToRemove), null);
- }
- }
-}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 223f4f1..8d02a4a 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,6 +16,7 @@
package com.android.launcher3.provider;
+import static com.android.launcher3.model.DeviceGridState.TYPE_PHONE;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.app.backup.BackupManager;
@@ -38,6 +39,7 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.model.DeviceGridState;
import com.android.launcher3.model.GridBackupTable;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -57,7 +59,7 @@
public class RestoreDbTask {
private static final String TAG = "RestoreDbTask";
- private static final String RESTORE_TASK_PENDING = "restore_task_pending";
+ private static final String RESTORED_DEVICE_TYPE = "restored_task_pending";
private static final String INFO_COLUMN_NAME = "name";
private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value";
@@ -65,13 +67,33 @@
private static final String APPWIDGET_OLD_IDS = "appwidget_old_ids";
private static final String APPWIDGET_IDS = "appwidget_ids";
- public static boolean performRestore(Context context, DatabaseHelper helper,
- BackupManager backupManager) {
+ /**
+ * Tries to restore the backup DB if needed
+ */
+ public static void restoreIfNeeded(Context context, DatabaseHelper helper) {
+ if (!isPending(context)) {
+ return;
+ }
+ if (!performRestore(context, helper)) {
+ helper.createEmptyDB(helper.getWritableDatabase());
+ }
+
+ // Set is pending to false irrespective of the result, so that it doesn't get
+ // executed again.
+ Utilities.getPrefs(context).edit().remove(RESTORED_DEVICE_TYPE).commit();
+ }
+
+ private static boolean performRestore(Context context, DatabaseHelper helper) {
+ if (new DeviceGridState(LauncherAppState.getIDP(context)).getDeviceType()
+ != Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE)) {
+ // DO not restore if the device types are different
+ return false;
+ }
SQLiteDatabase db = helper.getWritableDatabase();
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
RestoreDbTask task = new RestoreDbTask();
task.backupWorkspace(context, db);
- task.sanitizeDB(helper, db, backupManager);
+ task.sanitizeDB(helper, db, new BackupManager(context));
task.restoreAppWidgetIdsIfExists(context);
t.commit();
return true;
@@ -279,12 +301,17 @@
}
public static boolean isPending(Context context) {
- return Utilities.getPrefs(context).getBoolean(RESTORE_TASK_PENDING, false);
+ return Utilities.getPrefs(context).contains(RESTORED_DEVICE_TYPE);
}
- public static void setPending(Context context, boolean isPending) {
- FileLog.d(TAG, "Restore data received through full backup " + isPending);
- Utilities.getPrefs(context).edit().putBoolean(RESTORE_TASK_PENDING, isPending).commit();
+ /**
+ * Marks the DB state as pending restoration
+ */
+ public static void setPending(Context context) {
+ FileLog.d(TAG, "Restore data received through full backup ");
+ Utilities.getPrefs(context).edit()
+ .putInt(RESTORED_DEVICE_TYPE, new DeviceGridState(context).getDeviceType())
+ .commit();
}
private void restoreAppWidgetIdsIfExists(Context context) {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 944a41f..bc5129d 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -62,6 +62,10 @@
}
public Bundle call(String method) {
+ return call(method, /*arg=*/ null);
+ }
+
+ public Bundle call(String method, String arg) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT: {
@@ -102,8 +106,11 @@
return getUIProperty(Bundle::putParcelable, a -> {
WindowInsets insets = a.getWindow()
.getDecorView().getRootWindowInsets();
- return Insets.max(
- insets.getSystemGestureInsets(), insets.getSystemWindowInsets());
+ return Insets.subtract(
+ Insets.max(
+ insets.getSystemGestureInsets(),
+ insets.getSystemWindowInsets()),
+ Insets.of(0, 0, 0, mDeviceProfile.nonOverlappingTaskbarInset));
}, this::getCurrentActivity);
}
@@ -126,6 +133,10 @@
mDeviceProfile.isTwoPanels);
return response;
+ case TestProtocol.REQUEST_SET_FORCE_PAUSE_TIMEOUT:
+ TestProtocol.sForcePauseTimeout = Long.parseLong(arg);
+ return response;
+
default:
return null;
}
diff --git a/src/com/android/launcher3/testing/TestInformationProvider.java b/src/com/android/launcher3/testing/TestInformationProvider.java
index bd177c0..4f2619c 100644
--- a/src/com/android/launcher3/testing/TestInformationProvider.java
+++ b/src/com/android/launcher3/testing/TestInformationProvider.java
@@ -60,7 +60,7 @@
if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
TestInformationHandler handler = TestInformationHandler.newInstance(getContext());
handler.init(getContext());
- return handler.call(method);
+ return handler.call(method, arg);
}
return null;
}
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 65bec25..d73c4b4 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -98,6 +98,9 @@
public static final String REQUEST_IS_TABLET = "is-tablet";
public static final String REQUEST_IS_TWO_PANELS = "is-two-panel";
+ public static Long sForcePauseTimeout;
+ public static final String REQUEST_SET_FORCE_PAUSE_TIMEOUT = "set-force-pause-timeout";
+
public static boolean sDebugTracing = false;
public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
@@ -112,4 +115,5 @@
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String WORK_PROFILE_REMOVED = "b/159671700";
public static final String FALLBACK_ACTIVITY_NO_SET = "b/181019015";
+ public static final String THIRD_PARTY_LAUNCHER_NOT_SET = "b/187080582";
}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 90f37f3..5f8a4d4 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -65,12 +65,12 @@
protected LauncherState mToState;
protected AnimatorPlaybackController mCurrentAnimation;
protected boolean mGoingBetweenStates = true;
+ // Ratio of transition process [0, 1] to drag displacement (px)
+ protected float mProgressMultiplier;
private boolean mNoIntercept;
private boolean mIsLogContainerSet;
private float mStartProgress;
- // Ratio of transition process [0, 1] to drag displacement (px)
- private float mProgressMultiplier;
private float mDisplacementShift;
private boolean mCanBlockFling;
private boolean mAllAppsOvershootStarted;
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index cfd3153..1276ece 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -17,8 +17,6 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
-import static com.android.launcher3.Utilities.IS_RUNNING_IN_TEST_HARNESS;
-
import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
@@ -43,8 +41,7 @@
*/
public abstract class BaseSwipeDetector {
- // b/193440212: Debug swipe gesture in tests.
- private static final boolean DBG = IS_RUNNING_IN_TEST_HARNESS;
+ 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.*/
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index d047eca..816e5dc 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -205,6 +205,16 @@
}
@Override
+ public void setPrimaryScale(View view, float scale) {
+ view.setScaleY(scale);
+ }
+
+ @Override
+ public void setSecondaryScale(View view, float scale) {
+ view.setScaleX(scale);
+ }
+
+ @Override
public int getChildStart(View view) {
return view.getTop();
}
@@ -353,6 +363,25 @@
}
@Override
+ public void getInitialSplitPlaceholderBounds(int placeholderHeight, DeviceProfile dp,
+ SplitPositionOption splitPositionOption, Rect out) {
+ // In fake land/seascape, the placeholder always needs to go to the "top" of the device,
+ // which is the same bounds as 0 rotation.
+ int width = dp.widthPx;
+ out.set(0, 0, width, placeholderHeight);
+ }
+
+ @Override
+ public void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
+ SplitPositionOption initialSplitOption, Rect out1, Rect out2) {
+ // In fake land/seascape, the window bounds are always top and bottom half
+ int screenHeight = dp.heightPx;
+ int screenWidth = dp.widthPx;
+ out1.set(0, 0, screenWidth, screenHeight / 2 - splitDividerSize);
+ out2.set(0, screenHeight / 2 + splitDividerSize, screenWidth, screenHeight);
+ }
+
+ @Override
public FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
DeviceProfile deviceProfile) {
return primary;
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 266e05f..dae2dde 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -99,6 +99,8 @@
boolean getRecentsRtlSetting(Resources resources);
float getDegreesRotated();
int getRotation();
+ void setPrimaryScale(View view, float scale);
+ void setSecondaryScale(View view, float scale);
<T> T getPrimaryValue(T x, T y);
<T> T getSecondaryValue(T x, T y);
@@ -114,6 +116,22 @@
DeviceProfile deviceProfile);
int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
+ /**
+ * @param splitholderSize height of placeholder view in portrait, width in landscape
+ */
+ void getInitialSplitPlaceholderBounds(int splitholderSize, DeviceProfile dp,
+ SplitPositionOption splitPositionOption, Rect out);
+
+ /**
+ * @param splitDividerSize height of split screen drag handle in portrait, width in landscape
+ * @param initialSplitOption the split position option (top/left, bottom/right) of the first
+ * task selected for entering split
+ * @param out1 the bounds for where the first selected app will be
+ * @param out2 the bounds for where the second selected app will be, complimentary to
+ * {@param out1} based on {@param initialSplitOption}
+ */
+ void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
+ SplitPositionOption initialSplitOption, Rect out1, Rect out2);
// Overview TaskMenuView methods
float getTaskMenuX(float x, View thumbnailView, int overScroll);
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index dd97af5..1253589 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
import android.content.res.Resources;
+import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -47,6 +48,9 @@
public class PortraitPagedViewHandler implements PagedOrientationHandler {
+ private final Matrix mTmpMatrix = new Matrix();
+ private final RectF mTmpRectF = new RectF();
+
@Override
public <T> T getPrimaryValue(T x, T y) {
return x;
@@ -207,6 +211,16 @@
}
@Override
+ public void setPrimaryScale(View view, float scale) {
+ view.setScaleX(scale);
+ }
+
+ @Override
+ public void setSecondaryScale(View view, float scale) {
+ view.setScaleY(scale);
+ }
+
+ @Override
public int getChildStart(View view) {
return view.getLeft();
}
@@ -398,6 +412,62 @@
}
@Override
+ public void getInitialSplitPlaceholderBounds(int placeholderHeight, DeviceProfile dp,
+ SplitPositionOption splitPositionOption, Rect out) {
+ int width = dp.widthPx;
+ out.set(0, 0, width, placeholderHeight);
+ if (!dp.isLandscape) {
+ // portrait, phone or tablet - spans width of screen, nothing else to do
+ return;
+ }
+
+ // Now we rotate the portrait rect depending on what side we want pinned
+ boolean pinToRight = splitPositionOption.mStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT;
+
+ int screenHeight = dp.heightPx;
+ float postRotateScale = (float) screenHeight / width;
+ mTmpMatrix.reset();
+ mTmpMatrix.postRotate(pinToRight ? 90 : 270);
+ mTmpMatrix.postTranslate(pinToRight ? width : 0, pinToRight ? 0 : width);
+ // The placeholder height stays constant after rotation, so we don't change width scale
+ mTmpMatrix.postScale(1, postRotateScale);
+
+ mTmpRectF.set(out);
+ mTmpMatrix.mapRect(mTmpRectF);
+ mTmpRectF.roundOut(out);
+ }
+
+ @Override
+ public void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
+ SplitPositionOption initialSplitOption, Rect out1, Rect out2) {
+ int screenHeight = dp.heightPx;
+ int screenWidth = dp.widthPx;
+ out1.set(0, 0, screenWidth, screenHeight / 2 - splitDividerSize);
+ out2.set(0, screenHeight / 2 + splitDividerSize, screenWidth, screenHeight);
+ if (!dp.isLandscape) {
+ // Portrait - the window bounds are always top and bottom half
+ return;
+ }
+
+ // Now we rotate the portrait rect depending on what side we want pinned
+ boolean pinToRight = initialSplitOption.mStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT;
+ float postRotateScale = (float) screenHeight / screenWidth;
+
+ mTmpMatrix.reset();
+ mTmpMatrix.postRotate(pinToRight ? 90 : 270);
+ mTmpMatrix.postTranslate(pinToRight ? screenHeight : 0, pinToRight ? 0 : screenWidth);
+ mTmpMatrix.postScale(1 / postRotateScale, postRotateScale);
+
+ mTmpRectF.set(out1);
+ mTmpMatrix.mapRect(mTmpRectF);
+ mTmpRectF.roundOut(out1);
+
+ mTmpRectF.set(out2);
+ mTmpMatrix.mapRect(mTmpRectF);
+ mTmpRectF.roundOut(out2);
+ }
+
+ @Override
public FloatProperty getSplitSelectTaskOffset(FloatProperty primary, FloatProperty secondary,
DeviceProfile dp) {
if (dp.isLandscape) { // or seascape
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 4fa658e..20d2ad3 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -41,7 +41,6 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.views.OptionsPopupView;
/**
* Helper class to handle touch on empty space in workspace and show options popup on long press
@@ -175,7 +174,7 @@
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
mLauncher.getStatsLogManager().logger().log(LAUNCHER_WORKSPACE_LONGPRESS);
- OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);
+ mLauncher.showDefaultOptions(mTouchDownPoint.x, mTouchDownPoint.y);
} else {
cancelLongPress();
}
diff --git a/src/com/android/launcher3/util/IntSet.java b/src/com/android/launcher3/util/IntSet.java
index e5b4f59..4fd06fe 100644
--- a/src/com/android/launcher3/util/IntSet.java
+++ b/src/com/android/launcher3/util/IntSet.java
@@ -37,6 +37,15 @@
}
/**
+ * Appends the specified IntSet's values to the set if they does not exist, then returns the
+ * original set that now also contains the new values.
+ */
+ public IntSet addAll(IntSet other) {
+ other.forEach(this::add);
+ return this;
+ }
+
+ /**
* Removes the specified value from the set if it exist.
*/
public void remove(int value) {
diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java
index e449a4b..239b5ff 100644
--- a/src/com/android/launcher3/views/ArrowTipView.java
+++ b/src/com/android/launcher3/views/ArrowTipView.java
@@ -133,6 +133,21 @@
* @return The tooltip.
*/
public ArrowTipView show(String text, int gravity, int arrowMarginStart, int top) {
+ return show(text, gravity, arrowMarginStart, top, true);
+ }
+
+ /**
+ * Show the ArrowTipView (tooltip) center, start, or end aligned.
+ *
+ * @param text The text to be shown in the tooltip.
+ * @param gravity The gravity aligns the tooltip center, start, or end.
+ * @param arrowMarginStart The margin from start to place arrow (ignored if center)
+ * @param top The Y coordinate of the bottom of tooltip.
+ * @param shouldAutoClose If Tooltip should be auto close.
+ * @return The tooltip.
+ */
+ public ArrowTipView show(
+ String text, int gravity, int arrowMarginStart, int top, boolean shouldAutoClose) {
((TextView) findViewById(R.id.text)).setText(text);
ViewGroup parent = mActivity.getDragLayer();
parent.addView(this);
@@ -157,7 +172,9 @@
post(() -> setY(top - (mIsPointingUp ? 0 : getHeight())));
mIsOpen = true;
- mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS);
+ if (shouldAutoClose) {
+ mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS);
+ }
setAlpha(0);
animate()
.alpha(1f)
@@ -181,10 +198,32 @@
*/
@Nullable public ArrowTipView showAtLocation(String text, @Px int arrowXCoord, @Px int yCoord) {
return showAtLocation(
+ text,
+ arrowXCoord,
+ /* yCoordDownPointingTip= */ yCoord,
+ /* yCoordUpPointingTip= */ yCoord,
+ /* shouldAutoClose= */ true);
+ }
+
+ /**
+ * Show the ArrowTipView (tooltip) custom aligned. The tooltip is vertically flipped if it
+ * cannot fit on screen in the requested orientation.
+ *
+ * @param text The text to be shown in the tooltip.
+ * @param arrowXCoord The X coordinate for the arrow on the tooltip. The arrow is usually in the
+ * center of tooltip unless the tooltip goes beyond screen margin.
+ * @param yCoord The Y coordinate of the pointed tip end of the tooltip.
+ * @param shouldAutoClose If Tooltip should be auto close.
+ * @return The tool tip view. {@code null} if the tip can not be shown.
+ */
+ @Nullable public ArrowTipView showAtLocation(
+ String text, @Px int arrowXCoord, @Px int yCoord, boolean shouldAutoClose) {
+ return showAtLocation(
text,
arrowXCoord,
/* yCoordDownPointingTip= */ yCoord,
- /* yCoordUpPointingTip= */ yCoord);
+ /* yCoordUpPointingTip= */ yCoord,
+ /* shouldAutoClose= */ shouldAutoClose);
}
/**
@@ -204,7 +243,8 @@
text,
arrowXCoord,
/* yCoordDownPointingTip= */ rect.top - margin,
- /* yCoordUpPointingTip= */ rect.bottom + margin);
+ /* yCoordUpPointingTip= */ rect.bottom + margin,
+ /* shouldAutoClose= */ true);
}
/**
@@ -218,10 +258,11 @@
* tooltip is placed pointing downwards.
* @param yCoordUpPointingTip The Y coordinate of the pointed tip end of the tooltip when the
* tooltip is placed pointing upwards.
+ * @param shouldAutoClose If Tooltip should be auto close.
* @return The tool tip view. {@code null} if the tip can not be shown.
*/
@Nullable private ArrowTipView showAtLocation(String text, @Px int arrowXCoord,
- @Px int yCoordDownPointingTip, @Px int yCoordUpPointingTip) {
+ @Px int yCoordDownPointingTip, @Px int yCoordUpPointingTip, boolean shouldAutoClose) {
ViewGroup parent = mActivity.getDragLayer();
@Px int parentViewWidth = parent.getWidth();
@Px int parentViewHeight = parent.getHeight();
@@ -279,7 +320,9 @@
});
mIsOpen = true;
- mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS);
+ if (shouldAutoClose) {
+ mHandler.postDelayed(() -> handleClose(true), AUTO_CLOSE_TIMEOUT_MILLIS);
+ }
setAlpha(0);
animate()
.alpha(1f)
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index ecdd206..257b18f 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -176,16 +176,6 @@
return launcher.findViewById(R.id.popup_container);
}
- public static void showDefaultOptions(Launcher launcher, float x, float y) {
- float halfSize = launcher.getResources().getDimension(R.dimen.options_menu_thumb_size) / 2;
- if (x < 0 || y < 0) {
- x = launcher.getDragLayer().getWidth() / 2;
- y = launcher.getDragLayer().getHeight() / 2;
- }
- RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
- show(launcher, target, getOptions(launcher), false);
- }
-
/**
* Returns the list of supported actions
*/
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
index b92c476..d2d569f 100644
--- a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -49,6 +49,8 @@
private final Rect mInsets;
private ScrollView mWidgetPreviewScrollView;
+ private int mContentHorizontalMarginInPx;
+
public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -56,6 +58,8 @@
public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mInsets = new Rect();
+ mContentHorizontalMarginInPx = getResources().getDimensionPixelSize(
+ R.dimen.widget_list_horizontal_margin);
}
/**
@@ -173,6 +177,26 @@
}
mContent.setPadding(mContent.getPaddingStart(),
mContent.getPaddingTop(), mContent.getPaddingEnd(), mInsets.bottom);
+
+ int contentHorizontalMarginInPx = getResources().getDimensionPixelSize(
+ R.dimen.widget_list_horizontal_margin);
+ if (contentHorizontalMarginInPx != mContentHorizontalMarginInPx) {
+ setContentHorizontalMargin(findViewById(R.id.widget_appName),
+ contentHorizontalMarginInPx);
+ setContentHorizontalMargin(findViewById(R.id.widget_drag_instruction),
+ contentHorizontalMarginInPx);
+ setContentHorizontalMargin(findViewById(R.id.widget_cell), contentHorizontalMarginInPx);
+ setContentHorizontalMargin(findViewById(R.id.actions_container),
+ contentHorizontalMarginInPx);
+ mContentHorizontalMarginInPx = contentHorizontalMarginInPx;
+ }
return windowInsets;
}
+
+ private static void setContentHorizontalMargin(View view, int contentHorizontalMargin) {
+ ViewGroup.MarginLayoutParams layoutParams =
+ ((ViewGroup.MarginLayoutParams) view.getLayoutParams());
+ layoutParams.setMarginStart(contentHorizontalMargin);
+ layoutParams.setMarginEnd(contentHorizontalMargin);
+ }
}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index ee44174..b6cec12 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -66,8 +66,12 @@
/* Touch handling related member variables. */
private Toast mWidgetInstructionToast;
+ private int mContentHorizontalMarginInPx;
+
public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mContentHorizontalMarginInPx = getResources().getDimensionPixelSize(
+ R.dimen.widget_list_horizontal_margin);
}
protected int getScrimColor(Context context) {
@@ -119,8 +123,16 @@
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
+ int contentHorizontalMarginInPx = getResources().getDimensionPixelSize(
+ R.dimen.widget_list_horizontal_margin);
+ if (contentHorizontalMarginInPx != mContentHorizontalMarginInPx) {
+ onContentHorizontalMarginChanged(contentHorizontalMarginInPx);
+ mContentHorizontalMarginInPx = contentHorizontalMarginInPx;
+ }
}
+ /** Called when the horizontal margin of the content view has changed. */
+ protected abstract void onContentHorizontalMarginChanged(int contentHorizontalMarginInPx);
/**
* Measures the dimension of this view and its children by taking system insets, navigation bar,
@@ -188,11 +200,11 @@
dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
image.getWidth(), new Point(loc[0], loc[1]), this, new DragOptions());
} else {
- View preview = v.getAppWidgetHostViewPreview();
+ NavigableAppWidgetHostView preview = v.getAppWidgetHostViewPreview();
int[] loc = new int[2];
getPopupContainer().getLocationInDragLayer(preview, loc);
-
- Rect r = new Rect(0, 0, preview.getWidth(), preview.getHeight());
+ Rect r = new Rect();
+ preview.getWorkspaceVisualDragBounds(r);
dragHelper.startDrag(r, preview.getMeasuredWidth(), preview.getMeasuredWidth(),
new Point(loc[0], loc[1]), this, new DragOptions());
}
diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
index 149ac57..9c32e42 100644
--- a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
@@ -25,6 +25,7 @@
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.TypedValue;
+import android.view.View;
import android.widget.RemoteViews;
import com.android.launcher3.R;
@@ -55,6 +56,11 @@
}
@Override
+ public void addView(View child) {
+ // Not allowed
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index fb6de9f..f0b4ba0 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -19,9 +19,7 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Canvas;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Handler;
import android.os.SystemClock;
import android.util.SparseBooleanArray;
@@ -35,23 +33,17 @@
import android.widget.Advanceable;
import android.widget.RemoteViews;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.CheckLongPressHelper;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
-import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
-
-import java.util.List;
/**
* {@inheritDoc}
@@ -60,8 +52,6 @@
implements TouchCompleteListener, View.OnLongClickListener,
LocalColorExtractor.Listener {
- private static final String LOG_TAG = "LauncherAppWidgetHostView";
-
// Related to the auto-advancing of widgets
private static final long ADVANCE_INTERVAL = 20000;
private static final long ADVANCE_STAGGER = 250;
@@ -71,9 +61,9 @@
// Maximum duration for which updates can be deferred.
private static final long UPDATE_LOCK_TIMEOUT_MILLIS = 1000;
+ private final Rect mTempRect = new Rect();
private final CheckLongPressHelper mLongPressHelper;
protected final Launcher mLauncher;
- private final Workspace mWorkspace;
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mReinflateOnConfigChange;
@@ -84,28 +74,23 @@
private boolean mIsScrollable;
private boolean mIsAttachedToWindow;
private boolean mIsAutoAdvanceRegistered;
- private boolean mIsInDragMode = false;
private Runnable mAutoAdvanceRunnable;
- private RectF mLastLocationRegistered = null;
- @Nullable private AppWidgetHostViewDragListener mDragListener;
- // Used to store the widget sizes in drag layer coordinates.
- private final Rect mCurrentWidgetSize = new Rect();
- private final Rect mWidgetSizeAtDrag = new Rect();
-
- private final RectF mTempRectF = new RectF();
- private final Object mUpdateLock = new Object();
- private final ViewGroupFocusHelper mDragLayerRelativeCoordinateHelper;
private long mDeferUpdatesUntilMillis = 0;
private RemoteViews mDeferredRemoteViews;
private boolean mHasDeferredColorChange = false;
private @Nullable SparseIntArray mDeferredColorChange = null;
- private boolean mEnableColorExtraction = true;
+
+ // The following member variables are only used during drag-n-drop.
+ private boolean mIsInDragMode = false;
+ /** The drag content width which is only set when the drag content scale is not 1f. */
+ private int mDragContentWidth = 0;
+ /** The drag content height which is only set when the drag content scale is not 1f. */
+ private int mDragContentHeight = 0;
public LauncherAppWidgetHostView(Context context) {
super(context);
mLauncher = Launcher.getLauncher(context);
- mWorkspace = mLauncher.getWorkspace();
mLongPressHelper = new CheckLongPressHelper(this, this);
setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
setBackgroundResource(R.drawable.widget_internal_focus_bg);
@@ -114,9 +99,6 @@
setOnLightBackground(true);
}
mColorExtractor = LocalColorExtractor.newInstance(getContext());
- mColorExtractor.setListener(this);
-
- mDragLayerRelativeCoordinateHelper = new ViewGroupFocusHelper(mLauncher.getDragLayer());
}
@Override
@@ -129,14 +111,6 @@
}
@Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (mIsInDragMode && mDragListener != null) {
- mDragListener.onDragContentChanged();
- }
- }
-
- @Override
public boolean onLongClick(View view) {
if (mIsScrollable) {
DragLayer dragLayer = mLauncher.getDragLayer();
@@ -148,13 +122,11 @@
@Override
public void updateAppWidget(RemoteViews remoteViews) {
- synchronized (mUpdateLock) {
- if (isDeferringUpdates()) {
- mDeferredRemoteViews = remoteViews;
- return;
- }
- mDeferredRemoteViews = null;
+ if (isDeferringUpdates()) {
+ mDeferredRemoteViews = remoteViews;
+ return;
}
+ mDeferredRemoteViews = null;
super.updateAppWidget(remoteViews);
@@ -205,9 +177,7 @@
* {@link #onColorsChanged} call after {@link #UPDATE_LOCK_TIMEOUT_MILLIS} have elapsed.
*/
public void beginDeferringUpdates() {
- synchronized (mUpdateLock) {
- mDeferUpdatesUntilMillis = SystemClock.uptimeMillis() + UPDATE_LOCK_TIMEOUT_MILLIS;
- }
+ mDeferUpdatesUntilMillis = SystemClock.uptimeMillis() + UPDATE_LOCK_TIMEOUT_MILLIS;
}
/**
@@ -219,20 +189,19 @@
RemoteViews remoteViews;
SparseIntArray deferredColors;
boolean hasDeferredColors;
- synchronized (mUpdateLock) {
- mDeferUpdatesUntilMillis = 0;
- remoteViews = mDeferredRemoteViews;
- mDeferredRemoteViews = null;
- deferredColors = mDeferredColorChange;
- hasDeferredColors = mHasDeferredColorChange;
- mDeferredColorChange = null;
- mHasDeferredColorChange = false;
- }
+ mDeferUpdatesUntilMillis = 0;
+ remoteViews = mDeferredRemoteViews;
+ mDeferredRemoteViews = null;
+ deferredColors = mDeferredColorChange;
+ hasDeferredColors = mHasDeferredColorChange;
+ mDeferredColorChange = null;
+ mHasDeferredColorChange = false;
+
if (remoteViews != null) {
updateAppWidget(remoteViews);
}
if (hasDeferredColors) {
- onColorsChanged(null /* rectF */, deferredColors);
+ onColorsChanged(deferredColors);
}
}
@@ -257,13 +226,9 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
-
mIsAttachedToWindow = true;
checkIfAutoAdvance();
-
- if (mLastLocationRegistered != null) {
- mColorExtractor.addLocation(List.of(mLastLocationRegistered));
- }
+ mColorExtractor.setListener(this);
}
@Override
@@ -274,7 +239,7 @@
// state is updated. So isAttachedToWindow() will return true until next frame.
mIsAttachedToWindow = false;
checkIfAutoAdvance();
- mColorExtractor.removeLocations();
+ mColorExtractor.setListener(null);
}
@Override
@@ -305,107 +270,62 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
-
mIsScrollable = checkScrollableRecursively(this);
- updateColorExtraction();
+
+ if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+ mTempRect.set(left, top, right, bottom);
+ mColorExtractor.setWorkspaceLocation(mTempRect, (View) getParent(), info.screenId);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (mIsInDragMode && mDragContentWidth > 0 && mDragContentHeight > 0
+ && getChildCount() == 1) {
+ measureChild(getChildAt(0), MeasureSpec.getSize(mDragContentWidth),
+ MeasureSpec.getSize(mDragContentHeight));
+ }
}
/** Starts the drag mode. */
- public void startDrag(AppWidgetHostViewDragListener dragListener) {
+ public void startDrag() {
mIsInDragMode = true;
- mDragListener = dragListener;
+ // In the case of dragging a scaled preview from widgets picker, we should reuse the
+ // previously measured dimension from WidgetCell#measureAndComputeWidgetPreviewScale, which
+ // measures the dimension of a widget preview without its parent's bound before scaling
+ // down.
+ if ((getScaleX() != 1f || getScaleY() != 1f) && getChildCount() == 1) {
+ mDragContentWidth = getChildAt(0).getMeasuredWidth();
+ mDragContentHeight = getChildAt(0).getMeasuredHeight();
+ }
}
- /** Handles a drag event occurred on a workspace page, {@code pageId}. */
- public void handleDrag(Rect rectInDragLayer, int pageId) {
- mWidgetSizeAtDrag.set(rectInDragLayer);
- updateColorExtraction(mWidgetSizeAtDrag, pageId);
+ /** Handles a drag event occurred on a workspace page corresponding to the {@code screenId}. */
+ public void handleDrag(Rect rectInView, View view, int screenId) {
+ if (mIsInDragMode) {
+ mColorExtractor.setWorkspaceLocation(rectInView, view, screenId);
+ }
}
/** Ends the drag mode. */
public void endDrag() {
mIsInDragMode = false;
- mDragListener = null;
- mWidgetSizeAtDrag.setEmpty();
- }
-
- /**
- * @param rectInDragLayer Rect of widget in drag layer coordinates.
- * @param pageId The workspace page the widget is on.
- */
- private void updateColorExtraction(Rect rectInDragLayer, int pageId) {
- if (!mEnableColorExtraction) return;
- mColorExtractor.getExtractedRectForViewRect(mLauncher, pageId, rectInDragLayer, mTempRectF);
-
- if (mTempRectF.isEmpty()) {
- return;
- }
- if (!isSameLocation(mTempRectF, mLastLocationRegistered, /* epsilon= */ 1e-6f)) {
- if (mLastLocationRegistered != null) {
- mColorExtractor.removeLocations();
- }
- mLastLocationRegistered = new RectF(mTempRectF);
- mColorExtractor.addLocation(List.of(mLastLocationRegistered));
- }
- }
-
- /**
- * Update the color extraction, using the current position of the app widget.
- */
- private void updateColorExtraction() {
- if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {
- LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
- mDragLayerRelativeCoordinateHelper.viewToRect(this, mCurrentWidgetSize);
- updateColorExtraction(mCurrentWidgetSize,
- mWorkspace.getPageIndexForScreenId(info.screenId));
- }
- }
-
- /**
- * Enables the local color extraction.
- *
- * @param updateColors If true, this will update the color extraction using the current location
- * of the App Widget.
- */
- public void enableColorExtraction(boolean updateColors) {
- mEnableColorExtraction = true;
- if (updateColors) {
- updateColorExtraction();
- }
- }
-
- /**
- * Disables the local color extraction.
- */
- public void disableColorExtraction() {
- mEnableColorExtraction = false;
- }
-
- // Compare two location rectangles. Locations are always in the [0;1] range.
- private static boolean isSameLocation(@NonNull RectF rect1, @Nullable RectF rect2,
- float epsilon) {
- if (rect2 == null) return false;
- return isSameCoordinate(rect1.left, rect2.left, epsilon)
- && isSameCoordinate(rect1.right, rect2.right, epsilon)
- && isSameCoordinate(rect1.top, rect2.top, epsilon)
- && isSameCoordinate(rect1.bottom, rect2.bottom, epsilon);
- }
-
- private static boolean isSameCoordinate(float c1, float c2, float epsilon) {
- return Math.abs(c1 - c2) < epsilon;
+ mDragContentWidth = 0;
+ mDragContentHeight = 0;
+ requestLayout();
}
@Override
- public void onColorsChanged(RectF rectF, SparseIntArray colors) {
- synchronized (mUpdateLock) {
- if (isDeferringUpdates()) {
- mDeferredColorChange = colors;
- mHasDeferredColorChange = true;
- return;
- }
- mDeferredColorChange = null;
- mHasDeferredColorChange = false;
+ public void onColorsChanged(SparseIntArray colors) {
+ if (isDeferringUpdates()) {
+ mDeferredColorChange = colors;
+ mHasDeferredColorChange = true;
+ return;
}
+ mDeferredColorChange = null;
+ mHasDeferredColorChange = false;
// setColorResources will reapply the view, which must happen in the UI thread.
post(() -> setColorResources(colors));
diff --git a/src/com/android/launcher3/widget/LocalColorExtractor.java b/src/com/android/launcher3/widget/LocalColorExtractor.java
index 23d9e15..96e7531 100644
--- a/src/com/android/launcher3/widget/LocalColorExtractor.java
+++ b/src/com/android/launcher3/widget/LocalColorExtractor.java
@@ -20,18 +20,14 @@
import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.util.SparseIntArray;
import android.view.View;
import androidx.annotation.Nullable;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.util.ResourceBasedOverride;
-import java.util.List;
-
/** Extracts the colors we need from the wallpaper at given locations. */
public class LocalColorExtractor implements ResourceBasedOverride {
@@ -44,7 +40,7 @@
* their value, in a format that can be passed directly to
* {@link AppWidgetHostView#setColorResources(SparseIntArray)}.
*/
- void onColorsChanged(RectF rect, SparseIntArray extractedColors);
+ void onColorsChanged(SparseIntArray extractedColors);
}
/**
@@ -60,15 +56,13 @@
// no-op
}
- /** Adds a list of locations to track with this listener. */
- public void addLocation(List<RectF> locations) {
- // no-op
- }
-
- /** Stops tracking any locations. */
- public void removeLocations() {
- // no-op
- }
+ /**
+ * Sets the location used for color extraction
+ * @param pos position to use for color extraction
+ * @param child view whose coordinate space is used for {@code pos}
+ * @param screenId the workspace screenId
+ */
+ public void setWorkspaceLocation(Rect pos, View child, int screenId) { }
/**
* Updates the base context to contain the colors override
@@ -83,32 +77,4 @@
return null;
}
- /**
- * Takes a view and returns its rect that can be used by the wallpaper local color extractor.
- *
- * @param launcher Launcher class class.
- * @param pageId The page the workspace item is on.
- * @param v The view.
- * @param colorExtractionRectOut The location rect, but converted to a format expected by the
- * wallpaper local color extractor.
- */
- public void getExtractedRectForView(Launcher launcher, int pageId, View v,
- RectF colorExtractionRectOut) {
- // no-op
- }
-
- /**
- * Takes a rect in drag layer coordinates and returns the rect that can be used by the wallpaper
- * local color extractor.
- *
- * @param launcher Launcher class.
- * @param pageId The page the workspace item is on.
- * @param rectInDragLayer The relevant bounds of the view in drag layer coordinates.
- * @param colorExtractionRectOut The location rect, but converted to a format expected by the
- * wallpaper local color extractor.
- */
- public void getExtractedRectForViewRect(Launcher launcher, int pageId, Rect rectInDragLayer,
- RectF colorExtractionRectOut) {
- // no-op
- }
}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index a4003d4..991910d 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -205,10 +205,6 @@
draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
}
- // Since we are not going through the workspace for starting the drag, set drag related
- // information on the workspace before starting the drag.
- launcher.getWorkspace().prepareDragWithProvider(this);
-
int dragLayerX = screenPos.x + previewBounds.left
+ (int) ((scale * previewWidth - previewWidth) / 2);
int dragLayerY = screenPos.y + previewBounds.top
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index d3f4528..167eb09 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -18,6 +18,7 @@
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
import static com.android.launcher3.Utilities.ATLEAST_S;
@@ -372,7 +373,7 @@
if (shouldScale) {
setNoClip(mWidgetImageContainer);
setNoClip(mAppWidgetHostViewPreview);
- mAppWidgetHostViewScale = computeWidgetPreviewScale();
+ mAppWidgetHostViewScale = measureAndComputeWidgetPreviewScale();
mAppWidgetHostViewPreview.setScaleToFit(mAppWidgetHostViewScale);
}
}
@@ -473,7 +474,7 @@
view.setClipToPadding(false);
}
- private float computeWidgetPreviewScale() {
+ private float measureAndComputeWidgetPreviewScale() {
if (mAppWidgetHostViewPreview.getChildCount() != 1) {
return 1f;
}
@@ -482,12 +483,25 @@
mAppWidgetHostViewPreview.measure(
makeMeasureSpec(MAX_MEASURE_SPEC_DIMENSION, MeasureSpec.UNSPECIFIED),
makeMeasureSpec(MAX_MEASURE_SPEC_DIMENSION, MeasureSpec.UNSPECIFIED));
- int appWidgetContentWidth = mAppWidgetHostViewPreview.getChildAt(0).getMeasuredWidth();
- int appWidgetContentHeight = mAppWidgetHostViewPreview.getChildAt(0).getMeasuredHeight();
+ View widgetContent = mAppWidgetHostViewPreview.getChildAt(0);
+ int appWidgetContentWidth = widgetContent.getMeasuredWidth();
+ int appWidgetContentHeight = widgetContent.getMeasuredHeight();
if (appWidgetContentWidth == 0 || appWidgetContentHeight == 0) {
return 1f;
}
+ // If the width / height of the widget content is set to wrap content, overrides the width /
+ // height with the measured dimension. This avoids incorrect measurement after scaling.
+ FrameLayout.LayoutParams layoutParam =
+ (FrameLayout.LayoutParams) widgetContent.getLayoutParams();
+ if (layoutParam.width == WRAP_CONTENT) {
+ layoutParam.width = widgetContent.getMeasuredWidth();
+ }
+ if (layoutParam.height == WRAP_CONTENT) {
+ layoutParam.height = widgetContent.getMeasuredHeight();
+ }
+ widgetContent.setLayoutParams(layoutParam);
+
int horizontalPadding = mAppWidgetHostViewPreview.getPaddingStart()
+ mAppWidgetHostViewPreview.getPaddingEnd();
int verticalPadding = mAppWidgetHostViewPreview.getPaddingTop()
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 406de10..6beff3a 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -70,11 +70,10 @@
private static final int DEFAULT_CLOSE_DURATION = 200;
private static final long EDUCATION_TIP_DELAY_MS = 300;
- private final int mWidgetSheetContentHorizontalPadding;
-
private ItemInfo mOriginalItemInfo;
private final int mMaxTableHeight;
private int mMaxHorizontalSpan = DEFAULT_MAX_HORIZONTAL_SPANS;
+ private final int mWidgetCellHorizontalPadding;
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
new OnLayoutChangeListener() {
@@ -119,9 +118,8 @@
if (!hasSeenEducationTip()) {
addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
}
-
- mWidgetSheetContentHorizontalPadding = getResources().getDimensionPixelSize(
- R.dimen.widget_list_horizontal_margin);
+ mWidgetCellHorizontalPadding = getResources().getDimensionPixelSize(
+ R.dimen.widget_cell_horizontal_padding);
}
@Override
@@ -142,8 +140,7 @@
private boolean updateMaxSpansPerRow() {
if (getMeasuredWidth() == 0) return false;
- int maxHorizontalSpan = computeMaxHorizontalSpans(mContent,
- mWidgetSheetContentHorizontalPadding);
+ int maxHorizontalSpan = computeMaxHorizontalSpans(mContent, mWidgetCellHorizontalPadding);
if (mMaxHorizontalSpan != maxHorizontalSpan) {
// Ensure the table layout is showing widgets in the right column after measure.
mMaxHorizontalSpan = maxHorizontalSpan;
@@ -275,6 +272,14 @@
}
@Override
+ protected void onContentHorizontalMarginChanged(int contentHorizontalMarginInPx) {
+ ViewGroup.MarginLayoutParams layoutParams =
+ ((ViewGroup.MarginLayoutParams) findViewById(R.id.widgets_table).getLayoutParams());
+ layoutParams.setMarginStart(contentHorizontalMarginInPx);
+ layoutParams.setMarginEnd(contentHorizontalMarginInPx);
+ }
+
+ @Override
protected Pair<View, String> getAccessibilityTarget() {
return Pair.create(findViewById(R.id.title), getContext().getString(
mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
diff --git a/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java b/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java
index 4a60983..3e54b33 100644
--- a/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java
+++ b/src/com/android/launcher3/widget/dragndrop/AppWidgetHostViewDragListener.java
@@ -24,7 +24,6 @@
/** A drag listener of {@link LauncherAppWidgetHostView}. */
public final class AppWidgetHostViewDragListener implements DragController.DragListener {
private final Launcher mLauncher;
- private DropTarget.DragObject mDragObject;
private LauncherAppWidgetHostView mAppWidgetHostView;
public AppWidgetHostViewDragListener(Launcher launcher) {
@@ -34,9 +33,8 @@
@Override
public void onDragStart(DropTarget.DragObject dragObject, DragOptions unused) {
if (dragObject.dragView.getContentView() instanceof LauncherAppWidgetHostView) {
- mDragObject = dragObject;
mAppWidgetHostView = (LauncherAppWidgetHostView) dragObject.dragView.getContentView();
- mAppWidgetHostView.startDrag(this);
+ mAppWidgetHostView.startDrag();
} else {
mLauncher.getDragController().removeDragListener(this);
}
@@ -47,11 +45,4 @@
mAppWidgetHostView.endDrag();
mLauncher.getDragController().removeDragListener(this);
}
-
- /** Notifies when there is a content change in the drag view. */
- public void onDragContentChanged() {
- if (mDragObject.dragView != null) {
- mDragObject.dragView.invalidate();
- }
- }
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 5e1a534..be83f9a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.widget.picker;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -357,6 +359,29 @@
}
@Override
+ protected void onContentHorizontalMarginChanged(int contentHorizontalMarginInPx) {
+ setContentViewChildHorizontalMargin(mSearchAndRecommendationViewHolder.mContainer,
+ contentHorizontalMarginInPx);
+ if (mViewPager == null) {
+ setContentViewChildHorizontalMargin(
+ mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView,
+ contentHorizontalMarginInPx);
+ } else {
+ setContentViewChildHorizontalMargin(mViewPager, contentHorizontalMarginInPx);
+ }
+ setContentViewChildHorizontalMargin(
+ mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView,
+ contentHorizontalMarginInPx);
+ }
+
+ private static void setContentViewChildHorizontalMargin(View view, int horizontalMarginInPx) {
+ ViewGroup.MarginLayoutParams layoutParams =
+ (ViewGroup.MarginLayoutParams) view.getLayoutParams();
+ layoutParams.setMarginStart(horizontalMarginInPx);
+ layoutParams.setMarginEnd(horizontalMarginInPx);
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
doMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -377,7 +402,10 @@
private boolean updateMaxSpansPerRow() {
if (getMeasuredWidth() == 0) return false;
- int maxHorizontalSpans = computeMaxHorizontalSpans(mContent,
+ View content = mHasWorkProfile
+ ? mViewPager
+ : mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView;
+ int maxHorizontalSpans = computeMaxHorizontalSpans(content,
mWidgetSheetContentHorizontalPadding);
if (mMaxSpansPerRow != maxHorizontalSpans) {
mMaxSpansPerRow = maxHorizontalSpans;
@@ -520,7 +548,12 @@
mNoWidgetsView.getText().length(), noWidgetsViewTextBounds);
noWidgetsViewHeight = noWidgetsViewTextBounds.height();
}
- float maxTableHeight = (mActivityContext.getDeviceProfile().availableHeightPx
+ doMeasure(
+ makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx,
+ MeasureSpec.EXACTLY),
+ makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
+ MeasureSpec.EXACTLY));
+ float maxTableHeight = (mContent.getMeasuredHeight()
- mTabsHeight - mViewPagerTopPadding - getHeaderViewHeight()
- noWidgetsViewHeight) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index c606861..cc90e6c 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -39,9 +39,9 @@
}
/**
- * Returns the minimum space that should be left empty at the start of hotseat
+ * Returns the minimum space that should be left empty at the end of hotseat
*/
- public static int getHotseatStartOffset(Context context) {
+ public static int getHotseatEndOffset(Context context) {
return 0;
}
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index bf4eba0..dcb6dc1 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -153,6 +153,8 @@
public static String dumpHprofData() {
String result;
if (sDumpWasGenerated) {
+ Log.d("b/195319692", "dump has already been generated by another test",
+ new Exception());
result = "dump has already been generated by another test";
} else {
try {
@@ -167,6 +169,7 @@
"am dumpheap " + device.getLauncherPackageName() + " " + fileName);
}
sDumpWasGenerated = true;
+ Log.d("b/195319692", "sDumpWasGenerated := true", new Exception());
result = "memory dump filename: " + fileName;
} catch (Throwable e) {
Log.e(TAG, "dumpHprofData failed", e);
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index dad4f2b..2e8048a 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -27,6 +27,7 @@
import com.android.launcher3.tapl.Widget;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -80,6 +81,7 @@
*/
@Test
@PortraitLandscape
+ @ScreenRecord //b/195263971
public void testDragCustomShortcut() throws Throwable {
clearHomescreen();
mDevice.pressHome();
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 641e53a..a5694fc 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -87,7 +87,6 @@
}
@Test
- @ScreenRecord //b/192005114
public void testPinWidgetNoConfig_customPreview() throws Throwable {
// Command to set custom preview
Intent command = RequestPinItemActivity.getCommandIntent(
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index dc59bdd..5fbf847 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -61,13 +61,23 @@
out.putNextEntry(new ZipEntry("visible_windows.zip"));
dumpCommand("cmd window dump-visible-window-views", out);
out.closeEntry();
- } catch (IOException ex) { }
+ } catch (IOException ex) {
+ }
Log.e(TAG, "Failed test " + description.getMethodName()
+ ",\nscreenshot will be saved to " + sceenshot
+ ",\nUI dump at: " + hierarchy
+ " (use go/web-hv to open the dump file)", e);
device.takeScreenshot(sceenshot);
+
+ // Dump accessibility hierarchy
+ final File accessibilityHierarchyFile = new File(parentFile,
+ "AccessibilityHierarchy-" + description.getMethodName() + ".uix");
+ try {
+ device.dumpWindowHierarchy(accessibilityHierarchyFile);
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to save accessibility hierarchy", ex);
+ }
}
private static void dumpStringCommand(String cmd, OutputStream out) throws IOException {
diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index 0e27b61..de36d5f 100644
--- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -41,9 +41,7 @@
Pattern.compile("^("
+ "(?<local>(BuildFromAndroidStudio|"
+ "([0-9]+|[A-Z])-eng\\.[a-z]+\\.[0-9]+\\.[0-9]+))|"
- + "(?<presubmit>([0-9]+|[A-Z])-P[0-9]+)|"
- + "(?<postsubmit>([0-9]+|[A-Z])-[0-9]+)|"
- + "(?<platform>[0-9]+|[A-Z])"
+ + "(?<platform>[A-Z]([a-z]|[0-9])*)"
+ ")$");
private static final Pattern PLATFORM_BUILD =
Pattern.compile("^("
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index a15131d..7ec5208 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -56,24 +56,29 @@
protected abstract String launchableType();
private Background launch(BySelector selector) {
- LauncherInstrumentation.log("Launchable.launch before click "
- + mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
- final String label = mObject.getText();
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "want to launch an app from " + launchableType())) {
+ LauncherInstrumentation.log("Launchable.launch before click "
+ + mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(mObject));
+ final String label = mObject.getText();
- mLauncher.executeAndWaitForEvent(
- () -> {
- mLauncher.clickLauncherObject(mObject);
- expectActivityStartEvents();
- },
- event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
- () -> "Launching an app didn't open a new window: " + label,
- "clicking " + launchableType());
+ mLauncher.executeAndWaitForEvent(
+ () -> {
+ mLauncher.clickLauncherObject(mObject);
+ expectActivityStartEvents();
+ },
+ event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
+ () -> "Launching an app didn't open a new window: " + label,
+ "clicking " + launchableType());
- mLauncher.assertTrue(
- "App didn't start: " + label + " (" + selector + ")",
- TestHelpers.wait(Until.hasObject(selector),
- LauncherInstrumentation.WAIT_TIME_MS));
- return new Background(mLauncher);
+ try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("clicked")) {
+ mLauncher.assertTrue(
+ "App didn't start: " + label + " (" + selector + ")",
+ TestHelpers.wait(Until.hasObject(selector),
+ LauncherInstrumentation.WAIT_TIME_MS));
+ return new Background(mLauncher);
+ }
+ }
}
/**
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 9da3e71..abcc778 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -96,6 +96,7 @@
private static final String TAG = "Tapl";
private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;
private static final int GESTURE_STEP_MS = 16;
+ private static final long FORCE_PAUSE_TIMEOUT_MS = 700;
static final Pattern EVENT_TOUCH_DOWN = getTouchEventPattern("ACTION_DOWN");
static final Pattern EVENT_TOUCH_UP = getTouchEventPattern("ACTION_UP");
@@ -105,6 +106,7 @@
static final Pattern EVENT_TOUCH_DOWN_TIS = getTouchEventPatternTIS("ACTION_DOWN");
static final Pattern EVENT_TOUCH_UP_TIS = getTouchEventPatternTIS("ACTION_UP");
+
private final String mLauncherPackage;
private Boolean mIsLauncher3;
private long mTestStartTime = -1;
@@ -123,8 +125,6 @@
OUTSIDE_WITHOUT_PILFER, OUTSIDE_WITH_PILFER, INSIDE, INSIDE_TO_OUTSIDE
}
- ;
-
// Base class for launcher containers.
static abstract class VisibleContainer {
protected final LauncherInstrumentation mLauncher;
@@ -272,9 +272,13 @@
}
Bundle getTestInfo(String request) {
+ return getTestInfo(request, /*arg=*/ null);
+ }
+
+ Bundle getTestInfo(String request, String arg) {
try (ContentProviderClient client = getContext().getContentResolver()
.acquireContentProviderClient(mTestProviderUri)) {
- return client.call(request, null, null);
+ return client.call(request, arg, null);
} catch (DeadObjectException e) {
fail("Launcher crashed");
return null;
@@ -298,6 +302,10 @@
.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ private void setForcePauseTimeout(long timeout) {
+ getTestInfo(TestProtocol.REQUEST_SET_FORCE_PAUSE_TIMEOUT, Long.toString(timeout));
+ }
+
void setActiveContainer(VisibleContainer container) {
sActiveContainer = new WeakReference<>(container);
}
@@ -383,6 +391,14 @@
if (hasSystemUiObject("keyguard_status_view")) return "Phone is locked";
+ final String visibleApps = mDevice.findObjects(getAnyObjectSelector())
+ .stream()
+ .map(LauncherInstrumentation::getApplicationPackageSafe)
+ .distinct()
+ .filter(pkg -> pkg != null)
+ .collect(Collectors.joining(","));
+ if (SYSTEMUI_PACKAGE.equals(visibleApps)) return "Only System UI views are visible";
+
if (!mDevice.wait(Until.hasObject(getAnyObjectSelector()), WAIT_TIME_MS)) {
return "Screen is empty";
}
@@ -406,12 +422,15 @@
}
private String getVisiblePackages() {
- return mDevice.findObjects(getAnyObjectSelector())
+ final String apps = mDevice.findObjects(getAnyObjectSelector())
.stream()
.map(LauncherInstrumentation::getApplicationPackageSafe)
.distinct()
- .filter(pkg -> pkg != null && !"com.android.systemui".equals(pkg))
+ .filter(pkg -> pkg != null && !SYSTEMUI_PACKAGE.equals(pkg))
.collect(Collectors.joining(", "));
+ return !apps.isEmpty()
+ ? "active app: " + apps
+ : "the test doesn't see views from any app, including Launcher";
}
private static String getApplicationPackageSafe(UiObject2 object) {
@@ -717,18 +736,24 @@
// otherwise waitForIdle may return immediately in case when there was a big enough
// pause in accessibility events prior to pressing Home.
final String action;
- final boolean launcherWasVisible = isLauncherVisible();
if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
checkForAnomaly();
+ setForcePauseTimeout(FORCE_PAUSE_TIMEOUT_MS);
final Point displaySize = getRealDisplaySize();
+ boolean gestureStartFromLauncher = isTablet()
+ ? !isLauncher3() || hasLauncherObject(WORKSPACE_RES_ID)
+ : isLauncherVisible();
+ GestureScope gestureScope = gestureStartFromLauncher
+ ? GestureScope.INSIDE_TO_OUTSIDE
+ : GestureScope.OUTSIDE_WITH_PILFER;
if (hasLauncherObject(CONTEXT_MENU_RES_ID)) {
linearGesture(
displaySize.x / 2, displaySize.y - 1,
displaySize.x / 2, 0,
ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
- false, GestureScope.INSIDE_TO_OUTSIDE);
+ false, gestureScope);
try (LauncherInstrumentation.Closable c1 = addContextLayer(
"Swiped up from context menu to home")) {
waitUntilLauncherObjectGone(CONTEXT_MENU_RES_ID);
@@ -745,17 +770,11 @@
dumpViewHierarchy();
action = "swiping up to home";
- final boolean launcherIsVisible = isLauncherVisible();
swipeToState(
displaySize.x / 2, displaySize.y - 1,
displaySize.x / 2, 0,
ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, NORMAL_STATE_ORDINAL,
- launcherWasVisible
- ? GestureScope.INSIDE_TO_OUTSIDE
- : GestureScope.OUTSIDE_WITH_PILFER);
- // b/193653850: launcherWasVisible is a flaky indicator.
- log("launcherWasVisible: " + launcherWasVisible + ", launcherIsVisible: "
- + launcherIsVisible);
+ gestureScope);
}
} else {
log("Hierarchy before clicking home:");
@@ -1108,9 +1127,9 @@
"swiping");
}
- private int getBottomGestureSize() {
- return ResourceUtils.getNavbarSize(
- ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources()) + 1;
+ int getBottomGestureSize() {
+ return Math.max(getTargetInsets().bottom, ResourceUtils.getNavbarSize(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources())) + 1;
}
int getBottomGestureMarginInContainer(UiObject2 container) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 2acf7b4..db2e250 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -34,7 +34,6 @@
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
-import com.android.launcher3.ResourceUtils;
import com.android.launcher3.testing.TestProtocol;
import java.util.regex.Pattern;
@@ -72,8 +71,7 @@
mLauncher.addContextLayer("want to switch from workspace to all apps")) {
verifyActiveContainer();
final int deviceHeight = mLauncher.getDevice().getDisplayHeight();
- final int bottomGestureMargin = ResourceUtils.getNavbarSize(
- ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources());
+ final int bottomGestureMargin = mLauncher.getBottomGestureSize();
final int windowCornerRadius = (int) Math.ceil(mLauncher.getWindowCornerRadius());
final int startY = deviceHeight - Math.max(bottomGestureMargin, windowCornerRadius) - 1;
final int swipeHeight = mLauncher.getTestInfo(