diff --git a/Android.bp b/Android.bp
index cd2ec2902d..e07d69d045 100644
--- a/Android.bp
+++ b/Android.bp
@@ -21,6 +21,9 @@ min_launcher3_sdk_version = "26"
android_library {
name: "launcher-aosp-tapl",
+ libs: [
+ "framework-statsd",
+ ],
static_libs: [
"androidx.annotation_annotation",
"androidx.test.runner",
@@ -137,9 +140,13 @@ android_app {
],
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src_shortcuts_overrides/**/*.java",
+ "src_shortcuts_overrides/**/*.kt",
"src_ui_overrides/**/*.java",
+ "src_ui_overrides/**/*.kt",
"ext_tests/src/**/*.java",
+ "ext_tests/src/**/*.kt",
],
resource_dirs: [
"ext_tests/res",
@@ -180,8 +187,12 @@ android_library {
resource_dirs: [
"quickstep/res",
],
+ libs: [
+ "framework-statsd",
+ ],
static_libs: [
"Launcher3ResLib",
+ "lottie",
"SystemUISharedLib",
"SystemUI-statsd",
],
@@ -193,7 +204,10 @@ android_library {
// Source code used for test helpers
filegroup {
name: "launcher-src-ext-tests",
- srcs: ["ext_tests/src/**/*.java"],
+ srcs: [
+ "ext_tests/src/**/*.java",
+ "ext_tests/src/**/*.kt",
+ ],
}
// Common source files used to build launcher
@@ -201,8 +215,11 @@ filegroup {
name: "launcher-src-no-build-config",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src_shortcuts_overrides/**/*.java",
+ "src_shortcuts_overrides/**/*.kt",
"quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
],
}
@@ -212,20 +229,27 @@ filegroup {
srcs: ["proguard.flags"],
}
-
// Library with all the dependencies for building Launcher Go
android_library {
name: "LauncherGoResLib",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
"go/src/**/*.java",
+ "go/src/**/*.kt",
"go/quickstep/src/**/*.java",
+ "go/quickstep/src/**/*.kt",
],
resource_dirs: [
"go/res",
"go/quickstep/res",
],
+ // Note the ordering here is important when it comes to resource
+ // overriding. We want the most specific resource overrides defined
+ // in QuickstepResLib to take precendece, so it should be the final
+ // dependency. See b/205278434 for how this can go wrong.
static_libs: [
"Launcher3CommonDepsLib",
"QuickstepResLib",
@@ -241,3 +265,30 @@ android_library {
},
}
+// Build rule for Quickstep library
+android_library {
+ name: "Launcher3QuickStepLib",
+ srcs: [
+ ":launcher-src-no-build-config",
+ ],
+ resource_dirs: [],
+ libs: [
+ "framework-statsd",
+ ],
+ // Note the ordering here is important when it comes to resource
+ // overriding. We want the most specific resource overrides defined
+ // in QuickstepResLib to take precendece, so it should be the final
+ // dependency. See b/208647810 for how this can go wrong.
+ static_libs: [
+ "SystemUI-statsd",
+ "SystemUISharedLib",
+ "Launcher3CommonDepsLib",
+ "QuickstepResLib",
+ ],
+ manifest: "quickstep/AndroidManifest.xml",
+ platform_apis: true,
+ min_sdk_version: "current",
+ lint: {
+ baseline_filename: "lint-baseline-launcher3.xml",
+ },
+}
diff --git a/Android.mk b/Android.mk
index 95c8b70d81..1bc8b283c7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -53,43 +53,6 @@ LOCAL_LICENSE_PACKAGE_NAME := Android Launcher3
LOCAL_NOTICE_FILE := build/soong/licenses/LICENSE
include $(BUILD_PACKAGE)
-#
-# Build rule for Quickstep library.
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- SystemUI-statsd \
- SystemUISharedLib
-ifneq (,$(wildcard frameworks/base))
- LOCAL_PRIVATE_PLATFORM_APIS := true
-else
- LOCAL_SDK_VERSION := system_current
- LOCAL_MIN_SDK_VERSION := 26
-endif
-LOCAL_MODULE := Launcher3QuickStepLib
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_LICENSE_PACKAGE_NAME := Android Launcher3
-LOCAL_NOTICE_FILE := build/soong/licenses/LICENSE
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
-
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-java-files-under, quickstep/src) \
- $(call all-java-files-under, src_shortcuts_overrides)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
-LOCAL_PROGUARD_ENABLED := disabled
-
-
-LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
#
# Build rule for Quickstep app.
#
@@ -144,7 +107,7 @@ else
LOCAL_SDK_VERSION := system_current
LOCAL_MIN_SDK_VERSION := 26
endif
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+LOCAL_STATIC_ANDROID_LIBRARIES := LauncherGoResLib
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index ea75ea9549..3fd7375c3f 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -31,7 +31,6 @@
with some minor changed based on the derivative app.
-->
-
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f793131fd3..398489044e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -31,6 +31,7 @@
android:fullBackupOnly="true"
android:fullBackupContent="@xml/backupscheme"
android:hardwareAccelerated="true"
+ android:debuggable="true"
android:icon="@drawable/ic_launcher_home"
android:label="@string/derived_app_name"
android:theme="@style/AppTheme"
@@ -49,7 +50,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/buglist_with_title.txt b/buglist_with_title.txt
deleted file mode 100644
index aa8b413284..0000000000
--- a/buglist_with_title.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-144170434 twickham P1 FIXED Improve Overview -> Home transition ----
-149934536 twickham P2 FIXED Update gesture nav pullback logic ----
-154951045 peanutbutter P1 FIXED Odd animation occuring at times when swiping to home ----
-154964045 awickham P2 FIXED "Clear all" text is not in the middle of app's window vertically ----
-158701272 twickham P4 FIXED Discontinuities when long-swiping to home ----
-160361464 tracyzhou P2 FIXED Place launcher above the target app in live tile mode ----
-160568387 twickham P2 FIXED Can't get to app switcher by swiping up (motion pause not detected) ----
-160718310 xuqiu P1 FIXED With "Select" overview action selected, App icon is missing in other overview apps after orientation change ----
-160748731 sunnygoyal P2 ASSIGNED Unify prediction model with Launcher model ----
-160759508 twickham P2 FIXED Swipe up cannot back to home screen in overview. ----
-161273376 xuqiu P2 FIXED [Overview Actions] Add logging and helpful messages ----
-161536946 twickham P2 FIXED Haptics don't indicate snap-to in overview, ----
-161685099 winsonc P2 FIXED Screen still stay at the quick settings/notification when I swipe up with 3 finger to check the all apps. ----
-161801331 hyunyoungs P2 FIXED Change AllAppsSearch plugin to support only data fetch ----
-161901771 xuqiu P1 FIXED Overlapping layer of highlights with app layout getting darker when keep rotating the device from "Feedback" viewpoint in split screen ----
-161939759 sunnygoyal P2 FIXED RD1A: Going to overview in landscape mode clips the screen content ----
-162012217 perumaal P2 ASSIGNED Leaked Activity Caused by Gleams ----
-162454040 bookatz P2 ASSIGNED Create multiuser test that checks that opening an app works properly ----
-162480567 sfufa P4 FIXED Enable Item Decorations for search items ----
-162564471 tracyzhou P2 FIXED [Live tile] Handle tapping overview actions in live tile mode ----
-162623012 zakcohen P1 ASSIGNED Enable chips flag ----
-162812884 winsonc P2 ASSIGNED [R]The color have not changed in some page after turning on the dark theme. ----
-162861289 hyunyoungs P2 FIXED Add FocusIndicator support to DEVICE_SEARCH feature in S ----
-162871508 sfufa P2 ASSIGNED Introduce support for Hero app section ----
diff --git a/build.gradle b/build.gradle
index 0622d87764..e4ade88af8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,7 +2,6 @@ buildscript {
repositories {
mavenCentral()
google()
- jcenter()
}
dependencies {
classpath GRADLE_CLASS_PATH
@@ -164,6 +163,8 @@ dependencies {
androidTestImplementation 'com.android.support.test:rules:1.0.0'
androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
androidTestImplementation "androidx.annotation:annotation:${ANDROID_X_VERSION}"
+
+ api 'com.airbnb.android:lottie:3.3.0'
}
protobuf {
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
index 72b8d3fcae..0f61d149d0 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -18,6 +18,8 @@ package com.android.launcher3.testing;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import android.app.Activity;
+import android.app.Application;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
@@ -31,7 +33,10 @@ import com.android.launcher3.LauncherSettings;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedList;
+import java.util.Map;
+import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -41,9 +46,48 @@ import java.util.concurrent.TimeUnit;
public class DebugTestInformationHandler extends TestInformationHandler {
private static LinkedList sLeaks;
private static Collection sEvents;
+ private static Application.ActivityLifecycleCallbacks sActivityLifecycleCallbacks;
+ private static final Map sActivities =
+ Collections.synchronizedMap(new WeakHashMap<>());
+ private static int sActivitiesCreatedCount = 0;
public DebugTestInformationHandler(Context context) {
init(context);
+ if (sActivityLifecycleCallbacks == null) {
+ sActivityLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() {
+ @Override
+ public void onActivityCreated(Activity activity, Bundle bundle) {
+ sActivities.put(activity, true);
+ ++sActivitiesCreatedCount;
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ }
+ };
+ ((Application) context.getApplicationContext())
+ .registerActivityLifecycleCallbacks(sActivityLifecycleCallbacks);
+ }
}
private static void runGcAndFinalizersSync() {
@@ -80,7 +124,7 @@ public class DebugTestInformationHandler extends TestInformationHandler {
}
@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: {
@@ -160,8 +204,22 @@ public class DebugTestInformationHandler extends TestInformationHandler {
}
}
+ case TestProtocol.REQUEST_GET_ACTIVITIES_CREATED_COUNT: {
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, sActivitiesCreatedCount);
+ return response;
+ }
+
+ case TestProtocol.REQUEST_GET_ACTIVITIES: {
+ response.putStringArray(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ sActivities.keySet().stream().map(
+ a -> a.getClass().getSimpleName() + " ("
+ + (a.isDestroyed() ? "destroyed" : "current") + ")")
+ .toArray(String[]::new));
+ return response;
+ }
+
default:
- return super.call(method);
+ return super.call(method, arg);
}
}
}
diff --git a/go/AndroidManifest-launcher.xml b/go/AndroidManifest-launcher.xml
index 6a8f715bb2..2223036a7a 100644
--- a/go/AndroidManifest-launcher.xml
+++ b/go/AndroidManifest-launcher.xml
@@ -49,7 +49,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density|uiMode"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index 0e718ca08d..196541f0a9 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.
-->
-
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom">
+
+
\ No newline at end of file
diff --git a/go/quickstep/res/values-af/strings.xml b/go/quickstep/res/values-af/strings.xml
deleted file mode 100644
index 363eff5050..0000000000
--- a/go/quickstep/res/values-af/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Deel program"
- "Luister"
- "Vertaal"
- "Lens"
- "HET DIT"
- "KANSELLEER"
- "INSTELLINGS"
- "Vertaal of luister na teks op skerm"
- "Inligting soos teks op jou skerm, webadresse en skermskote kan met Google gedeel word.\n\nGaan na ""Instellings > Programme > Verstekprogramme > Digitale Assistent-program"" om te verander watter inligting jy deel."
- "Kies \'n assistent om hierdie kenmerk te gebruik"
- "Kies \'n digitalebystandprogram in Instellings om na teks op jou skerm te luister of dit te vertaal"
- "Verander jou assistent om hierdie kenmerk te gebruik"
- "Verander jou digitalebystandprogram in Instellings om na teks op jou skerm te luister of dit te vertaal"
- "Tik hier om na teks op hierdie skerm te luister"
- "Tik hier om teks op hierdie skerm te vertaal"
-
diff --git a/go/quickstep/res/values-am/strings.xml b/go/quickstep/res/values-am/strings.xml
deleted file mode 100644
index 5d8a76603c..0000000000
--- a/go/quickstep/res/values-am/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "መተግበሪያን አጋራ"
- "ያዳምጡ"
- "ተርጉም"
- "ሌንስ"
- "ገባኝ"
- "ይቅር"
- "ቅንብሮች"
- "በማያ ገጹ ላይ ጽሑፍን ይተረጉሙ ወይም ያዳምጡ"
- "እንደ በማያ ገጽዎ ላይ ያለ ጽሑፍ፣ የድር አድራሻዎች እና ቅጽበታዊ ገጽ እይታዎች ያሉ መረጃዎች ለGoogle ሊጋሩ ይችላሉ።\n\nምን መረጃ እንደሚያጋሩ ለመቀየር ወደ ""ቅንብሮች > መተግበሪያዎች > ነባሪ መተግበሪያዎች > ዲጂታል ረዳት መተግበሪያ"" ይሂዱ።"
- "ይህንን ባህሪ ለመጠቀም ረዳት ይምረጡ"
- "በማያ ገጽዎ ላይ ጽሑፍን ለማዳመጥ ወይም ለመተርጎም በቅንብሮች ውስጥ የዲጂታል ረዳት መተግበሪያን ይምረጡ"
- "ይህንን ባህሪ ለመጠቀም ረዳትዎን ይቀይሩ"
- "በማያ ገጽዎ ላይ ጽሑፍን ለማዳመጥ ወይም ለመተርጎም በቅንብሮች ውስጥ የዲጂታል ረዳት መተግበሪያዎን ይቀይሩ"
- "በዚህ ማያ ገጽ ላይ ጽሑፍ ለማዳመጥ እዚህ መታ ያድርጉ"
- "በዚህ ማያ ገጽ ላይ ጽሑፍ ለመተርጎም እዚህ መታ ያድርጉ"
-
diff --git a/go/quickstep/res/values-ar/strings.xml b/go/quickstep/res/values-ar/strings.xml
deleted file mode 100644
index bbe35f5a5f..0000000000
--- a/go/quickstep/res/values-ar/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "مشاركة التطبيق"
- "استماع"
- "ترجمة Google"
- "عدسة Google"
- "حسنًا"
- "إلغاء"
- "الإعدادات"
- "ترجمة النص الظاهر على الشاشة أو الاستماع إليه"
- "قد تتم مشاركة معلومات مثل النص الظاهر على الشاشة وعناوين الويب ولقطات الشاشة مع Google.\n\nلتغيير المعلومات التي تتم مشاركتها، انتقِل إلى ""الإعدادات > التطبيقات > التطبيقات التلقائية > تطبيق المساعد الرقمي""."
- "اختيار مساعد لاستخدام هذه الميزة"
- "للاستماع للنص الظاهر على الشاشة أو ترجمته، اختَر تطبيق مساعد رقمي في الإعدادات."
- "تغيير المساعد لاستخدام هذه الميزة"
- "للاستماع للنص الظاهر على الشاشة أو ترجمته، عليك تغيير تطبيق المساعد الرقمي في الإعدادات."
- "انقر هنا للاستماع للنص الظاهر على هذه الشاشة."
- "انقر هنا لترجمة النص الظاهر على هذه الشاشة."
-
diff --git a/go/quickstep/res/values-as/strings.xml b/go/quickstep/res/values-as/strings.xml
deleted file mode 100644
index cd123b5643..0000000000
--- a/go/quickstep/res/values-as/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "এপ্ শ্বেয়াৰ কৰক"
- "শুনক"
- "অনুবাদ কৰক"
- "লেন্স"
- "বুজি পালোঁ"
- "বাতিল কৰক"
- "ছেটিং"
- "স্ক্ৰীনত থকা পাঠ অনুবাদ কৰক অথবা শুনক"
- "আপোনাৰ স্ক্ৰীনত থকা পাঠ, ৱেব ঠিকনা আৰু স্ক্ৰীনশ্বটৰ দৰে তথ্য Googleৰ সৈতে হয়তো শ্বেয়াৰ কৰা হ’ব।\n\nআপুনি কোনসমুহ তথ্য শ্বেয়াৰ কৰিব সেয়া সলনি কৰিবলৈ, ""ছেটিং > এপ্ > ডিফ’ল্ট এপ্ > ডিজিটেল সহায়ক এপ""লৈ যাওক।"
- "এই সুবিধাটো ব্যৱহাৰ কৰিবলৈ এটা সহায়ক বাছনি কৰক"
- "আপোনাৰ স্ক্ৰীনত থকা পাঠ শুনিবলৈ অথবা সেই পাঠৰ অনুবাদ কৰিবলৈ, ছেটিঙত এটা ডিজিটেল সহায়ক এপ্ বাছনি কৰক"
- "এই সুবিধাটো ব্যৱহাৰ কৰিবলৈ আপোনাৰ সহায়ক সলনি কৰক"
- "আপোনাৰ স্ক্ৰীনত থকা পাঠ শুনিবলৈ অথবা সেই পাঠৰ অনুবাদ কৰিবলৈ, ছেটিঙত আপোনাৰ ডিজিটেল সহায়ক এপ্টো সলনি কৰক"
- "এই স্ক্ৰীনখনত থকা পাঠ শুনিবলৈ ইয়াত টিপক"
- "এই স্ক্ৰীনখনত থকা পাঠৰ অনুবাদ কৰিবলৈ ইয়াত টিপক"
-
diff --git a/go/quickstep/res/values-az/strings.xml b/go/quickstep/res/values-az/strings.xml
deleted file mode 100644
index f097ad322b..0000000000
--- a/go/quickstep/res/values-az/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Tətbiqi paylaşın"
- "Dinləyin"
- "Tərcümə"
- "Linza"
- "ANLADIM"
- "LƏĞV EDİN"
- "AYARLAR"
- "Ekrandakı mətni tərcümə edin və ya dinləyin"
- "Ekrandakı mətn, veb ünvanlar və ekran görüntüləri kimi məlumatlar Google ilə paylaşıla bilər.\n\nHansı məlumatların paylaşılmasını dəyişmək üçün ""Ayarlar > Tətbiqlər > Defolt tətbiqlər > Rəqəmsal assistent tətbiqi"" bölməsinə keçin."
- "Bu funksiyadan istifadə etmək üçün assistenti seçin"
- "Ekrandakı mətni dinləmək və ya tərcümə etmək üçün Ayarlarda rəqəmsal assistent tətbiqini seçin"
- "Bu funksiyadan istifadə etmək üçün assistenti dəyişin"
- "Ekrandakı mətni dinləmək və ya tərcümə etmək üçün Ayarlarda rəqəmsal assistent tətbiqini dəyişin"
- "Bu ekrandakı mətni dinləmək üçün buraya toxunun"
- "Bu ekrandakı mətni tərcümə etmək üçün buraya toxunun"
-
diff --git a/go/quickstep/res/values-b+sr+Latn/strings.xml b/go/quickstep/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index 8663c8171d..0000000000
--- a/go/quickstep/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Deli aplikaciju"
- "Pusti"
- "Prevedi"
- "Objektiv"
- "VAŽI"
- "OTKAŽI"
- "PODEŠAVANJA"
- "Prevodite ili slušajte tekst na ekranu"
- "Informacije poput teksta na ekranu, veb-adresa i snimaka ekrana mogu da se dele sa Google-om.\n\nDa biste promenili informacije koje delite, idite u ""Podešavanja > Aplikacije > Podrazumevane aplikacije > Aplikacija digitalnog pomoćnika""."
- "Odaberite pomoćnika da biste koristili ovu funkciju"
- "Da biste čuli tekst sa ekrana ili ga preveli, odaberite aplikaciju digitalnog pomoćnika u Podešavanjima"
- "Promenite pomoćnika da biste koristili ovu funkciju"
- "Da biste čuli tekst sa ekrana ili ga preveli, promenite aplikaciju digitalnog pomoćnika u Podešavanjima"
- "Dodirnite ovde da biste čuli tekst sa ovog ekrana"
- "Dodirnite ovde da biste preveli tekst sa ovog ekrana"
-
diff --git a/go/quickstep/res/values-be/strings.xml b/go/quickstep/res/values-be/strings.xml
deleted file mode 100644
index d4600cc0e6..0000000000
--- a/go/quickstep/res/values-be/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Абагуліць праграму"
- "Праслухаць"
- "Перакласці"
- "Аб\'ектыў"
- "ЗРАЗУМЕЛА"
- "СКАСАВАЦЬ"
- "НАЛАДЫ"
- "Перакласці ці праслухаць тэкст на экране"
- "Такая інфармацыя з вашага экрана, як тэксты, вэб-адрасы і здымкі экрана, можа абагульвацца з Google.\n\nКаб змяніць тып інфармацыі для абагульвання, адкрыйце ""Налады > Праграмы > Стандартныя праграмы > Лічбавы памочнік""."
- "Для карыстання гэтай функцыяй выберыце памочніка"
- "Каб праслухаць або перакласці тэкст на экране, выберыце ў Наладах лічбавага памочніка"
- "Для карыстання гэтай функцыяй змяніце памочніка"
- "Каб праслухаць ці перакласці тэкст на экране, змяніце ў Наладах лічбавага памочніка"
- "Націсніце тут, каб праслухаць тэкст на экране"
- "Націсніце тут, каб перакласці тэкст на экране"
-
diff --git a/go/quickstep/res/values-bg/strings.xml b/go/quickstep/res/values-bg/strings.xml
deleted file mode 100644
index 3741646f7c..0000000000
--- a/go/quickstep/res/values-bg/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Споделяне на прилож."
- "Слушане"
- "Превод"
- "Обектив"
- "РАЗБРАХ"
- "ОТКАЗ"
- "НАСТРОЙКИ"
- "Превеждане или четене на текста на екрана"
- "Определена информация може да бъде споделена с Google, като например текстът на екрана ви, уеб адресите и екранните снимки.\n\nЗа да промените информацията, която споделяте, отворете ""„Настройки“ > „Приложения“ > „Приложения по подразбиране“ > „Приложение за дигитален асистент“""."
- "Изберете приложение за асистент, за да използвате тази функция"
- "За да слушате или превеждате текст на екрана си, от настройките изберете приложение за дигитален асистент"
- "Изберете приложение за асистент, за да използвате тази функция"
- "За да слушате или превеждате текст на екрана си, от настройките променете приложението си за дигитален асистент"
- "Докоснете тук, за да слушате текста на този екран"
- "Докоснете тук, за да преведете текста на този екран"
-
diff --git a/go/quickstep/res/values-bn/strings.xml b/go/quickstep/res/values-bn/strings.xml
deleted file mode 100644
index 4fb714da7a..0000000000
--- a/go/quickstep/res/values-bn/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "অ্যাপ শেয়ার করুন"
- "শুনুন"
- "অনুবাদ করুন"
- "লেন্স"
- "বুঝেছি"
- "বাতিল করুন"
- "সেটিংস"
- "অনুবাদ করুন বা স্ক্রিনে দেখানো টেক্সট শুনুন"
- "আপনার স্ক্রিনে থাকা তথ্য যেমন ওয়েব ঠিকানা এবং স্ক্রিনশট Google-এর সাথে শেয়ার করা হতে পারে।\n\nকোন কোন তথ্য শেয়ার করবেন তা বেছে নিতে, ""সেটিংস > অ্যাপ > ডিফল্ট অ্যাপ > ডিজিটাল অ্যাসিস্ট্যান্ট অ্যাপ"" বিকল্পগুলি বেছে নিন।"
- "এই ফিচার ব্যবহার করতে অ্যাসিস্ট্যান্ট বেছে নিন"
- "আপনার স্ক্রিনে থাকা টেক্সট শুনতে বা অনুবাদ করতে, সেটিংস থেকে ডিজিটাল অ্যাসিস্ট্যান্ট অ্যাপ বেছে নিন"
- "এই ফিচার ব্যবহার করতে অ্যাসিস্ট্যান্ট পরিবর্তন করুন"
- "আপনার স্ক্রিনে থাকা টেক্সট শুনতে বা অনুবাদ করতে, সেটিংস থেকে ডিজিটাল অ্যাসিস্ট্যান্ট অ্যাপ পরিবর্তন করুন"
- "স্ক্রিনে থাকা টেক্সট শুনতে এখানে ট্যাপ করুন"
- "স্ক্রিনে থাকা টেক্সট অনুবাদ করতে এখানে ট্যাপ করুন"
-
diff --git a/go/quickstep/res/values-bs/strings.xml b/go/quickstep/res/values-bs/strings.xml
deleted file mode 100644
index 675e5b8935..0000000000
--- a/go/quickstep/res/values-bs/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Dijeli aplikaciju"
- "Poslušajte"
- "Prevedi"
- "Objektiv"
- "RAZUMIJEM"
- "OTKAŽI"
- "POSTAVKE"
- "Prevedite ili slušajte tekst na ekranu"
- "Informacije kao što su tekst na ekranu, web adrese i snimci ekrana mogu se dijeliti s Googleom.\n\nDa promijenite koje informacije dijelite, idite u ""Postavke > Aplikacije > Zadane aplikacije > Aplikacija digitalnog asistenta""."
- "Odaberite asistenta da koristite ovu funkciju"
- "Da slušate ili prevedete tekst na ekranu, odaberite aplikaciju digitalnog asistenta u Postavkama"
- "Promijenite asistenta da koristite ovu funkciju"
- "Da slušate ili prevedete tekst na ekranu, promijenite aplikaciju digitalnog asistenta u Postavkama"
- "Dodirnite ovdje da slušate tekst na ovom ekranu"
- "Dodirnite ovdje da prevedete tekst na ovom ekranu"
-
diff --git a/go/quickstep/res/values-ca/strings.xml b/go/quickstep/res/values-ca/strings.xml
deleted file mode 100644
index 212df2871d..0000000000
--- a/go/quickstep/res/values-ca/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Comparteix aplicació"
- "Escolta"
- "Tradueix"
- "Lens"
- "ENTESOS"
- "CANCEL·LA"
- "CONFIGURACIÓ"
- "Tradueix o escolta el text en pantalla"
- "És possible que determinada informació es comparteixi amb Google, com ara el text en pantalla, les adreces web i les captures de pantalla.\n\nPer canviar quina informació comparteixes, ves a ""Configuració > Aplicacions > Aplicacions predeterminades > Aplicació de l\'assistent digital""."
- "Tria un assistent per utilitzar aquesta funció"
- "Per escoltar o traduir text en pantalla, tria una aplicació d\'assistent digital a Configuració"
- "Canvia l\'assistent per utilitzar aquesta funció"
- "Per escoltar o traduir text en pantalla, canvia l\'aplicació d\'assistent digital a Configuració"
- "Toca aquí per escoltar text en pantalla"
- "Toca aquí per traduir text en pantalla"
-
diff --git a/go/quickstep/res/values-cs/strings.xml b/go/quickstep/res/values-cs/strings.xml
deleted file mode 100644
index 886b5c2e88..0000000000
--- a/go/quickstep/res/values-cs/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Sdílet aplikaci"
- "Poslechnout"
- "Přeložit"
- "Lens"
- "ROZUMÍM"
- "ZRUŠIT"
- "NASTAVENÍ"
- "Překládejte nebo poslouchejte text na obrazovce"
- "S Googlem mohou být sdílena data, jako je text na obrazovce, webové adresy a snímky obrazovky.\n\nSdílená data můžete upřesnit v ""Nastavení > Aplikace > Výchozí aplikace > Aplikace digitálního asistenta""."
- "Pokud chcete použít tuto funkci, vyberte asistenta"
- "Pokud si chcete poslechnout nebo přeložit text na obrazovce, v Nastavení vyberte aplikaci digitálního asistenta"
- "Pokud chcete použít tuto funkci, změňte asistenta"
- "Pokud si chcete poslechnout nebo přeložit text na obrazovce, v Nastavení změňte aplikaci digitálního asistenta"
- "Klepnutím sem si poslechnete text na této obrazovce"
- "Klepnutím sem přeložíte text na této obrazovce"
-
diff --git a/go/quickstep/res/values-da/strings.xml b/go/quickstep/res/values-da/strings.xml
deleted file mode 100644
index 2bc179c316..0000000000
--- a/go/quickstep/res/values-da/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Del app"
- "Lyt"
- "Oversæt"
- "Lens"
- "OK"
- "ANNULLER"
- "INDSTILLINGER"
- "Oversæt eller hør tekst på skærmen"
- "Oplysninger såsom tekst på din skærm, webadresser og screenshots deles muligvis med Google.\n\nHvis du vil ændre, hvilke oplysninger du deler, kan du gå til ""Indstillinger > Apps > Standardapps > App for digital assistent""."
- "Vælg en assistent for at bruge denne funktion"
- "Hvis du vil høre eller oversætte tekst på din skærm, skal du vælge en digital assistent i Indstillinger"
- "Skift assistent for at bruge denne funktion"
- "Hvis du vil høre eller oversætte tekst på din skærm, skal du ændre din digitale assistent i Indstillinger"
- "Tryk her for at høre teksten på denne skærm"
- "Tryk her for at oversætte teksten på denne skærm"
-
diff --git a/go/quickstep/res/values-de/strings.xml b/go/quickstep/res/values-de/strings.xml
deleted file mode 100644
index 3825b9d441..0000000000
--- a/go/quickstep/res/values-de/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "App teilen"
- "Anhören"
- "Übersetzen"
- "Lens"
- "OK"
- "ABBRECHEN"
- "EINSTELLUNGEN"
- "Text auf dem Bildschirm übersetzen oder anhören"
- "Informationen, wie Text auf deinem Bildschirm, Webadressen und Screenshots, werden möglicherweise an Google weitergegeben.\n\nWenn du ändern möchtest, welche Informationen weitergegeben werden, gehe zu ""Einstellungen > Apps > Standard-Apps > App für digitalen Assistenten""."
- "Assistenten auswählen, um diese Funktion zu nutzen"
- "Wenn du dir auf deinem Display Text anhören oder übersetzen lassen möchtest, wähle in den Einstellungen eine App für einen digitalen Assistenten"
- "Assistenten ändern, um diese Funktion zu nutzen"
- "Wenn du dir auf deinem Display Text anhören oder übersetzen lassen möchtest, ändere in den Einstellungen deine App für den digitalen Assistenten"
- "Hier tippen, um dir Text auf diesem Display anzuhören"
- "Hier tippen, um dir Text auf diesem Display übersetzen zu lassen"
-
diff --git a/go/quickstep/res/values-el/strings.xml b/go/quickstep/res/values-el/strings.xml
deleted file mode 100644
index bfa6279f36..0000000000
--- a/go/quickstep/res/values-el/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Κοινή χρήση εφαρμογ."
- "Ακρόαση"
- "Μετάφραση"
- "Lens"
- "ΤΟ ΚΑΤΑΛΑΒΑ"
- "ΑΚΥΡΩΣΗ"
- "ΡΥΘΜΙΣΕΙΣ"
- "Μετάφραση ή ακρόαση του κειμένου στην οθόνη"
- "Πληροφορίες όπως είναι το κείμενο στην οθόνη, οι διευθύνσεις ιστού και τα στιγμιότυπα οθόνης, ενδέχεται να κοινοποιηθούν στην Google.\n\nΓια να αλλάξετε τις πληροφορίες που κοινοποιείτε, μεταβείτε στις ""Ρυθμίσεις > Εφαρμογές > Προεπιλεγμένες εφαρμογές > Εφαρμογή ψηφιακού βοηθού""."
- "Επιλέξτε έναν βοηθό για να χρησιμοποιήσετε αυτήν τη λειτουργία"
- "Για να ακούσετε ή να μεταφράσετε κείμενο στην οθόνη σας, επιλέξτε μια εφαρμογή ψηφιακού βοηθού στις Ρυθμίσεις."
- "Αλλάξτε τον βοηθό σας για να χρησιμοποιήσετε αυτήν τη λειτουργία"
- "Για να ακούσετε ή να μεταφράσετε κείμενο στην οθόνη σας, αλλάξτε την εφαρμογή ψηφιακού βοηθού στις Ρυθμίσεις."
- "Πατήστε εδώ για να ακούσετε το κείμενο σε αυτήν την οθόνη"
- "Πατήστε εδώ για να μεταφράσετε το κείμενο σε αυτήν την οθόνη"
-
diff --git a/go/quickstep/res/values-en-rAU/strings.xml b/go/quickstep/res/values-en-rAU/strings.xml
deleted file mode 100644
index f1d43a879a..0000000000
--- a/go/quickstep/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Share app"
- "Listen"
- "Translate"
- "Lens"
- "OK"
- "CANCEL"
- "SETTINGS"
- "Translate or listen to text on screen"
- "Information such as text on your screen, web addresses and screenshots may be shared with Google.\n\nTo change what information you share, go to ""Settings > Apps > Default apps > Digital assistant app""."
- "Choose an assistant to use this feature"
- "To listen to or translate text on your screen, choose a digital assistant app in settings"
- "Change your assistant to use this feature"
- "To listen to or translate text on your screen, change your digital assistant app in settings"
- "Tap here to listen to text on this screen"
- "Tap here to translate text on this screen"
-
diff --git a/go/quickstep/res/values-en-rCA/strings.xml b/go/quickstep/res/values-en-rCA/strings.xml
deleted file mode 100644
index f1d43a879a..0000000000
--- a/go/quickstep/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Share app"
- "Listen"
- "Translate"
- "Lens"
- "OK"
- "CANCEL"
- "SETTINGS"
- "Translate or listen to text on screen"
- "Information such as text on your screen, web addresses and screenshots may be shared with Google.\n\nTo change what information you share, go to ""Settings > Apps > Default apps > Digital assistant app""."
- "Choose an assistant to use this feature"
- "To listen to or translate text on your screen, choose a digital assistant app in settings"
- "Change your assistant to use this feature"
- "To listen to or translate text on your screen, change your digital assistant app in settings"
- "Tap here to listen to text on this screen"
- "Tap here to translate text on this screen"
-
diff --git a/go/quickstep/res/values-en-rGB/strings.xml b/go/quickstep/res/values-en-rGB/strings.xml
deleted file mode 100644
index f1d43a879a..0000000000
--- a/go/quickstep/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Share app"
- "Listen"
- "Translate"
- "Lens"
- "OK"
- "CANCEL"
- "SETTINGS"
- "Translate or listen to text on screen"
- "Information such as text on your screen, web addresses and screenshots may be shared with Google.\n\nTo change what information you share, go to ""Settings > Apps > Default apps > Digital assistant app""."
- "Choose an assistant to use this feature"
- "To listen to or translate text on your screen, choose a digital assistant app in settings"
- "Change your assistant to use this feature"
- "To listen to or translate text on your screen, change your digital assistant app in settings"
- "Tap here to listen to text on this screen"
- "Tap here to translate text on this screen"
-
diff --git a/go/quickstep/res/values-en-rIN/strings.xml b/go/quickstep/res/values-en-rIN/strings.xml
deleted file mode 100644
index f1d43a879a..0000000000
--- a/go/quickstep/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Share app"
- "Listen"
- "Translate"
- "Lens"
- "OK"
- "CANCEL"
- "SETTINGS"
- "Translate or listen to text on screen"
- "Information such as text on your screen, web addresses and screenshots may be shared with Google.\n\nTo change what information you share, go to ""Settings > Apps > Default apps > Digital assistant app""."
- "Choose an assistant to use this feature"
- "To listen to or translate text on your screen, choose a digital assistant app in settings"
- "Change your assistant to use this feature"
- "To listen to or translate text on your screen, change your digital assistant app in settings"
- "Tap here to listen to text on this screen"
- "Tap here to translate text on this screen"
-
diff --git a/go/quickstep/res/values-en-rXC/strings.xml b/go/quickstep/res/values-en-rXC/strings.xml
deleted file mode 100644
index c729cd845c..0000000000
--- a/go/quickstep/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Share App"
- "Listen"
- "Translate"
- "Lens"
- "GOT IT"
- "CANCEL"
- "SETTINGS"
- "Translate or listen to text on screen"
- "Information such as text on your screen, web addresses, and screenshots may be shared with Google.\n\nTo change what information you share, go to ""Settings > Apps > Default apps > Digital assistant app""."
- "Choose an assistant to use this feature"
- "To listen to or translate text on your screen, choose a digital assistant app in Settings"
- "Change your assistant to use this feature"
- "To listen to or translate text on your screen, change your digital assistant app in Settings"
- "Tap here to listen to text on this screen"
- "Tap here to translate text on this screen"
-
diff --git a/go/quickstep/res/values-es-rUS/strings.xml b/go/quickstep/res/values-es-rUS/strings.xml
deleted file mode 100644
index cde1cd7345..0000000000
--- a/go/quickstep/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Compartir app"
- "Escuchar"
- "Traducir"
- "Lens"
- "ENTENDIDO"
- "CANCELAR"
- "CONFIGURACIÓN"
- "Traduce o escucha el texto que aparece en la pantalla"
- "Es posible que se comparta información con Google, como el texto de la pantalla, direcciones web y capturas de pantalla.\n\nPara cambiar la información que se comparte, ve a ""Configuración > Apps > Apps predeterminadas > App de asistente digital""."
- "Elige un asistente para usar esta función"
- "Para escuchar o traducir texto en la pantalla, elige una app de asistente digital en Configuración"
- "Cambia el asistente para usar esta función"
- "Para escuchar o traducir texto en la pantalla, cambia la app de asistente digital en Configuración"
- "Presiona aquí para escuchar texto en esta pantalla"
- "Presiona aquí para traducir texto en esta pantalla"
-
diff --git a/go/quickstep/res/values-es/strings.xml b/go/quickstep/res/values-es/strings.xml
deleted file mode 100644
index 00494433d6..0000000000
--- a/go/quickstep/res/values-es/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Compartir aplicación"
- "Escuchar"
- "Traducir"
- "Lens"
- "ENTENDIDO"
- "CANCELAR"
- "AJUSTES"
- "Traduce o escucha texto que haya en pantalla"
- "Se puede compartir con Google cierta información, como el texto que aparece en pantalla, direcciones web o capturas de pantalla.\n\nPara cambiar la información que compartes, ve a ""Ajustes > Aplicaciones > Aplicaciones predeterminadas > Asistente digital""."
- "Elige un asistente para usar esta función"
- "Para escuchar o traducir texto que haya en tu pantalla, elige una aplicación de asistente digital en Ajustes"
- "Cambia tu asistente para usar esta función"
- "Para escuchar o traducir texto que haya en tu pantalla, cambia tu aplicación de asistente digital en Ajustes"
- "Toca aquí para escuchar el texto que hay en esta pantalla"
- "Toca aquí para traducir el texto que hay en esta pantalla"
-
diff --git a/go/quickstep/res/values-et/strings.xml b/go/quickstep/res/values-et/strings.xml
deleted file mode 100644
index 9a7c1186bd..0000000000
--- a/go/quickstep/res/values-et/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Jaga rakendust"
- "Kuula"
- "Tõlge"
- "Lens"
- "SELGE"
- "TÜHISTA"
- "SEADED"
- "Ekraanil oleva teksti tõlkimine või kuulamine"
- "Teavet, nagu teie ekraanil olev tekst, veebiaadressid ja ekraanipildid, võidakse jagada Google\'iga.\n\nKui soovite muuta, millist teavet jagate, avage ""Seaded > Rakendused > Vaikerakendused > Digitaalse assistendi rakendus""."
- "Valige selle funktsiooni kasutamiseks assistent"
- "Ekraanil kuvatud teksti kuulamiseks või tõlkimiseks valige seadetes digitaalse assistendi rakendus"
- "Vahetage selle funktsiooni kasutamiseks assistenti"
- "Ekraanil kuvatud teksti kuulamiseks või tõlkimiseks vahetage seadetes digitaalse assistendi rakendust"
- "Puudutage siin, et ekraanil kuvatud teksti kuulda"
- "Puudutage siin, et ekraanil kuvatud tekst tõlkida"
-
diff --git a/go/quickstep/res/values-eu/strings.xml b/go/quickstep/res/values-eu/strings.xml
deleted file mode 100644
index 79b1acbfd2..0000000000
--- a/go/quickstep/res/values-eu/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Partekatu aplikazioa"
- "Entzun"
- "Itzuli"
- "Lens"
- "ADOS"
- "UTZI"
- "EZARPENAK"
- "Itzuli edo entzun pantailako testua"
- "Agian pantailako testua, web-helbideak, pantaila-argazkiak eta antzeko informazioa partekatuko duzu Google-rekin.\n\nPartekatzen duzun informazioa aldatzeko, joan hona: ""Ezarpenak > Aplikazioak > Aplikazio lehenetsiak > Laguntzaile digitalaren aplikazioa""."
- "Hautatu laguntzaile bat eginbidea erabiltzeko"
- "Pantailako testua entzun edo itzultzeko, aukeratu laguntzaile digitalaren aplikazio bat Ezarpenak atalean"
- "Aldatu laguntzailea eginbidea erabiltzeko"
- "Pantailako testua entzun edo itzultzeko, aldatu laguntzaile digitalaren aplikazioa Ezarpenak atalean"
- "Sakatu hau pantailako testua entzuteko"
- "Sakatu hau pantailako testua itzultzeko"
-
diff --git a/go/quickstep/res/values-fa/strings.xml b/go/quickstep/res/values-fa/strings.xml
deleted file mode 100644
index c86fddb785..0000000000
--- a/go/quickstep/res/values-fa/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "همرسانی برنامه"
- "گوش دادن"
- "ترجمه"
- "لنز"
- "متوجهام"
- "لغو"
- "تنظیمات"
- "ترجمه نوشتار روی صفحهنمایش یا گوش دادن به آن"
- "ممکن است اطلاعاتی مثل نوشتار روی صفحهنمایش، نشانیهای وب، و نماگرفتها با Google همرسانی شود.\n\nبرای تغییر اطلاعاتی که همرسانی میکنید، به ""تنظیمات < برنامهها < برنامههای پیشفرض < برنامه دستیار دیجیتال"" بروید."
- "برای استفاده از این ویژگی، دستیاری انتخاب کنید"
- "برای گوش کردن به نوشتار در صفحهنمایشتان یا ترجمه کردن آن، یکی از برنامههای دستیار دیجیتالی را در «تنظیمات» انتخاب کنید"
- "برای استفاده از این ویژگی، دستیارتان را تغییر دهید"
- "برای گوش کردن به نوشتار در صفحهنمایشتان یا ترجمه کردن آن، برنامه دستیار دیجیتالیتان را در «تنظیمات» تغییر دهید"
- "برای گوش کردن به نوشتار در این صفحه، اینجا ضربه بزنید"
- "برای ترجمه نوشتار در این صفحه، اینجا ضربه بزنید"
-
diff --git a/go/quickstep/res/values-fi/strings.xml b/go/quickstep/res/values-fi/strings.xml
deleted file mode 100644
index c13a92c7b4..0000000000
--- a/go/quickstep/res/values-fi/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Jaa sovellus"
- "Kuuntele"
- "Käännä"
- "Lens"
- "OK"
- "PERU"
- "ASETUKSET"
- "Käännä tai kuuntele näytöllä oleva teksti"
- "Googlelle saatetaan jakaa näytöllä olevaa tekstiä, verkko-osoitteita, kuvakaappauksia ja muita tietoja.\n\nVoit valita jaettavat tiedot valitsemalla ""Asetukset > Sovellukset > Oletussovellukset > Digiavustajasovellus""."
- "Valitse avustaja tämän ominaisuuden käyttöön"
- "Jos haluat kuunnella tai kääntää näytöllä näkyvää tekstiä, valitse digiavustajasovellus asetuksista"
- "Vaihda avustaja tämän ominaisuuden käyttöä varten"
- "Jos haluat kuunnella tai kääntää näytöllä näkyvää tekstiä, vaihda digiavustajasovellus asetuksista"
- "Kuuntele näytöllä näkyvä teksti napauttamalla tästä"
- "Käännä näytöllä näkyvä teksti napauttamalla tästä"
-
diff --git a/go/quickstep/res/values-fr-rCA/strings.xml b/go/quickstep/res/values-fr-rCA/strings.xml
deleted file mode 100644
index d04abd898d..0000000000
--- a/go/quickstep/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Partager application"
- "Écouter"
- "Traduire"
- "Lentille"
- "OK"
- "ANNULER"
- "PARAMÈTRES"
- "Traduire ou écouter le texte à l\'écran"
- "Des renseignements comme du texte sur votre écran, des adresses Web et des captures d\'écran peuvent être partagés avec Google.\n\nPour modifier les renseignements que vous partagez, accédez à ""Paramètres > Applications > Applications par défaut > Application d\'assistant numérique""."
- "Choisir un assistant pour utiliser cette fonctionnalité"
- "Pour écouter ou traduire le texte affiché sur votre écran, choisissez l\'application d\'un assistant numérique dans les paramètres"
- "Modifier votre assistant pour utiliser cette fonctionnalité"
- "Pour écouter ou traduire le texte affiché sur votre écran, modifiez l\'application de votre assistant numérique dans les paramètres"
- "Touchez ce bouton pour écouter le texte affiché sur cet écran"
- "Touchez ce bouton pour traduire le texte affiché sur cet écran"
-
diff --git a/go/quickstep/res/values-fr/strings.xml b/go/quickstep/res/values-fr/strings.xml
deleted file mode 100644
index 045a8a0705..0000000000
--- a/go/quickstep/res/values-fr/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Partager l\'appli"
- "Écouter"
- "Traduire"
- "Lens"
- "OK"
- "ANNULER"
- "PARAMÈTRES"
- "Traduire ou écouter le texte à l\'écran"
- "Des informations comme le texte sur votre écran, des adresses Web et des captures d\'écran peuvent être partagées avec Google.\n\nPour modifier les types d\'informations que vous partagez, accédez à ""Paramètres > Applis > Applis par défaut > Appli d\'assistant numérique""."
- "Sélectionnez un assistant pour utiliser cette fonctionnalité"
- "Pour écouter ou traduire le texte à l\'écran, sélectionnez une appli d\'assistant numérique dans \"Paramètres\""
- "Changez d\'assistant pour utiliser cette fonctionnalité"
- "Pour écouter ou traduire le texte à l\'écran, modifiez l\'appli d\'assistant numérique dans \"Paramètres\""
- "Appuyez ici pour écouter le texte à l\'écran"
- "Appuyez ici pour traduire le texte à l\'écran"
-
diff --git a/go/quickstep/res/values-gl/strings.xml b/go/quickstep/res/values-gl/strings.xml
deleted file mode 100644
index 0c013177bf..0000000000
--- a/go/quickstep/res/values-gl/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Compartir aplicación"
- "Escoitar"
- "Traducir"
- "Lens"
- "ENTENDIDO"
- "CANCELAR"
- "CONFIGURACIÓN"
- "Traducir ou escoitar o texto que aparece na pantalla"
- "É posible que se comparta con Google información como o texto que aparece na pantalla, os enderezos web e as capturas de pantalla.\n\nPara cambiar os datos que se comparten, vai a ""Configuración > Aplicacións > Aplicacións predeterminadas > Aplicación de asistente dixital""."
- "Escolle un asistente para utilizar esta función"
- "Para escoitar ou traducir o texto da pantalla, escolle unha aplicación de asistente dixital en Configuración"
- "Cambia o asistente para utilizar esta función"
- "Para escoitar ou traducir o texto da pantalla, cambia a aplicación de asistente dixital en Configuración"
- "Tocar aquí para escoitar o texto desta pantalla"
- "Tocar aquí para traducir o texto desta pantalla"
-
diff --git a/go/quickstep/res/values-gu/strings.xml b/go/quickstep/res/values-gu/strings.xml
deleted file mode 100644
index 7c627e18f8..0000000000
--- a/go/quickstep/res/values-gu/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ઍપ શેર કરો"
- "સાંભળો"
- "અનુવાદ કરો"
- "લેન્સ"
- "સમજાઈ ગયું"
- "રદ કરો"
- "સેટિંગ"
- "સ્ક્રીન પરની ટેક્સ્ટનો અનુવાદ કરો અથવા સાંભળો"
- "તમારી સ્ક્રીન પરની ટેક્સ્ટ, વેબ ઍડ્રેસ અને સ્ક્રીનશૉટ જેવી માહિતી Google સાથે શેર કરવામાં આવી શકે છે.\n\nતમે શેર કરતા હો તેવી માહિતીમાં ફેરફાર કરવા માટે, ""સેટિંગ > ઍપ > ડિફૉલ્ટ ઍપ > ડિજિટલ આસિસ્ટંટ ઍપ"" પર જાઓ."
- "આ સુવિધાનો ઉપયોગ કરવા માટે આસિસ્ટંટ પસંદ કરો"
- "તમારી સ્ક્રીન પર ટેક્સ્ટ સાંભળવા માટે અથવા તેનો અનુવાદ કરવા માટે, સેટિંગમાં જઈને ડિજિટલ આસિસ્ટંટ ઍપ પસંદ કરો"
- "આ સુવિધાનો ઉપયોગ કરવા માટે તમારું આસિસ્ટંટ બદલો"
- "તમારી સ્ક્રીન પર ટેક્સ્ટ સાંભળવા માટે અથવા તેનો અનુવાદ કરવા માટે, સેટિંગમાં જઈને તમારી ડિજિટલ આસિસ્ટંટ ઍપ બદલો"
- "આ સ્ક્રીન પર ટેક્સ્ટ સાંભળવા માટે અહીં ટૅપ કરો"
- "આ સ્ક્રીન પર ટેક્સ્ટનો અનુવાદ કરવા માટે અહીં ટૅપ કરો"
-
diff --git a/go/quickstep/res/values-hi/strings.xml b/go/quickstep/res/values-hi/strings.xml
deleted file mode 100644
index 95a8dd8f02..0000000000
--- a/go/quickstep/res/values-hi/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ऐप्लिकेशन शेयर करें"
- "सुनें"
- "अनुवाद करें"
- "Google Lens"
- "ठीक है"
- "रद्द करें"
- "सेटिंग"
- "स्क्रीन पर मौजूद टेक्स्ट का अनुवाद पाएं या उसे सुनें"
- "आपकी स्क्रीन पर मौजूद टेक्स्ट, वेब पते, और स्क्रीनशॉट जैसी जानकारी Google के साथ शेयर की जा सकती है.\n\nआप Google के साथ किस जानकारी को शेयर करते हैं, इसे कंट्रोल करने के लिए ""सेटिंग > ऐप्लिकेशन > डिफ़ॉल्ट ऐप्लिकेशन > डिजिटल असिस्टेंट ऐप्लिकेशन"" पर जाएं."
- "इस सुविधा का इस्तेमाल करने के लिए, कोई डिजिटल असिस्टेंट ऐप्लिकेशन चुनें"
- "स्क्रीन पर मौजूद टेक्स्ट का अनुवाद करने या उसे सुनने के लिए, \'सेटिंग\' में जाकर कोई डिजिटल असिस्टेंट ऐप्लिकेशन चुनें"
- "इस सुविधा का इस्तेमाल करने के लिए, अपना डिजिटल असिस्टेंट ऐप्लिकेशन बदलें"
- "स्क्रीन पर मौजूद टेक्स्ट का अनुवाद करने या उसे सुनने के लिए, \'सेटिंग\' में जाकर अपना डिजिटल असिस्टेंट ऐप्लिकेशन बदलें"
- "स्क्रीन पर मौजूद टेक्स्ट को सुनने के लिए, यहां टैप करें"
- "स्क्रीन पर मौजूद टेक्स्ट का अनुवाद करने के लिए, यहां टैप करें"
-
diff --git a/go/quickstep/res/values-hr/strings.xml b/go/quickstep/res/values-hr/strings.xml
deleted file mode 100644
index bef6b71775..0000000000
--- a/go/quickstep/res/values-hr/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Dijeli aplikaciju"
- "Slušajte"
- "Prevedi"
- "Objektiv"
- "SHVAĆAM"
- "ODUSTANI"
- "POSTAVKE"
- "Prevedite ili slušajte tekst na zaslonu"
- "Informacije kao što su tekst na vašem zaslonu, web-adrese i snimke zaslona mogu se dijeliti s Googleom.\n\nDa biste promijenili informacije koje dijelite, otvorite ""Postavke > Aplikacije > Zadane aplikacije > Aplikacija digitalnog asistenta""."
- "Odaberite asistenta za upotrebu te značajke"
- "Da biste poslušali ili preveli tekst na zaslonu, odaberite aplikaciju digitalnog asistenta u postavkama"
- "Promijenite asistenta da biste koristili tu značajku"
- "Da biste poslušali ili preveli tekst na zaslonu, promijenite aplikaciju digitalnog asistenta u postavkama"
- "Dodirnite ovdje da biste poslušali tekst na ovom zaslonu"
- "Dodirnite ovdje da biste preveli tekst na ovom zaslonu"
-
diff --git a/go/quickstep/res/values-hu/strings.xml b/go/quickstep/res/values-hu/strings.xml
deleted file mode 100644
index f2cd08995c..0000000000
--- a/go/quickstep/res/values-hu/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "App megosztása"
- "Lejátszás"
- "Fordítás"
- "Lens"
- "ÉRTEM"
- "MÉGSE"
- "BEÁLLÍTÁSOK"
- "Képernyőn megjelenő szöveg fordítása és hallgatása"
- "Előfordulhat, hogy a rendszer megoszt bizonyos adatokat (például képernyőn megjelenő szöveget, internetcímeket és képernyőképeket) a Google-lal.\n\nHa módosítani szeretné, hogy milyen adatokat oszt meg, lépjen a ""Beállítások és alkalmazások; Alapértelmezett alkalmazások; Digitális asszisztens app"" menüpontra."
- "Válasszon asszisztenst a funkció használatához"
- "A képernyőn megjelenő szöveg meghallgatásához vagy lefordításához válasszon digitálisasszisztens-alkalmazást a Beállítások menüben"
- "Módosítsa az asszisztenst a funkció használatához"
- "A képernyőn megjelenő szöveg meghallgatásához vagy lefordításához módosítsa a digitálisasszisztens-alkalmazást a Beállítások menüben"
- "Koppintson ide a jelenleg képernyőn lévő szöveg meghallgatásához"
- "Koppintson ide a jelenleg képernyőn lévő szöveg lefordításához"
-
diff --git a/go/quickstep/res/values-hy/strings.xml b/go/quickstep/res/values-hy/strings.xml
deleted file mode 100644
index b238a92c0f..0000000000
--- a/go/quickstep/res/values-hy/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Կիսվել հավելվածով"
- "Լսել"
- "Թարգմանել"
- "Տեսապակի"
- "ԵՂԱՎ"
- "ՉԵՂԱՐԿԵԼ"
- "ԿԱՐԳԱՎՈՐՈՒՄՆԵՐ"
- "Էկրանի տեքստի թարգմանություն կամ ունկնդրում"
- "Որոշակի տեղեկություններ (օր․՝ էկրանի տեքստը, վեբ հասցեները և սքրինշոթները) կարող են ուղարկվել Google-ին։\n\nՏեղեկությունները, որոնցով դուք կիսվում եք, կարող եք փոխել՝ անցնելով ""Կարգավորումներ > Հավելվածներ > Կանխադրված հավելվածներ > Թվային օգնականի հավելված""։"
- "Այս գործառույթն օգտագործելու համար ընտրեք օգնական"
- "Էկրանի տեքստը լսելու կամ թարգմանելու համար կարգավորումներում ընտրեք թվային օգնականի հավելված։"
- "Այս գործառույթն օգտագործելու համար փոխեք ձեր օգնականը"
- "Էկրանի տեքստը լսելու կամ թարգմանելու համար կարգավորումներում փոխեք ձեր թվային օգնականի հավելվածը։"
- "Հպեք այստեղ՝ այս էկրանի տեքստը լսելու համար"
- "Հպեք այստեղ` այս էկրանի տեքստը թարգմանելու համար"
-
diff --git a/go/quickstep/res/values-in/strings.xml b/go/quickstep/res/values-in/strings.xml
deleted file mode 100644
index 7e240e8da6..0000000000
--- a/go/quickstep/res/values-in/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Bagikan Aplikasi"
- "Dengarkan"
- "Terjemahkan"
- "Lens"
- "OKE"
- "BATAL"
- "SETELAN"
- "Terjemahkan atau dengarkan teks di layar"
- "Informasi seperti teks di layar, alamat web, dan screenshot dapat dibagikan ke Google.\n\nUntuk mengubah informasi yang Anda bagikan, buka ""Setelan > Aplikasi > Aplikasi default > Aplikasi asisten digital""."
- "Pilih asisten untuk menggunakan fitur ini"
- "Untuk mendengarkan atau menerjemahkan teks di layar, pilih aplikasi asisten digital di Setelan"
- "Ubah asisten untuk menggunakan fitur ini"
- "Untuk mendengarkan atau menerjemahkan teks di layar, ubah aplikasi asisten digital Anda di Setelan"
- "Ketuk di sini untuk mendengarkan teks di layar ini"
- "Ketuk di sini untuk menerjemahkan teks di layar ini"
-
diff --git a/go/quickstep/res/values-is/strings.xml b/go/quickstep/res/values-is/strings.xml
deleted file mode 100644
index c882c99b20..0000000000
--- a/go/quickstep/res/values-is/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Deila forriti"
- "Hlusta"
- "Þýða"
- "Linsa"
- "ÉG SKIL"
- "HÆTTA VIÐ"
- "STILLINGAR"
- "Þýða eða hlusta á texta á skjánum"
- "Mögulegt er að upplýsingum á borð við texta á skjánum, vefslóðum og skjámyndum verði deilt með Google.\n\nTil að breyta því hvaða upplýsingum þú deilir skaltu opna ""Stillingar > Forrit > Sjálfgefin forrit > Forrit stafræns hjálpara""."
- "Veldu hjálpara til að nota þennan eiginleika"
- "Veldu stafrænan hjálpara í stillingum til að hlusta á eða þýða texta á skjánum"
- "Breyttu hjálparanum til að nota þennan eiginleika"
- "Breyttu forriti stafræna hjálparans í stillingum til að hlusta á eða þýða texta"
- "Ýttu hér til að hlusta á texta á þessum skjá"
- "Ýttu hér til að þýða texta á þessum skjá"
-
diff --git a/go/quickstep/res/values-it/strings.xml b/go/quickstep/res/values-it/strings.xml
deleted file mode 100644
index 75afcbb236..0000000000
--- a/go/quickstep/res/values-it/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Condividi l\'app"
- "Ascolta"
- "Traduttore"
- "Lens"
- "OK"
- "ANNULLA"
- "IMPOSTAZIONI"
- "Traduci o ascolta il testo sullo schermo"
- "Alcune informazioni, come il testo sullo schermo, gli indirizzi web e gli screenshot, potrebbero essere condivise con Google.\n\nPer modificare quali informazioni condividere, vai a ""Impostazioni > App > App predefinite > App assistente digitale""."
- "Scegli un assistente per usare questa funzionalità"
- "Per ascoltare o tradurre il testo mostrato sullo schermo, scegli l\'app di un assistente digitale nelle Impostazioni"
- "Cambia l\'assistente per usare questa funzionalità"
- "Per ascoltare o tradurre il testo mostrato sullo schermo, cambia l\'app dell\'assistente digitale nelle Impostazioni"
- "Tocca qui per ascoltare il testo mostrato in questa schermata"
- "Tocca qui per tradurre il testo mostrato in questa schermata"
-
diff --git a/go/quickstep/res/values-iw/strings.xml b/go/quickstep/res/values-iw/strings.xml
deleted file mode 100644
index fd3747eb36..0000000000
--- a/go/quickstep/res/values-iw/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "לשיתוף האפליקציה"
- "האזנה"
- "תרגום"
- "Lens"
- "הבנתי"
- "ביטול"
- "הגדרות"
- "תרגום טקסט שמוצג במסך או האזנה לו"
- "ייתכן שישותף עם Google מידע כגון טקסט שמוצג במסך, כתובות אינטרנט וצילומי מסך.\n\nכדי לקבוע איזה מידע ישותף, יש לעבור אל ""הגדרות > אפליקציות > אפליקציות ברירת מחדל > אפליקציית עוזר דיגיטלי""."
- "יש לבחור עוזר דיגיטלי כדי להשתמש בתכונה הזו"
- "כדי להאזין לטקסט שבמסך או לתרגם אותו, צריך לבחור אפליקציית עוזר דיגיטלי ב\'הגדרות\'"
- "צריך לשנות את העוזר הדיגיטלי כדי להשתמש בתכונה הזו"
- "כדי להאזין לטקסט שבמסך או לתרגם אותו, צריך לשנות את אפליקציית העוזר הדיגיטלי ב\'הגדרות\'"
- "צריך להקיש כאן כדי להאזין לטקסט שבמסך הזה"
- "צריך להקיש כאן כדי לתרגם את הטקסט שבמסך הזה"
-
diff --git a/go/quickstep/res/values-ja/strings.xml b/go/quickstep/res/values-ja/strings.xml
deleted file mode 100644
index cfbfecaad2..0000000000
--- a/go/quickstep/res/values-ja/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "アプリを共有"
- "聴く"
- "翻訳"
- "レンズ"
- "OK"
- "キャンセル"
- "設定"
- "画面上のテキストを翻訳または聞く"
- "画面上のテキスト、ウェブアドレス、スクリーンショットなどの情報が Google と共有される場合があります。\n\n共有される情報を変更するには、""[設定] > [アプリ] > [デフォルトのアプリ] > [デジタル アシスタント アプリ]"" に移動してください。"
- "この機能を使用するにはアシスタントを選択してください"
- "画面上のテキストを翻訳するかまたは聞くには、[設定] でデジタル アシスタント アプリを選択してください"
- "この機能を使用するにはアシスタントを変更してください"
- "画面上のテキストを翻訳するかまたは聞くには、[設定] でデジタル アシスタント アプリを変更してください"
- "この画面上のテキストを聞くには、ここをタップしてください"
- "この画面上のテキストを翻訳するには、ここをタップしてください"
-
diff --git a/go/quickstep/res/values-ka/strings.xml b/go/quickstep/res/values-ka/strings.xml
deleted file mode 100644
index 3280a7eedd..0000000000
--- a/go/quickstep/res/values-ka/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "აპის გაზიარება"
- "მოსმენა"
- "თარგმნა"
- "Lens"
- "გასაგებია"
- "გაუქმება"
- "პარამეტრები"
- "თარგმნეთ ან მოისმინეთ ეკრანზე ნაჩვენები ტექსტი"
- "ისეთი ინფორმაცია, როგორიც არის ტექსტი თქვენს ეკრანზე, ვებ-მისამართები და ეკრანის ანაბეჭდები შეიძლება გაზიარდეს Google-თან.\n\nთუ გსურთ, შეცვალოთ, რა ინფორმაციას აზიარებთ, გადადით: ""პარამეტრები > აპები > ნაგულისხმევი აპები > ციფრული ასისტენტის აპი""."
- "ამ ფუნქციით სარგებლობისთვის აირჩიეთ ასისტენტი"
- "თქვენს ეკრანზე ნაჩვენები ტექსტის მოსასმენად ან სათარგმნად, აირჩიეთ ციფრული ასისტენტის აპი პარამეტრებიდან"
- "ამ ფუნქციით სარგებლობისთვის შეცვალეთ ასისტენტი"
- "თქვენს ეკრანზე ნაჩვენები ტექსტის მოსასმენად ან სათარგმნად, შეცვალეთ ციფრული ასისტენტის აპი პარამეტრებიდან"
- "შეეხეთ აქ ამ ეკრანზე ნაჩვენები ტექსტის მოსასმენად"
- "შეეხეთ აქ ამ ეკრანზე ნაჩვენები ტექსტის სათარგმნად"
-
diff --git a/go/quickstep/res/values-kk/strings.xml b/go/quickstep/res/values-kk/strings.xml
deleted file mode 100644
index b68ab3e86b..0000000000
--- a/go/quickstep/res/values-kk/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Қолданбаны бөлісу"
- "Тыңдау"
- "Аудару"
- "Объектив"
- "ТҮСІНІКТІ"
- "БАС ТАРТУ"
- "ПАРАМЕТРЛЕР"
- "Экрандағы мәтінді аудару немесе тыңдау"
- "Экрандағы мәтін, веб-мекенжайлар мен скриншоттар сияқты ақпарат Google-мен бөлісілуі мүмкін.\n\nБөлісілетін ақпаратты өзгерту үшін ""Параметрлер > Қолданбалар > Әдепкі қолданбалар > Цифрлық көмекші қолданбасы"" тармағына өтіңіз."
- "Осы функцияны пайдалану үшін көмекшіні таңдау"
- "Экрандағы мәтінді тыңдау немесе аудару үшін параметрлерден цифрлық көмекшіні таңдаңыз."
- "Осы функцияны пайдалану үшін көмекшіні өзгерту"
- "Экрандағы мәтінді тыңдау немесе аудару үшін параметрлерден цифрлық көмекшіні өзгертіңіз."
- "Экрандағы мәтінді тыңдау үшін осы жерде түртіңіз."
- "Экрандағы мәтінді аудару үшін осы жерде түртіңіз."
-
diff --git a/go/quickstep/res/values-km/strings.xml b/go/quickstep/res/values-km/strings.xml
deleted file mode 100644
index b44ff0a104..0000000000
--- a/go/quickstep/res/values-km/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ចែករំលែកកម្មវិធី"
- "ស្តាប់"
- "បកប្រែ"
- "Lens"
- "យល់ហើយ"
- "បោះបង់"
- "ការកំណត់"
- "បកប្រែ ឬស្ដាប់អត្ថបទនៅលើអេក្រង់"
- "ព័ត៌មានដូចជា អត្ថបទនៅលើអេក្រង់របស់អ្នក អាសយដ្ឋានទំព័រ និងរូបថតអេក្រង់អាចនឹងត្រូវបានចែករំលែកជាមួយ Google។\n\nដើម្បីប្ដូរព័ត៌មានដែលអ្នកចែករំលែក សូមចូលទៅកាន់""ការកំណត់ > កម្មវិធី > កម្មវិធីលំនាំដើម > កម្មវិធីជំនួយការឌីជីថល""។"
- "ជ្រើសរើសជំនួយការ ដើម្បីប្រើមុខងារនេះ"
- "ដើម្បីស្ដាប់ ឬបកប្រែអត្ថបទនៅលើអេក្រង់របស់អ្នក សូមជ្រើសរើសកម្មវិធីជំនួយការឌីជីថលនៅក្នុងការកំណត់"
- "ប្ដូរជំនួយការរបស់អ្នក ដើម្បីប្រើមុខងារនេះ"
- "ដើម្បីស្ដាប់ ឬបកប្រែអត្ថបទនៅលើអេក្រង់របស់អ្នក សូមប្ដូរកម្មវិធីជំនួយការឌីជីថលរបស់អ្នកនៅក្នុងការកំណត់"
- "ចុចត្រង់នេះ ដើម្បីស្ដាប់អត្ថបទនៅលើអេក្រង់នេះ"
- "ចុចត្រង់នេះ ដើម្បីបកប្រែអត្ថបទនៅលើអេក្រង់នេះ"
-
diff --git a/go/quickstep/res/values-kn/strings.xml b/go/quickstep/res/values-kn/strings.xml
deleted file mode 100644
index ef1954199b..0000000000
--- a/go/quickstep/res/values-kn/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ಆ್ಯಪ್ ಹಂಚಿಕೊಳ್ಳಿ"
- "ಆಲಿಸಿ"
- "ಅನುವಾದಿಸಿ"
- "Lens"
- "ಅರ್ಥವಾಯಿತು"
- "ರದ್ದುಗೊಳಿಸಿ"
- "ಸೆಟ್ಟಿಂಗ್ಗಳು"
- "ಸ್ಕ್ರೀನ್ ಮೇಲಿರುವ ಪಠ್ಯವನ್ನು ಅನುವಾದಿಸಿ ಅಥವಾ ಆಲಿಸಿ"
- "ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಮೇಲಿರುವ ಪಠ್ಯ, ವೆಬ್ ವಿಳಾಸಗಳು, ಮತ್ತು ಸ್ಕ್ರೀನ್ಶಾಟ್ಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು Google ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಬಹುದು.\n\nನೀವು ಯಾವ ಮಾಹಿತಿಯನ್ನು ಹಂಚಿಕೊಳ್ಳುತ್ತೀರಿ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಲು, ""ಸೆಟ್ಟಿಂಗ್ಗಳು, ಆ್ಯಪ್ಗಳು ಮತ್ತು ಡೀಫಾಲ್ಟ್ ಆ್ಯಪ್ಗಳು, ಡಿಜಿಟಲ್ ಅಸಿಸ್ಟೆಂಟ್ ಆ್ಯಪ್ ಎಂಬಲ್ಲಿ ಹೋಗಿ""."
- "ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಬಳಸಲು ಅಸಿಸ್ಟಂಟ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"
- "ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನಲ್ಲಿರುವ ಪಠ್ಯವನ್ನು ಆಲಿಸಲು ಅಥವಾ ಅನುವಾದಿಸಲು ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಡಿಜಿಟಲ್ ಅಸಿಸ್ಟೆಂಟ್ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"
- "ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಬಳಸಲು ನಿಮ್ಮ ಅಸಿಸ್ಟಂಟ್ ಅನ್ನು ಬದಲಾಯಿಸಿ"
- "ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನಲ್ಲಿರುವ ಪಠ್ಯವನ್ನು ಆಲಿಸಲು ಅಥವಾ ಅನುವಾದಿಸಲು ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ನಿಮ್ಮ ಡಿಜಿಟಲ್ ಅಸಿಸ್ಟೆಂಟ್ ಆ್ಯಪ್ ಅನ್ನು ಬದಲಾಯಿಸಿ"
- "ಈ ಸ್ಕ್ರೀನ್ನಲ್ಲಿರುವ ಪಠ್ಯವನ್ನು ಆಲಿಸಲು ಇಲ್ಲಿ ಟ್ಯಾಪ್ ಮಾಡಿ"
- "ಈ ಸ್ಕ್ರೀನ್ನಲ್ಲಿರುವ ಪಠ್ಯವನ್ನು ಅನುವಾದಿಸಲು ಇಲ್ಲಿ ಟ್ಯಾಪ್ ಮಾಡಿ"
-
diff --git a/go/quickstep/res/values-ko/strings.xml b/go/quickstep/res/values-ko/strings.xml
deleted file mode 100644
index 7b298e93fe..0000000000
--- a/go/quickstep/res/values-ko/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "앱 공유"
- "듣기"
- "번역"
- "렌즈"
- "확인"
- "취소"
- "설정"
- "화면의 텍스트 번역 또는 듣기"
- "화면의 텍스트, 웹 주소, 스크린샷과 같은 정보가 Google과 공유될 수 있습니다.\n\n공유되는 정보를 변경하려면 ""설정 > 앱 > 기본 앱 > 디지털 어시스턴트 앱""으로 이동하세요."
- "이 기능을 사용하려면 어시스턴트를 선택하세요."
- "화면에서 텍스트를 듣거나 번역하려면 설정에서 디지털 어시스턴트 앱을 선택하세요."
- "어시스턴트가 이 기능을 사용하도록 변경하세요."
- "화면에서 텍스트를 듣거나 번역하려면 설정에서 디지털 어시스턴트 앱을 변경하세요."
- "화면에서 텍스트를 들으려면 여기를 탭하세요."
- "화면에서 텍스트를 번역하려면 여기를 탭하세요."
-
diff --git a/go/quickstep/res/values-ky/strings.xml b/go/quickstep/res/values-ky/strings.xml
deleted file mode 100644
index 66fb264601..0000000000
--- a/go/quickstep/res/values-ky/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Колдонмону бөлүшүү"
- "Угуу"
- "Которуу"
- "Lens"
- "ТҮШҮНДҮМ"
- "ЖОККО ЧЫГАРУУ"
- "ЖӨНДӨӨЛӨР"
- "Экрандагы текстти которуу же угуу"
- "Экрандагы текст, веб-даректер жана скриншоттор сыяктуу маалымат Google менен бөлүшүлүшү мүмкүн.\n\nБөлүшүлгөн маалыматты өзгөртүү үчүн""Жөндөөлөр > Колдонмолор > Демейки колдонмолор > Санариптик жардамчы колдонмосуна өтүңүз""."
- "Бул функцияны колдонуу үчүн жардамчыны тандаңыз"
- "Экраныңыздагы текстти угуу же которуу үчүн Жөндөөлөрдөн санариптик жардамчы колдонмосун тандаңыз"
- "Бул функцияны колдонуу үчүн жардамчыңызды өзгөртүңүз"
- "Экраныңыздагы текстти угуу же которуу үчүн Жөндөөлөрдөн санариптик жардамчы колдонмосун өзгөртүңүз"
- "Бул экрандагы текстти угуу үчүн бул жерди басыңыз"
- "Бул экрандагы текстти которуу үчүн бул жерди басыңыз"
-
diff --git a/go/quickstep/res/values-lo/strings.xml b/go/quickstep/res/values-lo/strings.xml
deleted file mode 100644
index f2c6ffacc7..0000000000
--- a/go/quickstep/res/values-lo/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ແບ່ງປັນແອັບ"
- "ຟັງ"
- "ແປພາສາ"
- "Lens"
- "ເຂົ້າໃຈແລ້ວ"
- "ຍົກເລີກ"
- "ການຕັ້ງຄ່າ"
- "ແປພາສາ ຫຼື ຟັງຂໍ້ຄວາມຢູ່ໜ້າຈໍ"
- "ຂໍ້ມູນ ເຊັ່ນ: ຂໍ້ຄວາມຢູ່ໜ້າຈໍຂອງທ່ານ, ທີ່ຢູ່ເວັບ ແລະ ຮູບໜ້າຈໍອາດຖືກແບ່ງປັນໃຫ້ກັບ Google.\n\nເພື່ອປ່ຽນແປງຂໍ້ມູນທີ່ທ່ານແບ່ງປັນ, ໃຫ້ເຂົ້າໄປ ""ການຕັ້ງຄ່າ > ແອັບ > ແອັບເລີ່ມຕົ້ນ > ແອັບຜູ້ຊ່ວຍດິຈິຕອນ""."
- "ເລືອກຜູ້ຊ່ວຍເພື່ອໃຊ້ຄຸນສົມບັດນີ້"
- "ເພື່ອຟັງ ຫຼື ແປຂໍ້ຄວາມຢູ່ໜ້າຈໍຂອງທ່ານ, ໃຫ້ເລືອກຜູ້ຊ່ວຍດິຈິຕອນໃດໜຶ່ງໃນການຕັ້ງຄ່າ"
- "ປ່ຽນຜູ້ຊ່ວຍຂອງທ່ານເພື່ອໃຊ້ຄຸນສົມບັດນີ້"
- "ເພື່ອຟັງ ຫຼື ແປຂໍ້ຄວາມຢູ່ໜ້າຈໍຂອງທ່ານ, ໃຫ້ປ່ຽນຜູ້ຊ່ວຍດິຈິຕອນຂອງທ່ານໃນການຕັ້ງຄ່າ"
- "ແຕະບ່ອນນີ້ເພື່ອຟັງຂໍ້ຄວາມຢູ່ໜ້າຈໍນີ້"
- "ແຕະບ່ອນນີ້ເພື່ອແປຂໍ້ຄວາມຢູ່ໜ້າຈໍນີ້"
-
diff --git a/go/quickstep/res/values-lt/strings.xml b/go/quickstep/res/values-lt/strings.xml
deleted file mode 100644
index e47d2bb5ec..0000000000
--- a/go/quickstep/res/values-lt/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Bendrinti programą"
- "Klausyti"
- "Išversti"
- "Lens"
- "SUPRATAU"
- "ATŠAUKTI"
- "NUSTATYMAI"
- "Ekrane esančio teksto vertimas arba klausymas"
- "Tam tikra informacija, pvz., ekrane esantis tekstas, žiniatinklio adresai ir ekrano kopijos, gali būti bendrinama su „Google“.\n\nJei norite pakeisti, kokia informacija gali būti bendrinama, eikite į ""„Nustatymai“ > „Programos“ > „Numatytosios programos“ > „Skaitmeninio pagelbiklio programa“""."
- "Norint naudoti šią funkciją, reikia pasirinkti pagelbiklį"
- "Jei norite klausyti teksto ekrane ar jį išversti, pasirinkite skaitmeninio pagelbiklio programą „Nustatymų“ skiltyje"
- "Norint naudoti šią funkciją, reikia pakeisti pagelbiklį"
- "Jei norite klausyti teksto ekrane ar jį išversti, pakeiskite skaitmeninio pagelbiklio programą „Nustatymų“ skiltyje"
- "Palieskite čia, jei norite klausyti teksto šiame ekrane"
- "Palieskite čia, jei norite išversti tekstą šiame ekrane"
-
diff --git a/go/quickstep/res/values-lv/strings.xml b/go/quickstep/res/values-lv/strings.xml
deleted file mode 100644
index 831486addf..0000000000
--- a/go/quickstep/res/values-lv/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Kopīgot lietotni"
- "Klausīties"
- "Tulkot"
- "Lens"
- "LABI"
- "ATCELT"
- "IESTATĪJUMI"
- "Ekrānā redzamā teksta atskaņošana vai tulkošana"
- "Ar uzņēmumu Google var tikt kopīgota noteikta informācija, piemēram, ekrānā redzamais teksts, tīmekļa adreses un ekrānuzņēmumi.\n\nLai mainītu kopīgotās informācijas veidu, atveriet sadaļu ""Iestatījumi > Lietotnes > Noklusējuma lietotnes > Digitālā asistenta lietotne""."
- "Lai izmantotu šo funkciju, izvēlieties asistentu"
- "Lai klausītos vai tulkotu ekrānā parādīto tekstu, iestatījumos izvēlieties digitālā asistenta lietotni"
- "Lai izmantotu šo funkciju, mainiet asistentu"
- "Lai klausītos vai tulkotu ekrānā parādīto tekstu, iestatījumos mainiet digitālā asistenta lietotni"
- "Lai klausītos ekrānā parādīto tekstu, pieskarieties šeit"
- "Lai tulkotu ekrānā parādīto tekstu, pieskarieties šeit"
-
diff --git a/go/quickstep/res/values-mk/strings.xml b/go/quickstep/res/values-mk/strings.xml
deleted file mode 100644
index 93d582c311..0000000000
--- a/go/quickstep/res/values-mk/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Сподели апликација"
- "Слушај"
- "Преведи"
- "Lens"
- "СФАТИВ"
- "ОТКАЖИ"
- "ПОСТАВКИ"
- "Преведете или слушајте текст на екранот"
- "Информациите како текст на екранот, интернет-адреси и слики од екранот може да се споделуваат со Google.\n\nЗа да промените кои информации ќе се споделуваат, одете во ""Поставки > Апликации > Стандардни апликации > Апликација за дигитален помошник""."
- "Изберете помошник за да ја користите функцијава"
- "За да го слушнете или преведете текстот од екранот, изберете ја апликацијата за дигитален помошник во „Поставки“"
- "Променете го помошникот за да ја користите функцијава"
- "За да го слушнете или преведете текстот од екранот, променете ја апликацијата за дигитален помошник во „Поставки“"
- "Допрете тука за да го слушнете текстот од екранов"
- "Допрете тука за да го преведете текстот од екранов"
-
diff --git a/go/quickstep/res/values-ml/strings.xml b/go/quickstep/res/values-ml/strings.xml
deleted file mode 100644
index 04e8b0aa41..0000000000
--- a/go/quickstep/res/values-ml/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ആപ്പ് പങ്കിടുക"
- "കേൾക്കുക"
- "വിവർത്തനം ചെയ്യുക"
- "ലെൻസ്"
- "മനസ്സിലായി"
- "റദ്ദാക്കുക"
- "ക്രമീകരണം"
- "സ്ക്രീനിലെ ടെക്സ്റ്റ് വിവർത്തനം ചെയ്യുകയോ കേൾക്കുകയോ ചെയ്യുക"
- "നിങ്ങളുടെ സ്ക്രീനിലെ ടെക്സ്റ്റ്, വെബ് വിലാസങ്ങൾ, സ്ക്രീൻഷോട്ടുകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ Google-മായി പങ്കിട്ടേക്കാം.\n\nനിങ്ങൾ പങ്കിടുന്ന വിവരങ്ങൾ മാറ്റാൻ, ""ക്രമീകരണ > ആപ്പുകൾ > ഡിഫോൾട്ട് ആപ്പുകൾ > ഡിജിറ്റൽ അസിസ്റ്റന്റ് ആപ്പ്"" എന്നതിലേക്ക് പോകുക."
- "ഈ ഫീച്ചർ ഉപയോഗിക്കാൻ, ഒരു അസിസ്റ്റന്റ് തിരഞ്ഞെടുക്കുക"
- "നിങ്ങളുടെ സ്ക്രീനിലുള്ള ടെക്സ്റ്റ് കേൾക്കാനോ വിവർത്തനം ചെയ്യാനോ, ക്രമീകരണത്തിൽ നിന്ന് ഒരു ഡിജിറ്റൽ അസിസ്റ്റന്റ് ആപ്പ് തിരഞ്ഞെടുക്കുക"
- "ഈ ഫീച്ചർ ഉപയോഗിക്കാൻ, നിങ്ങളുടെ അസിസ്റ്റന്റ് മാറ്റുക"
- "നിങ്ങളുടെ സ്ക്രീനിലുള്ള ടെക്സ്റ്റ് കേൾക്കാനോ വിവർത്തനം ചെയ്യാനോ, ക്രമീകരണത്തിലെ നിങ്ങളുടെ ഡിജിറ്റൽ അസിസ്റ്റന്റ് ആപ്പ് മാറ്റുക"
- "ഈ സ്ക്രീനിലെ ടെക്സ്റ്റ് കേൾക്കാൻ, ഇവിടെ ടാപ്പ് ചെയ്യുക"
- "ഈ സ്ക്രീനിലെ ടെക്സ്റ്റ് വിവർത്തനം ചെയ്യാൻ, ഇവിടെ ടാപ്പ് ചെയ്യുക"
-
diff --git a/go/quickstep/res/values-mn/strings.xml b/go/quickstep/res/values-mn/strings.xml
deleted file mode 100644
index cf20677db6..0000000000
--- a/go/quickstep/res/values-mn/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Аппыг хуваалцах"
- "Сонсох"
- "Орчуулах"
- "Дуран"
- "ОЙЛГОЛОО"
- "ЦУЦЛАХ"
- "ТОХИРГОО"
- "Дэлгэц дээрх текстийг орчуулах эсвэл сонсох"
- "Таны дэлгэц дээрх текст, веб хаяг, дэлгэцийн агшин зэрэг мэдээллийг Google-тэй хуваалцаж болзошгүй.\n\nТа ямар мэдээлэл хуваалцахаа өөрчлөхийн тулд ""Тохиргоо > Апп > Өгөгдмөл апп > Дижитал туслах апп"" руу очно уу."
- "Энэ онцлогийг ашиглахын тулд туслах сонгоно уу"
- "Дэлгэц дээрээ текст сонсох эсвэл орчуулахын тулд Тохиргоо хэсэгт дижитал туслах аппыг сонгоно уу"
- "Энэ онцлогийг ашиглахын тулд туслахаа өөрчилнө үү"
- "Дэлгэц дээрээ текст сонсох эсвэл орчуулахын тулд Тохиргоо хэсэгт дижитал туслах аппаа өөрчилнө үү"
- "Энэ дэлгэц дээр текст сонсохын тулд энд товшино уу"
- "Энэ дэлгэц дээр текст орчуулахын тулд энд товшино уу"
-
diff --git a/go/quickstep/res/values-mr/strings.xml b/go/quickstep/res/values-mr/strings.xml
deleted file mode 100644
index e190359da2..0000000000
--- a/go/quickstep/res/values-mr/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "अॅप शेअर करा"
- "ऐका"
- "भाषांतर करा"
- "Lens"
- "समजले"
- "रद्द करा"
- "सेटिंग्ज"
- "स्क्रीनवरील मजकूर भाषांतरित करा किंवा ऐका"
- "तुमच्या स्क्रीनवरील मजकूर, वेब अॅड्रेस आणि स्क्रीनशॉट यांसारखी माहिती Google सह शेअर केली जाऊ शकते.\n\nतुम्ही कोणती माहिती शेअर करता हे बदलण्यासाठी ""सेटिंग्ज > ॲप्स > डीफॉल्ट ॲप्स > डिजिटल असिस्टंट ॲपवर जा""."
- "हे वैशिष्ट्य वापरण्यासाठी तुमचे असिस्टंट निवडा"
- "तुमच्या स्क्रीनवरील मजकूर ऐकण्यासाठी किंवा भाषांतर करण्यासाठी, सेटिंग्ज मध्ये तुमचे डिजिटल असिस्टंट अॅप निवडा"
- "हे वैशिष्ट्य वापरण्यासाठी असिस्टंट बदला"
- "तुमच्या स्क्रीनवरील मजकूर ऐकण्यासाठी किंवा भाषांतर करण्यासाठी, सेटिंग्ज मध्ये तुमचे डिजिटल असिस्टंट अॅप बदला"
- "या स्क्रीनवरील मजकूर ऐकण्यासाठी येथे टॅप करा"
- "या स्क्रीनवरील मजकुराचे भाषांतर करण्यासाठी येथे टॅप करा"
-
diff --git a/go/quickstep/res/values-ms/strings.xml b/go/quickstep/res/values-ms/strings.xml
deleted file mode 100644
index 8169256bfb..0000000000
--- a/go/quickstep/res/values-ms/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Kongsi Apl"
- "Dengar"
- "Terjemah"
- "Kanta"
- "OK"
- "BATAL"
- "TETAPAN"
- "Terjemahkan atau dengar teks pada skrin"
- "Maklumat seperti teks pada skrin anda, alamat web dan tangkapan skrin boleh dikongsi dengan Google.\n\nUntuk menukar maklumat yang anda kongsi, pergi ke ""Tetapan > Apl > Apl lalai > Apl pembantu digital""."
- "Pilih pembantu untuk menggunakan ciri ini"
- "Untuk mendengar atau menterjemahkan teks pada skrin anda, pilih apl pembantu digital dalam Tetapan"
- "Tukar pembantu anda untuk menggunakan ciri ini"
- "Untuk mendengar atau menterjemahkan teks pada skrin anda, tukar apl pembantu digital anda dalam Tetapan"
- "Ketik di sini untuk mendengar teks pada skrin ini"
- "Ketik di sini untuk menterjemahkan teks pada skrin ini"
-
diff --git a/go/quickstep/res/values-my/strings.xml b/go/quickstep/res/values-my/strings.xml
deleted file mode 100644
index e3183148c4..0000000000
--- a/go/quickstep/res/values-my/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "အက်ပ် မျှဝေရန်"
- "နားထောင်ရန်"
- "ဘာသာပြန်ရန်"
- "Lens"
- "ရပြီ"
- "မလုပ်တော့"
- "ဆက်တင်များ"
- "ဖန်သားပြင်ပေါ်ရှိ စာသားကို ဘာသာပြန်ပါ (သို့) နားထောင်ပါ"
- "သင့်ဖန်သားပြင်ပေါ်ရှိ စာသား၊ ဝဘ်လိပ်စာနှင့် ဖန်သားပြင်ဓာတ်ပုံများကဲ့သို့ အချက်အလက်များကို Google နှင့် မျှဝေနိုင်သည်။\n\nသင်မျှဝေသည့် အချက်အလက်များကို ပြောင်းရန် ""ဆက်တင်များ > အက်ပ်များ > မူရင်းအက်ပ်များ > ဒစ်ဂျစ်တယ် Assistant အက်ပ်"" သို့ သွားပါ။"
- "ဤဝန်ဆောင်မှုကို အသုံးပြုရန် assistant ရွေးပါ"
- "ဖန်သားပြင်ပေါ်ရှိ စာသားကို နားထောင်ရန် (သို့) ဘာသာပြန်ဆိုရန် ‘ဆက်တင်များ’ တွင် ဒစ်ဂျစ်တယ် assistant အက်ပ် ရွေးပါ"
- "ဤဝန်ဆောင်မှုကို သုံးရန် assistant ကို ပြောင်းပါ"
- "ဖန်သားပြင်ပေါ်ရှိ စာသားကို နားထောင်ရန် (သို့) ဘာသာပြန်ဆိုရန် ‘ဆက်တင်များ’ တွင် ဒစ်ဂျစ်တယ် assistant အက်ပ်ကို ပြောင်းပါ"
- "ဤဖန်သားပြင်ပေါ်ရှိ စာသားကို နားထောင်ရန် ဤနေရာကို တို့ပါ"
- "ဤဖန်သားပြင်ပေါ်ရှိ စာသားကို ဘာသာပြန်ဆိုရန် ဤနေရာကို တို့ပါ"
-
diff --git a/go/quickstep/res/values-nb/strings.xml b/go/quickstep/res/values-nb/strings.xml
deleted file mode 100644
index ec3ef595a5..0000000000
--- a/go/quickstep/res/values-nb/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Del appen"
- "Lytt"
- "Oversett"
- "Lens"
- "GREIT"
- "AVBRYT"
- "INNSTILLINGER"
- "Oversett eller lytt til tekst på skjermen"
- "Informasjon som tekst på skjermen, nettadresser og skjermdumper kan deles med Google.\n\nFor å endre hvilken informasjon du deler, gå til ""Innstillinger > Apper > Standardapper > Digital assistent-app""."
- "Velg en assistent for å bruke denne funksjonen"
- "For å høre eller oversette tekst på skjermen, velg en digital assistent-app i innstillingene"
- "Endre assistenten for å bruke denne funksjonen"
- "For å høre eller oversette tekst på skjermen, endre digital assistent-appen i innstillingene"
- "Trykk her for å høre teksten på denne skjermen"
- "Trykk her for å oversette teksten på denne skjermen"
-
diff --git a/go/quickstep/res/values-ne/strings.xml b/go/quickstep/res/values-ne/strings.xml
deleted file mode 100644
index cd1ee06001..0000000000
--- a/go/quickstep/res/values-ne/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "एप सेयर गर्नुहोस्"
- "सुन्नुहोस्"
- "अनुवाद गर्नुहोस्"
- "लेन्स"
- "बुझेँ"
- "रद्द गर्नुहोस्"
- "सेटिङ"
- "स्क्रिनमा देखिने पाठ अनुवाद गरियोस् वा पढेर सुनाइयोस्"
- "तपाईंको स्क्रिनमा देखिने पाठ, वेब ठेगाना र स्क्रिनसटलगायतका जानकारी Google सँग सेयर गर्न सकिन्छ।\n\nकुन कुन जानकारी सेयर गर्न दिने भन्ने सेटिङ बदल्न ""सेटिङ > एप > डिफल्ट एप > डिजिटल सहायक एप"" मा जानुहोस्।"
- "तपाईं यो सुविधा चलाउन चाहनुहुन्छ भने कुनै सहायक छनौट गर्नुहोस्"
- "तपाईं आफ्नो स्क्रिनमा देखिने पाठ सुन्न वा अनुवाद गर्न चाहनुहुन्छ भने सेटिङमा गई कुनै डिजिटल सहायक एप छनौट गर्नुहोस्"
- "तपाईं यो सुविधा चलाउन चाहनुहुन्छ भने आफ्नो सहायक परिवर्तन गर्नुहोस्"
- "तपाईं आफ्नो स्क्रिनमा देखिने पाठ सुन्न वा अनुवाद गर्न चाहनुहुन्छ भने सेटिङमा गई कुनै डिजिटल सहायक एप परिर्वर्तन गर्नुहोस्"
- "तपाईं यो स्क्रिनमा देखिने पाठ सुन्न चाहनुहुन्छ यहाँ ट्याप गर्नुहोस्"
- "तपाईं यो स्क्रिनमा देखिने पाठ अनुवाद गर्न चाहनुहुन्छ यहाँ ट्याप गर्नुहोस्"
-
diff --git a/go/quickstep/res/values-nl/strings.xml b/go/quickstep/res/values-nl/strings.xml
deleted file mode 100644
index 82a851929f..0000000000
--- a/go/quickstep/res/values-nl/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "App delen"
- "Luisteren"
- "Vertalen"
- "Lens"
- "OK"
- "ANNULEREN"
- "INSTELLINGEN"
- "Tekst op het scherm vertalen of beluisteren"
- "Informatie zoals tekst op je scherm, webadressen en screenshots kan met Google worden gedeeld.\n\nAls je wilt aanpassen welke informatie je deelt, ga je naar ""Instellingen > Apps > Standaard-apps > Digitale-assistent-app""."
- "Kies een assistent om deze functie te gebruiken"
- "Als je tekst op je scherm wilt beluisteren of vertalen, kies je een digitale-assistent-app in Instellingen"
- "Wijzig de assistent om deze functie te gebruiken"
- "Als je tekst op je scherm wilt beluisteren of vertalen, wijzig je de digitale-assistent-app in Instellingen"
- "Tik hier om tekst op dit scherm te beluisteren"
- "Tik hier om tekst op dit scherm te vertalen"
-
diff --git a/go/quickstep/res/values-or/strings.xml b/go/quickstep/res/values-or/strings.xml
deleted file mode 100644
index df8febf331..0000000000
--- a/go/quickstep/res/values-or/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ଆପ୍ ସେୟାର୍ କରନ୍ତୁ"
- "ଶୁଣନ୍ତୁ"
- "ଅନୁବାଦ କରନ୍ତୁ"
- "Lens"
- "ବୁଝିଗଲି"
- "ବାତିଲ୍ କରନ୍ତୁ"
- "ସେଟିଂସ୍"
- "ସ୍କିନରେ ଥିବା ଟେକ୍ସଟକୁ ଅନୁବାଦ କରନ୍ତୁ କିମ୍ବା ଶୁଣନ୍ତୁ"
- "ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଟେକ୍ସଟ୍, ୱେବ୍ ଠିକଣା ଏବଂ ସ୍କ୍ରିନସଟଗୁଡ଼ିକ ପରି ସୂଚନାକୁ Google ସହ ସେୟାର୍ କରାଯାଇପାରେ।\n\nଆପଣ କେଉଁ ସୂଚନା ସେୟାର୍ କରନ୍ତି ତାହା ପରିବର୍ତ୍ତନ କରିବାକୁ, ""ସେଟିଂସ୍ > ଆପ୍ସ > ଡିଫଲ୍ଟ ଆପ୍ସ > ଡିଜିଟାଲ୍ ଆସିଷ୍ଟାଣ୍ଟ ଆପ""କୁ ଯାଆନ୍ତୁ।"
- "ଏହି ଫିଚର୍ ବ୍ୟବହାର କରିବାକୁ ଏକ ଆସିଷ୍ଟାଣ୍ଟ ବାଛନ୍ତୁ"
- "ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଶୁଣିବା ପାଇଁ କିମ୍ବା ଅନୁବାଦ କରିବାକୁ, ସେଟିଂସରେ ଏକ ଡିଜିଟାଲ୍ ଆସିଷ୍ଟାଣ୍ଟ ଆପ୍ ଚୟନ କରନ୍ତୁ"
- "ଏହି ଫିଚର୍ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପଣଙ୍କ ଆସିଷ୍ଟାଣ୍ଟକୁ ବଦଳାନ୍ତୁ"
- "ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଶୁଣିବା ପାଇଁ କିମ୍ବା ଅନୁବାଦ କରିବାକୁ, ସେଟିଂସରେ ଆପଣଙ୍କ ଡିଜିଟାଲ୍ ଆସିଷ୍ଟାଣ୍ଟ ଆପକୁ ବଦଳାନ୍ତୁ"
- "ଏହି ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଶୁଣିବା ପାଇଁ ଏଠାରେ ଟାପ୍ କରନ୍ତୁ"
- "ଏହି ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଅନୁବାଦ କରିବା ପାଇଁ ଏଠାରେ ଟାପ୍ କରନ୍ତୁ"
-
diff --git a/go/quickstep/res/values-pa/strings.xml b/go/quickstep/res/values-pa/strings.xml
deleted file mode 100644
index c3bc875b51..0000000000
--- a/go/quickstep/res/values-pa/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ਐਪ ਨੂੰ ਸਾਂਝਾ ਕਰੋ"
- "ਸੁਣੋ"
- "ਅਨੁਵਾਦ ਕਰੋ"
- "Lens"
- "ਸਮਝ ਲਿਆ"
- "ਰੱਦ ਕਰੋ"
- "ਸੈਟਿੰਗਾਂ"
- "ਸਕ੍ਰੀਨ \'ਤੇ ਦਿੱਤੀ ਲਿਖਤ ਦਾ ਅਨੁਵਾਦ ਕਰੋ ਜਾਂ ਉਸਨੂੰ ਸੁਣੋ"
- "ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿੱਤੀ ਲਿਖਤ, ਵੈੱਬ ਪਤਿਆਂ ਅਤੇ ਸਕ੍ਰੀਨਸ਼ਾਟਾਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਨੂੰ Google ਨਾਲ ਸਾਂਝਾ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।\n\nਤੁਹਾਡੇ ਵੱਲੋਂ ਸਾਂਝੀ ਕੀਤੀ ਜਾਣਕਾਰੀ ਨੂੰ ਬਦਲਣ ਲਈ, ""ਸੈਟਿੰਗਾਂ > ਐਪਾਂ > ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਐਪਾਂ > ਡਿਜੀਟਲ ਸਹਾਇਕ ਐਪ"" \'ਤੇ ਜਾਓ।"
- "ਇਸ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਵਰਤਣ ਲਈ ਸਹਾਇਕ ਐਪ ਚੁਣੋ"
- "ਆਪਣੀ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਖਤ ਨੂੰ ਸੁਣਨ ਅਤੇ ਉਸਦਾ ਅਨੁਵਾਦ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਡਿਜੀਟਲ ਸਹਾਇਕ ਐਪ ਚੁਣੋ"
- "ਇਸ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਵਰਤਣ ਲਈ ਆਪਣੀ ਸਹਾਇਕ ਐਪ ਬਦਲੋ"
- "ਆਪਣੀ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਖਤ ਨੂੰ ਸੁਣਨ ਅਤੇ ਉਸਦਾ ਅਨੁਵਾਦ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਆਪਣੀ ਡਿਜੀਟਲ ਸਹਾਇਕ ਐਪ ਬਦਲੋ"
- "ਇਸ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਖਤ ਨੂੰ ਸੁਣਨ ਲਈ ਇੱਥੇ ਟੈਪ ਕਰੋ"
- "ਇਸ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਖਤ ਦਾ ਅਨੁਵਾਦ ਕਰਨ ਲਈ ਇੱਥੇ ਟੈਪ ਕਰੋ"
-
diff --git a/go/quickstep/res/values-pl/strings.xml b/go/quickstep/res/values-pl/strings.xml
deleted file mode 100644
index a03e05e8c3..0000000000
--- a/go/quickstep/res/values-pl/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Udostępnij aplikację"
- "Posłuchaj"
- "Przetłumacz"
- "Obiektyw"
- "OK"
- "ANULUJ"
- "USTAWIENIA"
- "Przetłumacz lub odsłuchaj tekst na ekranie"
- "Informacje takie jak tekst na ekranie, adresy internetowe i zrzuty ekranu mogą być udostępniane Google.\n\nAby zmienić zakres udostępnianych informacji, kliknij ""Ustawienia > Aplikacje > Aplikacje domyślne > Asystent cyfrowy""."
- "Aby użyć tej funkcji, wybierz asystenta"
- "Aby odsłuchać lub przetłumaczyć tekst widoczny na ekranie, wybierz w Ustawieniach aplikację asystenta cyfrowego"
- "Aby użyć tej funkcji, zmień asystenta"
- "Aby odsłuchać lub przetłumaczyć tekst widoczny na ekranie, zmień w Ustawieniach aplikację asystenta cyfrowego"
- "Kliknij tutaj, aby odsłuchać tekst widoczny na ekranie"
- "Kliknij tutaj, aby przetłumaczyć tekst widoczny na ekranie"
-
diff --git a/go/quickstep/res/values-pt-rPT/strings.xml b/go/quickstep/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 9764134cbb..0000000000
--- a/go/quickstep/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Partilhar app"
- "Ouvir"
- "Traduzir"
- "Lens"
- "OK"
- "CANCELAR"
- "DEFINIÇÕES"
- "Traduza ou ouça o texto no ecrã"
- "Informações como o texto no ecrã, endereços Web e capturas de ecrã podem ser partilhadas com a Google.\n\nPara alterar as informações que partilha, aceda a ""Definições > Apps > App predefinidas > App de assistente digital""."
- "Escolha um assistente para utilizar esta funcionalidade"
- "Para ouvir ou traduzir o texto no ecrã, escolha uma app de assistente digital nas Definições"
- "Mude de assistente para utilizar esta funcionalidade"
- "Para ouvir ou traduzir o texto no ecrã, mude de app de assistente digital nas Definições"
- "Toque aqui para ouvir o texto neste ecrã"
- "Toque aqui para traduzir o texto neste ecrã"
-
diff --git a/go/quickstep/res/values-pt/strings.xml b/go/quickstep/res/values-pt/strings.xml
deleted file mode 100644
index 0a0da3790a..0000000000
--- a/go/quickstep/res/values-pt/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Compartilhar app"
- "Ouvir"
- "Traduzir"
- "Lens"
- "OK"
- "CANCELAR"
- "CONFIGURAÇÕES"
- "Traduzir ou ouvir o texto na tela"
- "Informações como o texto exibido, endereços da Web e capturas de tela poderão ser compartilhadas com o Google.\n\nPara mudar quais dados são compartilhados, acesse ""Configurações > Apps > Apps padrão > App assistente digital""."
- "Escolha um assistente para usar esse recurso"
- "Para ouvir ou traduzir o texto exibido na tela, escolha um app assistente digital nas Configurações"
- "Mude seu assistente para usar esse recurso"
- "Para ouvir ou traduzir o texto exibido na tela, mude seu app assistente digital nas Configurações"
- "Toque aqui para ouvir o texto exibido na tela"
- "Toque aqui para traduzir o texto exibido na tela"
-
diff --git a/go/quickstep/res/values-ro/strings.xml b/go/quickstep/res/values-ro/strings.xml
deleted file mode 100644
index 37cf48db72..0000000000
--- a/go/quickstep/res/values-ro/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Trimiteți aplicația"
- "Ascultați"
- "Traduceți"
- "Lens"
- "OK"
- "ANULAȚI"
- "SETĂRI"
- "Traduceți sau ascultați textul de pe ecran"
- "Informații precum textul de pe ecran, adresele web și capturile de ecran pot fi trimise la Google.\n\nCa să schimbați informațiile trimise, accesați ""Setări > Aplicații > Aplicații prestabilite > Aplicația asistent digital""."
- "Alegeți un asistent pentru a folosi această funcție"
- "Pentru a asculta sau a traduce text de pe ecran, alegeți o aplicație asistent digital în Setări"
- "Schimbați asistentul pentru a folosi această funcție"
- "Pentru a asculta sau a traduce text de pe ecran, schimbați aplicația asistent digital în Setări"
- "Atingeți aici pentru a asculta text de pe ecran"
- "Atingeți aici pentru a traduce text de pe ecran"
-
diff --git a/go/quickstep/res/values-ru/strings.xml b/go/quickstep/res/values-ru/strings.xml
deleted file mode 100644
index d31c42a7b0..0000000000
--- a/go/quickstep/res/values-ru/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Поделиться"
- "Слушать"
- "Перевести"
- "Объектив"
- "ОК"
- "ОТМЕНА"
- "ОТКРЫТЬ НАСТРОЙКИ"
- "Перевод или прослушивание текста на экране"
- "Определенные сведения (например, текст на экране, веб-адреса и скриншоты) могут быть отправлены в Google.\n\nИзменить информацию, которой вы делитесь, можно в меню ""Настройки > Приложения > Приложения по умолчанию > Цифровой помощник""."
- "Выберите помощника, чтобы пользоваться этой функцией"
- "Чтобы слушать или переводить текст на экране, укажите цифрового помощника в настройках."
- "Смените помощника, чтобы пользоваться этой функцией"
- "Чтобы слушать или переводить текст на экране, выберите другого цифрового помощника в настройках."
- "Нажмите, чтобы прослушать текст на этой странице"
- "Нажмите, чтобы перевести текст на этой странице"
-
diff --git a/go/quickstep/res/values-si/strings.xml b/go/quickstep/res/values-si/strings.xml
deleted file mode 100644
index cd6060ca0d..0000000000
--- a/go/quickstep/res/values-si/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "යෙදුම බෙදා ගන්න"
- "සවන් දෙන්න"
- "පරිවර්තනය කරන්න"
- "Lens"
- "තේරුණා"
- "අවලංගු කරන්න"
- "සැකසීම්"
- "තිරය මත පෙළ පරිවර්තනය කරන්න හෝ එයට සවන් දෙන්න"
- "ඔබගේ තිරයේ ඇති පෙළ, වෙබ් ලිපින සහ තිර රූ වැනි තොරතුරු Google සමඟ බෙදා ගත හැකිය.\n\nඔබ බෙදා ගන්නා තොරතුරු වෙනස් කිරීමට, ""සැකසීම් > යෙදුම් > පෙරනිමි යෙදුම් > ඩිජිටල් සහායක යෙදුම"" වෙත යන්න."
- "මෙම විශේෂාංගය භාවිත කිරීමට සහායකයකු තෝරන්න"
- "ඔබගේ තිරයේ පෙළ සවන් දීමට හෝ පරිවර්තනය කිරීමට, සැකසීම්වල ඩිජිටල් සහායක යෙදුමක් තෝරන්න"
- "මෙම විශේෂාංගය භාවිත කිරීමට ඔබගේ සහායක වෙනස් කරන්න"
- "ඔබගේ තිරයේ පෙළට සවන් දීමට හෝ පරිවර්තනය කිරීමට, සැකසීම් තුළ ඔබගේ ඩිජිටල් සහායක යෙදුම වෙනස් කරන්න"
- "මෙම තිරයේ පෙළට සවන් දීමට මෙහි තට්ටු කරන්න"
- "මෙම තිරයේ පෙළ පරිවර්තනය කිරීමට මෙහි තට්ටු කරන්න"
-
diff --git a/go/quickstep/res/values-sk/strings.xml b/go/quickstep/res/values-sk/strings.xml
deleted file mode 100644
index 880d8ad3f4..0000000000
--- a/go/quickstep/res/values-sk/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Zdieľať aplikáciu"
- "Počúvať"
- "Preložiť"
- "Lens"
- "DOBRE"
- "ZRUŠIŤ"
- "NASTAVENIA"
- "Prekladajte alebo počúvajte text na obrazovke"
- "Údaje, napríklad text na obrazovke, webové adresy a snímky obrazovky, môžu byť zdieľané s Googlom.\n\nAk chcete zmeniť, ktoré údaje zdieľate, prejdite do sekcie ""Nastavenia > Aplikácie > Predvolené aplikácie > Digitálny asistent""."
- "Ak chcete používať túto funkciu, vyberte asistenta"
- "Ak si chcete vypočuť alebo nechať preložiť text na obrazovke, vyberte v Nastaveniach aplikáciu digitálneho asistenta"
- "Ak chcete použígvať túto funkciu, zmeňte svojho asistenta"
- "Ak si chcete vypočuť alebo nechať preložiť text na obrazovke, zmeňte v Nastaveniach aplikáciu digitálneho asistenta"
- "Klepnutím tu si vypočujte text na tejto obrazovke"
- "Klepnutím tu si nechajte preložiť text na tejto obrazovke"
-
diff --git a/go/quickstep/res/values-sl/strings.xml b/go/quickstep/res/values-sl/strings.xml
deleted file mode 100644
index 31fcffca84..0000000000
--- a/go/quickstep/res/values-sl/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Deli aplikacijo"
- "Poslušanje"
- "Prevedi"
- "Lens"
- "RAZUMEM"
- "PREKLIČI"
- "NASTAVITVE"
- "Prevod ali poslušanje besedila na zaslonu"
- "Podatki, kot so besedilo na zaslonu, spletni naslovi in posnetki zaslonov, bodo morda deljeni z Googlom.\n\nČe želite spremeniti, katere podatke delite, odprite ""Nastavitve > Aplikacije > Privzete aplikacije > Digitalni pomočnik""."
- "Za uporabo te funkcije izberite pomočnika"
- "Za poslušanje ali prevod besedila na zaslonu v nastavitvah izberite digitalnega pomočnika."
- "Za uporabo te funkcije izberite drugega pomočnika"
- "Za poslušanje ali prevod besedila na zaslonu v nastavitvah izberite drugega digitalnega pomočnika."
- "Dotaknite se tukaj za poslušanje besedila na zaslonu."
- "Dotaknite se tukaj za prevod besedila na zaslonu."
-
diff --git a/go/quickstep/res/values-sq/strings.xml b/go/quickstep/res/values-sq/strings.xml
deleted file mode 100644
index bc9c429d05..0000000000
--- a/go/quickstep/res/values-sq/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Ndaj aplikacionin"
- "Dëgjo"
- "Përkthe"
- "Lentja"
- "E KUPTOVA"
- "ANULO"
- "CILËSIMET"
- "Përkthe ose dëgjo tekstin në ekran"
- "Informacionet si teksti në ekranin tënd, adresat e uebit dhe pamjet e ekranit mund të ndahen me Google.\n\nPër të ndryshuar se çfarë informacionesh ndahen, shko te ""Cilësimet > Aplikacionet > Aplikacionet e parazgjedhura > Aplikacioni i asistentit dixhital""."
- "Zgjidh një asistent për të përdorur këtë veçori"
- "Për të dëgjuar ose përkthyer tekstin në ekran, zgjidh një aplikacion të asistentit dixhital te \"Cilësimet\""
- "Ndrysho asistentin për të përdorur këtë veçori"
- "Për të dëgjuar ose përkthyer tekstin në ekran, ndrysho aplikacionin e asistentit dixhital te \"Cilësimet\""
- "Trokit këtu për të dëgjuar tekstin në këtë ekran"
- "Trokit këtu për të përkthyer tekstin në këtë ekran"
-
diff --git a/go/quickstep/res/values-sr/strings.xml b/go/quickstep/res/values-sr/strings.xml
deleted file mode 100644
index 9c9a332a17..0000000000
--- a/go/quickstep/res/values-sr/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Дели апликацију"
- "Пусти"
- "Преведи"
- "Објектив"
- "ВАЖИ"
- "ОТКАЖИ"
- "ПОДЕШАВАЊА"
- "Преводите или слушајте текст на екрану"
- "Информације попут текста на екрану, веб-адреса и снимака екрана могу да се деле са Google-ом.\n\nДа бисте променили информације које делите, идите у ""Подешавања > Апликације > Подразумеване апликације > Апликација дигиталног помоћника""."
- "Одаберите помоћника да бисте користили ову функцију"
- "Да бисте чули текст са екрана или га превели, одаберите апликацију дигиталног помоћника у Подешавањима"
- "Промените помоћника да бисте користили ову функцију"
- "Да бисте чули текст са екрана или га превели, промените апликацију дигиталног помоћника у Подешавањима"
- "Додирните овде да бисте чули текст са овог екрана"
- "Додирните овде да бисте превели текст са овог екрана"
-
diff --git a/go/quickstep/res/values-sv/strings.xml b/go/quickstep/res/values-sv/strings.xml
deleted file mode 100644
index cb70a58477..0000000000
--- a/go/quickstep/res/values-sv/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Dela app"
- "Lyssna"
- "Översätt"
- "Lens"
- "OK"
- "AVBRYT"
- "INSTÄLLNINGAR"
- "Översätt eller lyssna på texten på skärmen"
- "Information som text på skärmen, webbadresser och skärmbilder kan delas med Google.\n\nFör att ändra vilken information du delar öppnar du ""Inställningar > Appar > Standardappar > Digital assistentapp""."
- "Välj en assistent om du vill använda den här funktionen"
- "Välj en digital assistentapp i Inställningar om du vill lyssna på eller översätta text på skärmen"
- "Byt assistent om du vill använda den här funktionen"
- "Byt digital assistentapp i Inställningar om du vill lyssna på eller översätta text på skärmen"
- "Tryck här för att lyssna på texten på skärmen"
- "Tryck här för att översätta texten på skärmen"
-
diff --git a/go/quickstep/res/values-sw/strings.xml b/go/quickstep/res/values-sw/strings.xml
deleted file mode 100644
index a78980a84e..0000000000
--- a/go/quickstep/res/values-sw/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Shiriki Programu"
- "Sikiliza"
- "Tafsiri"
- "Lenzi"
- "NIMEELEWA"
- "GHAIRI"
- "MIPANGILIO"
- "Tafsiri au usikilize maandishi kwenye skrini"
- "Maelezo kama vile maandishi kwenye skrini yako, anwani za wavuti na picha za skrini yanaweza kushirikiwa na Google.\n\nIli ubadilishe maelezo unayoshiriki, nenda kwenye ""Mipangilio > Programu > Programu chaguomsingi > Programu ya mratibu dijitali""."
- "Chagua programu ya mratibu ili utumie kipengele hiki"
- "Ili usikilize au utafsiri maandishi kwenye skrini yako, chagua programu ya mratibu dijitali katika Mipangilio"
- "Badilisha programu yako ya mratibu ili utumie kipengele hiki"
- "Ili usikilize au utafsiri maandishi kwenye skrini yako, badilisha programu yako ya mratibu dijitali katika Mipangilio"
- "Gusa hapa ili usikilize maandishi kwenye skrini hii"
- "Gusa hapa ili utafsiri maandishi kwenye skrini hii"
-
diff --git a/go/quickstep/res/values-ta/strings.xml b/go/quickstep/res/values-ta/strings.xml
deleted file mode 100644
index 896c7c6e8c..0000000000
--- a/go/quickstep/res/values-ta/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ஆப்ஸைப் பகிருங்கள்"
- "கேளுங்கள்"
- "மொழிபெயர்"
- "லென்ஸ்"
- "சரி"
- "ரத்துசெய்"
- "அமைப்புகள்"
- "திரையிலுள்ள உரையை மொழிபெயருங்கள் அல்லது கேளுங்கள்"
- "உங்கள் திரையிலுள்ள உரை, வலை முகவரிகள், ஸ்கிரீன்ஷாட்டுகள் போன்ற தகவல்கள் Googleளுடன் பகிரப்படலாம்.\n\nஎந்தத் தகவல்கள் பகிரப்படலாம் என்பதை மாற்ற, ""அமைப்புகள் > ஆப்ஸ் > இயல்பு ஆப்ஸ் > டிஜிட்டல் அசிஸ்டண்ட் ஆப்ஸ்"" என்பதற்குச் செல்லுங்கள்."
- "இந்த அம்சத்தைப் பயன்படுத்த அசிஸ்டண்ட்டைத் தேர்வுசெய்யவும்"
- "திரையில் தோன்றும் வார்த்தைகளைக் கேட்கவோ மொழிபெயர்க்கவோ அமைப்புகளில் டிஜிட்டல் அசிஸ்டண்ட் ஆப்ஸைத் தேர்வுசெய்யவும்"
- "இந்த அம்சத்தைப் பயன்படுத்த அசிஸ்டண்ட்டை மாற்றவும்"
- "திரையில் தோன்றும் வார்த்தைகளைக் கேட்கவோ மொழிபெயர்க்கவோ அமைப்புகளில் டிஜிட்டல் அசிஸ்டண்ட் ஆப்ஸை மாற்றவும்"
- "இந்தத் திரையில் தோன்றும் வார்த்தைகளைக் கேட்க இங்கே தட்டவும்"
- "இந்தத் திரையில் தோன்றும் வார்த்தைகளை மொழிபெயர்க்க இங்கே தட்டவும்"
-
diff --git a/go/quickstep/res/values-te/strings.xml b/go/quickstep/res/values-te/strings.xml
deleted file mode 100644
index cb481d0709..0000000000
--- a/go/quickstep/res/values-te/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "యాప్ను షేర్ చేయండి"
- "వినండి"
- "అనువదించండి"
- "Lens"
- "అర్థమైంది"
- "రద్దు చేయండి"
- "సెట్టింగ్లు"
- "స్క్రీన్పై టెక్స్ట్ అనువదించండి లేదా వినండి"
- "మీ స్క్రీన్పై టెక్స్ట్, వెబ్ అడ్రస్లు, అలాగే స్క్రీన్షాట్ల వంటి సమాచారం Googleతో షేర్ చేయడం జరగవచ్చు.\n\nమీరు ఏ సమాచారాన్ని షేర్ చేసుకుంటారో మార్చడానికి ""సెట్టింగ్లు > యాప్లు > ఆటోమేటిక్ సెట్టింగ్ యాప్లు > డిజిటల్ అసిస్టెంట్ యాప్ల""కు వెళ్లండి."
- "ఈ ఫీచర్ను ఉపయోగించడానికి అసిస్టెంట్ను ఎంచుకోండి"
- "మీ స్క్రీన్పై ఉన్న టెక్స్ట్ను వినడానికి లేదా అనువదించడానికి, సెట్టింగ్లలో డిజిటల్ అసిస్టెంట్ యాప్ను ఎంచుకోండి"
- "ఈ ఫీచర్ను ఉపయోగించడానికి మీ అసిస్టెంట్ను మార్చండి"
- "మీ స్క్రీన్పై ఉన్న టెక్స్ట్ను వినడానికి లేదా అనువదించడానికి, సెట్టింగ్లలో మీ డిజిటల్ అసిస్టెంట్ యాప్ను మార్చండి"
- "ఈ స్క్రీన్పై ఉన్న టెక్స్ట్ను వినడానికి ఇక్కడ ట్యాప్ చేయండి"
- "ఈ స్క్రీన్పై ఉన్న టెక్స్ట్ను అనువదించడానికి ఇక్కడ ట్యాప్ చేయండి"
-
diff --git a/go/quickstep/res/values-th/strings.xml b/go/quickstep/res/values-th/strings.xml
deleted file mode 100644
index f19cb2ae14..0000000000
--- a/go/quickstep/res/values-th/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "แชร์แอป"
- "ฟัง"
- "แปลภาษา"
- "Lens"
- "รับทราบ"
- "ยกเลิก"
- "การตั้งค่า"
- "แปลหรือฟังข้อความบนหน้าจอ"
- "อาจมีการแชร์ข้อมูลอย่างเช่น ข้อความบนหน้าจอ ที่อยู่เว็บ และภาพหน้าจอกับ Google\n\nหากต้องการเปลี่ยนประเภทข้อมูลที่คุณแชร์ ให้ไปที่""การตั้งค่า > แอป > แอปเริ่มต้น > แอปผู้ช่วยดิจิทัล"
- "เลือกผู้ช่วยเพื่อใช้ฟีเจอร์นี้"
- "เลือกแอปผู้ช่วยดิจิทัลในการตั้งค่าเพื่อฟังหรือแปลข้อความบนหน้าจอ"
- "เปลี่ยนผู้ช่วยเพื่อใช้ฟีเจอร์นี้"
- "เปลี่ยนแอปผู้ช่วยดิจิทัลในการตั้งค่าเพื่อฟังหรือแปลข้อความบนหน้าจอ"
- "แตะที่นี่เพื่อฟังข้อความบนหน้าจอนี้"
- "แตะที่นี่เพื่อแปลข้อความบนหน้าจอนี้"
-
diff --git a/go/quickstep/res/values-tl/strings.xml b/go/quickstep/res/values-tl/strings.xml
deleted file mode 100644
index 1810c4c036..0000000000
--- a/go/quickstep/res/values-tl/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Ibahagi ang App"
- "Makinig"
- "Isalin"
- "Lens"
- "OK"
- "KANSELAHIN"
- "MGA SETTING"
- "I-translate o pakinggan ang text sa screen"
- "Posibleng ibahagi sa Google ang impormasyong gaya ng text sa iyong screen, mga web address, at screenshot.\n\nPara baguhin kung anong impormasyon ang ibinabahagi mo, pumunta sa ""Mga Setting > Mga App > Mga default na app > Digital assistant app""."
- "Pumili ng assistant para magamit ang feature na ito"
- "Para pakinggan o isalin ang text sa iyong screen, pumili ng app ng digital na assistant sa Mga Setting"
- "Palitan ang iyong assistant para magamit ang feature na ito"
- "Para pakinggan o isalin ang text sa iyong screen, palitan ang iyong app ng digital na assistant sa Mga Setting"
- "Mag-tap dito para pakinggan ang text sa screen na ito"
- "Mag-tap dito para isalin ang text sa screen na ito"
-
diff --git a/go/quickstep/res/values-tr/strings.xml b/go/quickstep/res/values-tr/strings.xml
deleted file mode 100644
index 0854dec347..0000000000
--- a/go/quickstep/res/values-tr/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Uygulamayı paylaş"
- "Dinle"
- "Çevir"
- "Lens"
- "ANLADIM"
- "İPTAL"
- "AYARLAR"
- "Ekrandaki metni çevirin veya dinleyin"
- "Ekranınızdaki metin, web adresleri ve ekran görüntüleri gibi bilgiler Google ile paylaşılabilir.\n\nPaylaştığınız bilgileri değiştirmek için ""Ayarlar > Uygulamalar > Varsayılan uygulamalar > Dijital asistan uygulamasına gidin""."
- "Bu özelliği kullanmak için bir asistan seçin"
- "Ekranınızdaki metni dinlemek veya çevirmek için Ayarlar\'dan bir dijital asistan uygulaması seçin"
- "Bu özelliği kullanmak için asistanınızı değiştirin"
- "Ekranınızdaki metni dinlemek veya çevirmek için Ayarlar\'dan dijital asistan uygulamanızı değiştirin"
- "Bu ekrandaki metni dinlemek için buraya dokunun"
- "Bu ekrandaki metni çevirmek için buraya dokunun"
-
diff --git a/go/quickstep/res/values-uk/strings.xml b/go/quickstep/res/values-uk/strings.xml
deleted file mode 100644
index 475ff20582..0000000000
--- a/go/quickstep/res/values-uk/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Поділитися додатком"
- "Слухати"
- "Перекласти"
- "Об’єктив"
- "OK"
- "СКАСУВАТИ"
- "НАЛАШТУВАННЯ"
- "Перекласти або прослухати текст на екрані"
- "Певна інформація (наприклад, текст на екрані, веб-адреси, знімки екрана) може надсилатися на сервери Google.\n\nЩоб змінити типи даних, які надсилаються, відкрийте ""Налаштування > Додатки > Додатки за умовчанням > Цифровий помічник""."
- "Щоб користуватися цією функцією, виберіть помічника"
- "Щоб прослухати чи перекласти текст на екрані, виберіть цифрового помічника в налаштуваннях"
- "Змініть помічника, щоб користуватися цією функцією"
- "Щоб прослухати чи перекласти текст на екрані, змініть цифрового помічника в налаштуваннях"
- "Натисніть тут, щоб прослухати текст на цьому екрані"
- "Натисніть тут, щоб перекласти текст на цьому екрані"
-
diff --git a/go/quickstep/res/values-ur/strings.xml b/go/quickstep/res/values-ur/strings.xml
deleted file mode 100644
index 6393127100..0000000000
--- a/go/quickstep/res/values-ur/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "ایپ کا اشتراک کریں"
- "سنیں"
- "Google ترجمہ"
- "Google لینز"
- "سمجھ آ گئی"
- "منسوخ کریں"
- "ترتیبات"
- "اسکرین پر موجود ٹیکسٹ کو سنیں یا ترجمہ کریں"
- "آپ کی اسکرین پر ٹیکسٹ، ویب پتے اور اسکرین شاٹس جیسی معلومات کا اشتراک Google کے ساتھ کیا جا سکتا ہے۔\n\nآپ جس معلومات کا اشتراک کرتے ہیں اسے تبدیل کرنے کیلئے ""ترتیبات > ایپس > ڈیفالٹ ایپس > ڈیجیٹل اسسٹنٹ ایپ"" پر جائیں۔"
- "اس خصوصیت کا استعمال کرنے کے لیے اسسٹنٹ کا انتخاب کریں"
- "اپنی اسکرین پر موجود ٹیکسٹ کو سننے یا اس کا ترجمہ کرنے کیلئے ترتیبات میں ڈیجیٹل اسسٹنٹ ایپ کا انتخاب کریں"
- "اس خصوصیت کا استعمال کرنے کے لیے اپنی اسسٹنٹ کا استعمال کریں"
- "اپنی اسکرین پر موجود ٹیکسٹ کو سننے یا اس کا ترجمہ کرنے کیلئے ترتیبات میں اپنی ڈیجیٹل اسسٹنٹ ایپ کو تبدیل کریں"
- "اس اسکرین پر موجود ٹیکسٹ کو سننے کے لیے یہاں تھپتھپائیں"
- "اس اسکرین پر موجود ٹیکسٹ کا ترجمہ کرنے کے لیے یہاں تھپتھپائیں"
-
diff --git a/go/quickstep/res/values-uz/strings.xml b/go/quickstep/res/values-uz/strings.xml
deleted file mode 100644
index 5228cfe5a2..0000000000
--- a/go/quickstep/res/values-uz/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Ilovani ulashish"
- "Tinglash"
- "Tarjima"
- "Lens"
- "OK"
- "BEKOR QILISH"
- "SOZLAMALAR"
- "Ekrandagi matnni tarjima qilish yoki tinglash"
- "Ekraningizdagi matn, veb-manzillar va skrinshot kabilar Googlega yuborilishi mumkin.\n\nQanday maʼlumotlarni ulashishni tanlash uchun ""Sozlamalar > Ilovalar > Standart ilovalar > Raqamli assistent"" ilovasini oching."
- "Bu funksiyadan foydalanish uchun assistentni tanlang"
- "Ekrandagi matnni eshittirish yoki tarjima qilish uchun Sozlamalar orqali raqamli assistent ilovasini tanlang"
- "Bu funksiyadan foydalanish uchun assistentni almashtiring"
- "Ekrandagi matnni eshittirish yoki tarjima qilish uchun Sozlamalar orqali raqamli assistent ilovasini almashtiring"
- "Ekrandagi matnni eshittirish uchun bosing"
- "Ekrandagi matnni tarjima qilish uchun bosing"
-
diff --git a/go/quickstep/res/values-vi/strings.xml b/go/quickstep/res/values-vi/strings.xml
deleted file mode 100644
index cebb934820..0000000000
--- a/go/quickstep/res/values-vi/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Chia sẻ ứng dụng"
- "Nghe"
- "Dịch"
- "Ống kính"
- "OK"
- "HỦY"
- "CÀI ĐẶT"
- "Dịch hoặc nghe văn bản trên màn hình"
- "Những thông tin như văn bản trên màn hình, địa chỉ web và ảnh chụp màn hình có thể được chia sẻ với Google.\n\nĐể thay đổi những thông tin mà bạn chia sẻ, hãy chuyển đến phần ""Cài đặt > Ứng dụng > Ứng dụng mặc định > Ứng dụng trợ lý kỹ thuật số""."
- "Chọn một ứng dụng trợ lý để dùng tính năng này"
- "Để nghe hoặc dịch văn bản trên màn hình, hãy chọn một ứng dụng trợ lý kỹ thuật số trong phần Cài đặt"
- "Thay đổi ứng dụng trợ lý để dùng tính năng này"
- "Để nghe hoặc dịch văn bản trên màn hình, hãy thay đổi ứng dụng trợ lý kỹ thuật số trong phần Cài đặt"
- "Nhấn vào đây để nghe văn bản trên màn hình này"
- "Nhấn vào đây để dịch văn bản trên màn hình này"
-
diff --git a/go/quickstep/res/values-zh-rCN/strings.xml b/go/quickstep/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 9a71dd79fa..0000000000
--- a/go/quickstep/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "分享应用"
- "聆听"
- "翻译"
- "智能镜头"
- "知道了"
- "取消"
- "设置"
- "翻译或聆听屏幕上的文字"
- "系统可能会将屏幕上的文字、网址和屏幕截图等信息分享给 Google。\n\n如需更改要分享哪些信息,请依次转到""设置 > 应用 > 默认应用 > 数字助理应用""。"
- "需选择一款助理应用,才能使用此功能"
- "如需收听或翻译屏幕上的文字,请在“设置”部分选择一款数字助理应用"
- "需更改助理应用,才能使用此功能"
- "如需收听或翻译屏幕上的文字,请在“设置”部分更改数字助理应用"
- "点按此处即可收听屏幕上的文字"
- "点按此处即可翻译屏幕上的文字"
-
diff --git a/go/quickstep/res/values-zh-rHK/strings.xml b/go/quickstep/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 29402d857c..0000000000
--- a/go/quickstep/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "分享應用程式"
- "聆聽"
- "翻譯"
- "智能鏡頭"
- "知道了"
- "取消"
- "設定"
- "翻譯或聆聽畫面上的文字"
- "可能會與 Google 分享螢幕上的文字、網址和螢幕截圖等資料。\n\n如要變更分享的資料,請前往 ""[設定] > [應用程式] > [預設應用程式] > [數碼助理應用程式]""。"
- "必須選擇數碼助理才可使用此功能"
- "如要聆聽或翻譯畫面上的文字,請在「設定」中選擇數碼助理應用程式"
- "必須變更數碼助理才可使用此功能"
- "如要聆聽或翻譯畫面上的文字,請在「設定」中變更數碼助理應用程式"
- "輕按這裡即可聆聽此畫面上的文字"
- "輕按這裡即可翻譯此畫面上的文字"
-
diff --git a/go/quickstep/res/values-zh-rTW/strings.xml b/go/quickstep/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 86d78c6c0e..0000000000
--- a/go/quickstep/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "分享應用程式"
- "聆聽"
- "翻譯"
- "智慧鏡頭"
- "我知道了"
- "取消"
- "設定"
- "翻譯或朗讀畫面上的文字"
- "系統可能會將畫面上的文字、網址和螢幕截圖等資訊分享給 Google。\n\n如要變更分享的資訊類型,請前往 [設定] > [應用程式] > [預設應用程式] > [數位助理應用程式]""。"
- "必須選擇數位助理應用程式才能使用這項功能"
- "如要聽取或翻譯畫面上的文字,請前往「設定」選擇數位助理應用程式"
- "必須變更數位助理應用程式才能使用這項功能"
- "如要聽取或翻譯畫面上的文字,請前往「設定」變更數位助理應用程式"
- "輕觸這裡即可聽取這個畫面上的文字"
- "輕觸這裡即可翻譯這個畫面上的文字"
-
diff --git a/go/quickstep/res/values-zu/strings.xml b/go/quickstep/res/values-zu/strings.xml
deleted file mode 100644
index 64b163549f..0000000000
--- a/go/quickstep/res/values-zu/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- "Yabelana nge-App"
- "Lalela"
- "Humusha"
- "Ilensi"
- "NGIYITHOLILE"
- "KHANSELA"
- "AMASETHINGI"
- "Humusha noma ulalele umbhalo osesikrinini"
- "Imininingwane efana nombhalo esikrinini sakho, amakheli wewebhu, nezithombe-skrini kungabiwa ne-Google.\n\nUkuze ushintshe ukuthi yiluphi ulwazi olwabayo, yiya kokuthi ""Amasethingi > ama-App > Ama-app azenzekelayo > Umsizi we-app odijithali""."
- "Khetha umsizi ukuze usebenzise lesi sakhi"
- "Ukuze ulalele noma uhumushe umbhalo kusikrini sakho, khetha i-app yomsizi odijithali kokuthi Amasethingi"
- "Shintsha umsizi wakho ukuze usebenzise lesi sakhi"
- "Ukuze ulalele noma uhumushe umbhalo kusikrini sakho, shintsha i-app yomsizi wakho odijithali kokuthi Amasethingi"
- "Thepha lapha ukuze ulalele umbhalo kusikrini"
- "Thepha lapha ukuze uhumushe umbhalo kulesi sikrini"
-
diff --git a/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java b/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
index 97ba5905e0..d4eca2fd40 100644
--- a/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
@@ -35,6 +35,7 @@ import com.android.quickstep.util.RecentsOrientedState;
*/
public class GoOverviewActionsView extends OverviewActionsView {
+ @Nullable
private ArrowTipView mArrowTipView;
public GoOverviewActionsView(Context context) {
@@ -117,7 +118,7 @@ public class GoOverviewActionsView extends OverviewActionsView
+ errorLine1=" setColorResources(mWallpaperColorResources);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
+ line="528"
+ column="17"/>
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 6d49d75953..c5599887dd 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -59,6 +59,8 @@ message ContainerInfo {
SettingsContainer settings_container = 9;
PredictedHotseatContainer predicted_hotseat_container = 10;
TaskSwitcherContainer task_switcher_container = 11;
+ TaskBarContainer task_bar_container = 12;
+ WallpapersContainer wallpapers_container = 13;
ExtendedContainers extended_containers = 20;
}
}
@@ -100,6 +102,16 @@ message SettingsContainer {
message TaskSwitcherContainer {
}
+// Container for taskbar.
+// Configured to show up on large screens(tablet-sized) such as foldables in expanded state, within
+// an app view(not in launcher screen).
+message TaskBarContainer {
+ optional int32 index = 1;
+
+ // Bit encoded value to capture pinned and predicted taskbar positions.
+ optional int32 cardinality = 2;
+}
+
enum Attribute {
UNKNOWN = 0;
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
@@ -141,6 +153,8 @@ enum Attribute {
ALL_APPS_SEARCH_RESULT_NAVVYSITE = 25;
ALL_APPS_SEARCH_RESULT_TIPS = 26;
ALL_APPS_SEARCH_RESULT_PEOPLE_TILE = 27;
+ ALL_APPS_SEARCH_RESULT_LEGACY_SHORTCUT = 30;
+ ALL_APPS_SEARCH_RESULT_ASSISTANT_MEMORY = 31;
WIDGETS_BOTTOM_TRAY = 28;
WIDGETS_TRAY_PREDICTION = 29;
@@ -230,9 +244,16 @@ message FolderContainer {
oneof ParentContainer {
WorkspaceContainer workspace = 4;
HotseatContainer hotseat = 5;
+ TaskBarContainer taskbar = 6;
}
}
+// Represents wallpapers container for quick switching.
+message WallpapersContainer {
+ // Number of wallpapers in the container.
+ optional int32 cardinality = 1;
+}
+
// Represents state of EditText field before update.
enum FromState {
// Default value.
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index 96797c376d..70b1438c38 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -22,3 +22,19 @@ filegroup {
path: "robolectric_tests",
srcs: ["robolectric_tests/src/**/*.java"],
}
+
+filegroup {
+ name: "launcher3-quickstep-tests-src",
+ path: "tests",
+ srcs: ["tests/src/**/*.java"],
+}
+
+filegroup {
+ name: "launcher3-quickstep-oop-tests-src",
+ path: "tests",
+ srcs: [
+ "tests/src/com/android/quickstep/NavigationModeSwitchRule.java",
+ "tests/src/com/android/quickstep/AbstractQuickStepTest.java",
+ "tests/src/com/android/quickstep/TaplTestsQuickstep.java",
+ ]
+}
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index 6808222258..53910e344b 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -49,7 +49,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index dc92731e16..352cd3e7b6 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -28,6 +28,7 @@
+
@@ -35,6 +36,7 @@
+
@@ -65,7 +67,7 @@
android:stateNotNeeded="true"
android:theme="@style/LauncherTheme"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""/>
@@ -100,7 +102,6 @@
@@ -116,7 +117,6 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/button_taskbar_edu_bordered.xml b/quickstep/res/drawable/button_taskbar_edu_bordered.xml
new file mode 100644
index 0000000000..47f8e8f8cd
--- /dev/null
+++ b/quickstep/res/drawable/button_taskbar_edu_bordered.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_picker_handle.xml b/quickstep/res/drawable/button_taskbar_edu_colored.xml
similarity index 56%
rename from res/drawable/bg_widgets_picker_handle.xml
rename to quickstep/res/drawable/button_taskbar_edu_colored.xml
index 68681a684d..70bfc9f255 100644
--- a/res/drawable/bg_widgets_picker_handle.xml
+++ b/quickstep/res/drawable/button_taskbar_edu_colored.xml
@@ -13,17 +13,17 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/default_sandbox_mock_launcher.xml b/quickstep/res/drawable/default_sandbox_mock_launcher.xml
deleted file mode 100644
index 38fbcf09b6..0000000000
--- a/quickstep/res/drawable/default_sandbox_mock_launcher.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
diff --git a/quickstep/res/drawable/gesture_tutorial_finger_dot.xml b/quickstep/res/drawable/gesture_tutorial_finger_dot.xml
new file mode 100644
index 0000000000..5f8aafd30a
--- /dev/null
+++ b/quickstep/res/drawable/gesture_tutorial_finger_dot.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/gesture_tutorial_motion_back.xml b/quickstep/res/drawable/gesture_tutorial_motion_back.xml
deleted file mode 100644
index a6860fac64..0000000000
--- a/quickstep/res/drawable/gesture_tutorial_motion_back.xml
+++ /dev/null
@@ -1,1233 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/quickstep/res/drawable/gesture_tutorial_motion_home_dark_mode.xml b/quickstep/res/drawable/gesture_tutorial_motion_home_dark_mode.xml
deleted file mode 100644
index aff35c1bce..0000000000
--- a/quickstep/res/drawable/gesture_tutorial_motion_home_dark_mode.xml
+++ /dev/null
@@ -1,1254 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/quickstep/res/drawable/gesture_tutorial_motion_home_light_mode.xml b/quickstep/res/drawable/gesture_tutorial_motion_home_light_mode.xml
deleted file mode 100644
index 98d97ad62d..0000000000
--- a/quickstep/res/drawable/gesture_tutorial_motion_home_light_mode.xml
+++ /dev/null
@@ -1,1254 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/quickstep/res/drawable/gesture_tutorial_motion_overview_dark_mode.xml b/quickstep/res/drawable/gesture_tutorial_motion_overview_dark_mode.xml
deleted file mode 100644
index b007d20f34..0000000000
--- a/quickstep/res/drawable/gesture_tutorial_motion_overview_dark_mode.xml
+++ /dev/null
@@ -1,1623 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/res/drawable/gesture_tutorial_ripple.xml b/quickstep/res/drawable/gesture_tutorial_ripple.xml
similarity index 100%
rename from res/drawable/gesture_tutorial_ripple.xml
rename to quickstep/res/drawable/gesture_tutorial_ripple.xml
diff --git a/quickstep/res/drawable/ic_screenshot.xml b/quickstep/res/drawable/ic_screenshot.xml
index d97eae1d15..9ee6c44011 100644
--- a/quickstep/res/drawable/ic_screenshot.xml
+++ b/quickstep/res/drawable/ic_screenshot.xml
@@ -13,11 +13,20 @@
limitations under the License.
-->
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
-
+ android:pathData="M5.8334,1.666H8.3334V3.3327H5.8334V6.666H4.1667V3.3327C4.1667,2.4122 4.9129,1.666 5.8334,1.666Z"
+ android:fillColor="#000000"/>
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_sysbar_accessibility_button.xml b/quickstep/res/drawable/ic_sysbar_accessibility_button.xml
new file mode 100644
index 0000000000..e0d5406810
--- /dev/null
+++ b/quickstep/res/drawable/ic_sysbar_accessibility_button.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_sysbar_rotate_button_ccw_start_0.xml b/quickstep/res/drawable/ic_sysbar_rotate_button_ccw_start_0.xml
new file mode 100644
index 0000000000..ff5cb9ef6b
--- /dev/null
+++ b/quickstep/res/drawable/ic_sysbar_rotate_button_ccw_start_0.xml
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_sysbar_rotate_button_ccw_start_90.xml b/quickstep/res/drawable/ic_sysbar_rotate_button_ccw_start_90.xml
new file mode 100644
index 0000000000..90fedb17ec
--- /dev/null
+++ b/quickstep/res/drawable/ic_sysbar_rotate_button_ccw_start_90.xml
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_sysbar_rotate_button_cw_start_0.xml b/quickstep/res/drawable/ic_sysbar_rotate_button_cw_start_0.xml
new file mode 100644
index 0000000000..a89e7a34ad
--- /dev/null
+++ b/quickstep/res/drawable/ic_sysbar_rotate_button_cw_start_0.xml
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_sysbar_rotate_button_cw_start_90.xml b/quickstep/res/drawable/ic_sysbar_rotate_button_cw_start_90.xml
new file mode 100644
index 0000000000..0dc67b0d22
--- /dev/null
+++ b/quickstep/res/drawable/ic_sysbar_rotate_button_cw_start_90.xml
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/drawable/mock_conversation.xml b/quickstep/res/drawable/mock_conversation.xml
deleted file mode 100644
index 272d9ed8a8..0000000000
--- a/quickstep/res/drawable/mock_conversation.xml
+++ /dev/null
@@ -1,212 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/quickstep/res/drawable/mock_conversations_list.xml b/quickstep/res/drawable/mock_conversations_list.xml
deleted file mode 100644
index 2dbc88f0bf..0000000000
--- a/quickstep/res/drawable/mock_conversations_list.xml
+++ /dev/null
@@ -1,361 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/quickstep/res/drawable/mock_webpage_dark_mode.xml b/quickstep/res/drawable/mock_webpage_dark_mode.xml
deleted file mode 100644
index 93b22b7d31..0000000000
--- a/quickstep/res/drawable/mock_webpage_dark_mode.xml
+++ /dev/null
@@ -1,251 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/quickstep/res/drawable/mock_webpage_light_mode.xml b/quickstep/res/drawable/mock_webpage_light_mode.xml
deleted file mode 100644
index 98abb92ab7..0000000000
--- a/quickstep/res/drawable/mock_webpage_light_mode.xml
+++ /dev/null
@@ -1,263 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/quickstep/res/drawable/task_menu_item_bg.xml b/quickstep/res/drawable/task_menu_item_bg.xml
index b6a8b909ee..16c13ebebc 100644
--- a/quickstep/res/drawable/task_menu_item_bg.xml
+++ b/quickstep/res/drawable/task_menu_item_bg.xml
@@ -15,7 +15,8 @@
limitations under the License.
-->
-
-
-
+
+
+
diff --git a/quickstep/res/drawable/taskbar_edu_splitscreen.png b/quickstep/res/drawable/taskbar_edu_splitscreen.png
new file mode 100644
index 0000000000..f9d2a63a0e
Binary files /dev/null and b/quickstep/res/drawable/taskbar_edu_splitscreen.png differ
diff --git a/quickstep/res/drawable/taskbar_edu_stashing.png b/quickstep/res/drawable/taskbar_edu_stashing.png
new file mode 100644
index 0000000000..f9d2a63a0e
Binary files /dev/null and b/quickstep/res/drawable/taskbar_edu_stashing.png differ
diff --git a/quickstep/res/drawable/taskbar_edu_switch_apps.png b/quickstep/res/drawable/taskbar_edu_switch_apps.png
new file mode 100644
index 0000000000..f9d2a63a0e
Binary files /dev/null and b/quickstep/res/drawable/taskbar_edu_switch_apps.png differ
diff --git a/quickstep/res/drawable/taskbar_icon_click_feedback_roundrect.xml b/quickstep/res/drawable/taskbar_icon_click_feedback_roundrect.xml
index d6160def0f..534f241ae9 100644
--- a/quickstep/res/drawable/taskbar_icon_click_feedback_roundrect.xml
+++ b/quickstep/res/drawable/taskbar_icon_click_feedback_roundrect.xml
@@ -16,7 +16,7 @@
-->
+ android:color="@color/taskbar_nav_icon_selection_ripple">
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index e79e57efef..9ad10dc54e 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -14,68 +14,111 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+ android:id="@+id/root_view"
+ android:background="@color/all_set_page_background" >
-
+ android:layout_height="match_parent"
+ android:id="@+id/content_view"
+ android:fitsSystemWindows="true">
-
-
-
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:scaleType="centerCrop"
-
+
+
-
+ android:layout_height="match_parent"
+ android:layout_marginStart="@dimen/allset_page_margin_horizontal"
+ android:layout_marginEnd="@dimen/allset_page_margin_horizontal"
+ android:layoutDirection="locale"
+ android:textDirection="locale"
+ android:forceHasOverlappingRendering="false"
+ android:fitsSystemWindows="true" >
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml
index a43296f602..bfeb82d9f9 100644
--- a/quickstep/res/layout/fallback_recents_activity.xml
+++ b/quickstep/res/layout/fallback_recents_activity.xml
@@ -45,8 +45,7 @@
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
- android:outlineProvider="none"
- android:theme="@style/HomeScreenElementTheme" />
+ android:outlineProvider="none" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml b/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml
new file mode 100644
index 0000000000..e5cd9bce1e
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_foldable_mock_conversation_list.xml
@@ -0,0 +1,396 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_hotseat.xml b/quickstep/res/layout/gesture_tutorial_foldable_mock_hotseat.xml
new file mode 100644
index 0000000000..5612666b69
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_foldable_mock_hotseat.xml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_taskbar.xml b/quickstep/res/layout/gesture_tutorial_foldable_mock_taskbar.xml
new file mode 100644
index 0000000000..ddfeeecf04
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_foldable_mock_taskbar.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_foldable_mock_webpage.xml b/quickstep/res/layout/gesture_tutorial_foldable_mock_webpage.xml
new file mode 100644
index 0000000000..67e9b02b3d
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_foldable_mock_webpage.xml
@@ -0,0 +1,275 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index cdda43c8a8..08e6178bdb 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -25,13 +25,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
+ android:layout_alignParentBottom="true"/>
@@ -41,15 +40,56 @@
android:layout_height="20dp"
android:visibility="invisible" />
-
+ android:visibility="invisible">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_mock_conversation_list.xml b/quickstep/res/layout/gesture_tutorial_mock_conversation_list.xml
new file mode 100644
index 0000000000..364ad6d17d
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_mock_conversation_list.xml
@@ -0,0 +1,394 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml b/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml
new file mode 100644
index 0000000000..b3e86cf4de
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_mock_hotseat.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_mock_webpage.xml b/quickstep/res/layout/gesture_tutorial_mock_webpage.xml
new file mode 100644
index 0000000000..bb20968d8f
--- /dev/null
+++ b/quickstep/res/layout/gesture_tutorial_mock_webpage.xml
@@ -0,0 +1,271 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 68680d3f38..0fda0bf8d4 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.
-->
-
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom">
+
+
+
+
@@ -47,16 +60,6 @@
android:layout_height="1dp"
android:layout_weight="1" />
-
-
-
-
diff --git a/quickstep/res/layout/predicted_hotseat_edu.xml b/quickstep/res/layout/predicted_hotseat_edu.xml
index 1dab48267b..e4e3956c6e 100644
--- a/quickstep/res/layout/predicted_hotseat_edu.xml
+++ b/quickstep/res/layout/predicted_hotseat_edu.xml
@@ -73,6 +73,7 @@
launcher:containerType="hotseat" />
+
+
+
+
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
new file mode 100644
index 0000000000..cd5bcbdddd
--- /dev/null
+++ b/quickstep/res/layout/task_grouped.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/task_menu_with_arrow.xml b/quickstep/res/layout/task_menu_with_arrow.xml
new file mode 100644
index 0000000000..38573fd1e5
--- /dev/null
+++ b/quickstep/res/layout/task_menu_with_arrow.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml
index 5978b97dd4..8a8fc36b84 100644
--- a/quickstep/res/layout/task_view_menu_option.xml
+++ b/quickstep/res/layout/task_view_menu_option.xml
@@ -18,7 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ android:orientation="horizontal"
android:paddingTop="@dimen/task_card_menu_option_vertical_padding"
android:paddingBottom="@dimen/task_card_menu_option_vertical_padding"
android:background="@drawable/task_menu_item_bg"
diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml
index e680233e6a..3b1d217ec5 100644
--- a/quickstep/res/layout/taskbar.xml
+++ b/quickstep/res/layout/taskbar.xml
@@ -13,12 +13,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+ android:layout_height="wrap_content"
+ android:clipChildren="false">
+
+
+
+
-
+ android:paddingTop="@dimen/taskbar_contextual_padding_top"
+ android:gravity="center_vertical"
+ android:layout_gravity="start"/>
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:paddingLeft="@dimen/taskbar_nav_buttons_spacing"
+ android:paddingRight="@dimen/taskbar_nav_buttons_spacing"
+ android:layout_marginEnd="@dimen/taskbar_contextual_button_margin"
+ android:gravity="center_vertical"
+ android:layout_gravity="end"/>
-
+
+
-
+ android:background="@color/taskbar_stashed_handle_dark_color"
+ android:clipToOutline="true"
+ android:layout_gravity="bottom"/>
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_contextual_button.xml b/quickstep/res/layout/taskbar_contextual_button.xml
new file mode 100644
index 0000000000..4ffb8d81dc
--- /dev/null
+++ b/quickstep/res/layout/taskbar_contextual_button.xml
@@ -0,0 +1,21 @@
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_edu.xml b/quickstep/res/layout/taskbar_edu.xml
new file mode 100644
index 0000000000..3796ff930e
--- /dev/null
+++ b/quickstep/res/layout/taskbar_edu.xml
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_nav_button.xml b/quickstep/res/layout/taskbar_nav_button.xml
new file mode 100644
index 0000000000..aea4885d15
--- /dev/null
+++ b/quickstep/res/layout/taskbar_nav_button.xml
@@ -0,0 +1,24 @@
+
+
+
\ No newline at end of file
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 433ef861cf..815ba042b2 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -45,10 +45,12 @@
"Programvoorstelle is geaktiveer""Programvoorstelle is gedeaktiveer""Voorspelde program: %1$s"
- "Maak seker dat jy van die rand heel regs of heel links af swiep."
- "Maak seker dat jy van die regter- of linkerrand na die middel van die skerm swiep en laat los."
- "Jy het geleer hoe om van regs af te swiep om terug te gaan. Nou kan jy leer hoe om tussen programme te wissel."
- "Jy het die \"gaan terug\"-gebaar voltooi."
+ "Maak seker dat jy van die rand heel links af swiep."
+ "Maak seker dat jy van die linkerrand na die middel van die skerm swiep en laat los."
+ "Dis al! Probeer nou om van die regterrand af te swiep."
+ "Maak seker dat jy van die rand heel regs af swiep."
+ "Maak seker dat jy van die regterrand na die middel van die skerm swiep en laat los."
+ "Jy het die \"gaan terug\"-gebaar voltooi. Nou kan jy leer hoe om na tuisskerm te gaan.""Maak seker dat jy nie te naby aan die onderkant van die skerm swiep nie.""Gaan na Instellings om sensitiwiteit van teruggebaar te verander""Swiep om terug te gaan"
@@ -56,27 +58,22 @@
"Maak seker dat jy van die onderrand van die skerm af opswiep.""Maak seker jy onderbreek nie voordat jy laat los nie.""Maak seker jy swiep reguit op."
- "Jy het die \"gaan na tuisskerm\"-gebaar voltooi. Nou kan jy leer hoe om terug te gaan."
- "Jy het die \"gaan na tuisskerm\"-gebaar voltooi."
+ "Jy het die \"gaan na tuisskerm\"-gebaar voltooi. Nou kan jy leer hoe om tussen programme te wissel.""Swiep om na tuisskerm toe te gaan""Swiep op van die onderkant van jou skerm af. Hierdie gebaar neem jou altyd na die tuisskerm toe.""Maak seker dat jy van die onderrand van die skerm af opswiep.""Probeer om die venster langer te hou voordat jy laat los.""Maak seker dat jy reguit opswiep en dan onderbreek."
- "Jy het geleer hoe om gebare te gebruik. Gaan na Instellings om gebare af te skakel."
- "Jy het die \"wissel tussen programme\"-gebaar voltooi."
+ "Jy het die \"wissel tussen programme\"-gebaar voltooi. Jy is gereed om jou foon te gebruik!""Swiep om tussen programme te wissel"
- "Swiep van die onderkant van jou skerm af op, hou en laat los dan om tussen programme te wissel."
+ "Swiep op van die onderkant van jou skerm af, hou en laat los dan.""Gereed"
- "Klaar"
+ "Volgende"
+ "Klaar""Instellings""Probeer weer""Mooi so!""Tutoriaal %1$d/%2$d"
- "Gereed!"
- "Swiep op om na die tuisskerm toe te gaan"
- "Jy is gereed om jou foon te begin gebruik"
- "Stelselnavigasie-instellings""Deel""Skermkiekie""Jou organisasie laat nie hierdie program toe nie"
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 838dd60918..5a3df9d9bb 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -45,10 +45,12 @@
"የመተግበሪያ አስተያየት ጥቆማዎች ነቅቷል""የመተግበሪያ አስተያየቶች ቦዝነዋል""የተገመተው መተግበሪያ፦ %1$s"
- "ከቀኝ ጠርዝ ወይም ከግራ ጠርዝ ጥግ ጀምሮ ማንሸራተትዎን ያረጋግጡ።"
- "ከቀኝ ወይም ከግራ ጠርዝ ወደ ማያ ገጹ መሃል ማንሸራተትዎን እና መልቀቅዎን ያረጋግጡ።"
- "ወደ ኋላ ለመመለስ ከቀኝ ጀምሮ እንዴት ማንሸራተት እንደሚችሉ አውቀዋል። ቀጥለው መተግበሪያዎችን እንዴት መቀየር እንደሚችሉ ይወቁ።"
- "ወደኋላ የመመለስ ምልክትን አጠናቀዋል።"
+ "ከግራ ጠርዝ ጥግ ጀምሮ ማንሸራተትዎን ያረጋግጡ።"
+ "ከግራ ጠርዝ ወደ ማያ ገጹ መሃል ማንሸራተትዎን እና መልቀቅዎን ያረጋግጡ።"
+ "ይሄው ነው! አሁን ደግሞ ከግራ ጥግ ጠረግ ማንሸራተትን ይሞክሩ።"
+ "ከቀኝ ጠርዝ ጥግ ጀምሮ ማንሸራተትዎን ያረጋግጡ።"
+ "ከቀኝ ጠርዝ ወደ ማያ ገጹ መሃል ማንሸራተትዎን እና መልቀቅዎን ያረጋግጡ።"
+ "ወደኋላ የመመለስ ምልክትን አጠናቀዋል። ቀጥሎም ወደ ቤት እንዴት መሄድ እንደሚችሉ ይወቁ።""ከማያ ገጹ ታችኛው ክፍል ጋር በጣም ጠጋ ብለው አለማንሸራተትዎን ያረጋግጡ።""ከኋላ ስሜት ሰጭነት ደረጃ ለመለወጥ ወደ ቅንብሮች ይመለሱ""ወደኋላ ለመመለስ ያንሸራትቱ"
@@ -56,27 +58,22 @@
"ከማያ ገጹ የታችኛው ጫፍ ወደ ላይ ማንሸራተትዎን ያረጋግጡ።""ከመልቀቅዎ በፊት ለአፍታ እንዳልቆሙ ያረጋግጡ።""በቀጥታ ወደ ላይ ማንሸራተትዎን ያረጋግጡ።"
- "የወደ መነሻ ሂድ ምልክትን አጠናቀዋል። ቀጥሎም ወደ ኋላ እንዴት መሄድ እንደሚችሉ ይወቁ።"
- "የወደ መነሻ ሂድ ምልክትን አጠናቀዋል።"
+ "የመነሻ ምልክትን አጠናቀዋል። ቀጥሎም መተግበሪያዎችን እንዴት መቀየር እንደሚችሉ ይወቁ።""ወደ መነሻ ለመሄድ ያንሸራትቱ""ከእርስዎ ማያ ገጽ ግርጌ ላይ ወደ ላይ በጣት ጠረግ ያድርጉ። ይህ የእጅ ውዝዋዜ ሁልጊዜ ወደ መነሻ ማያ ገጽ ይወስድዎታል።""ከማያ ገጹ የታችኛው ጫፍ ወደ ላይ ማንሸራተትዎን ያረጋግጡ።""ከመልቀቅዎ በፊት መስኮቱን ረዘም ላለ ጊዜ ለመያዝ ይሞክሩ።""በቀጥታ ወደ ላይ ማንሸራተትዎን ያረጋግጡ፣ ከዚያ ለአፍታ ያቁሙ።"
- "የእጅ ምልክቶችን እንዴት እንደሚጠቀሙ ተምረዋል። የእጅ ምልክቶችን ለማጥፋት ወደ ቅንብሮች ይሂዱ።"
- "መተግበሪያዎችን የመቀያየር ምልክትን አጠናቀዋል።"
+ "መተግበሪያዎችን የመቀያየር ምልክትን አጠናቀዋል። ስልክዎን ለመጠቀም ዝግጁ ነዎት!""መተግበሪያዎችን ለመቀየር ያንሸራትቱ"
- "በመተግበሪያዎች መካከል ለመቀያየር ከማያ ገጽዎ ግርጌ ወደ ላይ ያንሸራትቱ፣ ይያዙ፣ ከዚያ ይለቀቁ።"
+ "ከእርስዎ ማያ ገጽ ግርጌ ላይ ወደ ላይ በጣት ጠረግ ያድርጉ፣ ይያዙ፣ በመቀጠል ይልቀቁ።""ሁሉም ዝግጁ"
- "ተጠናቋል"
+ "ቀጣይ"
+ "ተጠናቋል""ቅንብሮች""እንደገና ሞክር""ጥሩ!""አጋዥ ሥልጠና %1$d/%2$d"
- "ሁሉም ዝግጁ!"
- "ወደ መነሻ ለመሄድ በጣት ወደ ላይ ማንሸራተት"
- "ስልክዎን መጠቀም ለመጀመር ዝግጁ ነዎት"
- "የስርዓት አሰሳ ቅንብሮች""አጋራ""ቅጽበታዊ ገጽ እይታ""ይህ ድርጊት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 3f26977245..8205f89444 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -45,10 +45,12 @@
"تم تفعيل ميزة \"التطبيقات المقترحة\".""ميزة \"التطبيقات المقترحة\" غير مفعّلة.""التطبيق المتوقع: %1$s"
- "تأكّد من التمرير سريعًا من أقصى الحافة اليسرى أو اليمنى."
- "تأكّد من التمرير سريعًا من الحافة اليسرى أو اليمنى إلى وسط الشاشة ثم ارفع إصبعك."
- "لقد تعلمت كيفية التمرير سريعًا من اليسار للرجوع. تعرّف بعد ذلك على كيفية التبديل بين التطبيقات."
- "لقد أكملت التدريب على إيماءة الرجوع."
+ "تأكّد من التمرير سريعًا من أقصى الحافة اليمنى."
+ "تأكّد من التمرير سريعًا من الحافة اليمنى إلى وسط الشاشة ثم ارفع إصبعك."
+ "أكملت هذه الخطوة. جرِّب الآن التمرير سريعًا من الحافة اليسرى"
+ "تأكّد من التمرير سريعًا من أقصى الحافة اليسرى."
+ "تأكّد من التمرير سريعًا من الحافة اليسرى إلى وسط الشاشة ثم ارفع إصبعك."
+ "لقد أكملت التدريب على إيماءة الرجوع. تعرّف بعد ذلك على كيفية الانتقال إلى الشاشة الرئيسية.""تأكّد من عدم التمرير بالقرب من أسفل الشاشة.""لتغيير مستوى حساسية إيماءة الرجوع، انتقِل إلى \"الإعدادات\"""مرِّر سريعًا للرجوع."
@@ -56,32 +58,27 @@
"تأكّد من التمرير سريعًا من الحافة السفلى للشاشة إلى أعلاها.""تأكّد من عدم التوقّف قليلاً قبل رفع إصبعك.""تأكّد من التمرير إلى الأعلى مباشرةً."
- "لقد أكملت التدريب على إيماءة الانتقال إلى الشاشة الرئيسية. تعرّف بعد ذلك على كيفية الرجوع."
- "أكملت التدريب على إيماءة الانتقال إلى الشاشة الرئيسية."
+ "أكملت التدريب على إيماءة الانتقال إلى الشاشة الرئيسية. تعرّف بعد ذلك على كيفية التبديل بين التطبيقات.""مرِّر سريعًا للانتقال إلى الشاشة الرئيسية""مرِّر سريعًا من أسفل الشاشة إلى أعلاها. تنقلك هذه الإيماءة دائمًا إلى الشاشة الرئيسية.""تأكّد من التمرير سريعًا من الحافة السفلى للشاشة إلى أعلاها.""حاوِل إبقاء إصبعك على النافذة لمدة أطول قبل رفعه.""تأكّد من التمرير سريعًا للأعلى مباشرةً ثم التوقّف قليلاً."
- "لقد تعرّفت على كيفية استخدام الإيماءات. لإيقاف الإيماءات، انتقِل إلى \"الإعدادات\"."
- "أكملت التدريب على إيماءة التبديل بين التطبيقات."
+ "أكملت التدريب على إيماءة التبديل بين التطبيقات. أنت جاهز لاستخدام هاتفك.""مرِّر سريعًا للتبديل بين التطبيقات"
- "للتبديل بين التطبيقات، مرِّر سريعًا من أسفل الشاشة لأعلاها مع تثبيت إصبعك ثم ارفعه."
+ "مرِّر سريعًا من أسفل الشاشة إلى أعلاها، وأبقِ إصبعك على الشاشة قليلاً ثم ارفعه.""اكتمل التدريب على الإيماءة"
- "تم"
+ "التالي"
+ "تم""الإعدادات""إعادة المحاولة""أحسنت""الدليل التوجيهي %1$d من إجمالي %2$d"
- "اكتملت عملية الإعداد"
- "مرِّر سريعًا للأعلى للانتقال إلى الشاشة الرئيسية."
- "يمكنك الآن بدء استخدام هاتفك."
- "إعدادات التنقّل داخل النظام""مشاركة""لقطة شاشة""لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء.""هل تريد تخطي الدليل التوجيهي؟"
- "يمكنك العثور على هذا الدليل التوجيهي لاحقًا في التطبيق \"%1$s\""
+ "يمكنك العثور على هذا الدليل التوجيهي لاحقًا في التطبيق %1$s""إلغاء""التخطي"
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 110267f659..9b22c62e93 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -22,14 +22,14 @@
"পিন""Freeform""কোনো শেহতীয়া বস্তু নাই"
- "এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিং"
- "আটাইবোৰ মচক"
+ "এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিংসমূহ"
+ "সকলো মচক""শেহতীয়া এপসমূহ""%1$s, %2$s""< ১ মিনিট""আজি %1$s বাকী আছ""এপ চাজেশ্বন"
- "আটাইবোৰ এপ্"
+ "সকলো এপ্""আপোনাৰ প্ৰয়োজন হ\'ব পৰা এপ্""আপোনাৰ গৃহ স্ক্ৰীনৰ একেবাৰে তলৰ শাৰীটোত এপৰ পৰামর্শসমূহ পাওক""আপোনাৰ গৃহ স্ক্ৰীনৰ প্ৰিয় সমলৰ শাৰীটোত এপৰ পৰামর্শসমূহ পাওক"
@@ -38,17 +38,19 @@
"আপোনাৰ সকলোতকৈ বেছিকৈ ব্যৱহৃত এপ্সমূহ গৃহ স্ক্ৰীনতে সহজে এক্সেছ কৰক। আপোনাৰ ৰুটিনসমূহৰ ভিত্তিত পৰামর্শসমূহ সলনি হ\'ব। একেবাৰে তলৰ শাৰীটোত থকা এপ্সমূহ এটা নতুন ফ\'ল্ডাৰলৈ যাব।""এপৰ পৰামর্শসমূহ পাওক""নালাগে, ধন্যবাদ"
- "ছেটিং"
+ "ছেটিংসমূহ""সকলোতকৈ বেছিকৈ ব্যৱহৃত এপ্সমূহ ইয়াত প্ৰদর্শিত হয় আৰু ৰুটিনসমূহ ওপৰত ভিত্তি কৰি সলনি হয়""এপৰ পৰামর্শসমূহ পাবলৈ একেবাৰে তলৰ শাৰীত থকা এপ্সমূহ টানি আঁতৰাওক""খালী ঠাইত এপৰ পৰামর্শসমূহ যোগ কৰা হ\'ল""এপৰ পৰামৰ্শসমূহ সক্ষম কৰা আছে""এপৰ পৰামৰ্শসমূহ অক্ষম কৰা আছে""পূৰ্বানুমান কৰা এপ্: %1$s"
- "আপুনি সোঁ অথবা বাওঁ প্ৰান্তৰৰ একেবাৰে সীমাৰ পৰা ছোৱাইপ কৰাটো নিশ্চিত কৰক।"
- "আপুনি স্ক্ৰীনৰ সোঁ অথবা বাওঁ প্ৰান্তৰৰ পৰা মধ্যভাগলৈকে ছোৱাইপ কৰি এৰি দিয়াটো নিশ্চিত কৰক।"
- "সোঁফালৰ পৰা ছোৱাইপ কৰি কেনেকৈ উভতি যাব লাগে, সেইটো আপুনি জানিলে। ইয়াৰ পাছত, এপ্ কেনেকৈ সলনি কৰিব সেয়া জানক।"
- "আপুনি উভতি যাওক নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"
+ "আপুনি বাওঁ প্ৰান্তৰৰ একেবাৰে সীমাৰ পৰা ছোৱাইপ কৰাটো নিশ্চিত কৰক।"
+ "আপুনি স্ক্ৰীনৰ বাওঁ প্ৰান্তৰৰ পৰা সোঁ প্ৰান্তৰৰ ফালে মধ্যভাগলৈকে ছোৱাইপ কৰি এৰি দিয়াটো নিশ্চিত কৰক।"
+ "ইমানেই! এতিয়া বাওঁ প্ৰান্তৰৰ পৰা ছোৱাইপ কৰি চাওক।"
+ "আপুনি সোঁ প্ৰান্তৰৰ একেবাৰে সীমাৰ পৰা ছোৱাইপ কৰাটো নিশ্চিত কৰক।"
+ "আপুনি স্ক্ৰীনৰ সোঁ প্ৰান্তৰৰ পৰা মধ্যভাগলৈকে ছোৱাইপ কৰি এৰি দিয়াটো নিশ্চিত কৰক।"
+ "আপুনি উভতি যাওক নিৰ্দেশটো সম্পূৰ্ণ কৰিলে। ইয়াৰ পাছত, গৃহ স্ক্ৰীনলৈ কেনেকৈ যাব সেয়া জানক।""আপুনি স্ক্ৰীনৰ তলৰ অংশৰ বেছি ওচৰলৈ ছোৱাইপ নকৰাটো নিশ্চিত কৰক।""উভতি যোৱাৰ নির্দেশটোৰ সংবেদনশীলতা সলনি কৰিবলৈ ছেটিঙলৈ যাওক""উভতি যাবলৈ ছোৱাইপ কৰক"
@@ -56,27 +58,22 @@
"আপুনি স্ক্ৰীনৰ তলৰ প্ৰান্তৰ পৰা ওপৰলৈ ছোৱাইপ কৰাটো নিশ্চিত কৰক।""আপুনি এৰি দিয়াৰ পূৰ্বে অলপো নোৰোৱাটো নিশ্চিত কৰক।""আপুনি পোনকৈ ওপৰলৈ ছোৱাইপ কৰাটো নিশ্চিত কৰক।"
- "আপুনি গৃহ স্ক্ৰীনলৈ যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে। ইয়াৰ পাছত, গৃহ স্ক্ৰীনলৈ কেনেকৈ যাব সেয়া জানক।"
- "আপুনি গৃহ স্ক্ৰীনলৈ যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"
+ "আপুনি গৃহ স্ক্ৰীনলৈ যোৱাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে। ইয়াৰ পাছত, এপ্ কেনেকৈ সলনি কৰিব সেয়া জানক।""গৃহ স্ক্ৰীনলৈ যাবলৈ ছোৱাইপ কৰক""আপোনাৰ স্ক্ৰীনৰ তলৰ অংশৰ পৰা ওপৰলৈ ছোৱাইপ কৰক। এই নিৰ্দেশটোৱে আপোনাক সদায় গৃহ স্ক্ৰীনলৈ লৈ যায়।""আপুনি স্ক্ৰীনৰ তলৰ প্ৰান্তৰ পৰা ওপৰলৈ ছোৱাইপ কৰাটো নিশ্চিত কৰক।""এৰি দিয়াৰ পূৰ্বে ৱিণ্ডখন দীৰ্ঘ সময়ৰ বাবে ধৰি ৰাখিবলৈ চেষ্টা কৰক।""আপুনি স্ক্ৰীনৰ ওপৰলৈ পোনকৈ ছোৱাইপ কৰি তাৰ পাছত ৰোৱাটো নিশ্চিত কৰক।"
- "আপুনি নিৰ্দেশসমূহ কেনেকৈ ব্যৱহাৰ কৰিব লাগে সেয়া জানিলে। নিৰ্দেশসমূহ অফ কৰিবলৈ, ছেটিঙলৈ যাওক।"
- "আপুনি এপ্ সলনি কৰাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে।"
+ "আপুনি এপ্ সলনি কৰাৰ নিৰ্দেশটো সম্পূৰ্ণ কৰিলে। আপুনি নিজৰ ফ’নটো ব্যৱহাৰ কৰিবলৈ সাজু!""এপ্ সলনি কৰিবলৈ ছোৱাইপ কৰক"
- "এপ্সমূহ সালসলনিকৈ ব্যৱহাৰ কৰিবলৈ আপোনাৰ স্ক্ৰীনৰ একেবাৰে তলৰ অংশৰ পৰা ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক আৰু তাৰ পাছত এৰি দিয়ক।"
+ "আপোনাৰ স্ক্ৰীনৰ একেবাৰে তলৰ অংশৰ পৰা ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক আৰু তাৰ পাছত এৰি দিয়ক।""সম্পূৰ্ণ সাজু"
- "হ’ল"
+ "পৰৱৰ্তী"
+ "হ’ল""ছেটিং""পুনৰ চেষ্টা কৰক""সুন্দৰ!""টিউট’ৰিয়েল %1$d/%2$d"
- "সকলো সাজু!"
- "গৃহ স্ক্ৰীনলৈ যাবলৈ ওপৰলৈ ছোৱাইপ কৰক"
- "আপুনি আপোনাৰ ফ’নটো ব্যৱহাৰ কৰিবলৈ সাজু"
- "ছিষ্টেম নেভিগেশ্বনৰ ছেটিং""শ্বেয়াৰ কৰক""স্ক্ৰীনশ্বট""এপ্টোৱে অথবা আপোনাৰ প্ৰতিষ্ঠানে এই কাৰ্যটোৰ অনুমতি নিদিয়ে"
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index d01bf3f57f..bd88392075 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -45,40 +45,37 @@
"Tətbiq təklifləri aktivdir""Tətbiq təklifləri deaktivdir""Proqnozlaşdırılan tətbiq: %1$s"
- "Ekranın ən sağ və ya sol kənarından sürüşdürün."
- "Ekranın sağ və ya sol kənarından ortasına sürüşdürüb buraxın."
- "Geri qayıtmaq üçün sağdan sürüşdürmək qaydasını öyrəndiniz. Sonra tətbiqləri keçirməyi öyrənin."
- "Geri getmə jestini tamamladınız."
+ "Ən sol tərəfdən sürüşdürdüyünüzə əmin olun."
+ "Ekranın sol kənarından ortasına sürüşdürüb buraxın."
+ "Bu qədər! İndi isə sağ kənardan sürüşdürün."
+ "Ən sağ tərəfdən sürüşdürdüyünüzə əmin olun."
+ "Ekranın sağ kənarından ortasına sürüşdürüb buraxın."
+ "Geri getmə jestini tamamladınız. Sonra Əsas səhifəyə keçməyi öyrənin.""Ekranın altına çox yaxın sürüşdürmədiyinizə əmin olun.""Geri qayıtma jestinin həssaslığını dəyişmək üçün Ayarlara keçin""Geri qayıtmaq üçün sürüşdürün""Sonuncu ekrana qayıtmaq üçün ekranın sol, yaxud sağ kənarından mərkəzinə doğru sürüşdürün."
- "Ekranın ən kənar aşağısından yuxarı sürüşdürün."
+ "Ekranın aşağı kənarından yuxarı sürüşdürdüyünüzə əmin olun.""Buraxmazdan əvvəl durdurmadığınıza əmin olun."
- "Birbaşa yuxarı sürüşdürün."
- "Əsas səhifəyə keçmə jestini tamamladınız. Sonra geri qayıtmağı öyrənin."
- "Əsas səhifəyə keçmə jestini tamamladınız."
+ "Birbaşa yuxarı sürüşdürdüyünüzə əmin olun."
+ "Əsas səhifəyə keçmə jestini tamamladınız. Sonra tətbiqləri keçirməyi öyrənin.""Əsas səhifəyə keçmək üçün sürüşdürün""Ekranın aşağısından yuxarısına sürüşdürün. Bu jest həmişə Əsas səhifəyə aparır."
- "Ekranın ən kənar aşağısından yuxarı sürüşdürün."
- "Barmağı buraxmadan öncə displeydə bir müddət saxlayın."
- "Sürüşdürüb ekranın yuxarı kənarında saxlayın."
- "Jestlərdən istifadə qaydasını öyrəndiniz. Jestləri deaktiv etmək üçün Ayarlara keçin."
- "Tətbiqləri keçirmə jestini tamamladınız."
+ "Ekranın aşağı kənarından yuxarı sürüşdürdüyünüzə əmin olun."
+ "Buraxmadan əvvəl pəncərəni daha uzun müddət saxlamağa çalışın."
+ "Birbaşa yuxarı sürüşdürdüyünüzə, sonra durdurduğunuza əmin olun."
+ "Tətbiqləri keçirmə jestini tamamladınız. Telefonunuzu istifadə etməyə hazırsınız!""Tətbiqi keçirmək üçün sürüşdürün"
- "Tətbiqlər arasında keçid üçün ekranın aşağısından yuxarı doğru sürüşdürüb saxlayın, sonra buraxın."
+ "Ekranın aşağısından yuxarı doğru sürüşdürüb saxlayın, sonra buraxın.""Tam hazır"
- "Oldu"
+ "Sonra"
+ "Oldu""Ayarlar""Yenə sınayın""Əla!""Dərslik %1$d/%2$d"
- "Hər şey hazırdır!"
- "Əsas səhifəyə keçmək üçün yuxarı çəkin"
- "Telefondan istifadəyə başlamağa hazırsınız"
- "Sistem naviqasiya ayarları""Paylaşın"
- "Skrinşot"
+ "Ekran şəkli""Bu əməliyyata tətbiq və ya təşkilatınız tərəfindən icazə verilmir""Naviqasiya dərsliyi ötürülsün?""Bunu sonra %1$s tətbiqində tapa bilərsiniz"
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index bde409f422..21295fc31a 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -45,38 +45,35 @@
"Predlozi aplikacija su omogućeni""Predlozi aplikacija su onemogućeni""Predviđamo aplikaciju: %1$s"
- "Obavezno prevucite od same desne ili leve ivice."
- "Obavezno prevucite od desne ili leve ivice do sredine ekrana i otpustite."
- "Naučili ste kako da prevlačite zdesna da biste se vratili unazad. Sada naučite da zamenite aplikacije."
- "Dovršili ste pokret za povratak."
+ "Obavezno prevucite od same leve ivice."
+ "Obavezno prevucite od leve ivice do sredine ekrana i otpustite."
+ "To je sve! Sada probajte da prevučete od desne ivice."
+ "Obavezno prevucite od same desne ivice."
+ "Obavezno prevucite od desne ivice do sredine ekrana i otpustite."
+ "Dovršili ste pokret za povratak. Sada saznajte kako da odete na početnu stranicu.""Nikako ne prevlačite previše blizu dna ekrana.""Osetljivost pok. za nazad možete da promenite u Podešavanjima"
- "Prevucite da biste se vratili unazad"
+ "Prevucite da biste se vratili""Da biste se vratili na poslednji ekran, prevucite od leve ili desne ivice do sredine ekrana.""Obavezno prevucite nagore od donje ivice ekrana.""Nikako ne stajte pre otpuštanja.""Obavezno prevucite pravo nagore."
- "Dovršili ste pokret za povratak na početnu stranicu. Sada saznajte kako da se vratite."
- "Dovršili ste pokret za povratak na početnu stranicu."
+ "Dovršili ste pokret za povratak na početnu stranicu. Sada saznajte kako da promenite aplikacije.""Prevucite da biste otišli na početnu stranicu""Prevucite nagore od dna ekrana. Ovaj pokret vas uvek vodi na početni ekran.""Obavezno prevucite nagore od donje ivice ekrana.""Probajte da držite prozor duže pre otpuštanja.""Obavezno prevucite pravo nagore, pa zastanite."
- "Naučili ste kako da koristite pokrete. Da biste isključili pokrete, idite na podešavanja."
- "Dovršili ste pokret za promenu aplikacija."
- "Prevucite da biste zamenili aplikacije"
- "Za prelazak sa jedne aplikacije na drugu prevucite nagore od dna ekrana, zadržite, pa pustite."
+ "Dovršili ste pokret za promenu aplikacija. Spremni ste za korišćenje telefona!"
+ "Prevucite da biste promenili aplikacije"
+ "Prevucite nagore od dna ekrana, zadržite, pa pustite.""To je to"
- "Gotovo"
+ "Dalje"
+ "Gotovo""Podešavanja""Probajte ponovo""Svaka čast!""Vodič %1$d/%2$d"
- "Gotovo!"
- "Prevucite nagore da biste otvorili početni ekran"
- "Spremni ste da počnete da koristite telefon"
- "Podešavanja kretanja kroz sistem""Deli""Snimak ekrana""Aplikacija ili organizacija ne dozvoljavaju ovu radnju"
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 8e57bd8ce3..d31468c2fd 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -45,10 +45,12 @@
"Прапановы праграм уключаны""Прапановы праграм выключаны""Праграма з падказкі: %1$s"
- "Пераканайцеся, што вы праводзіце пальцам ад самага вугла (правага ці левага) экрана."
- "Пераканайцеся, што праводзіце пальцам з правага ці левага вугла ў цэнтр экрана, а потым адпускаеце."
- "Вы даведаліся, як гартаць справа для вяртання. Цяпер даведайцеся, як пераключацца паміж праграмамі."
- "Вы навучыліся рабіць жэст вяртання."
+ "Пераканайцеся, што вы не праводзіце пальцам занадта далёка ад левага вугла экрана."
+ "Пераканайцеся, што праводзіце пальцам з левага вугла ў цэнтр экрана, а потым адпускаеце."
+ "Гатова! Цяпер правядзіце пальцам ад правага краю."
+ "Пераканайцеся, што вы не праводзіце пальцам занадта далёка ад правага вугла экрана."
+ "Пераканайцеся, што праводзіце пальцам з правага вугла ў цэнтр экрана, а потым адпускаеце."
+ "Вы навучыліся рабіць жэст вяртання. А зараз даведайцеся, як перайсці на галоўны экран.""Пераканайцеся, што вы не праводзіце пальцам занадта блізка да ніжняга краю экрана.""Каб змяніць адчувальнасць жэста вяртання, адкрыйце налады""Правядзіце пальцам, каб вярнуцца"
@@ -56,27 +58,22 @@
"Пераканайцеся, што праводзіце пальцам па экране знізу ўверх.""Пераканайцеся, што не затрымліваецеся перад адпусканнем.""Пераканайцеся, што праводзіце пальцам вертыкальна."
- "Вы навучыліся рабіць жэст пераходу на галоўны экран. А зараз даведайцеся, як вярнуцца назад."
- "Вы навучыліся рабіць жэст пераходу на галоўны экран."
- "Правядзіце пальцам для пераходу на галоўны экран"
+ "Вы навучыліся рабіць жэст пераходу на галоўны экран. А зараз даведайцеся, як пераключацца паміж праграмамі."
+ "Правесці пальцам для пераходу на галоўны экран""Правядзіце пальцам па экране знізу ўверх. Гэты жэст дазваляе вярнуцца на Галоўны экран.""Пераканайцеся, што праводзіце пальцам па экране знізу ўверх.""Перш чым адпусціць палец, паспрабуйце даўжэй утрымліваць акно націснутым.""Пераканайцеся, што праводзіце пальцам вертыкальна, а потым затрымліваеце яго."
- "Вы навучыліся выкарыстоўваць жэсты. Каб выключыць жэсты, адкрыйце Налады."
- "Вы навучыліся рабіць жэст пераключэння паміж праграмамі."
- "Правядзіце пальцам для пераключэння паміж праграмамі"
- "Каб пераключыцца на іншую праграму, правядзіце па экране знізу ўверх, патрымайце палец і адпусціце."
+ "Вы навучыліся рабіць жэст пераключэння паміж праграмамі. Цяпер вы можаце выкарыстоўваць тэлефон!"
+ "Правесці пальцам для пераключэння паміж праграмамі"
+ "Правядзіце па экране знізу ўверх, утрымліваючы палец націснутым, потым адпусціце.""Гатова"
- "Гатова"
+ "Далей"
+ "Гатова""Налады""Паўтарыць спробу""Выдатна!""Дапаможнік %1$d/%2$d"
- "Гатова!"
- "Каб перайсці на галоўны экран, правядзіце пальцам уверх"
- "Вы можаце пачаць карыстанне тэлефонам"
- "Налады навігацыі ў сістэме""Абагуліць""Здымак экрана""Гэта дзеянне не дазволена праграмай ці вашай арганізацыяй"
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 7305d9d1f4..d2554d5809 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -45,38 +45,35 @@
"Предложенията за приложения са активирани""Функцията „Предложения за приложения“ е деактивирана""Предвидено приложение: %1$s"
- "Трябва да прекарате пръст от най-дясната или най-лявата част на екрана."
- "Трябва да прекарате пръст от десния или левия край на екрана до средата, след което да освободите."
- "Научихте жеста за връщане с плъзгане от дясно. Сега научете как се превключва между приложения."
- "Изпълнихте жеста за връщане назад."
+ "Трябва да прекарате пръст от най-лявата част на екрана."
+ "Трябва да прекарате пръст от левия край на екрана до средата, след което да вдигнете пръста си."
+ "Това е всичко! Сега прекарайте пръст от десния край."
+ "Трябва да прекарате пръст от най-дясната част на екрана."
+ "Трябва да прекарате пръст от десния край на екрана до средата, след което да вдигнете пръста си."
+ "Изпълнихте жеста за връщане назад. В следващия урок ще научите как се преминава към началния екран.""Не прекарвайте пръст твърде близо до долната част на екрана.""Променете чувств. на жеста за връщане назад от настройките"
- "Жест за връщане назад"
+ "Прекарване на пръст за връщане назад""За да се върнете на предишния екран, прекарайте пръст от левия или десния край на екрана до средата.""Трябва да прекарате пръст нагоре от долния край на екрана.""Не задържайте, преди да вдигнете пръста си.""Трябва да прекарате пръст право нагоре."
- "Изпълнихте жеста за преминаване към началния екран. В следващия урок ще научите как да се върнете назад."
- "Изпълнихте жеста за преминаване към началния екран."
- "Жест за преминаване към началния екран"
+ "Изпълнихте жеста за преминаване към началния екран. В следващия урок ще научите как се превключва между приложенията."
+ "Прекарване на пръст за преминаване към началния екран""Прекарайте пръст нагоре от долната част на екрана. Този жест винаги ще ви отвежда до началния екран.""Трябва да прекарате пръст нагоре от долния край на екрана.""Задръжте прозореца по-дълго, преди да вдигнете пръста си.""Прекарайте пръст право нагоре, след което задръжте."
- "Научихте как да използвате жестовете. За да ги изключите, отворете настройките."
- "Изпълнихте жеста за превключване между приложения."
- "Жест за превключване между приложенията"
- "За превключване прекарайте пръст нагоре от долната част на екрана, задръжте и освободете"
+ "Изпълнихте жеста за превключване между приложенията. Вече можете да използвате телефона си!"
+ "Прекарване на пръст за превключване между приложенията"
+ "Прекарайте пръст нагоре от долната част на екрана, задръжте и след това вдигнете пръста си.""Готово"
- "Готово"
+ "Напред"
+ "Готово""Настройки""Опитайте отново""Чудесно!""Урок %1$d/%2$d"
- "Готово!"
- "Прекарайте пръст нагоре, за да отворите началния екран"
- "Можете да започнете да използвате телефона си"
- "Настройки за навигиране в системата""Споделяне""Екранна снимка""Това действие не е разрешено от приложението или организацията ви"
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 1d0b45fe59..48d26905c0 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -45,10 +45,12 @@
"অ্যাপ সাজেশন চালু করা আছে""অ্যাপ সাজেশন বন্ধ করা আছে""আপনার প্রয়োজন হতে পারে এমন অ্যাপ: %1$s"
- "স্ক্রিনের একেবারে ডান বা বাঁদিকের প্রান্ত থেকে সোয়াইপ করেছেন কিনা তা দেখে নিন।"
- "স্ক্রিনের ডান বা বাঁদিকের প্রান্ত থেকে মাঝখান পর্যন্ত সোয়াইপ করে আঙুল তুলে নিয়েছেন কিনা তা দেখে নিন।"
- "ফিরে যেতে, কীভাবে ডানদিক থেকে সোয়াইপ করতে হয় তা আপনি শিখেছেন। এরপর, একটি অ্যাপ থেকে অন্য অ্যাপে কীভাবে যাবেন জেনে নিন।"
- "আপনি ফিরে যাওয়ার জেসচার সম্পর্কে জেনেছেন।"
+ "একদম বাঁ প্রান্ত থেকে সোয়াইপ করছেন কিনা ভাল করে দেখে নিন।"
+ "আপনি বাঁ প্রান্ত থেকে স্ক্রিনের মাঝখান পর্যন্ত সোয়াইপ করছেন ও পরে আঙুল তুলে নিন। এটির খেয়াল রাখুন।"
+ "এটুকুই যথেষ্ট! এখন ডান প্রান্ত থেকে সোয়াইপের চেষ্টা করুন।"
+ "একদম ডান প্রান্ত থেকে সোয়াইপ করছেন কিনা ভাল করে দেখে নিন।"
+ "আপনি ডান প্রান্ত থেকে স্ক্রিনের মাঝখান পর্যন্ত সোয়াইপ করছেন ও পরে আঙুল তুলে নিন। এটি খেয়াল রাখুন।"
+ "আপনি ফিরে যাওয়ার জেসচার সম্পর্কে জেনেছেন। এরপর, হোম স্ক্রিনে কীভাবে যাবেন জেনে নিন।""স্ক্রিনের নিচের প্রান্তের খুব কাছে পর্যন্ত যাতে সোয়াইপ না করেন সেটি ভাল করে দেখে নিন।""ফিরে যাওয়ার জেসচারের সেন্সিটিভিটি পরিবর্তন করতে, সেটিংসে যান""ফিরে যেতে সোয়াইপ করুন"
@@ -56,27 +58,22 @@
"স্ক্রিনের নিচের প্রান্ত থেকে আপনি সোয়াইপ করেছেন কিনা ভাল করে দেখে নিন।""আঙুল তুলে নেওয়ার আগে আপনি যাতে পজ না করেন সেটি ভাল করে দেখে নিন।""আপনি উপরের দিকে সোজাসুজি সোয়াইপ করেছেন কিনা ভাল করে দেখে নিন।"
- "আপনি হোম স্ক্রিনে যাওয়ার জেসচার সম্পর্কে জেনেছেন। এরপর, ফিরে কীভাবে যাবেন তা জেনে নিন।"
- "আপনি হোম স্ক্রিনে যাওয়ার জেসচার সম্পর্কে জেনেছেন।"
+ "আপনি হোম স্ক্রিনে যাওয়ার জেসচার সম্পর্কে জেনেছেন। এরপর, একটি অ্যাপ থেকে অন্য অ্যাপে কীভাবে যাবেন জেনে নিন।""হোম স্ক্রিনে যেতে সোয়াইপ করুন""স্ক্রিনের নিচের প্রান্ত থেকে উপরের দিকে সোয়াইপ করুন। এটি করলে, আপনি সবসময় হোম স্ক্রিনে যেতে পারবেন।""স্ক্রিনের নিচের প্রান্ত থেকে আপনি সোয়াইপ করেছেন কিনা ভাল করে দেখে নিন।""চেষ্টা করুন যাতে আঙুল সরিয়ে নেওয়ার আগে উইন্ডো কিছুক্ষণ প্রেস করে রাখা যায়।""আপনি উপরের দিকে সোজাসুজি সোয়াইপ করেছেন কিনা ভাল করে দেখে নিয়ে তারপর পজ করুন।"
- "জেসচার কীভাবে ব্যবহার করতে হয় আপনি তা শিখে ফেলেছেন। জেসচার বন্ধ করতে, সেটিংসে যান।"
- "আপনি একটি অ্যাপ থেকে অন্য অ্যাপে যাওয়ার জেসচার সম্পর্কে জেনেছেন।"
+ "আপনি একটি অ্যাপ থেকে অন্য অ্যাপে যাওয়ার জেসচার সম্পর্কে জেনেছেন। আপনি এখন আপনার ফোন ব্যবহার করার জন্য প্রস্তুত!""একটি অ্যাপ থেকে অন্য অ্যাপে যেতে সোয়াইপ করুন"
- "একটি অ্যাপ থেকে অন্যটিতে পাল্টাতে, স্ক্রিনের নিচ থেকে উপরে সোয়াইপ করে ধরে রাখুন, তারপরে ছেড়ে দিন।"
+ "স্ক্রিনের নিচ থেকে উপরের দিকে সোয়াইপ করে ধরে থাকুন, তারপর ছেড়ে দিন।""সব প্রস্তুত"
- "সম্পূর্ণ হয়েছে"
+ "পরবর্তী"
+ "হয়ে গেছে""সেটিংস""আবার চেষ্টা করুন""সাবাস!""টিউটোরিয়াল %1$d/%2$d"
- "সব রেডি!"
- "হোম স্ক্রিনে যেতে উপরের দিকে সোয়াইপ করুন"
- "এবারে আপনি ফোন ব্যবহার করতে পারবেন"
- "সিস্টেম নেভিগেশন সেটিংস""শেয়ার করুন""স্ক্রিনশট নিন""এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index acd7b1003a..18494a9c19 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -45,38 +45,35 @@
"Prijedlozi aplikacija su omogućeni""Prijedlozi aplikacija su onemogućeni""Predviđena aplikacija: %1$s"
- "Vodite računa da prevučete s krajnjeg desnog ili krajnjeg lijevog ruba."
- "Vodite računa da prevučete s desnog ili lijevog ruba prema sredini ekrana i pustite."
- "Naučili ste kako prevući zdesna da se vratite. Sljedeće naučite kako prebacivati između aplikacija."
- "Završili ste pokret za vraćanje."
+ "Obratite pažnju da prevučete s krajnjeg lijevog ruba."
+ "Obratite pažnju da prevučete s lijevog ruba prema sredini ekrana, a zatim pustite."
+ "To je to! Sada pokušajte prevući s desnog ruba."
+ "Obratite pažnju da prevučete s krajnjeg desnog ruba."
+ "Obratite pažnju da prevučete s desnog ruba prema sredini ekrana, a zatim pustite."
+ "Završili ste pokret za vraćanje. Sljedeće naučite kako otvoriti Početni ekran.""Obratite pažnju da ne prevučete preblizu donjem dijelu ekrana.""Promijenite osjetljivost pokreta za povratak u Postavkama""Prevucite da se vratite""Da se vratite na posljednji ekran, prevucite s lijevog ili desnog ruba prema sredini ekrana."
- "Trebate prevući prema gore s donjeg ruba ekrana."
+ "Obratite pažnju da prevučete prema gore s donjeg ruba ekrana.""Obratite pažnju da ne zastanete prije puštanja."
- "Trebate prevući ravno prema gore."
- "Završili ste pokret za otvaranje početnog ekrana. Sljedeće naučite kako se vratiti."
- "Završili ste pokret za otvaranje početnog ekrana."
+ "Obratite pažnju da prevučete ravno prema gore."
+ "Završili ste pokret za otvaranje Početnog ekrana. Sljedeće naučite kako prebacivati između aplikacija.""Prevucite da odete na početni ekran"
- "Prevucite s dna ekrana prema gore. Tim pokretom uvijek idete na početni ekran."
- "Trebate prevući prema gore s donjeg ruba ekrana."
+ "Prevucite s dna ekrana prema gore. Tim pokretom uvijek idete na Početni ekran."
+ "Obratite pažnju da prevučete prema gore s donjeg ruba ekrana.""Pokušajte zadržati prozor duže prije puštanja."
- "Trebate prevući ravno prema gore, a zatim zastati."
- "Naučili ste kako koristiti pokrete. Idite u Postavke da isključite pokrete."
- "Završili ste pokret za prebacivanje između aplikacija."
+ "Obratite pažnju da prevučete ravno prema gore, a zatim zastanite."
+ "Završili ste pokret za prebacivanje između aplikacija. Spremni ste da koristite telefon!""Prevucite da prebacujete između aplikacija"
- "Da prebacujete između aplikacija, prevucite s dna ekrana prema gore, zadržite, a zatim pustite."
+ "Prevucite s dna ekrana prema gore, zadržite, a zatim pustite.""Sve je spremno"
- "Gotovo"
+ "Naprijed"
+ "Gotovo""Postavke"
- "Pokušajte ponovo"
- "Odlično!"
+ "Pokušaj ponovo"
+ "Lijepo!""Vodič %1$d/%2$d"
- "Sve je spremno!"
- "Prevucite prema gore da odete na početnu stranicu"
- "Sve je spremno da počnete koristiti telefon"
- "Postavke navigiranja sistemom""Dijeli""Snimak ekrana""Ovu radnju ne dozvoljava aplikacija ili vaša organizacija"
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index a0d6aeed4f..7c417effa0 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -45,10 +45,12 @@
"Els suggeriments d\'aplicacions estan activats""Els suggeriments d\'aplicacions estan desactivats""Predicció d\'aplicació: %1$s"
- "Assegura\'t de lliscar des de l\'extrem dret o esquerre de la pantalla."
- "Assegura\'t de lliscar des de la vora dreta o esquerra cap al centre de la pantalla i deixar anar."
- "Has après com pots lliscar des de la dreta per tornar enrere. Ara, descobreix com pots canviar d\'app."
- "Has completat el gest per tornar enrere."
+ "Assegura\'t de lliscar des de l\'extrem esquerre de la pantalla."
+ "Assegura\'t de lliscar des de la vora esquerra cap al centre de la pantalla i deixa anar."
+ "Ja està! Ara, prova de lliscar des de la vora dreta."
+ "Assegura\'t de lliscar des de l\'extrem dret de la pantalla."
+ "Assegura\'t de lliscar des de la vora dreta cap al centre de la pantalla i deixa anar."
+ "Has completat el gest per anar enrere. Ara, descobreix com pots anar a la pantalla d\'inici.""Assegura\'t de no lliscar massa a prop de la part inferior de la pantalla.""Per canviar la sensibilitat del gest, ves a Configuració""Llisca per anar enrere"
@@ -56,32 +58,27 @@
"Assegura\'t de lliscar des de la vora inferior de la pantalla.""Assegura\'t de no aturar-te abans de deixar anar.""Assegura\'t de lliscar directament cap amunt."
- "Has completat el gest per anar a la pantalla d\'inici. Ara, descobreix com pots tornar enrere."
- "Has completat el gest per anar a la pantalla d\'inici."
+ "Has completat el gest per anar a la pantalla d\'inici. Ara, descobreix com pots canviar d\'aplicació.""Llisca per anar a la pantalla d\'inici""Llisca cap amunt des de la part inferior de la pantalla. Aquest gest et porta a la pantalla d\'inici.""Assegura\'t de lliscar des de la vora inferior de la pantalla."
- "Prova de mantenir premuda la finestra durant més temps abans de deixar-la anar."
+ "Prova de mantenir premuda la finestra durant més temps abans de deixar anar.""Assegura\'t de lliscar directament cap amunt i després aturar-te."
- "Has après a utilitzar els gestos. Per desactivar-los, ves a Configuració."
- "Has completat el gest per canviar d\'aplicació."
+ "Has completat el gest per canviar d\'aplicació. Ja ho tens tot a punt per utilitzar el telèfon.""Llisca per canviar d\'aplicació"
- "Per canviar entre aplicacions, llisca cap amunt des de la part inferior, mantén premut i deixa anar."
+ "Llisca cap amunt des de la part inferior de la pantalla, mantén premut i deixa anar.""Tot a punt"
- "Fet"
+ "Següent"
+ "Fet""Configuració""Torna-ho a provar""Molt bé!""Tutorial %1$d/%2$d"
- "Tot a punt!"
- "Llisca cap amunt per anar a la pàgina d\'inici"
- "Ja pots començar a utilitzar el telèfon"
- "Configuració de navegació del sistema""Comparteix""Captura de pantalla""L\'aplicació o la teva organització no permeten aquesta acció""Vols ometre el tutorial de navegació?"
- "Pots trobar-lo més tard a l\'aplicació %1$s"
+ "Pots trobar-ho més tard a l\'aplicació %1$s""Cancel·la""Omet"
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index b2d092e07d..9d1b94e9cd 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -33,22 +33,24 @@
"Návrhy aplikací pro vás""Nechte si ve spodním řádku na ploše zobrazovat návrhy aplikací""Nechte si na řádku oblíbených na ploše zobrazovat návrhy aplikací"
- "Mějte nejpoužívanější aplikace k dispozici přímo na ploše. Návrhy se budou měnit podle vašich zvyklostí. Aplikace ve spodním řádku se přesunou nahoru na vaši plochu."
- "Mějte nejpoužívanější aplikace k dispozici přímo na ploše. Návrhy se budou měnit podle vašich zvyklostí. Aplikace na řádku oblíbených se přesunou na plochu."
- "Mějte nejpoužívanější aplikace k dispozici přímo na ploše. Návrhy se budou měnit podle vašich zvyklostí. Aplikace ve spodním řádku se přesunou do nové složky."
+ "Mějte nejpoužívanější aplikace k dispozici přímo na ploše. Návrhy se budou měnit v závislosti na sledech činností. Aplikace ve spodním řádku se přesunou na vaši plochu."
+ "Mějte nejpoužívanější aplikace k dispozici přímo na ploše. Návrhy se budou měnit v závislosti na sledech činností. Aplikace na řádku oblíbených se přesunou na plochu."
+ "Mějte nejpoužívanější aplikace k dispozici přímo na ploše. Návrhy se budou měnit v závislosti na sledech činností. Aplikace ve spodním řádku se přesunou do nové složky.""Zobrazovat návrhy aplikací""Ne, díky""Nastavení""Zde se zobrazují nejpoužívanější aplikace (které se mění podle sledů činností)"
- "Návrhy aplikací získáte přetažením aplikací z dolního řádku"
+ "Chcete-li získat návrhy aplikací, přetáhněte aplikace z dolního řádku""Volné místo bylo vyplněno návrhy aplikací""Návrhy aplikací jsou povoleny""Návrhy aplikací jsou zakázány""Předpokládaná aplikace: %1$s"
- "Přejeďte prstem z úplného pravého nebo levého okraje obrazovky."
- "Přejeďte prstem z pravého nebo levého okraje doprostřed obrazovky a zdvihněte prst."
- "Naučili jste se, jak se vrátit zpět přejetím prstem zprava. Teď se naučíte přepínat aplikace."
- "Dokončili jste gesto pro přechod zpět."
+ "Přejeďte prstem z úplného levého okraje obrazovky."
+ "Přejeďte prstem z levého okraje doprostřed obrazovky a zdvihněte prst."
+ "A je to! Teď zkuste přejet prstem z pravého okraje."
+ "Přejeďte prstem z úplného pravého okraje obrazovky."
+ "Přejeďte prstem z pravého okraje doprostřed obrazovky a zdvihněte prst."
+ "Dokončili jste gesto pro přechod zpět. Teď se naučíme přejít na plochu.""Dejte pozor, abyste prstem nepřejížděli moc blízko ke spodnímu okraji obrazovky.""Citlivost gesta pro přechod zpět můžete změnit v Nastavení""Přejetím prstem se vrátíte zpět"
@@ -56,27 +58,22 @@
"Přejeďte prstem nahoru z dolního okraje obrazovky.""Před zdvihnutím prstu nedělejte pauzu.""Přejeďte prstem přímo nahoru."
- "Dokončili jste gesto pro přechod na plochu. Teď se naučíte vrátit se zpět."
- "Dokončili jste gesto pro přechod na plochu."
+ "Dokončili jste gesto pro přechod na plochu. Teď se naučíme přepínat aplikace.""Přechod na plochu přejetím prstem""Přejeďte prstem ze spodní části obrazovky nahoru. Tímto gestem se vždy dostanete na plochu.""Přejeďte prstem nahoru z dolního okraje obrazovky.""Zkuste podržet okno delší dobu, než ho uvolníte.""Přejeďte prstem přímo nahoru a pak udělejte pauzu."
- "Naučili jste se používat gesta. Gesta můžete vypnout v nastavení."
- "Dokončili jste gesto pro přepínání aplikací."
+ "Dokončili jste gesto pro přepínání aplikací. Jste připraveni používat telefon.""Přepínání aplikací přejetím prstem"
- "Přepínání mezi aplikacemi: Přejeďte nahoru z dolního okraje obrazovky, podržte obrazovku a uvolněte."
+ "Přejeďte prstem nahoru z dolního okraje obrazovky, podržte obrazovku a potom prst uvolněte.""Vše je nastaveno"
- "Hotovo"
+ "Další"
+ "Hotovo""Nastavení""Zkusit znovu""Skvělé!""Výukový program %1$d/%2$d"
- "Hotovo!"
- "Přejetím nahoru se vrátíte na plochu"
- "Jste připraveni začít používat telefon"
- "Nastavení navigace v systému""Sdílet""Snímek obrazovky""Aplikace nebo organizace zakazuje tuto akci"
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index f2e2df02ec..42098dc036 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -45,10 +45,12 @@
"Appforslag er aktiveret""Appforslag er deaktiveret""App, du forventes at skulle bruge: %1$s"
- "Stryg fra kanten yderst til højre eller venstre."
- "Stryg fra højre eller venstre kant mod midten af skærmen, og løft fingeren."
- "Du har lært, hvordan du stryger fra højre for at gå tilbage. Nu skal du se, hvordan du skifter app."
- "Du har fuldført bevægelsen for Gå tilbage."
+ "Stryg fra kanten yderst til venstre."
+ "Stryg fra venstre kant mod midten af skærmen, og løft fingeren."
+ "Det var det. Nu kan du prøve at stryge fra højre kant."
+ "Stryg fra kanten yderst til højre."
+ "Stryg fra højre kant mod midten af skærmen, og løft fingeren."
+ "Du har fuldført bevægelsen for Gå tilbage. Som det næste kan du se, hvordan du går til startskærmen.""Undgå at stryge for tæt på bunden af skærmen.""Juster følsomheden for bevægelsen Gå tilbage i Indstillinger""Stryg for at gå tilbage"
@@ -56,27 +58,22 @@
"Stryg opad fra bunden af skærmen.""Undlad at holde fingeren stille, indtil du løfter fingeren.""Stryg lige opad."
- "Du har fuldført bevægelsen for Gå til startskærmen. Som det næste kan du se, hvordan du går tilbage."
- "Du har fuldført bevægelsen for Gå til startskærmen."
+ "Du har fuldført bevægelsen for Gå til start. Som det næste kan du se, hvordan du skifter app.""Stryg for at gå til startskærmen""Stryg opad fra bunden af skærmen. Denne bevægelse åbner altid startskærmen.""Stryg opad fra bunden af skærmen.""Prøv at holde fingeren nede på vinduet i længere tid, inden du løfter den.""Stryg lige opad, og hold derefter fingeren stille."
- "Du har lært, hvordan du bruger bevægelser. Du kan aktivere bevægelser i Indstillinger."
- "Du har fuldført bevægelsen for Skift app."
+ "Du har fuldført bevægelsen for Skift app. Du er klar til at bruge din telefon.""Stryg for at skifte app"
- "Skift mellem apps ved at stryge opad fra bunden af skærmen, holde fingeren stille og løfte den."
+ "Stryg opad fra bunden af skærmen, hold fingeren stille, og løft den.""Så er du klar"
- "Luk"
+ "Næste"
+ "Luk""Indstillinger""Prøv igen""Sådan!""Selvstudie %1$d/%2$d"
- "Alt er parat!"
- "Stryg opad for at gå til startsiden"
- "Du er klar til at bruge din telefon"
- "Indstillinger for systemnavigation""Del""Screenshot""Appen eller din organisation tillader ikke denne handling"
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 4a023e35cb..e7d9523c14 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -24,7 +24,7 @@
"Keine kürzlich verwendeten Elemente""Einstellungen zur App-Nutzung""Alle Apps schließen"
- "Kürzlich geöffnete Apps"
+ "Zuletzt aktive Apps""%1$s, %2$s""< 1 Min.""Heute noch %1$s"
@@ -42,46 +42,43 @@
"Hier erscheinen die meistverwendeten Apps. Die Angaben können sich je nach deiner gewöhnlichen Nutzung ändern""Ziehe Apps aus der unteren Reihe heraus, um Vorschläge für Apps zu erhalten""App-Vorschläge in freiem Bereich hinzugefügt"
- "Funktion „App-Vorschläge“ aktiviert"
+ "Funktion \"App-Vorschläge\" aktiviert""Funktion \"App-Vorschläge\" deaktiviert""Vorgeschlagene App: %1$s"
- "Wische vom äußersten rechten oder linken Displayrand."
- "Wische vom rechten oder linken Displayrand zur Displaymitte und lass los."
- "Du kannst jetzt vom rechten Displayrand aus wischen, um zurückzugehen. Gleich erfährst du, wie man zwischen Apps wechselt."
- "Du hast die „Zurück“-Touch-Geste abgeschlossen."
- "Wische nicht zu nah am unteren Displayrand."
+ "Wische vom äußersten linken Bildschirmrand."
+ "Wische vom linken Bildschirmrand zur Bildschirmmitte und lass los."
+ "Gut gemacht. Versuch es jetzt mal vom rechten Rand aus."
+ "Wische vom äußersten rechten Bildschirmrand."
+ "Wische vom rechten Bildschirmrand zur Bildschirmmitte und lass los."
+ "Du hast die „Zurück“-Touch-Geste abgeschlossen. Nun lernst du, wie du zum Startbildschirm gelangst."
+ "Wische nicht zu nah am unteren Bildschirmrand.""Du kannst die Empfindlichkeit von „Zurück“ in den Einstellungen ändern""Zum Zurückgehen wischen""Wenn du zum letzten Bildschirm zurückgehen möchtest, wische vom linken oder rechten Rand zur Mitte."
- "Wische vom unteren Displayrand nach oben."
+ "Wische vom unteren Bildschirmrand nach oben.""Achte darauf, nicht innezuhalten, bevor du loslässt.""Wische gerade nach oben."
- "Du hast die „Startbildschirm“-Touch-Geste abgeschlossen. Gleich erfährst du, wie du zurückgelangst."
- "Du hast die „Startbildschirm“-Touch-Geste abgeschlossen."
+ "Du hast die „Startbildschirm“-Touch-Geste abgeschlossen. Als Nächstes lernst du, wie du zwischen Apps wechseln kannst.""Zum Startbildschirm gehen"
- "Wenn du zum Startbildschirm gehen möchtest, wische einfach vom unteren Displayrand nach oben."
- "Wische vom unteren Displayrand nach oben."
+ "Wenn du zum Startbildschirm gehen möchtest, wische einfach vom unteren Bildschirmrand nach oben."
+ "Wische vom unteren Bildschirmrand nach oben.""Versuche, das Fenster länger festzuhalten, bevor du es loslässt.""Wische gerade nach oben und halte dann inne."
- "Nun weißt du, wie Touch-Gesten funktionieren. Du kannst sie in den Einstellungen deaktivieren."
- "Du hast die „Apps wechseln“-Touch-Geste abgeschlossen."
+ "Du hast die „Apps wechseln“-Touch-Geste abgeschlossen. Nun bist du bereit, dein Smartphone zu verwenden!""Zwischen Apps wechseln"
- "Wische auf dem Display von unten nach oben und lass dann los, um zwischen Apps zu wechseln."
+ "Wische auf dem Bildschirm von unten nach oben, halte ihn gedrückt und lass ihn dann los.""Fertig"
- "Fertig"
+ "Weiter"
+ "Fertig""Einstellungen""Wiederholen""Sehr gut!""Anleitung %1$d/%2$d"
- "Fertig!"
- "Nach oben wischen, um den Startbildschirm aufzurufen"
- "Du kannst dein Smartphone jetzt verwenden"
- "Einstellungen der Systemsteuerung""Teilen""Screenshot""Die App oder deine Organisation lässt diese Aktion nicht zu""Navigationstutorial überspringen?"
- "Du findest es später auch in der %1$s App"
+ "Das findest du später in der %1$s App""Abbrechen""Überspringen"
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 7243e039ab..21c29844f5 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -45,10 +45,12 @@
"Οι προτεινόμενες εφαρμογές ενεργοποιήθηκαν""Οι προτεινόμενες εφαρμογές είναι απενεργοποιημένες""Εφαρμογή από πρόβλεψη: %1$s"
- "Φροντίστε να σύρετε από το άκρο της δεξιάς ή της αριστερής πλευράς."
- "Σύρετε από το δεξί ή αριστερό άκρο προς το μέσο της οθόνης και απομακρύνετε το δάχτυλό σας."
- "Μάθατε πώς να σύρετε από τα δεξιά για επιστροφή. Στη συνέχεια, μάθετε πώς να κάνετε εναλλαγή εφαρμ."
- "Ολοκληρώσατε την κίνηση επιστροφής."
+ "Φροντίστε να σύρετε από το άκρο της αριστερής πλευράς."
+ "Φροντίστε να σύρετε από το αριστερό άκρο προς το μέσο της οθόνης και απομακρύνετε το δάχτυλό σας."
+ "Αυτό ήταν! Δοκιμάστε τώρα να σύρετε από το δεξί άκρο."
+ "Φροντίστε να σύρετε από το άκρο της δεξιάς πλευράς."
+ "Φροντίστε να σύρετε από το δεξί άκρο προς το μέσο της οθόνης και απομακρύνετε το δάχτυλό σας."
+ "Ολοκληρώσατε την κίνηση επιστροφής. Στη συνέχεια, μάθετε πώς να μεταβείτε στην αρχική σελίδα.""Φροντίστε να μην σύρετε υπερβολικά κοντά στο κάτω μέρος της οθόνης.""Μεταβείτε στις Ρυθμίσεις για αλλαγή ευαισθ. κίνησης επιστρ.""Σύρετε για επιστροφή"
@@ -56,27 +58,22 @@
"Φροντίστε να σύρετε προς τα επάνω από το κάτω άκρο της οθόνης.""Φροντίστε να μην κάνετε παύση προτού απομακρύνετε τα δάχτυλά σας.""Φροντίστε να σύρετε απευθείας προς τα επάνω."
- "Ολοκληρώσατε την κίνηση μετάβασης στην αρχική οθόνη. Στη συνέχεια, μάθετε πώς να κάνετε επιστροφή."
- "Ολοκληρώσατε την κίνηση μετάβασης στην αρχική οθόνη."
+ "Ολοκληρώσατε την κίνηση μετάβασης στην αρχική οθόνη. Στη συνέχεια, μάθετε πώς να κάνετε εναλλαγή εφαρμογών.""Σύρετε για μετάβαση στην αρχική οθόνη""Σύρετε προς τα πάνω από το κάτω μέρος της οθόνης. Αυτή η κίνηση σάς μεταφέρει πάντα στην αρχ. οθόνη.""Φροντίστε να σύρετε προς τα επάνω από το κάτω άκρο της οθόνης.""Δοκιμάστε να κρατήσετε περισσότερο το παράθυρο προτού απελευθερώσετε.""Φροντίστε να σύρετε απευθείας προς τα επάνω και έπειτα κάντε παύση."
- "Μάθατε πώς να χρησιμοποιείτε κινήσεις. Μεταβείτε στις Ρυθμίσεις για απενεργοποίηση των κινήσεων."
- "Ολοκληρώσατε την κίνηση εναλλαγής εφαρμογών."
+ "Ολοκληρώσατε την κίνηση εναλλαγής εφαρμογών. Είστε έτοιμοι να χρησιμοποιήσετε το τηλέφωνό σας!""Σύρετε για εναλλαγή εφαρμογών"
- "Για εναλλαγή εφαρμογών, σύρετε προς τα πάνω από το κάτω μέρος της οθόνης, πατήστε παρατεταμένα και μετά αφήστε."
+ "Σύρετε προς τα πάνω από το κάτω μέρος της οθόνης σας, κρατήστε παρατεταμένα και έπειτα ελευθερώστε.""Όλα είναι έτοιμα"
- "Τέλος"
+ "Επόμενο"
+ "Τέλος""Ρυθμίσεις""Δοκιμάστε ξανά""Ωραία!""Οδηγός %1$d/%2$d"
- "Όλα έτοιμα!"
- "Σύρετε προς τα πάνω για μετάβαση στην αρχική οθόνη."
- "Είστε έτοιμοι να ξεκινήσετε να χρησιμοποιείτε το τηλέφωνό σας"
- "Ρυθμίσεις πλοήγησης συστήματος""Κοινοποίηση""Στιγμιότυπο οθόνης""Αυτή η ενέργεια δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας."
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 7b42aace1f..487d6ccd77 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -45,10 +45,12 @@
"App suggestions enabled""App suggestions are disabled""Predicted app: %1$s"
- "Make sure that you swipe from the far-right or far-left edge."
- "Make sure that you swipe from the right or left edge to the middle of the screen and let go."
- "You learned how to swipe from the right to go back. Next, learn how to switch apps."
- "You completed the go back gesture."
+ "Make sure that you swipe from the far-left edge."
+ "Make sure that you swipe from the left edge to the middle of the screen and let go."
+ "That\'s it! Now try swiping from the right edge."
+ "Make sure that you swipe from the far-right edge."
+ "Make sure that you swipe from the right edge to the middle of the screen and let go."
+ "You completed the go back gesture. Next up, learn how to go Home.""Make sure that you don\'t swipe too close to the bottom of the screen.""To change sensitivity of the back gesture, go to Settings""Swipe to go back"
@@ -56,27 +58,22 @@
"Make sure that you swipe up from the bottom edge of the screen.""Make sure that you don\'t pause before letting go.""Make sure that you swipe straight up."
- "You completed the go home gesture. Next, learn how to go back."
- "You completed the go home gesture."
+ "You completed the go home gesture. Next up, learn how to switch apps.""Swipe to go home""Swipe up from the bottom of your screen. This gesture always takes you to the home screen.""Make sure that you swipe up from the bottom edge of the screen.""Try holding the window for longer before releasing.""Make sure that you swipe straight up, then pause."
- "You learned how to use gestures. To turn off gestures, go to Settings."
- "You completed the switch apps gesture."
+ "You completed the switch apps gesture. You\'re ready to use your phone!""Swipe to switch apps"
- "To switch between apps, swipe up from the bottom of your screen, hold, then release."
+ "Swipe up from the bottom of your screen, hold, then release.""All set"
- "Done"
+ "Next"
+ "Done""Settings""Try again""Nice!""Tutorial %1$d/%2$d"
- "Ready!"
- "Swipe up to go home"
- "You’re ready to start using your phone"
- "System navigation settings""Share""Screenshot""This action isn\'t allowed by the app or your organisation"
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 7b42aace1f..487d6ccd77 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -45,10 +45,12 @@
"App suggestions enabled""App suggestions are disabled""Predicted app: %1$s"
- "Make sure that you swipe from the far-right or far-left edge."
- "Make sure that you swipe from the right or left edge to the middle of the screen and let go."
- "You learned how to swipe from the right to go back. Next, learn how to switch apps."
- "You completed the go back gesture."
+ "Make sure that you swipe from the far-left edge."
+ "Make sure that you swipe from the left edge to the middle of the screen and let go."
+ "That\'s it! Now try swiping from the right edge."
+ "Make sure that you swipe from the far-right edge."
+ "Make sure that you swipe from the right edge to the middle of the screen and let go."
+ "You completed the go back gesture. Next up, learn how to go Home.""Make sure that you don\'t swipe too close to the bottom of the screen.""To change sensitivity of the back gesture, go to Settings""Swipe to go back"
@@ -56,27 +58,22 @@
"Make sure that you swipe up from the bottom edge of the screen.""Make sure that you don\'t pause before letting go.""Make sure that you swipe straight up."
- "You completed the go home gesture. Next, learn how to go back."
- "You completed the go home gesture."
+ "You completed the go home gesture. Next up, learn how to switch apps.""Swipe to go home""Swipe up from the bottom of your screen. This gesture always takes you to the home screen.""Make sure that you swipe up from the bottom edge of the screen.""Try holding the window for longer before releasing.""Make sure that you swipe straight up, then pause."
- "You learned how to use gestures. To turn off gestures, go to Settings."
- "You completed the switch apps gesture."
+ "You completed the switch apps gesture. You\'re ready to use your phone!""Swipe to switch apps"
- "To switch between apps, swipe up from the bottom of your screen, hold, then release."
+ "Swipe up from the bottom of your screen, hold, then release.""All set"
- "Done"
+ "Next"
+ "Done""Settings""Try again""Nice!""Tutorial %1$d/%2$d"
- "Ready!"
- "Swipe up to go home"
- "You’re ready to start using your phone"
- "System navigation settings""Share""Screenshot""This action isn\'t allowed by the app or your organisation"
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 7b42aace1f..487d6ccd77 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -45,10 +45,12 @@
"App suggestions enabled""App suggestions are disabled""Predicted app: %1$s"
- "Make sure that you swipe from the far-right or far-left edge."
- "Make sure that you swipe from the right or left edge to the middle of the screen and let go."
- "You learned how to swipe from the right to go back. Next, learn how to switch apps."
- "You completed the go back gesture."
+ "Make sure that you swipe from the far-left edge."
+ "Make sure that you swipe from the left edge to the middle of the screen and let go."
+ "That\'s it! Now try swiping from the right edge."
+ "Make sure that you swipe from the far-right edge."
+ "Make sure that you swipe from the right edge to the middle of the screen and let go."
+ "You completed the go back gesture. Next up, learn how to go Home.""Make sure that you don\'t swipe too close to the bottom of the screen.""To change sensitivity of the back gesture, go to Settings""Swipe to go back"
@@ -56,27 +58,22 @@
"Make sure that you swipe up from the bottom edge of the screen.""Make sure that you don\'t pause before letting go.""Make sure that you swipe straight up."
- "You completed the go home gesture. Next, learn how to go back."
- "You completed the go home gesture."
+ "You completed the go home gesture. Next up, learn how to switch apps.""Swipe to go home""Swipe up from the bottom of your screen. This gesture always takes you to the home screen.""Make sure that you swipe up from the bottom edge of the screen.""Try holding the window for longer before releasing.""Make sure that you swipe straight up, then pause."
- "You learned how to use gestures. To turn off gestures, go to Settings."
- "You completed the switch apps gesture."
+ "You completed the switch apps gesture. You\'re ready to use your phone!""Swipe to switch apps"
- "To switch between apps, swipe up from the bottom of your screen, hold, then release."
+ "Swipe up from the bottom of your screen, hold, then release.""All set"
- "Done"
+ "Next"
+ "Done""Settings""Try again""Nice!""Tutorial %1$d/%2$d"
- "Ready!"
- "Swipe up to go home"
- "You’re ready to start using your phone"
- "System navigation settings""Share""Screenshot""This action isn\'t allowed by the app or your organisation"
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 7b42aace1f..487d6ccd77 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -45,10 +45,12 @@
"App suggestions enabled""App suggestions are disabled""Predicted app: %1$s"
- "Make sure that you swipe from the far-right or far-left edge."
- "Make sure that you swipe from the right or left edge to the middle of the screen and let go."
- "You learned how to swipe from the right to go back. Next, learn how to switch apps."
- "You completed the go back gesture."
+ "Make sure that you swipe from the far-left edge."
+ "Make sure that you swipe from the left edge to the middle of the screen and let go."
+ "That\'s it! Now try swiping from the right edge."
+ "Make sure that you swipe from the far-right edge."
+ "Make sure that you swipe from the right edge to the middle of the screen and let go."
+ "You completed the go back gesture. Next up, learn how to go Home.""Make sure that you don\'t swipe too close to the bottom of the screen.""To change sensitivity of the back gesture, go to Settings""Swipe to go back"
@@ -56,27 +58,22 @@
"Make sure that you swipe up from the bottom edge of the screen.""Make sure that you don\'t pause before letting go.""Make sure that you swipe straight up."
- "You completed the go home gesture. Next, learn how to go back."
- "You completed the go home gesture."
+ "You completed the go home gesture. Next up, learn how to switch apps.""Swipe to go home""Swipe up from the bottom of your screen. This gesture always takes you to the home screen.""Make sure that you swipe up from the bottom edge of the screen.""Try holding the window for longer before releasing.""Make sure that you swipe straight up, then pause."
- "You learned how to use gestures. To turn off gestures, go to Settings."
- "You completed the switch apps gesture."
+ "You completed the switch apps gesture. You\'re ready to use your phone!""Swipe to switch apps"
- "To switch between apps, swipe up from the bottom of your screen, hold, then release."
+ "Swipe up from the bottom of your screen, hold, then release.""All set"
- "Done"
+ "Next"
+ "Done""Settings""Try again""Nice!""Tutorial %1$d/%2$d"
- "Ready!"
- "Swipe up to go home"
- "You’re ready to start using your phone"
- "System navigation settings""Share""Screenshot""This action isn\'t allowed by the app or your organisation"
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 35ec6bb674..36df9d1523 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -45,10 +45,12 @@
"App suggestions enabled""App suggestions are disabled""Predicted app: %1$s"
- "Make sure you swipe from the far-right or far-left edge."
- "Make sure you swipe from the right or left edge to the middle of the screen and let go."
- "You learned how to swipe from the right to go back. Next up, learn how to switch apps."
- "You completed the go back gesture."
+ "Make sure you swipe from the far-left edge."
+ "Make sure you swipe from the left edge to the middle of the screen and let go."
+ "That\'s it! Now try swiping from the right edge."
+ "Make sure you swipe from the far-right edge."
+ "Make sure you swipe from the right edge to the middle of the screen and let go."
+ "You completed the go back gesture. Next up, learn how to go Home.""Make sure you don\'t swipe too close to the bottom of the screen.""To change the sensitivity of the back gesture, go to Settings""Swipe to go back"
@@ -56,27 +58,22 @@
"Make sure you swipe up from the bottom edge of the screen.""Make sure you don\'t pause before letting go.""Make sure you swipe straight up."
- "You completed the go Home gesture. Next up, learn how to go back."
- "You completed the go Home gesture."
+ "You completed the go Home gesture. Next up, learn how to switch apps.""Swipe to go home""Swipe up from the bottom of your screen. This gesture always takes you to the Home screen.""Make sure you swipe up from the bottom edge of the screen.""Try holding the window for longer before releasing.""Make sure you swipe straight up, then pause."
- "You learned how to use gestures. To turn off gestures, go to Settings."
- "You completed the switch apps gesture."
+ "You completed the switch apps gesture. You\'re ready to use your phone!""Swipe to switch apps"
- "To switch between apps, swipe up from the bottom of your screen, hold, then release."
+ "Swipe up from the bottom of your screen, hold, then release.""All set"
- "Done"
+ "Next"
+ "Done""Settings""Try again""Nice!""Tutorial %1$d/%2$d"
- "All set!"
- "Swipe up to go Home"
- "You’re ready to start using your phone"
- """System navigation settings""""Share""Screenshot""This action isn\'t allowed by the app or your organization"
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index e61fd9135d..478d1cdb1e 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -45,38 +45,35 @@
"Sugerencias de apps habilitadas""Las sugerencias de aplicaciones están inhabilitadas""Predicción de app: %1$s"
- "Asegúrate de deslizar desde el extremo derecho o izquierdo."
- "Asegúrate de deslizar desde borde izquierdo o derecho hacia centro de la pantalla y, luego, soltar."
- "Aprendiste a deslizar el dedo desde la derecha para volver. Ahora, descubre cómo cambiar de app."
- "Completaste el gesto \"Atrás\"."
+ "Asegúrate de deslizar el dedo bien desde el borde izquierdo."
+ "Asegúrate de deslizar el dedo del borde izquierdo hacia el centro de la pantalla y, luego, suéltalo."
+ "Eso es todo. Ahora desliza el dedo desde el borde derecho."
+ "Asegúrate de deslizar el dedo bien desde el borde derecho."
+ "Asegúrate de deslizar el dedo del borde derecho hacia el centro de la pantalla y, luego, suéltalo."
+ "Completaste el gesto \"Atrás\". A continuación, obtén información para ir a la página principal.""Asegúrate de no hacerlo muy cerca de la parte inferior de la pantalla.""Cambia sensibilidad de gesto \"Atrás\" en Configuración""Desliza el dedo para volver""Desliza el dedo desde el borde derecho o izquierdo para volver a la última pantalla."
- "Desliza el dedo hacia arriba desde el borde inferior de la pantalla."
+ "Asegúrate de deslizar el dedo hacia arriba desde la borde inferior de la pantalla.""Asegúrate de no detenerte antes de soltarlo."
- "Desliza el dedo directamente hacia arriba."
- "Completaste el gesto para ir a la página principal. A continuación, obtén información para volver."
- "Completaste el gesto para ir a la página principal."
+ "Asegúrate de deslizar el dedo derecho hacia arriba."
+ "Completaste el gesto para ir a la página principal. A continuación, obtén información para cambiar de app.""Desliza el dedo para ir a la página principal""Desliza el dedo hacia arriba desde la parte inferior de la pantalla. Este gesto te llevará siempre a la pantalla principal."
- "Desliza el dedo hacia arriba desde el borde inferior de la pantalla."
+ "Asegúrate de deslizar el dedo hacia arriba desde la borde inferior de la pantalla.""Prueba mantener presionada la ventana más tiempo antes de soltarla."
- "Desliza el dedo directamente hacia arriba y luego detente."
- "Ya sabes cómo usar los gestos. Para desactivarlos, ve a Configuración."
- "Completaste el gesto para cambiar de app."
+ "Asegúrate de deslizar el dedo derecho hacia arriba y, luego, detente."
+ "Completaste el gesto para cambiar de app. El teléfono ya está listo para usar.""Desliza el dedo para cambiar de app"
- "Para cambiar de app, desliza hacia arriba desde parte inferior, mantén presionado y, luego, suelta."
+ "Desliza el dedo hacia arriba desde la parte inferior de la pantalla, mantenlo presionado y, luego, suéltalo.""Listo"
- "Listo"
+ "Siguiente"
+ "Listo""Configuración""Reintentar""¡Genial!""Instructivo %1$d/%2$d"
- "Todo listo"
- "Desliza el dedo hacia arriba para ir a la pantalla principal"
- "Ya puedes empezar a usar tu teléfono"
- "Configuración de navegación del sistema""Compartir""Captura de pantalla""La app o tu organización no permiten realizar esta acción"
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 8e8829eaf7..454bea7784 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -45,10 +45,12 @@
"Sugerencias de aplicaciones habilitadas""Las sugerencias de aplicaciones están inhabilitadas""Aplicación sugerida: %1$s"
- "Desliza el dedo desde el borde derecho o izquierdo de la pantalla."
- "Desliza el dedo desde el borde derecho o izquierdo de la pantalla hasta el centro y luego levántalo."
- "Ya sabes deslizar el dedo desde la derecha para ir atrás. Descubre ahora cómo cambiar de aplicación."
- "Has completado el gesto para volver."
+ "Desliza el dedo desde el extremo izquierdo."
+ "Desliza el dedo desde el borde izquierdo de la pantalla hasta el centro y levántalo."
+ "Eso es todo. Ahora desliza el dedo desde el borde derecho."
+ "Desliza el dedo desde el extremo derecho."
+ "Desliza el dedo desde el borde derecho de la pantalla hasta el centro y levántalo."
+ "Has completado el gesto para volver. Ahora, descubre cómo ir a la pantalla de inicio.""No deslices el dedo demasiado cerca de la parte inferior de la pantalla.""Para cambiar la sensibilidad del gesto, ve a Ajustes""Desliza el dedo para volver"
@@ -56,27 +58,22 @@
"Desliza el dedo hacia arriba desde el borde inferior de la pantalla.""No hagas ninguna pausa antes de levantar el dedo.""Desliza el dedo directamente hacia arriba."
- "Has completado el gesto para ir a la pantalla de inicio. Ahora, descubre cómo volver."
- "Has completado el gesto para ir a la pantalla de inicio."
+ "Has completado el gesto para ir a la pantalla de inicio. Ahora, descubre cómo cambiar de aplicación.""Desliza el dedo para ir a la pantalla de inicio""Desliza hacia arriba desde la parte inferior. Con este gesto, siempre irás a la pantalla de inicio.""Desliza el dedo hacia arriba desde el borde inferior de la pantalla.""Prueba a mantener pulsada la ventana durante más tiempo antes de soltarla.""Desliza el dedo directamente hacia arriba y luego mantenlo pulsado."
- "Ya sabes cómo utilizar gestos. Para desactivarlos, ve a Configuración."
- "Has completado el gesto para cambiar de aplicación."
+ "Has completado el gesto para cambiar de aplicación. Ya puedes usar el teléfono.""Deslizar el dedo para cambiar de aplicación"
- "Para cambiar de app, desliza el dedo hacia arriba desde el borde inferior y no lo levantes enseguida."
+ "Desliza el dedo hacia arriba desde la parte inferior de la pantalla, mantenlo pulsado y levántalo.""Todo listo"
- "Hecho"
+ "Siguiente"
+ "Hecho""Ajustes"
- "Vuélvelo a intentar"
+ "Reintentar""¡Muy bien!""Tutorial %1$d/%2$d"
- "¡Ya está!"
- "Desliza el dedo hacia arriba para ir a la pantalla de inicio"
- "Ya puedes empezar a usar tu teléfono"
- "Ajustes de navegación del sistema""Compartir""Hacer captura""No puedes hacerlo porque la aplicación o tu organización no lo permiten"
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 74b75281ab..b7299345ab 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -45,10 +45,12 @@
"Rakenduste soovitused on lubatud""Rakenduste soovitused on keelatud""Ennustatud rakendus: %1$s"
- "Pühkige kindlasti parem- või vasakpoolsest servast."
- "Pühkige ekraanikuva paremast või vasakust servast keskele ja eemaldage sõrm."
- "Õppisite, kuidas tagasiliikumiseks paremalt pühkida. Nüüd vaadake, kuidas rakenduste vahel vahetada."
- "Tegite tagasiliikumise liigutuse."
+ "Pühkige kindlasti vasakpoolsest servast."
+ "Pühkige ekraanikuva vasakust servast keskele ja eemaldage sõrm."
+ "Ongi kõik! Nüüd proovige paremast servast pühkida."
+ "Pühkige kindlasti parempoolsest servast."
+ "Pühkige ekraanikuva paremast servast keskele ja eemaldage sõrm."
+ "Tegite tagasiliikumise liigutuse. Järgmisena vaadake, kuidas minna avakuvale.""Veenduge, et te ei pühiks liiga ekraanikuva allosa lähedalt.""Tagasiliigutuse tundlikkuse muutmiseks avage menüü Seaded""Tagasiliikumiseks pühkige"
@@ -56,27 +58,22 @@
"Pühkige kindlasti ekraanikuva alumisest servast üles.""Veenduge, et te enne vabastamist liigutust ei peataks.""Pühkige kindlasti otse üles."
- "Tegite avakuvale minemise liigutuse. Järgmisena vaadake, kuidas minna tagasi."
- "Tegite avakuvale minemise liigutuse."
- "Pühkige avakuvale minemiseks"
+ "Tegite avakuvale minemise liigutuse. Järgmisena vaadake, kuidas rakenduste vahel vahetada."
+ "Pühkimine avakuvale minemiseks""Pühkige ekraani alaosast üles. See liigutus viib teid alati tagasi avakuvale.""Pühkige kindlasti ekraanikuva alumisest servast üles.""Hoidke sõrme aknal pisut kauem, enne kui vabastate.""Pühkige kindlasti otse üles, seejärel peatuge."
- "Õppisite liigutusi kasutama. Liigutuste väljalülitamiseks avage seaded."
- "Tegite rakenduste vahel vahetamise liigutuse."
- "Pühkige rakenduste vahetamiseks"
- "Rakenduste vahel vahetamiseks pühkige ekraanikuva alaosast üles, hoidke ja seejärel vabastage."
+ "Tegite rakenduste vahel vahetamise liigutuse. Olete oma telefoni kasutamiseks valmis!"
+ "Rakenduste vahel vahetamiseks pühkimine"
+ "Pühkige ekraanikuva alaosast üles, hoidke ja seejärel vabastage.""Valmis"
- "Valmis"
+ "Järgmine"
+ "Valmis""Seaded""Proovige uuesti""Tubli töö!""Õpetus %1$d/%2$d"
- "Valmis!"
- "Avakuvale liikumiseks pühkige üles"
- "Olete valmis oma telefoni kasutama."
- "Süsteemi navigeerimisseaded""Jaga""Ekraanipilt""Rakendus või teie organisatsioon on selle toimingu keelanud"
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 12a0dbc740..f6d3f235c4 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -37,7 +37,7 @@
"Atzitu erraz aplikazio erabilienak hasierako pantailatik bertatik. Ohituren arabera aldatuko dira iradokizunak. Gogokoen errenkadako aplikazioak hasierako pantailara eramango ditugu.""Atzitu erraz aplikazio erabilienak hasierako pantailatik bertatik. Ohituren arabera aldatuko dira iradokizunak. Karpeta berri batera eramango dira beheko errenkadan dauden aplikazioak.""Jaso aplikazioen iradokizunak"
- "Ez, eskerrik asko"
+ "Ez""Ezarpenak""Hemen agertzen dira aplikazio erabilienak, eta ohituren arabera aldatzen dira""Arrastatu aplikazioak beheko errenkadatik aplikazioen iradokizunak jasotzeko"
@@ -45,10 +45,12 @@
"Gaituta daude aplikazioen iradokizunak""Desgaituta daude aplikazioen iradokizunak""Iragarritako aplikazioa: %1$s"
- "Ziurtatu hatza pantailaren eskuineko edo ezkerreko ertzetik hasten zarela pasatzen."
- "Ziurtatu hatza pantailaren eskuineko edo ezkerreko ertzetik erdialdera pasatzen eta altxatzen duzula."
- "Hatza eskuinetik pasatuta atzera egiten ikasi duzu. Jarraian, ikasi aplikazioa aldatzen."
- "Ikasi duzu atzera egiteko keinua."
+ "Ziurtatu hatza ezkerreko ertzetik pasatzen duzula."
+ "Ziurtatu hatza pantailaren ezkerreko ertzetik erdialdera pasatzen eta askatzen duzula."
+ "Hori da. Orain, pasatu hatza eskuineko ertzetik."
+ "Ziurtatu hatza eskuineko ertzetik pasatzen duzula."
+ "Ziurtatu hatza pantailaren eskuineko ertzetik erdialdera pasatzen eta askatzen duzula."
+ "Ikasi duzu atzera egiteko keinua. Jarraian, ikasi hasierako pantailara joaten.""Ziurtatu hatza ez duzula pantailaren behealdetik gertuegi pasatzen.""Keinuaren sentikortasuna aldatzeko, joan ezarpenetara""Pasatu hatza atzera egiteko"
@@ -56,32 +58,27 @@
"Ziurtatu hatza pantailaren beheko ertzetik gora pasatzen duzula.""Ziurtatu askatu aurretik ez duzula hatza gelditzen.""Ziurtatu hatza zuzen gora pasatzen duzula."
- "Ikasi duzu hasierako pantailara joateko keinua. Jarraian, ikasi atzera egiten."
- "Ikasi duzu hasierako pantailara joateko keinua."
+ "Ikasi duzu hasierako pantailara joateko keinua. Jarraian, ikasi aplikazioa aldatzen.""Pasatu hatza hasierako pantailara joateko""Pasatu hatza pantailaren behealdetik gora. Keinu horrek hasierako pantailara eramango zaitu beti.""Ziurtatu hatza pantailaren beheko ertzetik gora pasatzen duzula.""Eduki sakatuta leihoa luzaroago hatza altxatu aurretik.""Ziurtatu hatza zuzen gora pasatzen duzula; ondoren, gelditu."
- "Ikasi duzu keinuak erabiltzen. Keinuak desaktibatzeko, joan ezarpenetara."
- "Ikasi duzu aplikazioa aldatzeko keinua."
+ "Ikasi duzu aplikazioa aldatzeko keinua. Prest zaude telefonoa erabiltzeko.""Pasatu hatza aplikazioa aldatzeko"
- "Aplikazio batetik bestera joateko, pasatu hatza pantailaren behealdetik gora, eduki pantaila sakatuta eta altxatu hatza."
+ "Pasatu hatza pantailaren behealdetik gora, eduki pantaila sakatuta eta altxatu hatza.""Dena prest"
- "Eginda"
+ "Hurrengoa"
+ "Eginda""Ezarpenak""Saiatu berriro""Ederki!""Tutoriala: %1$d/%2$d"
- "Dena prest!"
- "Pasatu hatza gora hasierako pantailara joateko"
- "Prest zaude telefonoa erabiltzen hasteko"
- "Sisteman nabigatzeko ezarpenak""Partekatu""Atera pantaila-argazki bat""Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena""Nabigazio-tutoriala saltatu nahi duzu?"
- "%1$s aplikazioan dago eskuragarri tutoriala"
+ "Tutorial hau %1$s aplikazioan aurki dezakezu geroago""Utzi""Saltatu"
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index ae260eda70..8ca0f95ec9 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -45,10 +45,12 @@
"«پیشنهاد برنامه» فعال است""«پیشنهاد برنامه» غیرفعال است""برنامه پیشبینیشده: %1$s"
- "دقت کنید که از انتهای لبه سمت راست یا سمت چپ تند بکشید."
- "دقت کنید که از لبه سمت راست یا سمت چپ تند به وسط صفحه بکشید و رها کنید."
- "یاد گرفتید چگونه برای رفتن به عقب از سمت راست تند بکشید. مورد بعدی، با نحوه جابهجا شدن بین برنامهها آشنا شوید."
- "اشاره برگشتن را تکمیل کردید."
+ "دقت کنید که از ابتدای لبه سمت چپ تند بکشید."
+ "دقت کنید که از لبه سمت چپ تند به وسط صفحه بکشید و رها کنید."
+ "تمام شد! اکنون از لبه سمت راست تند بکشید."
+ "دقت کنید که از ابتدای لبه سمت راست تند بکشید."
+ "دقت کنید که از لبه سمت راست تند به وسط صفحه بکشید و رها کنید."
+ "اشاره برگشتن را تکمیل کردید. مورد بعدی، با نحوه رفتن به «صفحه اصلی» آشنا شوید.""دقت کنید که موقع تند کشیدن بیشاز حد به پایین صفحه نزدیک نشوید.""برای تغییر حساسیت اشاره برگشت، به «تنظیمات» بروید""تند بکشید تا بهعقب برگردید"
@@ -56,27 +58,22 @@
"دقت کنید که از لبه پایینی صفحه تند به بالا بکشید.""دقت کنید که تا قبلاز رها کردن، کشیدن را متوقف نکنید.""دقت کنید که مستقیماً تند به بالا بکشید."
- "اشاره رفتن به «صفحه اصلی» را تکمیل کردید. مورد بعدی، با نحوه برگشتن به عقب آشنا شوید."
- "اشاره رفتن به «صفحه اصلی» را تکمیل کردید."
+ "اشاره رفتن به «صفحه اصلی» را تکمیل کردید. مورد بعدی، با نحوه جابهجا شدن بین برنامهها آشنا شوید.""تند کشیدن برای رفتن به صفحه اصلی""از پایین صفحه، تند بهسمت بالا بکشید. این اشاره همیشه شما را به صفحه اصلی میبرد.""دقت کنید که از لبه پایینی صفحه تند به بالا بکشید.""سعی کنید قبلاز رها کردن، پنجره را برای مدت طولانیتری نگه دارید.""دقت کنید که مستقیماً تند به بالا بکشید و سپس توقف کنید."
- "با نحوه استفاده از اشارهها آشنا شدید. برای خاموش کردن اشارهها، به «تنظیمات» بروید."
- "اشاره جابهجا شدن بین برنامهها را تکمیل کردید."
- "برای جابهجا شدن بین برنامهها، تند بهبالا بکشید"
- "برای جابهجا شدن بین برنامهها، از پایین صفحه تند بهبالا بکشید، نگه دارید، و سپس رها کنید."
+ "اشاره جابهجا شدن بین برنامهها را تکمیل کردید. آمادهاید از تلفنتان استفاده کنید!"
+ "تند کشیدن برای جابهجا شدن بین برنامهها"
+ "از پایین صفحهنمایش تند بهسمت بالا بکشید، نگه دارید، و سپس رها کنید.""همه چیز آماده است"
- "تمام"
+ "بعدی"
+ "تمام""تنظیمات""امتحان مجدد""عالی!""آموزش گامبهگام %1$d/%2$d"
- "همه چیز آماده است!"
- "برای رفتن به «صفحه اصلی»، تند بهبالا بکشید"
- "آمادهاید از تلفنتان استفاده کنید"
- "تنظیمات پیمایش سیستم""همرسانی""نماگرفت""برنامه یا سازمان شما اجازه نمیدهد این کنش انجام شود."
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 8762feb139..9ce7e6b4f2 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -31,24 +31,26 @@
"Sovellusehdotukset""Kaikki sovellukset""Sovellusennusteet"
- "Näytä sovellusehdotuksia aloitusnäytön alimmalla rivillä"
+ "Näytä sovellusehdotuksia aloitusnäytön alimmaisella rivillä""Näytä sovellusehdotuksia aloitusnäytön Suosikit-rivillä"
- "Voit avata käytetyimmät sovellukset kätevästi aloitusnäytöltä. Ehdotukset muuttuvat rutiiniesi perusteella. Alimmalla rivillä olevat sovellukset siirretään aloitusnäytön yläosaan."
+ "Voit avata käytetyimmät sovellukset kätevästi aloitusnäytöltä. Ehdotukset muuttuvat rutiiniesi perusteella. Alimmaisella rivillä olevat sovellukset siirretään aloitusnäytön yläosaan.""Voit avata käytetyimmät sovellukset kätevästi aloitusnäytöltä. Ehdotukset muuttuvat rutiiniesi perusteella. Suosikit-rivillä olevat sovellukset siirretään aloitusnäytölle."
- "Voit avata käytetyimmät sovellukset kätevästi aloitusnäytöltä. Ehdotukset muuttuvat rutiiniesi perusteella. Alimmalla rivillä olevat sovellukset siirretään uuteen kansioon."
+ "Voit avata käytetyimmät sovellukset kätevästi aloitusnäytöltä. Ehdotukset muuttuvat rutiiniesi perusteella. Alimmaisella rivillä olevat sovellukset siirretään uuteen kansioon.""Näytä sovellusehdotuksia""Ei kiitos""Asetukset""Käytetyimmät sovellukset näkyvät täällä ja muuttuvat rutiiniesi perusteella"
- "Siirrä sovelluksia pois alimmalta riviltä, niin voit saada sovellusehdotuksia"
+ "Siirrä sovelluksia pois alimmaiselta riviltä, niin voit saada sovellusehdotuksia""Sovellusehdotuksia lisätty tyhjään kohtaan""Sovellusehdotukset käytössä""Sovellusehdotukset on poistettu käytöstä""Ennakoitu sovellus: %1$s"
- "Muista pyyhkäistä aivan oikeasta tai vasemmasta reunasta."
- "Pyyhkäise näytön oikeasta tai vasemmasta reunasta keskelle ja päästä irti."
- "Osaat palata takaisin pyyhkäisemällä oikeasta reunasta. Opettele seuraavaksi vaihtamaan sovellusta."
- "Olet oppinut Takaisin-eleen."
+ "Muista pyyhkäistä aivan vasemmasta reunasta."
+ "Pyyhkäise näytön vasemmasta reunasta keskelle ja päästä irti."
+ "Valmista tuli! Kokeile nyt pyyhkäistä oikeasta reunasta."
+ "Muista pyyhkäistä aivan oikeasta reunasta."
+ "Pyyhkäise näytön oikeasta reunasta keskelle ja päästä irti."
+ "Olet oppinut Takaisin-eleen. Opettele seuraavaksi siirtymään aloitusnäytölle.""Varo, ettet pyyhkäise liian lähellä alareunaa.""Voit muuttaa Takaisin-eleen herkkyyttä asetuksista""Siirry takaisin pyyhkäisemällä"
@@ -56,27 +58,22 @@
"Pyyhkäise ylös näytön alareunasta.""Varo keskeyttämästä ennen kuin päästät irti.""Muista pyyhkäistä suoraan ylöspäin."
- "Olet oppinut aloitusnäytölle palaamiseleen. Opettele seuraavaksi siirtymään takaisin."
- "Olet oppinut aloitusnäytölle palaamiseleen."
+ "Olet oppinut aloitusnäytölle palaamiseleen. Opettele seuraavaksi vaihtamaan sovellusta.""Siirry aloitusnäytölle pyyhkäisemällä""Pyyhkäise ylös näytön alareunasta. Tämä ele vie sinut aina aloitusnäytölle.""Pyyhkäise ylös näytön alareunasta.""Kokeile pitää ikkunaa painettuna pidempään ennen kuin päästät irti.""Muista pyyhkäistä suoraan ylöspäin ja keskeytä sitten."
- "Olet oppinut käyttämään eleitä. Jos haluat laittaa eleet pois päältä, avaa Asetukset."
- "Olet oppinut sovellusten vaihtamiseleen."
+ "Olet oppinut sovellusten vaihtamiseleen. Olet valmis käyttämään puhelintasi.""Vaihda sovellusta pyyhkäisemällä"
- "Voit vaihtaa sovelluksesta toiseen pyyhkäisemällä ylöspäin näytön alareunasta ja päästämällä sitten irti."
+ "Pyyhkäise ylöspäin näytön alareunasta ja päästä irti.""Valmista"
- "Valmis"
+ "Seuraava"
+ "Valmis""Asetukset""Yritä uudelleen""Hienoa!""Ohje %1$d/%2$d"
- "Valmis"
- "Siirry aloitusnäytölle pyyhkäisemällä ylös"
- "Olet valmis aloittamaan puhelimen käytön"
- "Järjestelmän navigointiasetukset""Jaa""Kuvakaappaus""Sovellus tai organisaatio ei salli tätä toimintoa"
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index a3c9393080..da738495c7 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -45,38 +45,35 @@
"Les suggestions d\'applications sont activées""Les suggestions d\'applications sont désactivées""Application prédite : %1$s"
- "Assurez-vous de balayer l\'écran à partir de l\'extrémité droite ou gauche."
- "Balayez l\'écran de l\'extrémité droite ou gauche jusqu\'au centre de l\'écran, puis levez le doigt."
- "Vous avez appris à balayer de la droite pour revenir en arrière. Apprenez comment changer d\'appli."
- "Vous avez appris le geste de retour en arrière."
+ "Assurez-vous de balayer l\'écran à partir de l\'extrémité gauche."
+ "Assurez-vous de balayer l\'écran de l\'extrémité gauche jusqu\'au centre, puis de lever le doigt."
+ "C\'est tout! Maintenant, essayez à partir de la droite."
+ "Assurez-vous de balayer l\'écran à partir de l\'extrémité droite."
+ "Assurez-vous de balayer l\'écran de l\'extrémité droite jusqu\'au centre, puis de lever le doigt."
+ "Vous avez terminé le geste de retour. Ensuite, vous apprendrez comment revenir à l\'écran d\'accueil.""Assurez-vous de ne pas balayer trop près du bas de l\'écran.""Modifiez la sensibilité du geste de retour dans Paramètres"
- "Balayer l\'écran pour revenir en arrière"
- "Pour revenir à l\'écran précédent, balayez l\'écran de l\'extrémité gauche ou droite vers le centre."
+ "Balayez l\'écran pour revenir en arrière"
+ "Pour revenir à l\'écran précédent, balayez l\'écran de l\'extrémité gauche ou droite vers le centre""Assurez-vous de balayer l\'écran à partir de l\'extrémité inférieure vers le haut.""Assurez-vous de ne pas interrompre le geste avant de lever le doigt.""Assurez-vous de balayer l\'écran en ligne droite vers le haut."
- "Vous avez appris le geste de retour à l\'écran d\'accueil. Maintenant, apprenez à revenir en arrière."
- "Vous avez appris le geste de retour à l\'écran d\'accueil."
+ "Vous avez terminé le geste de retour à l\'écran d\'accueil. Ensuite, vous apprendrez comment basculer entre les applications.""Balayer pour revenir à l\'écran d\'accueil""Balayez l\'écran du bas vers le haut. Ce geste vous ramène toujours à l\'écran d\'accueil.""Assurez-vous de balayer l\'écran à partir de l\'extrémité inférieure vers le haut.""Essayez de tenir la fenêtre plus longtemps avant de relâcher.""Assurez-vous de balayer l\'écran vers le haut, puis de faire une pause."
- "Vous avez appris à utiliser les gestes. Pour les désactiver, accédez au menu Paramètres."
- "Vous avez appris le geste de changement d\'application."
+ "Vous avez terminé le geste de basculement entre les applications. Vous êtes prêt à utiliser votre téléphone!""Balayer pour basculer entre les applications"
- "Pour passer d\'une application à l\'autre, balayez l\'écran de bas en haut, maintenez la pression, puis relâchez."
+ "Balayez l\'écran de bas en haut, maintenez le doigt en place, puis relâchez-le.""Terminé"
- "OK"
+ "Suivant"
+ "Terminé""Paramètres""Réessayer""Bien!""Étape %1$d sur %2$d du tutoriel"
- "Tout est prêt!"
- "Balayez l\'écran vers le haut pour accéder à l\'écran d\'accueil"
- "Vous êtes maintenant prêt à utiliser votre téléphone"
- "Paramètres de navigation du système""Partager""Capture d\'écran""L\'application ou votre organisation n\'autorise pas cette action"
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 516479202d..b6abea7bc9 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -45,38 +45,35 @@
"Suggestions d\'applications activées""Les suggestions d\'applications sont désactivées""Application prédite : %1$s"
- "Veillez à bien balayer l\'écran depuis le bord gauche ou droit."
- "Balayez bien l\'écran depuis le bord gauche ou droit jusqu\'au centre avant de relever le doigt."
- "Vous savez revenir en arrière en balayant depuis la droite. Apprenez à passer d\'une appli à l\'autre."
- "Vous avez appris le geste pour revenir en arrière."
+ "Veillez à balayer l\'écran depuis le bord gauche."
+ "Veillez à bien balayer l\'écran depuis le bord gauche jusqu\'au centre avant de relever le doigt."
+ "Et voilà ! Balayez maintenant l\'écran depuis le côté droit."
+ "Veillez à balayer l\'écran depuis le bord droit."
+ "Veillez à bien balayer l\'écran depuis le bord droit jusqu\'au centre avant de relever le doigt."
+ "Vous avez appris le geste pour revenir en arrière. Apprenez ensuite à revenir à l\'écran d\'accueil.""Veillez à ne pas balayer l\'écran trop près du bas.""Modifiez la sensibilité du geste retour dans les paramètres""Balayez l\'écran pour revenir en arrière""Pour revenir à l\'écran précédent, balayez l\'écran depuis le bord droit ou gauche jusqu\'au centre."
- "Veillez à balayer l\'écran de bas en haut."
+ "Veillez à balayer l\'écran du bas vers le haut.""Veillez à ne pas marquer de pause dans votre geste avant de relever le doigt.""Veillez à balayer l\'écran vers le haut."
- "Vous savez désormais revenir à l\'écran d\'accueil. Apprenez maintenant à revenir en arrière."
- "Vous avez appris le geste pour revenir à l\'écran d\'accueil."
- "Balayez pour revenir à l\'écran d\'accueil"
+ "Vous avez appris le geste pour revenir à l\'écran d\'accueil. Apprenez ensuite à passer d\'une appli à l\'autre."
+ "Balayer pour revenir à l\'écran d\'accueil""Balayez l\'écran de bas en haut. Ce geste vous ramènera toujours à l\'écran d\'accueil."
- "Veillez à balayer l\'écran de bas en haut."
+ "Veillez à balayer l\'écran du bas vers le haut.""Essayez d\'appuyer plus longtemps sur la fenêtre avant de relever le doigt."
- "Veillez à balayer l\'écran vers le haut, puis à marquer une pause."
- "Vous avez appris à utiliser les gestes. Pour les désactiver, accédez aux paramètres."
- "Vous avez appris le geste pour passer d\'une appli à l\'autre."
- "Balayez pour passer d\'une appli à l\'autre"
- "Pour changer d\'appli, balayez l\'écran de bas en haut, appuyez de manière prolongée et relâchez."
+ "Veillez à balayer l\'écran vers le haut et à marquer une pause dans votre geste."
+ "Vous avez appris le geste pour passer d\'une appli à l\'autre. Vous êtes prêt à utiliser votre téléphone."
+ "Balayer pour passer d\'une appli à l\'autre"
+ "Balayez l\'écran du bas vers le haut, appuyez de manière prolongée, puis relevez le doigt.""Vous avez terminé"
- "OK"
+ "Suivant"
+ "OK""Paramètres""Réessayez""Bravo !""Tutoriel %1$d sur %2$d"
- "Tout est prêt !"
- "Balayez l\'écran vers le haut pour revenir à l\'accueil"
- "Vous pouvez maintenant utiliser votre téléphone"
- "Paramètres de navigation système""Partager""Capture d\'écran""Cette action n\'est pas autorisée par l\'application ou par votre organisation"
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index baa87e723b..9310d71f7d 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -45,10 +45,12 @@
"As suxestións de aplicacións están activadas""As suxestións de aplicacións están desactivadas""Aplicación predita: %1$s"
- "Asegúrate de pasar o dedo desde o bordo dereito ou esquerdo máis afastado."
- "Asegúrate de pasar o dedo desde o bordo dereito ou esquerdo ata o medio da pantalla e avanza."
- "Aprendiches a pasar o dedo desde a dereita para volver. Agora, aprende a cambiar de aplicación."
- "Completaches o xesto de volver á última pantalla."
+ "Asegúrate de pasar o dedo desde o bordo esquerdo máis afastado."
+ "Asegúrate de pasar o dedo desde o bordo esquerdo ata o medio da pantalla e avanza."
+ "Xa está! Proba a pasar o dedo desde o bordo dereito."
+ "Asegúrate de pasar o dedo desde o bordo dereito máis afastado."
+ "Asegúrate de pasar o dedo desde o bordo dereito ata o medio da pantalla e avanza."
+ "Completaches o xesto de volver. O próximo é aprender a ir ao inicio.""Asegúrate de non pasar o dedo demasiado preto da parte inferior da pantalla.""Podes cambiar a sensibilidade do xesto en Configuración""Pasar o dedo para volver"
@@ -56,27 +58,22 @@
"Asegúrate de pasar o dedo cara arriba desde o bordo inferior da pantalla.""Asegúrate de non facer unha pausa antes de avanzar.""Asegúrate de pasar o dedo cara arriba cun movemento vertical."
- "Completaches o xesto de ir ao inicio. O próximo é aprender a volver á última pantalla."
- "Completaches o xesto de ir ao inicio."
+ "Completaches o xesto de ir ao inicio. O próximo é aprender a cambiar de aplicación.""Pasar o dedo para ir ao inicio""Pasa o dedo cara arriba desde a parte inferior da pantalla. Ao facelo, irás á pantalla de inicio.""Asegúrate de pasar o dedo cara arriba desde o bordo inferior da pantalla.""Proba a manter premida a pantalla máis tempo antes de soltala.""Asegúrate de pasar o dedo cara arriba cun movemento vertical. Despois, fai unha pausa."
- "Aprendiches a usar os xestos. Para desactivalos, vai a Configuración."
- "Completaches o xesto para cambiar de aplicación."
+ "Completaches o xesto para cambiar de aplicación. Xa podes usar o teléfono!""Pasar o dedo para cambiar de aplicación"
- "Para cambiar de aplicación, pasa o dedo cara arriba desde abaixo, mantén premido e levanta o dedo."
+ "Pasa o dedo cara arriba desde a parte inferior da pantalla, mantena premida e sepárao.""Todo listo"
- "Feito"
+ "Seguinte"
+ "Feito""Configuración""Téntao de novo""Excelente!""Titorial %1$d/%2$d"
- "Todo listo"
- "Pasa o dedo cara arriba para ir á pantalla de inicio"
- "Todo está listo para comezar a utilizar o teléfono"
- "Configuración da navegación do sistema""Compartir""Facer captura""A aplicación ou a túa organización non permite realizar esta acción"
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 33e86171d8..496d33b79a 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -45,10 +45,12 @@
"ઍપના સુઝાવો ચાલુ છે""ઍપના સુઝાવો બંધ છે""પૂર્વાનુમાનિત ઍપ: %1$s"
- "ખાતરી કરો કે તમે એકદમ દૂરની જમણી કે ડાબી કિનારીએથી સ્વાઇપ કરો છો."
- "ખાતરી કરો કે તમે જમણી કે ડાબી કિનારીએથી સ્ક્રીનના મધ્ય ભાગ સુધી સ્વાઇપ કરો છો અને આંગળી ઊંચકી લો છો."
- "પાછળ જવા જમણેથી કેવી રીતે સ્વાઇપ કરવું એ તમે શીખી લીધું છે. હવે પછી, ઍપ સ્વિચ કરવાની રીત જાણો."
- "તમે પાછા જવાનો સંકેત પૂર્ણ કર્યો છે."
+ "ખાતરી કરો કે તમે એકદમ દૂરની ડાબી કિનારીએથી સ્વાઇપ કરો છો."
+ "ખાતરી કરો કે તમે ડાબી કિનારીએથી સ્ક્રીનના મધ્ય ભાગ સુધી સ્વાઇપ કરો છે અને આંગળી ઊંચકી લો છો."
+ "બસ થઈ ગયું! હવે જમણી કિનારીએથી સ્વાઇપ કરવાનો પ્રયાસ કરો."
+ "ખાતરી કરો કે તમે એકદમ દૂરની જમણી કિનારીએથી સ્વાઇપ કરો છો."
+ "ખાતરી કરો કે તમે જમણી કિનારીએથી સ્ક્રીનના મધ્ય ભાગ સુધી સ્વાઇપ કરો છે અને આંગળી ઊંચકી લો છો."
+ "તમે પાછા જવાનો સંકેત પૂર્ણ કર્યો છે. હવે પછી, હોમ સ્ક્રીન પર જવાની રીત વિશે જાણો.""ખાતરી કરો કે તમારાથી સ્ક્રીનની એકદમ નીચેની કિનારીની ખૂબ નજીક સુધી સ્વાઇપ ન થઈ જાય.""પાછા જવાના સંકેતની સંવેદિતા બદલવા માટે, સેટિંગમાં જાઓ""પાછળ જવા માટે સ્વાઇપ કરો"
@@ -56,27 +58,22 @@
"ખાતરી કરો કે તમે સ્ક્રીનની નીચેની કિનારીએથી ઉપરની તરફ સ્વાઇપ કરો છો.""ખાતરી કરો કે તમે આંગળી ઊંચકી લેતા પહેલાં સ્વાઇપ કરવાનું થોભાવતા નથી.""ખાતરી કરો કે તમે સીધું ઉપરની તરફ સ્વાઇપ કરો છો."
- "તમે હોમ સ્ક્રીન પર પાછા જવાનો સંકેત પૂર્ણ કર્યો છે. હવે પછી, પાછા જવાની રીત વિશે જાણો."
- "તમે હોમ સ્ક્રીન પર પાછા જવાનો સંકેત પૂર્ણ કર્યો છે."
+ "તમે હોમ સ્ક્રીન પર પાછા જવાનો સંકેત પૂર્ણ કર્યો છે. હવે પછી, ઍપ સ્વિચ કરવાની રીત વિશે જાણો.""હોમ સ્ક્રીન પર જવા માટે સ્વાઇપ કરો""તમારી સ્ક્રીનના નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરો. આ સંકેત તમને હંમેશાં હોમ સ્ક્રીન પર લઈ જાય છે.""ખાતરી કરો કે તમે સ્ક્રીનની નીચેની કિનારીએથી ઉપરની તરફ સ્વાઇપ કરો છો.""તમારી આંગળી ઊંચકતા પહેલાં તેને વિન્ડો પર થોડી વધારે વાર માટે દબાવી રાખવાનો પ્રયાસ કરો.""ખાતરી કરો કે તમે સીધું ઉપર સ્વાઇપ કરો છો, પછી થોભી જાઓ છો."
- "સંકેતોનો ઉપયોગ કરવાની રીત વિશે તમે જાણ્યું. સંકેતો બંધ કરવા, સેટિંગમાં જાઓ."
- "તમે ઍપ સ્વિચ કરવાનો સંકેત પૂર્ણ કર્યો છે."
+ "તમે ઍપ સ્વિચ કરવાનો સંકેત પૂર્ણ કર્યો છે. તમે તમારા ફોનનો ઉપયોગ કરવા માટે તૈયાર છો!""ઍપ સ્વિચ કરવા સ્વાઇપ કરો"
- "એક ઍપ પરથી બીજી ઍપ પર સ્વિચ કરવા માટે, તમારી સ્ક્રીનના નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરીને, થોડીવાર દબાવી રાખો, પછી છોડી દો."
+ "તમારી સ્ક્રીનના નીચેના ભાગથી ઉપરની તરફ સ્વાઇપ કરીને, થોડીવાર દબાવી રાખો, પછી છોડી દો.""બધું સેટ થઈ ગયું"
- "થઈ ગયું"
+ "આગળ"
+ "થઈ ગયું""સેટિંગ""ફરી પ્રયાસ કરો""સરસ!""ટ્યૂટૉરિઅલ %1$d/%2$d"
- "બધું સેટ થઈ ગયું!"
- "હોમપેજ પર જવા માટે ઉપરની તરફ સ્વાઇપ કરો"
- "તમે તમારા ફોનનો ઉપયોગ કરવા માટે તૈયાર છો"
- "સિસ્ટમના નૅવિગેશન સેટિંગ""શેર કરો""સ્ક્રીનશૉટ""ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 50ebb27f4b..a7711fe10c 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -45,43 +45,40 @@
"सुझाए गए ऐप्लिकेशन की सुविधा चालू है""सुझाए गए ऐप्लिकेशन की सुविधा बंद है""सुझाया गया ऐप्लिकेशन: %1$s"
- "पक्का करें कि आप स्क्रीन की दाईं या बाईं ओर के बिल्कुल किनारे से स्वाइप कर रहे हों."
- "स्क्रीन के दाएं या बाएं किनारे से स्क्रीन के बीच तक स्वाइप करें और अपनी उंगली उठा लें."
- "आपने स्क्रीन के दाएं किनारे से स्वाइप करके, पिछली स्क्रीन पर वापस जाने का तरीका सीख लिया है. अब, एक ऐप से दूसरे ऐप पर जाने का तरीका सीखें."
- "आपने पेज पर पीछे ले जाने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है."
- "देख लें कि आप स्क्रीन पर बिल्कुल नीचे तक स्वाइप न कर रहे हों."
+ "देख लें कि आप स्क्रीन की बाईं तरफ़ के बिल्कुल किनारे से स्वाइप कर रहे हों."
+ "देख लें कि आप स्क्रीन के बाएं किनारे से बीचों-बीच तक स्वाइप कर रहे हों और फिर अपनी उंगली उठा लें."
+ "हो गया! अब, दाएं किनारे से स्वाइप करने की कोशिश करें."
+ "देख लें कि आप स्क्रीन की दाईं तरफ़ के बिल्कुल किनारे से स्वाइप कर रहे हों."
+ "देख लें कि आप स्क्रीन के दाएं किनारे से बीचों-बीच तक स्वाइप कर रहे हों और फिर अपनी उंगली उठा लें."
+ "आपने पीछे जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है. अब, होम स्क्रीन पर जाने का तरीका जानें."
+ "देखे लें कि आप स्क्रीन पर बिल्कुल नीचे तक स्वाइप न कर रहे हों.""\'सेटिंग\' में जाकर, पीछे जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर (हाव-भाव) की संवेदनशीलता बदलें""पिछली स्क्रीन पर वापस जाने के लिए स्वाइप करें""पिछली स्क्रीन पर वापस जाने के लिए, स्क्रीन के बाएं या दाएं किनारे से बीचों-बीच तक स्वाइप करें.""देख लें कि आप स्क्रीन के निचले किनारे से ऊपर की ओर स्वाइप कर रहे हों.""देख लें कि आप स्क्रीन से अपनी उंगली उठाने से पहले, इसे कहीं न रोक रहे हों.""देख लें कि आप ऊपर की ओर बिल्कुल सीधे स्वाइप कर रहे हों."
- "आपने होम स्क्रीन पर ले जाने वाले हाथ के जेस्चर के बारे में जान लिया है. अब, वापस जाने का तरीका जानें."
- "आपने होम स्क्रीन पर ले जाने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है."
+ "आपने होम स्क्रीन पर जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है. अब, एक से दूसरे ऐप्लिकेशन पर जाने का तरीका जानें.""होम स्क्रीन पर जाने के लिए स्वाइप करें""स्क्रीन पर नीचे से ऊपर की ओर स्वाइप करें. हाथ का यह जेस्चर आपको हमेशा होम स्क्रीन पर ले जाता है.""देख लें कि आप स्क्रीन के निचले किनारे से ऊपर की ओर स्वाइप कर रहे हों.""कोशिश करें कि स्क्रीन से उंगली उठाने से पहले, इसे कुछ देर स्क्रीन पर दबाकर रखें.""देख लें कि आप स्क्रीन पर ऊपर की तरफ़, बिल्कुल सीधे स्वाइप कर रहे हों और फिर रुकें."
- "आपने हाथ के जेस्चर (हाव-भाव) इस्तेमाल करने सीख लिए हैं. जेस्चर बंद करने के लिए, सेटिंग में जाएं."
- "आपने एक ऐप्लिकेशन से दूसरे पर जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर के बारे में जान लिया है."
+ "आपने एक ऐप्लिकेशन से दूसरे पर जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है. आप अपना फ़ोन इस्तेमाल करने के लिए तैयार हैं!""एक ऐप्लिकेशन से दूसरे पर जाने के लिए स्वाइप करें"
- "एक ऐप से दूसरे पर जाने के लिए, स्क्रीन पर नीचे से ऊपर की ओर स्वाइप करें, दबाकर रखें, और फिर छोड़ दें."
+ "अपनी स्क्रीन पर नीचे से ऊपर की तरफ़ स्वाइप करें, दबाकर रखें, फिर छोड़ दें.""आप पूरी तरह तैयार हैं"
- "हो गया"
+ "आगे बढ़ें"
+ "हो गया""सेटिंग""फिर से कोशिश करें""बहुत बढ़िया!""ट्यूटोरियल %1$d/%2$d"
- "हो गया!"
- "होम स्क्रीन पर जाने के लिए, ऊपर की ओर स्वाइप करें"
- "अब आप अपना फ़ोन इस्तेमाल कर सकते हैं"
- "सिस्टम नेविगेशन सेटिंग""शेयर करें"
- "स्क्रीनशॉट लें"
+ "स्क्रीनशॉट""ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता""नेविगेशन ट्यूटोरियल छोड़ना चाहते हैं?"
- "आप बाद में %1$s ऐप्लिकेशन पर इसे देख सकते हैं"
+ "आप बाद में, %1$s ऐप्लिकेशन पर इसे देख सकते हैं""अभी नहीं"
- "अभी नहीं"
+ "छोड़ें"
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 50efb74aab..d5e4b9dd93 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -28,10 +28,10 @@
"%1$s, %2$s""< 1 min""Još %1$s danas"
- "Prijedlozi aplikacija"
+ "Predložene aplikacije""Sve aplikacije""Vaše predviđene aplikacije"
- "Primajte prijedloge aplikacija u donjem retku početnog zaslona"
+ "Prijedloge aplikacija vidjet ćete u donjem retku početnog zaslona""Primajte prijedloge aplikacija u retku omiljenih na početnom zaslonu""Lako pristupite najčešće upotrebljavanim aplikacijama s početnog zaslona. Prijedlozi će se mijenjati na temelju vaših rutina. Aplikacije iz donjeg retka pomaknut će se na početni zaslon.""Lako pristupite najčešće upotrebljavanim aplikacijama s početnog zaslona. Prijedlozi će se mijenjati na temelju vaših rutina. Aplikacije koje se nalaze u retku omiljenih pomaknut će se na početni zaslon."
@@ -45,10 +45,12 @@
"Predlaganje apl. omogućeno""Predlaganje apl. onemogućeno""Predviđena aplikacija: %1$s"
- "Pazite da prijeđete prstom od krajnjeg desnog ili krajnjeg lijevog ruba."
- "Pazite da prijeđete prstom od desnog ili lijevog ruba do sredine zaslona i podignite prst."
- "Naučili ste kako prijeći prstom zdesna da biste se vratili. Sad saznajte kako promijeniti aplikaciju."
- "Izvršili ste pokret za povratak."
+ "Pazite da prijeđete prstom od krajnjeg lijevog ruba."
+ "Pazite da prijeđete prstom od lijevog ruba do sredine zaslona i podignite prst."
+ "To je to! Sad pokušajte prijeći prstom od desnog ruba."
+ "Pazite da prijeđete prstom od krajnjeg desnog ruba."
+ "Pazite da prijeđete prstom od desnog ruba do sredine zaslona i podignite prst."
+ "Izvršili ste pokret za povratak. Sad saznajte kako otvoriti početni zaslon.""Pazite da ne prijeđete prstom preblizu dnu zaslona.""Osjetljivost pokreta povratka promijenite u postavkama""Prijeđite prstom da biste se vratili"
@@ -56,27 +58,22 @@
"Pazite da prijeđete prstom prema gore od donjeg ruba zaslona.""Pazite da ne zastanete prije podizanja prsta.""Pazite da prijeđete prstom ravno prema gore."
- "Izvršili ste pokret za otvaranje početnog zaslona. Sad saznajte kako se vratiti."
- "Izvršili ste pokret za otvaranje početnog zaslona."
+ "Izvršili ste pokret za otvaranje početnog zaslona. Sad saznajte kako promijeniti aplikaciju.""Prijeđite prstom da biste otvorili početni zaslon""Prijeđite prstom od dna zaslona prema gore. Tim pokretom uvijek će se otvoriti početni zaslon.""Pazite da prijeđete prstom prema gore od donjeg ruba zaslona.""Pokušajte zadržati prozor dulje prije podizanja prsta.""Pazite da prijeđete prstom ravno prema gore, a zatim zastanete."
- "Naučili ste koristiti pokrete. Pokrete možete isključiti u postavkama."
- "Izvršili ste pokret za promjenu aplikacije."
- "Povlačenje prstom za promjenu aplikacije"
- "Za promjenu aplikacije prijeđite prstom od dna zaslona prema gore, zadržite pritisak pa pustite."
+ "Izvršili ste pokret za promjenu aplikacije. Spremni ste za upotrebu telefona!"
+ "Prijeđite prstom da biste promijenili aplikaciju"
+ "Prijeđite prstom od dna zaslona prema gore, zadržite pritisak pa podignite prst.""Sve je spremno"
- "Gotovo"
+ "Dalje"
+ "Gotovo""Postavke""Pokušajte ponovo""Odlično!""Vodič %1$d/%2$d"
- "Sve je spremno!"
- "Prijeđite prstom prema gore da biste otvorili početni zaslon"
- "Spremni ste za početak upotrebe telefona"
- "Postavke navigacije sustavom""Podijeli""Snimka zaslona""Aplikacija ili vaša organizacija ne dopuštaju ovu radnju"
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index e9bd2bff8c..386ef3ee3f 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -45,10 +45,12 @@
"Alkalmazásjavaslatok engedélyezve""Alkalmazásjavaslatok letiltva""Várható alkalmazás: %1$s"
- "Csúsztasson a képernyő jobb vagy bal széléről."
- "Csúsztassa ujját a képernyő jobb vagy bal széléről a képernyő közepéig, majd emelje fel."
- "Megtanulta, hogyan léphet vissza jobbról csúsztatva. A következő az appok közötti váltás."
- "Teljesítette a visszalépési kézmozdulatot."
+ "Csúsztasson a képernyő bal széléről."
+ "Csúsztasson a képernyő bal széléről a képernyő közepéig, és engedje el a képernyőt."
+ "Ennyi az egész! Most csúsztasson a jobb szélről."
+ "Csúsztasson a képernyő jobb széléről."
+ "Csúsztasson a képernyő jobb széléről a képernyő közepéig, és engedje el a képernyőt."
+ "Teljesítette a visszalépési kézmozdulatot. Most megtanulhatja, hogyan léphet a kezdőképernyőre.""Ne csúsztasson túl közel a képernyő aljához.""A vissza mozdulat érzékenysége a Beállításokban módosítható""Csúsztasson a visszalépéshez"
@@ -56,27 +58,22 @@
"Csúsztasson felfelé a képernyő aljától.""Ne álljon meg, mielőtt elengedi a képernyőt.""Csúsztasson egyenesen felfelé."
- "Teljesítette a kezdőképernyőre lépés kézmozdulatát. Most megtanulhatja, hogyan léphet vissza."
- "Teljesítette a kezdőképernyőre lépés kézmozdulatát."
+ "Teljesítette a kezdőképernyőre lépés kézmozdulatát. Most megtanulhatja, hogyan válthat az alkalmazások között.""Csúsztatás a kezdőképernyőre lépéshez""Csúsztassa ujját felfelé a képernyő aljától. Ez a mozdulat mindig a kezdőképernyőre visz.""Csúsztasson felfelé a képernyő aljától.""Próbálja tovább lenyomva tartani az ablakot, mielőtt elengedi a képernyőt.""Csúsztasson egyenesen felfelé, majd várjon egy kicsit."
- "Eddig megismerhette a kézmozdulatok használatát. A kézmozdulatokat a Beállításokban kapcsolhatja ki."
- "Teljesítette az alkalmazásváltás kézmozdulatát."
+ "Teljesítette az alkalmazásváltás kézmozdulatát. Készen áll a telefonja használatára!""Alkalmazásváltás csúsztatással"
- "Appok közti váltáshoz csúsztasson felfelé a kép aljáról, tartsa lenyomva az ujját, majd emelje fel."
+ "Csúsztasson felfelé a képernyő aljáról, tartsa lenyomva az ujját, majd emelje fel.""Minden kész"
- "Kész"
+ "Tovább"
+ "Kész""Beállítások""Újra""Remek!""Útmutató (%2$d/%1$d.)"
- "Kész is!"
- "Felfelé csúsztatva megjelenik a Kezdőképernyő"
- "Készen áll a telefon használatára"
- "Rendszer-navigációs beállítások""Megosztás""Képernyőkép""Az alkalmazás vagy az Ön szervezete nem engedélyezi ezt a műveletet"
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index e2c0af37c2..3ff9d0d5c2 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -45,10 +45,12 @@
"«Առաջարկվող հավելվածներ» գործառույթը միացված է""«Առաջարկվող հավելվածներ» գործառույթն անջատված է""Առաջարկվող հավելված՝ %1$s"
- "Համոզվեք, որ մատը սահեցնում եք էկրանի աջ կամ ձախ եզրից։"
- "Մատը սահեցրեք էկրանի աջ կամ ձախ եզրից դեպի կենտրոն և բաց թողեք։"
- "Դուք սովորեցիք՝ ինչպես մատը աջից սահեցնելով հետ գնալ։ Այժմ սովորենք՝ ինչպես անցնել մի հավելվածից մյուսը։"
- "Դուք սովորեցիք հետ գնալու ժեստը։"
+ "Համոզվեք, որ մատը սահեցնում եք էկրանի ձախ եզրից։"
+ "Սահեցրեք մատն էկրանի ձախ եզրից դեպի կենտրոն և բաց թողեք։"
+ "Ահա և վերջ։ Հիմա փորձեք սահեցնել մատն էկրանի աջ եզրից։"
+ "Համոզվեք, որ մատը սահեցնում եք էկրանի աջ եզրից։"
+ "Սահեցրեք մատն էկրանի աջ եզրից դեպի կենտրոն և բաց թողեք։"
+ "Դուք սովորեցիք հետ գնալու ժեստը։ Այժմ սովորենք՝ ինչպես անցնել հիմնական էկրան։""Համոզվեք, որ մատը չափազանց մոտ չեք սահեցնում էկրանին ներքևի հատվածին։""Հետ գնալու ժեստի զգայունությունը փոփոխեք կարգավորումներում""Սահեցրեք մատը՝ հետ գնալու համար"
@@ -56,27 +58,22 @@
"Համոզվեք, որ մատն էկրանի ներքևի եզրից վերև եք սահեցնում։""Համոզվեք, որ դադար չեք տալիս նախքան բաց թողնելը։""Համոզվեք, որ մատն ուղիղ վերև եք սահեցնում։"
- "Դուք սովորեցիք հիմնական էկրան անցնելու ժեստը։ Այժմ սովորենք՝ ինչպես հետ գնալ։"
- "Դուք սովորեցիք հիմնական էկրան անցնելու ժեստը։"
+ "Դուք սովորեցիք հիմնական էկրան անցնելու ժեստը։ Այժմ սովորենք՝ ինչպես անցնել մի հավելվածից մյուսին։""Սահեցրեք մատը՝ հիմնական էկրան անցնելու համար""Մատը սահեցրեք էկրանի ներքևից վերև։ Այս ժեստը բացում է հիմնական էկրանը։""Համոզվեք, որ մատն էկրանի ներքևի եզրից վերև եք սահեցնում։""Նախքան բաց թողնելը փորձեք հնարավորինս երկար պահել պատուհանը։""Համոզվեք, որ մատն ուղիղ վերև եք սահեցնում, այնուհետև դադար տվեք։"
- "Դուք սովորեցիք՝ ինչպես օգտագործել ժեստերը։ Ժեստերը կարող եք անջատել կարգավորումներում։"
- "Դուք սովորեցիք մի հավելվածից մյուսն անցնելու ժեստը։"
+ "Դուք սովորեցիք մի հավելվածից մյուսին անցնելու ժեստը։ Այժմ հանգիստ կարող եք օգտագործել ձեր հեռախոսը։""Մատը սահեցրեք՝ մյուս հավելվածին անցնելու համար"
- "Մեկ հավելվածից մյուսն անցնելու համար մատը էկրանի ներքևից սահեցրեք վերև, ապա հեռացրեք այն էկրանից։"
+ "Մատը սահեցրեք էկրանի ներքևից վերև, պահեք և բաց թողեք։""Պատրաստ է"
- "Պատրաստ է"
+ "Առաջ"
+ "Պատրաստ է""Կարգավորումներ""Նորից փորձեք""Գերազանց է""Ուղեցույց %1$d/%2$d"
- "Պատրաստ է"
- "Մատը սահեցրեք վերև՝ հիմնական էկրան անցնելու համար"
- "Դուք արդեն կարող եք օգտագործել ձեր հեռախոսը"
- "Նավիգացիայի համակարգային կարգավորումներ""Կիսվել""Սքրինշոթ անել""Այս գործողությունն արգելված է հավելվածի կամ ձեր կազմակերպության կողմից"
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 3e24fcb620..941bdb7dd0 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -45,10 +45,12 @@
"Saran aplikasi diaktifkan""Saran aplikasi dinonaktifkan""Aplikasi yang diprediksi: %1$s"
- "Pastikan Anda menggeser dari tepi ujung kanan atau ujung kiri."
- "Pastikan Anda menggeser dari tepi kanan atau kiri ke tengah layar, lalu lepaskan."
- "Anda telah belajar cara geser dari kanan untuk kembali. Berikutnya, pelajari cara beralih aplikasi."
- "Anda telah menyelesaikan gestur kembali."
+ "Pastikan Anda menggeser dari tepi ujung kiri."
+ "Pastikan Anda menggeser dari tepi kiri ke tengah layar, lalu lepaskan."
+ "Selesai. Sekarang, coba geser dari tepi kanan."
+ "Pastikan Anda menggeser dari tepi ujung kanan."
+ "Pastikan Anda menggeser dari tepi kanan ke tengah layar, lalu lepaskan."
+ "Anda telah menyelesaikan gestur kembali. Selanjutnya, pelajari cara beralih ke Layar utama.""Pastikan Anda tidak menggeser terlalu dekat ke bagian bawah layar.""Untuk mengubah sensitivitas gestur kembali, buka Setelan""Geser untuk kembali"
@@ -56,27 +58,22 @@
"Pastikan Anda menggeser ke atas dari tepi bawah layar.""Pastikan Anda tidak menjeda sebelum melepaskan.""Pastikan Anda menggeser lurus ke atas."
- "Anda telah menyelesaikan gestur menuju Layar utama. Selanjutnya, pelajari cara beralih kembali."
- "Anda telah menyelesaikan gestur menuju Layar utama."
+ "Anda telah menyelesaikan gestur beralih ke Layar utama. Selanjutnya, pelajari cara beralih aplikasi.""Geser untuk beralih ke layar utama""Geser ke atas dari bagian bawah layar. Gestur ini akan selalu membawa Anda ke Layar utama.""Pastikan Anda menggeser ke atas dari tepi bawah layar.""Coba tahan jendela lebih lama sebelum melepaskan.""Pastikan Anda menggeser lurus ke atas, lalu menjedanya."
- "Anda telah mempelajari cara menggunakan gestur. Untuk menonaktifkan gestur, buka Setelan."
- "Anda telah menyelesaikan gestur beralih aplikasi."
+ "Anda telah menyelesaikan gestur beralih aplikasi. Anda siap menggunakan ponsel Anda!""Geser untuk beralih aplikasi"
- "Untuk beralih antar-aplikasi, geser ke atas dari bagian bawah layar, tahan, lalu lepaskan."
+ "Geser ke atas dari bagian bawah layar, tahan, lalu lepaskan.""Semua siap"
- "Selesai"
+ "Berikutnya"
+ "Selesai""Setelan""Coba lagi""Bagus!""Tutorial %1$d/%2$d"
- "Semua siap."
- "Geser ke atas untuk beralih ke Layar utama"
- "Anda sudah siap untuk mulai menggunakan ponsel"
- "Setelan navigasi sistem""Bagikan""Screenshot""Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index eeebc7136b..6042b47e45 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -45,10 +45,12 @@
"Kveikt á tillögum að forritum""Slökkt er á tillögðum forritum""Tillaga að forriti: %1$s"
- "Passaðu að strjúka frá jaðri hægri eða vinstri brúnar."
- "Passaðu að strjúka frá jaðri hægri eða vinstri brúnar að miðju skjásins og sleppa síðan."
- "Þú lærðir að strjúka frá hægri til að bakka. Næst skaltu læra hvernig þú skiptir á milli forrita."
- "Þú laukst við að kynna þér bendinguna „til baka“."
+ "Passaðu að strjúka frá jaðri vinstri brúnar."
+ "Passaðu að strjúka frá vinstri brún skjásins að miðju hans og sleppa svo."
+ "Það er komið! Prófaðu að strjúka frá vinstri brúninni."
+ "Passaðu að strjúka frá jaðri hægri brúnar."
+ "Passaðu að strjúka frá hægri brún skjásins að miðju hans og sleppa svo."
+ "Þú laukst við að kynna þér bendinguna „til baka“. Næst skaltu læra hvernig þú ferð „heim“.""Passaðu að strjúka ekki of nálægt neðri brún skjásins.""Til að breyta næmi til baka-bendingar ferðu í stillingar""Strjúktu til að fara til baka"
@@ -56,27 +58,22 @@
"Passaðu að strjúka upp frá neðri brún skjásins.""Passaðu að stoppa ekki áður en þú sleppir.""Passaðu að strjúka beint upp."
- "Þú laukst við að kynna þér bendinguna „heim“. Næst skaltu læra hvernig þú ferð „til baka“."
- "Þú laukst við að kynna þér bendinguna „heim“."
+ "Þú laukst við að kynna þér bendinguna „heim“. Næst skaltu læra hvernig þú skiptir á milli forrita.""Strjúktu til að fara heim""Strjúktu upp frá neðri hluta skjásins. Þetta flytur þig alltaf á heimaskjáinn.""Passaðu að strjúka upp frá neðri brún skjásins.""Prófaðu að halda fingrinum lengur á glugganum áður en þú sleppir.""Passaðu að strjúka beint upp og stoppa svo."
- "Þú kynntir þér hvernig á að nota bendingar. Opnaðu stillingar til að slökkva á bendingum."
- "Þú laukst við að kynna þér bendinguna „skipta um forrit“."
+ "Þú laukst við að kynna þér bendinguna „skipta um forrit“. Nú geturðu notað símann þinn!""Strjúktu til að skipta á milli forrita"
- "Strjúktu upp frá neðri hluta skjásins, haltu og slepptu svo til að skipta á milli forrita."
+ "Strjúktu upp frá neðri hluta skjásins, haltu fingrinum á skjánum og slepptu svo.""Allt til reiðu"
- "Lokið"
+ "Áfram"
+ "Lokið""Stillingar""Reyna aftur""Flott!""Leiðsögn %1$d/%2$d"
- "Allt tilbúið!"
- "Strjúktu upp til að fara á heimaskjáinn"
- "Þú getur byrjað að nota símann"
- "Stillingar kerfisstjórnunar""Deila""Skjámynd""Forritið eða fyrirtækið leyfir ekki þessa aðgerð"
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 5a33a38161..6c81d1720e 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -19,7 +19,7 @@
- "Blocca su schermo"
+ "Blocca""Forma libera""Nessun elemento recente""Impostazioni di utilizzo delle app"
@@ -45,10 +45,12 @@
"La funzionalità app suggerite è attiva""La funzionalità app suggerite è disattivata""App prevista: %1$s"
- "Assicurati di scorrere dal bordo all\'estrema destra o all\'estrema sinistra."
- "Assicurati di scorrere dal bordo destro o sinistro verso il centro dello schermo e solleva il dito."
- "Hai imparato a scorrere da destra per tornare indietro. Ora impara come passare da un\'app all\'altra."
- "Hai completato il gesto Indietro."
+ "Assicurati di scorrere dall\'estremità del bordo sinistro."
+ "Assicurati di scorrere dal bordo sinistro verso il centro dello schermo e solleva il dito."
+ "È tutto. Ora prova a scorrere dal bordo destro."
+ "Assicurati di scorrere dall\'estremità del bordo destro."
+ "Assicurati di scorrere dal bordo destro verso il centro dello schermo e solleva il dito."
+ "Hai completato il gesto Indietro. Ora, impara come andare alla schermata Home.""Assicurati di non scorrere troppo vicino alla parte inferiore dello schermo.""Usa Impostazioni per cambiare sensibilità del gesto Indietro""Scorri per tornare indietro"
@@ -56,27 +58,22 @@
"Assicurati di scorrere verso l\'alto dal bordo inferiore dello schermo.""Assicurati di non fare pause prima di sollevare il dito.""Assicurati di scorrere verso l\'alto senza fermarti."
- "Hai completato il gesto per andare alla schermata Home. Ora, impara come tornare indietro."
- "Hai completato il gesto Vai alla schermata Home."
+ "Hai completato il gesto Vai alla schermata Home. Ora, impara come passare da un\'app all\'altra.""Scorri per andare alla schermata Home"
- "Scorri verso l\'alto dalla parte inferiore dello schermo. Questo gesto ti porta sempre alla schermata Home."
+ "Scorri verso l\'alto dalla parte inferiore dello schermo; così arrivi sempre alla schermata Home.""Assicurati di scorrere verso l\'alto dal bordo inferiore dello schermo.""Prova a tenere premuta la finestra più a lungo prima di rilasciarla.""Assicurati di scorrere verso l\'alto senza fermarti, poi fai una pausa."
- "Hai imparato a usare i gesti. Per disattivarli, vai alle Impostazioni."
- "Hai completato il gesto Cambia app."
+ "Hai completato il gesto Cambia app. Ora è tutto pronto per usare il telefono.""Scorri per passare da un\'app all\'altra"
- "Per spostarti tra le app, scorri verso l\'alto dal fondo dello schermo, tieni premuto e rilascia."
+ "Scorri verso l\'alto dalla parte inferiore dello schermo, tieni premuto e rilascia.""Fatto"
- "Fine"
+ "Avanti"
+ "Fine""Impostazioni""Riprova""Bene!""Tutorial %1$d/%2$d"
- "Finito."
- "Scorri verso l\'alto per andare alla schermata Home"
- "Puoi iniziare a usare il tuo telefono"
- "Impostazioni Navigazione del sistema""Condividi""Screenshot""Questa azione non è consentita dall\'app o dall\'organizzazione"
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 267769093b..b77faeb4fa 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -33,22 +33,24 @@
"האפליקציות החזויות שלך""קבלת הצעות לאפליקציות בשורה התחתונה של מסך הבית""קבלת הצעות לאפליקציות בשורת המועדפות של מסך הבית"
- "גישה נוחה לאפליקציות שנעשה בהן שימוש תכוף – ישירות ממסך הבית. ההצעות ישתנו בהתאם להרגלי השימוש שלך. אפליקציות שמופיעות בשורה התחתונה יעברו למעלה למסך הבית."
+ "גישה נוחה לאפליקציות הכי נפוצות ישירות ממסך הבית. ההצעות ישתנו בהתאם להרגלי השימוש שלך. אפליקציות שמופיעות בשורה התחתונה יעברו למעלה למסך הבית.""גישה נוחה לאפליקציות שהשתמשת בהן הכי הרבה, ישירות ממסך הבית. ההצעות ישתנו בהתאם להרגלי השימוש שלך. אפליקציות בשורת המועדפות יועברו למסך הבית."
- "גישה נוחה לאפליקציות שנעשה בהן שימוש תכוף – ישירות ממסך הבית. ההצעות ישתנו בהתאם להרגלי השימוש שלך. אפליקציות שמופיעות בשורה התחתונה יעברו לתיקייה חדשה."
+ "גישה נוחה לאפליקציות הכי נפוצות ישירות ממסך הבית. ההצעות ישתנו בהתאם להרגלי השימוש שלך. אפליקציות שמופיעות בשורה התחתונה יעברו למעלה למסך הבית.""קבלת הצעות לאפליקציות""לא, תודה""הגדרות""רוב האפליקציות הכי נפוצות מופיעות כאן ומשתנות בהתאם להרגלי השימוש שלך"
- "כדי לקבל הצעות נוספות לאפליקציות, צריך לגרור אפליקציות מהשורה התחתונה"
+ "יש לגרור אפליקציות מהשורה התחתונה כדי לקבל הצעות לאפליקציות""הצעות לאפליקציות נוספו לאזור ריק"
- "התכונה \'הצעות לאפליקציות\' מופעלת"
+ "ההצעות לאפליקציות מופעלות""ההצעות לאפליקציות מושבתות""האפליקציות החזויות: %1$s"
- "חשוב להקפיד להחליק מהקצה השמאלי או הימני."
- "חשוב להקפיד להחליק מהקצה השמאלי או הימני למרכז המסך ואז לשחרר."
- "למדת איך להחליק מצד ימין כדי לחזור אחורה. בשלב הבא לומדים איך לעבור בין אפליקציות."
- "השלמת את תנועת \'הקודם\'."
+ "חשוב להקפיד להחליק מהקצה הימני."
+ "חשוב להקפיד להחליק מהקצה הימני למרכז המסך ואז לשחרר."
+ "זהו! עכשיו צריך לנסות להחליק מהקצה השמאלי."
+ "חשוב להקפיד להחליק מהקצה השמאלי."
+ "חשוב להקפיד להחליק מהקצה השמאלי למרכז המסך ואז לשחרר."
+ "השלמת את תנועת \'הקודם\'. בשלב הבא לומדים איך לעבור למסך הבית.""חשוב להקפיד שלא להחליק קרוב מדי לתחתית המסך.""כדי לשנות את מידת הרגישות של תנועת החזרה, יש לעבור להגדרות""יש להחליק כדי לחזור"
@@ -56,27 +58,22 @@
"חשוב להקפיד להחליק למעלה מהקצה התחתון של המסך.""חשוב לוודא שלא מחכים לפני שמשחררים.""חשוב להקפיד להחליק ישר למעלה."
- "השלמת את תנועת המעבר למסך הבית. בשלב הבא לומדים איך לחזור למסך הקודם."
- "השלמת את תנועת המעבר למסך הבית."
+ "השלמת את תנועת המעבר למסך הבית. בשלב הבא לומדים איך לעבור בין אפליקציות.""יש להחליק כדי לעבור למסך הבית""החלקה למעלה מתחתית המסך תמיד תעביר אותך למסך הבית.""חשוב להקפיד להחליק למעלה מהקצה התחתון של המסך."
- "אפשר להחזיק את החלון זמן רב יותר לפני שמשחררים."
+ "יש לנסות להחזיק את החלון לזמן רב יותר לפני שמשחררים.""חשוב להקפיד להחליק ישר למעלה ואז להמתין."
- "למדת איך להשתמש בתנועות. ניתן להשבית את התנועות ב\'הגדרות\'."
- "השלמת את תנועת המעבר בין האפליקציות."
+ "השלמת את תנועת המעבר בין האפליקציות. הטלפון מוכן לשימוש!""יש להחליק כדי לעבור בין אפליקציות"
- "כדי לעבור בין אפלקציות, יש להחליק למעלה מתחתית המסך, להחזיק ולאחר מכן לשחרר."
+ "יש להחליק למעלה מתחתית המסך, להחזיק ולאחר מכן לשחרר.""הכול מוכן"
- "סיום"
+ "הבא"
+ "סיום""הגדרות"
- "ניסיון חוזר"
+ "אפשר לנסות שוב""איזה יופי!""מדריך %1$d/%2$d"
- "הכול מוכן!"
- "כדי לעבור לדף הבית, מחליקים כלפי מעלה"
- "הכול מוכן ואפשר להתחיל להשתמש בטלפון"
- "הגדרות הניווט של המערכת""שיתוף""צילום מסך""האפליקציה או הארגון שלך אינם מתירים את הפעולה הזאת"
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 9c2adefecd..1cbdf7331c 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -31,9 +31,9 @@
"アプリの候補""すべてのアプリ""予測されたアプリ"
- "ホーム画面の一番下にアプリの候補を表示できます"
+ "ホーム画面の一番下の行でアプリの候補を利用できます""ホーム画面のお気に入りの行でアプリの候補を利用できます"
- "ホーム画面で、使用頻度の高いアプリに簡単にアクセスできるようになります。アプリの候補はルーティンに応じて変わります。一番下の行にあるアプリは上に移動します。"
+ "ホーム画面で、使用頻度の高いアプリに簡単にアクセスできるようになります。アプリの候補はルーティンに応じて変わります。一番下の行にあるアプリがホーム画面に移動します。""ホーム画面で、使用頻度の高いアプリに簡単にアクセスできるようになります。アプリの候補はルーティンに応じて変わります。お気に入りの行にあるアプリがホーム画面に移動します。""ホーム画面で、使用頻度の高いアプリに簡単にアクセスできるようになります。アプリの候補はルーティンに応じて変わります。一番下の行にあるアプリが新しいフォルダに移動します。""アプリの候補を利用"
@@ -42,46 +42,43 @@
"使用頻度の高いアプリがここに表示されます(ルーティンに応じて変わります)""一番下の行からアプリをドラッグするとアプリの候補が表示されます""空いたスペースにアプリの候補が追加されます"
- "アプリの候補表示が有効です"
+ "アプリの候補は有効です""アプリの候補は無効です""予測されたアプリ: %1$s"
- "右端または左端からスワイプしてください。"
- "画面の右端または左端から中央に向かってスワイプし、指を離してください。"
- "右側からスワイプして前の画面に戻る方法を学習しました。次は、アプリを切り替える方法を覚えましょう。"
- "「戻る」操作を学習しました。"
+ "一番左端からスワイプしてください。"
+ "画面の左端から中央に向かってスワイプし、指を離してください。"
+ "そのとおりです。次に、右端からスワイプしてみましょう。"
+ "一番右端からスワイプしてください。"
+ "画面の右端から中央に向かってスワイプし、指を離してください。"
+ "「戻る」操作を完了しました。次は、ホームに戻る方法を覚えましょう。""スワイプする際は画面の下部に近づきすぎないようにしましょう。""「戻る」操作の感度を変更するには [設定] に移動します"
- "スワイプで戻る"
+ "スワイプで戻りましょう""直前の画面に戻るには、画面の左端または右端から中央に向かってスワイプします。""画面の下端から上にスワイプしてください。""指を離す前にいったん止めないでください。""まっすぐ上にスワイプしてください。"
- "「ホームに戻る」操作を学習しました。次は、前の画面に戻る方法を覚えましょう。"
- "「ホームに戻る」操作を学習しました。"
+ "「ホームに戻る」操作を完了しました。次は、アプリを切り替える方法を覚えましょう。""スワイプでホームに戻る""画面を下から上にスワイプします。この操作でいつでもホーム画面に戻れます。""画面の下端から上にスワイプしてください。"
- "ウィンドウをもう少し長く押してから指を離すようにしてみましょう。"
+ "指を離す前にウィンドウをもう少し長押ししてみましょう。""まっすぐ上にスワイプしてから、いったん指を止めてください。"
- "主な操作方法を覚えました。操作を OFF にするには、設定に移動してください。"
- "「アプリを切り替える」操作を完了しました。"
- "スワイプでアプリを切り替える"
- "アプリを切り替えるには、画面を下から上にスワイプして長押しし、指を離します。"
+ "「アプリを切り替える」操作を完了しました。スマートフォンをご利用いただけるようになりました。"
+ "スワイプでアプリを切り替え"
+ "画面を下から上にスワイプして長押しし、指を離します。""設定完了"
- "完了"
+ "次へ"
+ "完了""設定"
- "もう一度"
- "成功しました"
+ "再試行"
+ "成功""チュートリアル %1$d/%2$d"
- "設定完了"
- "ホームに移動するには上にスワイプします"
- "スマートフォンを使い始めることができます"
- "システム ナビゲーションの設定""共有""スクリーンショット""この操作はアプリまたは組織で許可されていません""操作チュートリアルをスキップしますか?"
- "チュートリアルは後から %1$s アプリで確認できます"
+ "これは後から %1$s アプリで確認できます""キャンセル""スキップ"
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index d9420c826c..5dd818d9ac 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -45,10 +45,12 @@
"აპის შეთავაზებები ჩართულია""აპის შეთავაზებები გათიშულია""ნაწინასწარმეტყველები აპი: %1$s"
- "გადაფურცლეთ უკიდურესი მარჯვენა ან მარცხენა ბოლოდან."
- "გადაფურცლეთ მარჯვენა ან მარცხენა კიდიდან ეკრანის ცენტრისკენ და თითი აუშვით."
- "თქვენ ისწავლეთ მარჯვნიდან გადაფურცვლა უკან დასაბრუნებლად. ახლა კი შეიტყვეთ, როგორ გადართოთ აპები."
- "თქვენ შეასრულეთ უკან დაბრუნების ჟესტი."
+ "არ გადაფურცლოთ მარცხენა კიდის ბოლოდან."
+ "გადაფურცლეთ მარცხენა კიდიდან ეკრანის ცენტრისკენ და თითი აუშვით."
+ "სულ ეს არის! ახლა კი ცადეთ, გადაფურცლოთ მარჯვენა კიდიდან."
+ "არ გადაფურცლოთ მარჯვენა კიდის ბოლოდან."
+ "გადაფურცლეთ მარჯვენა კიდიდან ეკრანის ცენტრისკენ და თითი აუშვით."
+ "თქვენ შეასრულეთ უკან დაბრუნების ჟესტი. ახლა კი შევიტყოთ, თუ როგორ დავბრუნდეთ მთავარ გვერდზე.""არ გადაფურცლოთ ეკრანის ბოლოსთან ახლოს.""დაბრუნების ჟესტის მგრძნობელობის შესაცვლელად გადადით პარამეტრებზე""უკან დასაბრუნებლად გადაფურცლეთ"
@@ -56,27 +58,22 @@
"გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ.""არ დააპაუზოთ თითის აშვებამდე.""გადაფურცლეთ ზემოთ."
- "თქვენ შეასრულეთ მთავარ ეკრანზე დაბრუნების ჟესტი. ახლა კი შევიტყოთ, თუ როგორ დავბრუნდეთ უკან."
- "თქვენ შეასრულეთ მთავარ ეკრანზე დაბრუნების ჟესტი."
- "მთავარი გვერდის სანახავად გადაფურცლეთ"
+ "თქვენ შეასრულეთ მთავარ ეკრანზე დაბრუნების ჟესტი. ახლა კი შევიტყოთ, როგორ გადავრთოთ აპები."
+ "მთავარ გვერდზე გადასასვლელად გადაფურცლეთ""გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ. ამ ჟესტს ყოველთვის მთავარი გვერდის ეკრანზე გადაყავხართ.""გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ.""უფრო ხანგრძლივად დააჭირეთ თითი ფანჯარას, რომ არ დაიხუროს.""გადაფურცლეთ პირდაპირ ზემოთ და შემდეგ დააპაუზეთ."
- "თქვენ ისწავლეთ ჟესტების გამოყენება. ჟესტების გამოსართავად გადადით პარამეტრებში."
- "თქვენ შეასრულეთ აპების გადართვის ჟესტი."
+ "თქვენ შეასრულეთ აპების გადართვის ჟესტი. შეგიძლიათ ტელეფონით სარგებლობა!""აპების გადასართავად გადაფურცლეთ"
- "აპების გადასართავად, გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ, დააყოვნეთ, შემდეგ თითი აუშვით."
+ "გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ, დააყოვნეთ, შემდეგ თითი აუშვით.""მზად არის"
- "მზადაა"
+ "შემდეგ"
+ "მზადაა""პარამეტრები""ხელახლა ცდა""მშვენიერია!""სახელმძღვანელო %1$d/%2$d"
- "მზადაა!"
- "მთავარ გვერდზე გადასასვლელად გადაფურცლეთ ზევით"
- "მზად ხართ ტელეფონის გამოსაყენებლად"
- "სისტემის ნავიგაციის პარამეტრები""გაზიარება""ეკრანის ანაბეჭდი""ეს მოქმედება არ არის დაშვებული აპის ან თქვენი ორგანიზაციის მიერ"
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index d762bd87a9..554d10dc82 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -29,7 +29,7 @@
"< 1 мин""Бүгін %1$s қалды""Ұсынылған қолданбалар"
- "Барлық қолданба"
+ "Барлық қолданбалар""Ұсынылатын қолданбалар""Негізгі экранның төменгі жолында қолданбаларды ұсыну""Ұсынылған қолданбалар негізгі экранда таңдаулылар арасында көрсетілетін болады"
@@ -42,13 +42,15 @@
"Жиі пайдаланылатын қолданбалар осы жерде көрсетіледі. Олар күнделікті әрекеттеріңізге сәйкес өзгереді.""Ұсынылған қолданбаларды көру үшін төменгі қатардан керектерін сүйреп шығарыңыз.""Ұсынылған қолданбалар бос орынға қосылды."
- "Ұсынылған қолданбалар функциясы қосылды."
+ "\"Ұсынылған қолданбалар\" функциясы қосулы.""\"Ұсынылған қолданбалар\" функциясы өшірулі.""Болжалды қолданба: %1$s"
- "Экранның оң немесе сол жиегінен сырғытыңыз."
- "Экранның оң немесе сол жиегінен ортасына қарай сырғытып, саусағыңызды жіберіңіз."
- "Оңнан солға сырғыту арқылы артқа қайтуды үйрендіңіз. Енді қолданбаларды ауыстыруды үйреніңіз."
- "Артқа қайту қимылын аяқтадыңыз."
+ "Сол жақтағы ең шеткі нүктеден бастап сырғытыңыз."
+ "Экранның сол жақ шетінен ортасына қарай сырғытыңыз да, жіберіңіз."
+ "Дайын! Енді оң жақ шеттен сырғытып көріңіз."
+ "Оң жақтағы ең шеткі нүктеден бастап сырғытыңыз."
+ "Экранның оң жақ шетінен ортасына қарай сырғытыңыз да, жіберіңіз."
+ "Артқа қайту қимылын аяқтадыңыз. Енді негізгі экранға өтуді үйреніңіз.""Саусағыңызбен сырғыту кезінде экранның төменгі жағына тым жақындамаңыз.""Артқа қайту қимылы сезгіштігін параметрлерден өзгертіңіз.""Артқа қайту үшін сырғытыңыз"
@@ -56,27 +58,22 @@
"Экранның төменгі шетінен жоғары қарай сырғытыңыз.""Жіберер алдында кідіріс жасамаңыз.""Тігінен жоғары қарай сырғытыңыз."
- "Негізгі экранға қайту қимылын аяқтадыңыз. Енді артқа қайтуды үйреніңіз."
- "Негізгі экранға қайту қимылын аяқтадыңыз."
+ "Негізгі экранға қайту қимылын аяқтадыңыз. Енді қолданбаларды ауыстыруды үйреніңіз.""Негізгі экранға өту үшін сырғытыңыз""Экранның төменгі жағынан жоғары қарай сырғытыңыз. Сонда негізгі экран ашылады.""Экранның төменгі шетінен жоғары қарай сырғытыңыз.""Жіберер алдында терезені ұзағырақ ұстап тұруға тырысыңыз.""Тігінен жоғары қарай сырғытыңыз да, кідіріңіз."
- "Қимылдарды қолдануды үйрендіңіз. Қимылдарды өшіру үшін \"Параметрлер\" бөліміне өтіңіз."
- "Қолданбаларды ауыстыру қимылын аяқтадыңыз."
+ "Қолданбаларды ауыстыру қимылын аяқтадыңыз. Телефоныңызды пайдалануға дайынсыз!""Қолданбаларды ауыстыру үшін сырғытыңыз"
- "Бір қолданбадан екіншісіне ауысу үшін экранның төменгі жағынан жоғары қарай сырғытып, ұстап тұрып жіберіңіз."
+ "Экранның төменгі жағынан жоғары қарай сырғытып, ұстап тұрыңыз да, жіберіңіз.""Бәрі дайын"
- "Дайын"
+ "Келесі"
+ "Дайын""Параметрлер""Қайталау""Жақсы!""Оқулық: %1$d/%2$d"
- "Бәрі дайын!"
- "Негізгі экранға өту үшін жоғары қарай сырғытыңыз."
- "Телефоныңыз пайдалануға дайын."
- "Навигацияның жүйелік параметрлері""Бөлісу""Скриншот""Бұл әрекетке қолданба не ұйым рұқсат етпейді."
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 2700b8383c..62858ba625 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -45,10 +45,12 @@
"បានបើកការណែនាំកម្មវិធី""បានបិទការណែនាំកម្មវិធី""កម្មវិធីដែលបានព្យាករ៖ %1$s"
- "ត្រូវប្រាកដថាអ្នកអូសពីគែមខាងស្ដាំ ឬខាងឆ្វេង។"
- "ត្រូវប្រាកដថាអ្នកអូសពីគែមខាងស្ដាំ ឬខាងឆ្វេងទៅផ្នែកកណ្ដាលនៃអេក្រង់ រួចដកដៃ។"
- "អ្នកបានស្វែងយល់ពីរបៀបអូសពីខាងស្ដាំ ដើម្បីថយក្រោយ។ បន្ទាប់ទៀត សូមស្វែងយល់ពីរបៀបប្ដូរកម្មវិធី។"
- "អ្នកបានបញ្ចប់ចលនាថយក្រោយហើយ។"
+ "ត្រូវប្រាកដថាអ្នកអូសពីចុងគែមខាងឆ្វេង។"
+ "ត្រូវប្រាកដថាអ្នកអូសពីគែមខាងឆ្វេងទៅផ្នែកកណ្ដាលនៃអេក្រង់ រួចដកដៃ។"
+ "ត្រឹមត្រូវហើយ! ឥឡូវនេះ សូមសាកល្បងអូសពីគែមខាងស្ដាំ។"
+ "ត្រូវប្រាកដថាអ្នកអូសពីចុងគែមខាងស្ដាំ។"
+ "ត្រូវប្រាកដថាអ្នកអូសពីគែមខាងស្ដាំទៅផ្នែកកណ្ដាលនៃអេក្រង់ រួចដកដៃ។"
+ "អ្នកបានបញ្ចប់ចលនាថយក្រោយហើយ។ បន្ទាប់ទៀត សូមស្វែងយល់ពីរបៀបចូលទៅកាន់អេក្រង់ដើម។""ត្រូវប្រាកដថាអ្នកមិនអូសទៅជិតផ្នែកខាងក្រោមនៃអេក្រង់ពេក។""ដើម្បីប្ដូរកម្រិតរំញោចនឹងចលនាថយក្រោយ សូមចូលទៅកាន់ការកំណត់""អូសដើម្បីត្រឡប់ទៅវិញ"
@@ -56,27 +58,22 @@
"ត្រូវប្រាកដថាអ្នកអូសឡើងលើពីគែមខាងក្រោមនៃអេក្រង់។""ត្រូវប្រាកដថាអ្នកមិនផ្អាក មុនពេលដកដៃ។""ត្រូវប្រាកដថាអ្នកអូសត្រង់ឡើងលើ។"
- "អ្នកបានបញ្ចប់ចលនាចូលទៅកាន់ទំព័រដើមហើយ។ បន្ទាប់មកទៀត សូមស្វែងយល់ពីរបៀបថយក្រោយ។"
- "អ្នកបានបញ្ចប់ចលនាចូលទៅកាន់ទំព័រដើមហើយ។"
+ "អ្នកបានបញ្ចប់ចលនាចូលទៅកាន់អេក្រង់ដើមហើយ។ បន្ទាប់ទៀត សូមស្វែងយល់ពីរបៀបប្ដូរកម្មវិធី។""អូសដើម្បីចូលទៅកាន់អេក្រង់ដើម""អូសឡើងលើពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នក។ ចលនានេះនាំអ្នកទៅអេក្រង់ដើមជានិច្ច។""ត្រូវប្រាកដថាអ្នកអូសឡើងលើពីគែមខាងក្រោមនៃអេក្រង់។""សាកល្បងសង្កត់វិនដូឱ្យបានយូរជាងនេះ មុនពេលដកដៃ។""ត្រូវប្រាកដថាអ្នកអូសត្រង់ឡើងលើ រួចផ្អាក។"
- "អ្នកបានស្វែងយល់អំពីរបៀបប្រើចលនាហើយ។ ដើម្បីបិទចលនា សូមចូលទៅកាន់ការកំណត់។"
- "អ្នកបានបញ្ចប់ចលនាប្ដូរកម្មវិធីហើយ។"
+ "អ្នកបានបញ្ចប់ចលនាប្ដូរកម្មវិធីហើយ។ អ្នកអាចប្រើទូរសព្ទរបស់អ្នកបានហើយ!""អូសដើម្បីប្ដូរកម្មវិធី"
- "ដើម្បីប្ដូររវាងកម្មវិធី សូមអូសឡើងលើពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នក រួចចុចឱ្យជាប់ បន្ទាប់មកដកដៃចេញ។"
+ "អូសឡើងលើពីផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នក រួចសង្កត់ឱ្យជាប់ បន្ទាប់មកដកដៃចេញ។""រួចហើយ"
- "រួចរាល់"
+ "បន្ទាប់"
+ "រួចរាល់""ការកំណត់""ព្យាយាមម្ដងទៀត""ល្អ!""មេរៀនទី %1$d/%2$d"
- "រួចហើយ!"
- "អូសឡើងលើ ដើម្បីទៅកាន់អេក្រង់ដើម"
- "អ្នកអាចចាប់ផ្ដើមប្រើទូរសព្ទរបស់អ្នកបានហើយ"
- "ការកំណត់ការរុករកប្រព័ន្ធ""ចែករំលែក""រូបថតអេក្រង់""សកម្មភាពនេះមិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី ឬស្ថាប័នរបស់អ្នកទេ"
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 9b981c2b58..8fdba693bf 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -33,9 +33,9 @@
"ನಿಮ್ಮ ಮುನ್ಸೂಚಿತ ಆ್ಯಪ್ಗಳು""ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದ ಸಾಲಿನಲ್ಲಿ ಆ್ಯಪ್ ಸಲಹೆಗಳನ್ನು ಪಡೆಯಿರಿ""ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ನ ಮೆಚ್ಚಿನವುಗಳ ಸಾಲಿನಲ್ಲಿ ಆ್ಯಪ್ ಸಲಹೆಗಳನ್ನು ಪಡೆಯಿರಿ"
- "ನೀವು ಹೆಚ್ಚು ಬಳಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿಯೇ ಸುಲಭವಾಗಿ ಪ್ರವೇಶಿಸಿ. ನಿಮ್ಮ ದಿನಚರಿಯನ್ನು ಆಧರಿಸಿ ಸಲಹೆಗಳು ಬದಲಾಗುತ್ತವೆ. ಕೆಳಭಾಗದ ಸಾಲಿನಲ್ಲಿನ ಆ್ಯಪ್ಗಳು ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ ಚಲಿಸುತ್ತವೆ."
- "ನೀವು ಹೆಚ್ಚು ಬಳಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿಯೇ ಸುಲಭವಾಗಿ ಪ್ರವೇಶಿಸಿ. ನಿಮ್ಮ ದಿನಚರಿಯನ್ನು ಆಧರಿಸಿ ಸಲಹೆಗಳು ಬದಲಾಗುತ್ತವೆ. ಮೆಚ್ಚಿನವುಗಳ ಸಾಲಿನಲ್ಲಿನ ಆ್ಯಪ್ಗಳು ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಚಲಿಸುತ್ತವೆ."
- "ನೀವು ಹೆಚ್ಚು ಬಳಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿಯೇ ಸುಲಭವಾಗಿ ಪ್ರವೇಶಿಸಿ. ನಿಮ್ಮ ದಿನಚರಿಯನ್ನು ಆಧರಿಸಿ ಸಲಹೆಗಳು ಬದಲಾಗುತ್ತವೆ. ಕೆಳಭಾಗದ ಸಾಲಿನಲ್ಲಿನ ಆ್ಯಪ್ಗಳು ಹೊಸ ಫೋಲ್ಡರ್ಗೆ ಚಲಿಸುತ್ತವೆ."
+ "ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿಯೇ ನೀವು ಹೆಚ್ಚು ಬಳಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಸುಲಭವಾಗಿ ಪ್ರವೇಶಿಸಿ. ನಿಮ್ಮ ದಿನಚರಿಯನ್ನು ಆಧರಿಸಿ ಸಲಹೆಗಳು ಬದಲಾಗುತ್ತವೆ. ಕೆಳಭಾಗದ ಸಾಲಿನಲ್ಲಿನ ಆ್ಯಪ್ಗಳು ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ ಚಲಿಸುತ್ತವೆ."
+ "ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿಯೇ ನೀವು ಹೆಚ್ಚು ಬಳಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಸುಲಭವಾಗಿ ಪ್ರವೇಶಿಸಿ. ನಿಮ್ಮ ದಿನಚರಿಯನ್ನು ಆಧರಿಸಿ ಸಲಹೆಗಳು ಬದಲಾಗುತ್ತವೆ. ಮೆಚ್ಚಿನವುಗಳ ಸಾಲಿನಲ್ಲಿನ ಆ್ಯಪ್ಗಳು ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಚಲಿಸುತ್ತವೆ."
+ "ಹೋಮ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿಯೇ ನೀವು ಹೆಚ್ಚು ಬಳಸಿದ ಆ್ಯಪ್ಗಳನ್ನು ಸುಲಭವಾಗಿ ಪ್ರವೇಶಿಸಿ. ನಿಮ್ಮ ದಿನಚರಿಯನ್ನು ಆಧರಿಸಿ ಸಲಹೆಗಳು ಬದಲಾಗುತ್ತವೆ. ಕೆಳಭಾಗದ ಸಾಲಿನಲ್ಲಿನ ಆ್ಯಪ್ಗಳು ಹೊಸ ಫೋಲ್ಡರ್ಗೆ ಚಲಿಸುತ್ತವೆ.""ಆ್ಯಪ್ ಸಲಹೆಗಳನ್ನು ಪಡೆಯಿರಿ""ಬೇಡ""ಸೆಟ್ಟಿಂಗ್ಗಳು"
@@ -45,10 +45,12 @@
"ಆ್ಯಪ್ ಸಲಹೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ""ಆ್ಯಪ್ ಸಲಹೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ""ಶಿಫಾರಸು ಮಾಡಿದ ಆ್ಯಪ್: %1$s"
- "ನೀವು ಬಲಕೊನೆಯ ಅಂಚಿನಿಂದ ಅಥವಾ ಎಡಕೊನೆಯ ಅಂಚಿನಿಂದ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."
- "ನೀವು ಬಲ ಅಥವಾ ಎಡ ಅಂಚಿನಿಂದ ಸ್ಕ್ರೀನ್ನ ಮಧ್ಯಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಂಡು ಬಿಟ್ಟುಬಿಡಿ."
- "ಹಿಂದೆ ಹೋಗಲು ಬಲದಿಂದ ಸ್ವೈಪ್ ಮಾಡುವುದು ಹೇಗೆಂದು ಕಲಿತಿರಿ. ಮುಂದೆ, ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಿಸುವುದು ಹೇಗೆಂದು ತಿಳಿಯಿರಿ."
- "ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."
+ "ನೀವು ದೂರದ ಎಡ ಅಂಚಿನಿಂದ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."
+ "ಎಡ ಅಂಚಿನಿಂದ ಸ್ಕ್ರೀನ್ ಮಧ್ಯಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ ಹಾಗೂ ನಿಮ್ಮ ಬೆರಳನ್ನು ಮೇಲೆತ್ತಿ."
+ "ಅಷ್ಟೇ! ಈಗ ಬಲ ತುದಿಯಿಂದ ಸ್ವೈಪ್ ಮಾಡಲು ಪ್ರಯತ್ನಿಸಿ."
+ "ನೀವು ದೂರದ ಬಲ ಅಂಚಿನಿಂದ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."
+ "ಬಲ ಅಂಚಿನಿಂದ ಸ್ಕ್ರೀನ್ ಮಧ್ಯಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ ಹಾಗೂ ನಿಮ್ಮ ಬೆರಳನ್ನು ಮೇಲೆತ್ತಿ."
+ "ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ಮುಂದೆ, ಹೋಮ್ಗೆ ಹೋಗುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ.""ನೀವು ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗಕ್ಕೆ ಹೆಚ್ಚು ಹತ್ತಿರ ಸ್ವೈಪ್ ಮಾಡದಂತೆ ನೋಡಿಕೊಳ್ಳಿ.""ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ನ ಸೂಕ್ಷ್ಮತೆ ಬದಲಾಯಿಸಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ""ಹಿಂದಕ್ಕೆ ಹೋಗಲು ಸ್ವೈಪ್ ಮಾಡಿ"
@@ -56,27 +58,22 @@
"ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನ ಅಂಚಿನಿಂದ ನೀವು ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.""ವಿರಾಮಗೊಳಿಸದೆ ನಿಮ್ಮ ಬೆರಳನ್ನು ಸ್ಕ್ರೀನ್ನಿಂದ ಮೇಲೆತ್ತಿ.""ನೀವು ನೇರವಾಗಿ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."
- "ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ಮುಂದೆ, ಹಿಂದಕ್ಕೆ ಹೋಗುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ."
- "ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."
+ "ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ಮುಂದೆ, ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ.""ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಹಿಂತಿರುಗಲು ಸ್ವೈಪ್ ಮಾಡಿ""ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನಿಂದ ಮೇಲೆ ಸ್ವೈಪ್ ಮಾಡಿ. ಈ ಗೆಸ್ಚರ್ ಯಾವಾಗಲೂ ನಿಮ್ಮನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಕರೆದೊಯ್ಯುತ್ತದೆ.""ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನ ಅಂಚಿನಿಂದ ನೀವು ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.""ಬೆರಳನ್ನು ಮೇಲೆತ್ತುವ ಮೊದಲು ವಿಂಡೋವನ್ನು ಹೆಚ್ಚು ಸಮಯ ಹಿಡಿದಿಡಲು ಪ್ರಯತ್ನಿಸಿ.""ನೀವು ನೇರವಾಗಿ ಸ್ವೈಪ್ ಮಾಡಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ, ನಂತರ ವಿರಾಮಗೊಳಿಸಿ."
- "ಗೆಶ್ಚರ್ಗಳನ್ನು ಬಳಸುವುದು ಹೇಗೆಂದು ನೀವು ತಿಳಿದುಕೊಂಡಿರುವಿರಿ. ಗೆಶ್ಚರ್ಗಳನ್ನು ಆಫ್ ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ."
- "ನೀವು ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸುವ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ."
+ "ನೀವು ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸುವ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ನಿಮ್ಮ ಫೋನ್ ಬಳಸಲು ನೀವು ಸಿದ್ಧರಿದ್ದೀರಿ!""ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ"
- "ಆ್ಯಪ್ಗಳ ನಡುವೆ ಬದಲಿಸಲು, ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗದಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ, ನಂತರ ಬಿಟ್ಟುಬಿಡಿ."
+ "ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ, ಒತ್ತಿ ಹಿಡಿಯಿರಿ, ನಂತರ ಬಿಟ್ಟು ಬಿಡಿ.""ಸಂಪೂರ್ಣ ಸಿದ್ಧವಾಗಿದೆ"
- "ಮುಗಿದಿದೆ"
+ "ಮುಂದೆ"
+ "ಮುಗಿದಿದೆ""ಸೆಟ್ಟಿಂಗ್ಗಳು""ಪುನಃ ಪ್ರಯತ್ನಿಸಿ""ಚೆನ್ನಾಗಿದೆ!""ಟ್ಯುಟೋರಿಯಲ್ %1$d/%2$d"
- "ಎಲ್ಲವೂ ಸಿದ್ಧವಾಗಿದೆ!"
- "ಮುಖಪುಟಕ್ಕೆ ಹೋಗಲು ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"
- "ನಿಮ್ಮ ಫೋನ್ ಬಳಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸಲು ನೀವು ಸಿದ್ದರಾಗಿರುವಿರಿ"
- "ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಶನ್ ಸೆಟ್ಟಿಂಗ್ಗಳು""ಹಂಚಿಕೊಳ್ಳಿ""ಸ್ಕ್ರೀನ್ಶಾಟ್""ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index ba564a707b..fbbddd6699 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -45,38 +45,35 @@
"앱 제안이 사용 설정됨""앱 제안이 사용 중지됨""예상 앱: %1$s"
- "오른쪽 또는 왼쪽 가장자리 끝에서 스와이프하세요."
- "오른쪽 또는 왼쪽 가장자리에서 화면 중앙으로 스와이프한 후 손가락을 떼세요."
- "오른쪽에서 스와이프하여 뒤로 돌아가는 방법을 배웠습니다. 이번에는 앱 전환 방법을 알아보겠습니다."
- "돌아가기 동작을 완료했습니다."
+ "왼쪽 가장자리 끝에서 스와이프하세요."
+ "왼쪽 가장자리에서 화면 중앙으로 스와이프한 후 손가락을 떼세요."
+ "좋습니다. 이번에는 오른쪽 가장자리에서 스와이프해 보세요."
+ "오른쪽 가장자리 끝에서 스와이프하세요."
+ "오른쪽 가장자리에서 화면 중앙으로 스와이프한 후 손가락을 떼세요."
+ "돌아가기 동작을 완료했습니다. 이번에는 홈으로 가는 방법을 알아보겠습니다.""화면 하단에 지나치게 가까운 곳에서 스와이프하면 안 됩니다.""돌아가기 동작의 민감도를 변경하려면 설정으로 이동하세요""스와이프하여 돌아가기"
- "마지막 화면으로 돌아가려면 왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요."
+ "마지막 화면으로 돌아가려면 왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요""화면 하단 가장자리에서 위로 스와이프하세요.""손가락을 떼기 전에 멈추지 않아야 합니다.""위로 똑바르게 스와이프하세요."
- "홈으로 이동 동작을 완료했습니다. 이번에는 뒤로 돌아가는 방법을 알아보겠습니다."
- "홈으로 이동 동작을 완료했습니다."
+ "홈으로 이동 동작을 완료했습니다. 이번에는 앱 전환 방법을 알아보겠습니다.""스와이프하여 홈으로 이동"
- "화면 하단에서 위로 스와이프합니다. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다."
+ "화면 하단에서 위로 스와이프합니다. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다""화면 하단 가장자리에서 위로 스와이프하세요.""창을 더 오래 누르고 있다가 손가락을 떼 보세요.""위로 똑바르게 스와이프한 후 잠깐 멈추세요."
- "동작 사용 방법을 알아봤습니다. 동작을 사용 중지하려면 설정으로 이동하세요."
- "앱 전환 동작을 완료했습니다."
+ "앱 전환 동작을 완료했습니다. 휴대전화를 사용할 준비가 됐습니다.""스와이프로 앱 전환"
- "앱 간에 전환하려면 화면 하단에서 위로 스와이프하고 잠시 멈춘 다음 손가락을 떼세요."
+ "화면 하단에서 위로 스와이프하고 잠시 멈춘 다음 손가락을 떼세요""설정 완료"
- "완료"
+ "다음"
+ "완료""설정""다시 시도""잘하셨습니다""튜토리얼 %1$d/%2$d"
- "설정 완료"
- "위로 스와이프하여 홈으로 이동"
- "휴대전화를 사용할 준비가 되었습니다."
- "시스템 탐색 설정""공유""스크린샷""이 작업은 앱 또는 조직에서 허용되지 않습니다."
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 8be5c53f9a..bd50eed506 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -40,48 +40,45 @@
"Жок, рахмат""Жөндөөлөр""Көп иштетилген колдонмолор ушул жерде көрүнүп, тартиптин негизинде өзгөрөт"
- "Сунуштарды алып туруу үчүн ылдый жактагы тилкедеги колдонмолорду сүйрөп келиңиз"
+ "Сунуштарды алып туруу үчүн, ылдый жактагы тилкедеги колдонмолорду сүйрөп келиңиз""Сунушталган колдонмолор бош жерге кошулат""Сунушталган колдонмолор функциясы иштетилди""Сунушталган колдонмолор функциясы өчүрүлгөн""Божомолдонгон колдонмо: %1$s"
- "Экранды эң четинен оңдон солго же солдон оңго карай сүрүңүз."
- "Экранды оң же сол жагынан ортосуна карай сүрүп, манжаңызды алыңыз."
- "Артка кайтуу үчүн экранды оңдон солго карай сүрүүнү үйрөндүңүз. Эми колдонмолорду которуштурганды үйрөнүп алыңыз."
- "\"Артка\" жаңсоосун үйрөндүңүз."
+ "Экранды эң четинен солдон оңго карай сүрүңүз."
+ "Экранды сол жагынан ортосуна карай сүрүп, манжаңызды алыңыз."
+ "Бүттү! Эми экранды оң жагынан сүрүп көрүңүз."
+ "Экранды эң четинен оңдой солго карай сүрүңүз."
+ "Экранды оң жагынан ортосуна карай сүрүп, манжаңызды алыңыз."
+ "\"Артка\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз. Эми башкы бетке кантип өтүүнү үйрөнүп алыңыз.""Манжаңызды экрандын ылдый жагына өтө жакындатпай сүрүңүз."
- "\"Артка\" жаң-нун сезгичтигин өзгөртүү үчүн жөндөөлөргө өтүңүз"
+ "\"Артка\" жаң-нун сезгичтигин өзгөртүү үчүн Жөндөөлөргө өтүңүз""Артка кайтуу үчүн сүрүңүз""Акыркы экранга кайтуу үчүн экранды сол же оң жагынан ортосуна карай сүрүңүз."
- "Экранды ылдыйдан өйдө сүрүңүз."
+ "Экранды ылдыйдан өйдө карай сүрүңүз.""Манжаңызды алганга чейин токтотпоңуз."
- "Экранды өйдө сүрүңүз."
- "\"Башкы бетке өтүү\" жаңсоосун үйрөндүңүз. Эми артка кайтууну үйрөнүп алыңыз."
- "\"Башкы бетке өтүү\" жаңсоосун үйрөндүңүз."
+ "Экранды өйдө карай сүрүңүз."
+ "\"Башкы бетке өтүү\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз. Эми колдонмолорду которуштуруу ыкмасын үйрөнүп алыңыз.""Башкы бетке өтүү үчүн сүрүп коюңуз"
- "Экранды ылдый жагынан өйдө сүрүңүз. Бул жаңсоо сизди ар дайым Башкы экранга алып барат."
- "Экранды ылдыйдан өйдө сүрүңүз."
+ "Экранды ылдый жагынан өйдө карай сүрүңүз. Бул жаңсоо сизди ар дайым Башкы экранга алып барат."
+ "Экранды ылдыйдан өйдө карай сүрүңүз.""Манжаңызды алуудан мурун экранда узагыраак кармаңыз.""Экранды өйдө карай сүрүп, токтоп туруңуз."
- "Жаңсоолорду колдонгонду үйрөндүңүз. Жаңсоолорду өчүрүү үчүн жөндөөлөргө өтүңүз."
- "\"Колдонмолорду которуштуруу\" жаңсоосун үйрөндүңүз."
+ "\"Колдонмолорду которуштуруу\" жаңсоосу боюнча үйрөткүчтү бүтүрдүңүз. Телефонуңузду колдоно берсеңиз болот.""Колдонмолорду которуштуруу үчүн сүрүңүз"
- "Бир колдонмодон экинчисине өтүү үчүн экранды ылдыйдан өйдө карай сүрүп, бир аз коё бербей туруңуз."
+ "Экранды ылдыйдан өйдө карай сүрүп, бир аз коё бербей кармап туруңуз.""Дапдаяр!"
- "Бүттү"
+ "Кийинки"
+ "Бүттү""Жөндөөлөр"
- "Кайталап көрүңүз"
+ "Кайра аракет кылыңыз""Сонун!""Үйрөткүч: %1$d/%2$d"
- "Бүттү!"
- "Башкы бетке өтүү үчүн экранды өйдө сүрүңүз"
- "Телефонуңузду колдоно берсеңиз болот"
- "Өтүү аракетинин тутумдук жөндөөлөрү""Бөлүшүү""Скриншот""Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"
- "Жаңсоолор үйрөткүчүн өткөрүп жибересизби?"
+ "Жаңсап өтүү үйрөткүчүн өт-рүп жибер-би?""Аны кийин %1$s колдонмосунан табасыз""Жокко чыгаруу"
- "Өткрп жиберүү"
+ "Өтк-п жиберүү"
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 915578b8e7..e05b18e613 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -45,10 +45,12 @@
"ເປີດການນຳໃຊ້ການແນະນຳແອັບແລ້ວ""ປິດການນຳໃຊ້ການແນະນຳແອັບແລ້ວ""ແອັບທີ່ຄາດເດົາໄວ້: %1$s"
- "ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຂວາສຸດ ຫຼື ຊ້າຍສຸດ."
- "ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຂວາ ຫຼື ຊ້າຍໄປຫາທາງກາງຂອງໜ້າຈໍແລ້ວປ່ອຍນິ້ວ."
- "ທ່ານຮຽນຮູ້ວິທີປັດຈາກຂວາເພື່ອກັບຄືນແລ້ວ. ຕໍ່ໄປ, ມາສຶກສາວິທີສະຫຼັບແອັບ."
- "ທ່ານໃຊ້ທ່າທາງກັບຄືນສຳເລັດແລ້ວ."
+ "ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຊ້າຍສຸດ."
+ "ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຊ້າຍໄປຫາທາງກາງຂອງຈໍແລ້ວປ່ອຍ."
+ "ແລ້ວໆ! ຕອນນີ້ໃຫ້ລອງປັດຈາກຂອບຂວາເບິ່ງ."
+ "ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຂວາສຸດ."
+ "ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຂວາໄປຫາທາງກາງຂອງຈໍແລ້ວປ່ອຍ."
+ "ທ່ານໃຊ້ທ່າທາງກັບຄືນສຳເລັດແລ້ວ. ຕໍ່ໄປ, ມາສຶກສາວິທີໄປໜ້າຫຼັກ.""ກະລຸນາກວດສອບວ່າທ່ານບໍ່ໄດ້ປັດໃກ້ກັບທາງລຸ່ມຂອງໜ້າຈໍເກີນໄປ.""ເພື່ອປ່ຽນຄວາມລະອຽດອ່ອນຂອງທ່າທາງກັບຄືນ, ໃຫ້ໄປຫາການຕັ້ງຄ່າ""ປັດເພື່ອກັບຄືນ"
@@ -56,27 +58,22 @@
"ກະລຸນາກວດສອບວ່າທ່ານປັດຂຶ້ນຈາກຂອບລຸ່ມສຸດຂອງໜ້າຈໍ.""ກະລຸນາກວດສອບວ່າທ່ານບໍ່ຢຸດຊົ່ວຄາວກ່ອນປ່ອຍນິ້ວ.""ກະລຸນາກວດສອບວ່າທ່ານປັດຂຶ້ນໄປຊື່ໆ."
- "ທ່ານໃຊ້ທ່າທາງໄປໜ້າຫຼັກສຳເລັດແລ້ວ. ຕໍ່ໄປ, ມາສຶກສາວິທີກັບຄືນ."
- "ທ່ານໃຊ້ທ່າທາງໄປໜ້າຫຼັກສຳເລັດແລ້ວ."
+ "ທ່ານໃຊ້ທ່າທາງໄປໜ້າຫຼັກສຳເລັດແລ້ວ. ຕໍ່ໄປ, ມາສຶກສາວິທີສະຫຼັບແອັບ.""ປັດເພື່ອໄປໜ້າຫຼັກ""ປັດຂຶ້ນມາຈາກລຸ່ມສຸດຂອງໜ້າຈໍທ່ານ. ທ່າທາງນີ້ຈະພາທ່ານໄປໂຮມສະກຣີນສະເໝີ.""ກະລຸນາກວດສອບວ່າທ່ານປັດຂຶ້ນຈາກຂອບລຸ່ມສຸດຂອງໜ້າຈໍ.""ລອງກົດໃສ່ໜ້າຈໍຄ້າງໄວ້ດົນຂຶ້ນກ່ອນປ່ອຍນິ້ວ.""ກະລຸນາກວດສອບວ່າທ່ານປັດຂຶ້ນຊື່ໆ, ຈາກນັ້ນຢຸດຊົ່ວຄາວ."
- "ທ່ານໄດ້ສຶກສາວິທີໃຊ້ທ່າທາງແລ້ວ. ເພື່ອປິດທ່າທາງຕ່າງໆ, ໃຫ້ເຂົ້າໄປຫາການຕັ້ງຄ່າ."
- "ທ່ານໃຊ້ທ່າທາງສະຫຼັບແອັບສຳເລັດແລ້ວ."
+ "ທ່ານໃຊ້ທ່າທາງສະຫຼັບແອັບສຳເລັດແລ້ວ. ທ່ານພ້ອມໃຊ້ໂທລະສັບຂອງທ່ານແລ້ວ!""ປັດເພື່ອສະຫຼັບແອັບ"
- "ເພື່ອສະຫຼັບລະຫວ່າງແອັບ, ໃຫ້ປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍທ່ານ, ກົດຄ້າງໄວ້, ຈາກນັ້ນປ່ອຍ."
+ "ປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍທ່ານ, ຈາກນັ້ນປ່ອຍ.""ທຸກຢ່າງພ້ອມແລ້ວ"
- "ແລ້ວໆ"
+ "ຕໍ່ໄປ"
+ "ແລ້ວໆ""ການຕັ້ງຄ່າ""ລອງໃໝ່""ດີ!""ການສອນການນຳໃຊ້ທີ %1$d/%2$d"
- "ຮຽບຮ້ອຍໝົດແລ້ວ!"
- "ປັດຂຶ້ນເພື່ອໄປຫາໜ້າຫຼັກ"
- "ທ່ານພ້ອມເລີ່ມຕົ້ນໃຊ້ໂທລະສັບຂອງທ່ານແລ້ວ"
- "ການຕັ້ງຄ່າການນຳທາງລະບົບ""ແບ່ງປັນ""ຮູບໜ້າຈໍ""ແອັບ ຫຼື ອົງການຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຄຳສັ່ງນີ້"
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index b0c679c758..2f1db5038a 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -45,10 +45,12 @@
"Siūlomų programų funkcija įgalinta""Siūlomų programų funkcija išjungta""Numatoma programa: %1$s"
- "Turite perbraukti nuo dešiniojo ar kairiojo krašto."
- "Turite perbraukti nuo dešiniojo ar kairiojo krašto link ekrano vidurio ir pakelti pirštą."
- "Išmokote, kaip sugrįžti perbraukiant iš dešinės. Toliau sužinosite, kaip perjungti programas."
- "Atlikote grįžimo atgal gestą."
+ "Turite perbraukti nuo kairiojo krašto."
+ "Turite perbraukti nuo kairiojo krašto link ekrano vidurio ir pakelti pirštą."
+ "Tai viskas! Dabar pabandykite perbr. nuo dešiniojo krašto."
+ "Turite perbraukti nuo dešiniojo krašto."
+ "Turite perbraukti nuo dešiniojo krašto link ekrano vidurio ir pakelti pirštą."
+ "Atlikote grįžimo atgal gestą. Toliau sužinosite, kaip pereiti į pagrindinį ekraną.""Nebraukite per arti ekrano apačios.""Norėd. pak. grįžimo gesto jautr., eikite į sk. „Nustatymai“""Norėdami grįžti, perbraukite"
@@ -56,27 +58,22 @@
"Turite perbraukti aukštyn nuo apatinio ekrano krašto.""Nepristabdykite prieš pakeldami pirštą.""Turite tiesiai perbraukti aukštyn."
- "Atlikote perėjimo į pagrindinį ekraną gestą. Toliau sužinosite, kaip grįžti atgal."
- "Atlikote perėjimo į pagrindinį ekraną gestą."
+ "Atlikote perėjimo į pagrindinį ekraną gestą. Toliau sužinosite, kaip perjungti programas.""Perbraukite, kad pereitumėte į pagrindinį ekraną""Perbraukite aukštyn nuo ekrano apačios. Atlikus šį gestą, visada nukreipiama į pagrindinį ekraną.""Turite perbraukti aukštyn nuo apatinio ekrano krašto.""Pabandykite palaikyti langą ilgiau prieš pakeldami pirštą.""Turite tiesiai perbraukti aukštyn, o tada pristabdyti."
- "išmokote naudotis gestais. Gestus galite išjungti nustatymuose."
- "Atlikote programų perjungimo gestą."
+ "Atlikote programų perjungimo gestą. Esate pasirengę naudoti telefoną!""Perbraukite, kad perjungtumėte programas"
- "Norėdami perjungti programas, perbraukite aukštyn nuo ekrano apačios, palaikykite ir paleiskite."
+ "Perbraukite aukštyn nuo ekrano apačios, palaikykite ir paleiskite.""Viskas nustatyta"
- "Atlikta"
+ "Kitas"
+ "Atlikta""Nustatymai""Bandykite dar kartą""Šaunu!""Mokymo programa: %1$d iš %2$d"
- "Paruošta!"
- "Perbraukite aukštyn, kad grįžtumėte į pagrindinį ekraną"
- "Esate pasiruošę pradėti naudoti telefoną"
- "Sistemos naršymo nustatymai""Bendrinti""Ekrano kopija""Jūsų organizacijoje arba naudojant šią programą neleidžiama atlikti šio veiksmo"
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index df1c3e9088..ce941bc3d9 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -45,10 +45,12 @@
"Ieteicamās lietotnes ir iespējotas""Ieteicamās lietotnes ir atspējotas""Prognozētā lietotne: %1$s"
- "Velciet no pašas labās vai kreisās malas."
- "Velciet no ekrāna labās vai kreisās malas uz vidu un atlaidiet."
- "Jūs esat apguvis, kā vilkt no labās malas, lai pārietu atpakaļ. Tagad mācieties pārslēgt lietotnes."
- "Jūs sekmīgi veicāt atgriešanās žestu."
+ "Jāvelk no pašas kreisās malas."
+ "Jāvelk no ekrāna kreisās malas uz vidu un jāatlaiž."
+ "Tas arī viss! Tagad mēģiniet vilkt no labās malas."
+ "Jāvelk no pašas labās malas."
+ "Jāvelk no ekrāna labās malas uz vidu un jāatlaiž."
+ "Jūs sekmīgi veicāt atgriešanās žestu. Tagad varat iemācīties, kā pāriet uz sākumu.""Nevelciet pārāk tuvu ekrāna apakšdaļai.""Atgriešanās žesta jutīguma līmeni varat mainīt iestatījumos.""Vilkšana, lai atgrieztos"
@@ -56,27 +58,22 @@
"Jāvelk augšup no ekrāna apakšmalas.""Pirms atlaišanas nepārtrauciet kustību.""Jāvelk tieši uz augšu."
- "Jūs sekmīgi veicāt sākuma ekrāna atvēršanas žestu. Tagad varat iemācīties, kā pāriet atpakaļ."
- "Jūs sekmīgi veicāt sākuma ekrāna atvēršanas žestu."
+ "Jūs sekmīgi veicāt sākuma ekrāna atvēršanas žestu. Tagad varat iemācīties, kā pārslēgt lietotnes.""Vilkšana, lai pārietu uz sākumu""Velciet augšup no ekrāna apakšdaļas. Ar šo žestu vienmēr varat atvērt sākuma ekrānu.""Jāvelk augšup no ekrāna apakšmalas.""Mēģiniet ilgāk turēt logu, pirms atlaižat.""Jāvelk tieši uz augšu un pēc tam jāaptur kustība."
- "Jūs esat apguvis žestu izmantošanu. Lai izslēgtu žestus, pārejiet uz sadaļu Iestatījumi."
- "Jūs sekmīgi veicāt lietotņu pārslēgšanas žestu."
+ "Jūs sekmīgi veicāt lietotņu pārslēgšanas žestu. Esat gatavs izmantot tālruni!""Vilkšana, lai pārslēgtu lietotnes"
- "Lai pārslēgtu lietotnes, velciet augšup no ekrāna apakšdaļas, turiet un pēc tam atlaidiet."
+ "Velciet augšup no ekrāna apakšdaļas, turiet un pēc tam atlaidiet.""Gatavs"
- "Gatavs"
+ "Tālāk"
+ "Gatavs""Iestatījumi""Mēģināt vēlreiz""Lieliski!""%1$d. mācību darbība no %2$d"
- "Gatavs!"
- "Velciet augšup, lai pārietu uz sākuma ekrānu."
- "Varat sākt izmantot savu tālruni"
- "Sistēmas navigācijas iestatījumi""Kopīgot""Veikt ekrānuzņēmumu""Lietotne vai jūsu organizācija neatļauj veikt šo darbību."
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 98307da304..f9fd8b3d06 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -45,10 +45,12 @@
"Предлозите за апликации се овозможени""Предлозите за апликации се оневозможени""Предвидена апликација: %1$s"
- "Повлечете од крајниот десен или крајниот лев раб."
- "Повлечете од десниот или левиот раб кон средината на екранот и пуштете."
- "Научивте како да повлекувате оддесно за да одите назад. Следно, дознајте како да се префрлате помеѓу апликации."
- "Завршивте со упатството за враќање назад."
+ "Повлечете од подалечниот лев агол."
+ "Повлечете од левиот раб кон средината на екранот и пуштете."
+ "Тоа е сѐ! Сега пробајте да повлечете од десниот раб."
+ "Повлечете од подалечниот десен агол."
+ "Повлечете од десниот раб кон средината на екранот и пуштете."
+ "Завршивте со упатството за враќање назад. Следно, дознајте како да одите на почетната страница.""Не повлекувајте преблиску до долниот раб на екранот.""За да ја промените чувствителноста, одете во „Поставки“""Повлечете за да се вратите назад"
@@ -56,27 +58,22 @@
"Повлечете нагоре од долниот раб на екранот.""Не правете пауза пред да пуштите.""Повлечете право нагоре."
- "Завршивте со упатството за почетната страница. Следно, дознајте како да се вратите назад."
- "Завршивте со упатството за почетната страница."
+ "Завршивте со упатството за почетната страница. Следно, дознајте како да се префрлате помеѓу апликации.""Повлечете за да одите на почетната страница""Повлечете нагоре од долниот раб на екранот. Ова движење секогаш ќе ве одведе на почетниот екран.""Повлечете нагоре од долниот раб на екранот.""Задржете го прозорецот подолго пред да го пуштите.""Повлечете право нагоре, а потоа застанете."
- "Дознавте како се користат движењата. За да ги исклучите движењата, одете во „Поставки“."
- "Завршивте со упатството за префрлање помеѓу апликации."
+ "Завршивте со упатството за префрлање помеѓу апликации. Спремни сте да го користите телефонот.""Повлечете за префрлање помеѓу апликации"
- "За да смените апликација, повлечете нагоре од дното на екранот и задржете, па пуштете."
+ "Повлечете нагоре од дното на екранот и задржете, па пуштете.""Готово"
- "Готово"
+ "Следно"
+ "Готово""Поставки""Обиди се пак""Одлично!""Упатство %1$d/%2$d"
- "Готово!"
- "Повлечете нагоре за да појдете на почетниот екран"
- "Спремни сте да почнете да го користите телефонот"
- "Поставки за системска навигација""Сподели""Слика од екранот""Апликацијата или вашата организација не го дозволува дејствово"
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 52be3ac297..fc6bc82d01 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -45,10 +45,12 @@
"ആപ്പ് നിർദ്ദേശങ്ങൾ പ്രവർത്തനക്ഷമമാക്കി""ആപ്പ് നിർദ്ദേശങ്ങൾ പ്രവർത്തനരഹിതമാക്കി""പ്രവചിച്ച ആപ്പ്: %1$s"
- "വലത്തേയറ്റത്തെയോ ഇടത്തേയറ്റത്തെയോ അരികിൽ നിന്ന് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക."
- "വലതോ ഇടതോ അരികിൽ നിന്ന് സ്ക്രീനിന്റെ മധ്യഭാഗത്തേക്ക് സ്വെെപ്പ് ചെയ്ത് വിടുക."
- "മടങ്ങാൻ വലതുഭാഗത്ത് നിന്ന് സ്വൈപ്പ് ചെയ്യുന്ന രീതി മനസ്സിലായി. ഇനി, ആപ്പുകൾ മാറുന്ന രീതി അറിയുക."
- "മടങ്ങുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."
+ "ഇടത്തേയറ്റത്തെ അരികിൽ നിന്ന് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക."
+ "ഇടത്തേ അരികിൽ നിന്ന് സ്ക്രീനിന്റെ മധ്യഭാഗത്തേക്ക് സ്വെെപ്പ് ചെയ്ത് വിടുക."
+ "അത്ര മാത്രം! ഇനി വലത്തേ അരികിൽ നിന്ന് സ്വെെപ്പ് ചെയ്യൂ."
+ "വലത്തേയറ്റത്തെ അരികിൽ നിന്ന് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക."
+ "വലത്തേ അരികിൽ നിന്ന് സ്ക്രീനിന്റെ മധ്യഭാഗത്തേക്ക് സ്വെെപ്പ് ചെയ്ത് വിടുക."
+ "മടങ്ങുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി. അടുത്തത്, ഹോമിലേക്ക് പോകുന്നതെങ്ങനെയെന്ന് മനസ്സിലാക്കുക.""സ്ക്രീനിന്റെ ഏറ്റവും അടിഭാഗത്തേക്ക് സ്വെെപ്പ് ചെയ്യുന്നില്ലെന്ന് ഉറപ്പാക്കുക.""ബാക്ക്ജെസ്റ്ററിന്റെ സെൻസിറ്റിവിറ്റി മാറ്റാൻ ക്രമീകരണത്തിൽ പോകൂ""മടങ്ങാൻ സ്വെെപ്പ് ചെയ്യുക"
@@ -56,27 +58,22 @@
"സ്ക്രീനിന്റെ താഴത്തെ അരികിൽ നിന്ന് മുകളിലേക്ക് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക.""വിടുന്നതിന് മുമ്പ് നിങ്ങൾ താൽക്കാലികമായി നിർത്തുന്നില്ലെന്ന് ഉറപ്പാക്കുക.""നേരെ മുകളിലേക്ക് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പിക്കുക."
- "ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ പൂർത്തിയാക്കി. അടുത്തത്, എങ്ങനെ മടങ്ങാമെന്ന് അറിയുക."
- "ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."
+ "ഹോമിലേക്ക് പോകുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി. അടുത്തത്, എങ്ങനെ ആപ്പുകൾ മാറാമെന്ന് മനസ്സിലാക്കുക.""ഹോമിലേക്ക് പോകാൻ സ്വെെപ്പ് ചെയ്യുക""സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യൂ. ഈ ജെസ്ച്ചർ എപ്പോഴും ഹോം സ്ക്രീനിലേക്ക് നയിക്കുന്നു.""സ്ക്രീനിന്റെ താഴത്തെ അരികിൽ നിന്ന് മുകളിലേക്ക് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക.""റിലീസ് ചെയ്യുന്നതിന് മുമ്പ് വിൻഡോ കൂടുതൽ സമയം ഹോൾഡ് ചെയ്യാൻ ശ്രമിക്കുക.""നേരെ മുകളിലേക്ക് സ്വെെപ്പ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കുക, ശേഷം താൽക്കാലികമായി നിർത്തുക."
- "ജെസ്ച്ചറുകൾ ഉപയോഗിക്കുന്ന രീതി നിങ്ങൾ മനസ്സിലാക്കി. ജെസ്ച്ചറുകൾ ഓഫാക്കാൻ ക്രമീകരണത്തിലേക്ക് പോകുക."
- "ആപ്പുകൾ തമ്മിൽ മാറുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി."
+ "ആപ്പുകൾ മാറുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി. ഫോൺ ഉപയോഗിക്കാൻ നിങ്ങൾ തയ്യാറാണ്!""ആപ്പുകൾ മാറാൻ സ്വെെപ്പ് ചെയ്യുക"
- "ആപ്പുകൾക്കിടയിൽ മാറാൻ സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിച്ച ശേഷം വിടുക."
+ "സ്ക്രീനിന്റെ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്ത് പിടിച്ച ശേഷം വിടുക.""എല്ലാം സജ്ജീകരിച്ചു"
- "പൂർത്തിയായി"
+ "അടുത്തത്"
+ "പൂർത്തിയായി""ക്രമീകരണം""വീണ്ടും ശ്രമിക്കുക""കൊള്ളാം!""ട്യൂട്ടോറിയൽ %1$d/%2$d"
- "എല്ലാം സജ്ജീകരിച്ചു!"
- "ഹോമിലേക്ക് പോകാൻ മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"
- "ഫോൺ ഉപയോഗിച്ച് തുടങ്ങാൻ നിങ്ങൾ തയ്യാറാണ്"
- "സിസ്റ്റം നാവിഗേഷൻ ക്രമീകരണം""പങ്കിടുക""സ്ക്രീൻഷോട്ട്""ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 79fbca6e49..48513eb928 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -31,9 +31,9 @@
"Санал болгож буй аппууд""Бүх апп""Таны таамагласан аппууд"
- "Үндсэн нүүрнийхээ доод мөрд санал болгож буй аппуудыг аваарай"
+ "Үндсэн нүүрнийхээ доод мөрөнд санал болгож буй аппуудыг аваарай""Үндсэн нүүрний дуртай мөрнөөсөө санал болгож буй аппуудыг аваарай"
- "Хамгийн их ашигладаг аппууддаа Үндсэн нүүрнээс хялбархан хандаарай. Санал болгож буй аппуудыг таны хэвшлээс хамаарч өөрчилнө. Доод мөрд буй аппуудыг таны Үндсэн нүүр лүү дээш зөөнө."
+ "Хамгийн их ашигладаг аппууддаа Үндсэн нүүрнээс хялбархан хандаарай. Санал болгож буй аппуудыг таны хэвшлээс хамаарч өөрчилнө. Доод мөрөнд буй аппуудыг таны Үндсэн нүүр лүү дээш зөөнө.""Хамгийн их ашигладаг аппууддаа Үндсэн нүүрнээсээ хялбархан хандаарай. Санал болголтыг таны хэвшлээс хамааран өөрчилнө. Дуртай мөрөнд буй аппуудыг таны үндсэн нүүр лүү зөөнө.""Хамгийн их ашигладаг аппууддаа Үндсэн нүүрнээс хялбархан хандаарай. Санал болгож буй аппуудыг таны хэвшлээс хамаарч өөрчилнө. Доод мөрөнд буй аппуудыг шинэ фолдер луу зөөнө.""Санал болгож буй аппуудыг авах"
@@ -45,10 +45,12 @@
"Санал болгож буй аппуудыг идэвхжүүлсэн""Санал болгож буй аппуудыг идэвхгүй болгосон""Таамаглаж буй апп: %1$s"
- "Та баруун зах эсвэл зүүн захын булангаас шударна уу."
- "Та баруун эсвэл зүүн булангаас дэлгэцийн дунд хэсэг хүртэл шударч, суллана уу."
- "Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа. Дараа нь аппууд хооронд хэрхэн сэлгэхийг мэдэж аваарай."
- "Та буцах зангааг гүйцэтгэлээ."
+ "Та зүүн захын булангаас шударна уу."
+ "Та дэлгэцийн зүүн булангаас дунд хэсэг хүртэл шударч, суллаарай."
+ "Ингээд л боллоо! Одоо баруун булангаас шударч үзнэ үү."
+ "Та баруун захын булангаас шударна уу."
+ "Та дэлгэцийн баруун булангаас дунд хэсэг хүртэл шударч, суллаарай."
+ "Та буцах зангааг гүйцэтгэлээ. Дараа нь Нүүр лүү хэрхэн очихыг мэдэж авна уу.""Та дэлгэцийн доод хэсэгтэй хэт ойр бүү шудраарай.""Буцах зангааны мэдрэгшлийг өөрчлөх бол Тохиргоо руу очно уу""Буцахын тулд шудрах"
@@ -56,27 +58,22 @@
"Та дэлгэцийн доод булангаас дээш шударна уу.""Та суллахаасаа өмнө түр зогсоож болохгүй.""Та чигээрээ шударна уу."
- "Та Нүүр лүү очих зангааг гүйцэтгэлээ. Дараа нь хэрхэн буцахыг мэдэж авна уу."
- "Та Нүүр лүү очих зангааг гүйцэтгэлээ."
+ "Та Нүүр лүү очих зангааг гүйцэтгэлээ. Дараа нь аппуудыг хэрхэн сэлгэх талаар мэдэж авна уу.""Нүүр лүү очихын тулд шудрах""Дэлгэцийнхээ доороос дээш шударна уу. Энэ зангаа таныг тогтмол Үндсэн нүүрэнд аваачна.""Та дэлгэцийн доод булангаас дээш шударна уу.""Суллахаасаа өмнө цонхыг илүү удаан дарж үзнэ үү.""Та чигээрээ шударч, дараа нь түр зогсооно уу."
- "Та зангааг хэрхэн ашиглахыг мэдэж авлаа. Зангааг унтраахын тулд Тохиргоо руу очно уу."
- "Та аппуудыг сэлгэх зангааг гүйцэтгэлээ."
+ "Та аппуудыг сэлгэх зангааг гүйцэтгэлээ. Та утсаа ашиглахад бэлэн боллоо!""Аппуудыг сэлгэхийн тулд шудрах"
- "Аппуудын хооронд сэлгэхийн тулд дэлгэцийнхээ доод хэсгээс дээш шударч, удаан дараад, суллана уу."
+ "Дэлгэцийнхээ доод хэсгээс дээш шударч, удаан дараад суллана уу.""Бүгдийг тохируулсан"
- "Дууссан"
+ "Дараах"
+ "Дууссан""Тохиргоо""Дахин оролдох""Янзтай!""%1$d/%2$d практик хичээл"
- "Тохируулж дууслаа!"
- "Нүүр хуудас руу очихын тулд дээш шударна уу"
- "Та утсаа ашиглаж эхлэхэд бэлэн боллоо"
- "Системийн навигацын тохиргоо""Хуваалцах""Дэлгэцийн агшин дарах""Энэ үйлдлийг апп эсвэл танай байгууллага зөвшөөрдөггүй"
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 176dc3a5a9..c576cf139d 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -45,10 +45,12 @@
"अॅप सूचना सुरू केल्या आहेत""अॅप सूचना बंद केल्या आहेत""पूर्वानुमान केलेले अॅप: %1$s"
- "तुम्ही स्क्रीनच्या अगदी उजव्या किंवा अगदी डाव्या कडेला स्वाइप केल्याची खात्री करा."
- "तुम्ही स्क्रीनच्या उजव्या किंवा डाव्या कडेपासून मध्यभागी स्वाइप करून सोडून दिल्याची खात्री करा."
- "मागे जाण्यासाठी उजवीकडून कसे स्वाइप करावे ते शिकलात. आता पुढे, ॲप्स कशी स्विच करायची ते जाणून घ्या."
- "तुम्ही गो बॅक जेश्चर पूर्ण केले."
+ "तुम्ही स्क्रीनच्या अगदी डाव्या कडेपासून स्वाइप करत आहात याची खात्री करा."
+ "तुम्ही स्क्रीनच्या डाव्या कडेपासून मध्यावर स्वाइप करून बोट उचलत आहात याची खात्री करा."
+ "पूर्ण झाले! आता उजव्या कोपऱ्यावरून स्वाइप करून पहा."
+ "तुम्ही स्क्रीनच्या अगदी उजव्या कडेपासून स्वाइप करत आहात याची खात्री करा."
+ "तुम्ही स्क्रीनच्या उजव्या कडेपासून मध्यावर स्वाइप करून बोट उचलत आहात याची खात्री करा."
+ "तुम्ही गो बॅक जेश्चर पूर्ण केले. आता, होम वर कसे जायचे ते जाणून घ्या.""तुम्ही स्क्रीनच्या तळाच्या अगदी जवळून स्वाइप करत नाही याची खात्री करा.""बॅक जेश्चरची संवेदनशीलता बदलण्यासाठी, सेटिंग्ज वर जा""परत जाण्यासाठी स्वाइप करा"
@@ -56,31 +58,26 @@
"तुम्ही स्क्रीनच्या तळाच्या कडेपासून वर स्वाइप करत आहात याची खात्री करा.""तुम्ही स्क्रीनवरून बोट उचलण्यापूर्वी ते थांबवत नाही याची खात्री करा.""तुम्ही सरळ वर स्वाइप करत आहात याची खात्री करा."
- "तुम्ही गो होम जेश्चर पूर्ण केले. आता, मागे कसे जायचे ते जाणून घ्या."
- "तुम्ही गो होम जेश्चर पूर्ण केले."
+ "तुम्ही गो होम जेश्चर पूर्ण केले. आता, ॲप्स कशी स्विच करायची ते जाणून घ्या.""होमवर जाण्यासाठी स्वाइप करा""तुमच्या स्क्रीनच्या तळाकडून वर स्वाइप करा. हे जेश्चर तुम्हाला नेहमी होम स्क्रीनवर घेऊन जाते.""तुम्ही स्क्रीनच्या तळाच्या कडेपासून वर स्वाइप करत आहात याची खात्री करा.""विंडोवरून बोट उचलण्यापूर्वी थोडा वेळ ते तेथेच धरून ठेवा.""तुम्ही सरळ वर स्वाइप करून, त्यानंतर बोट थांबवत आहात याची खात्री करा."
- "तुम्ही जेश्चर कसे वापरायचे हे शिकलात. जेश्चर बंद करण्यासाठी, सेटिंग्ज वर जा."
- "तुम्ही ॲप्स स्विच करण्याचे जेश्चर पूर्ण केले."
+ "तुम्ही स्विच ॲप्स जेश्चर पूर्ण केले. तुम्ही तुमचा फोन वापरण्यासाठी तयार आहात!""अॅप्स स्विच करण्यासाठी स्वाइप करा"
- "ॲप्सदरम्यान स्विच करण्यासाठी, स्क्रीनच्या तळापासून वर स्वाइप करा, धरून ठेवा, त्यानंतर सोडून द्या."
+ "तुमच्या स्क्रीनच्या तळाकडून वर स्वाइप करा, धरून ठेवा, त्यानंतर बोट उचला.""सर्व तयार आहे"
- "पूर्ण झाले"
+ "पुढील"
+ "पूर्ण झाले""सेटिंग्ज""पुन्हा प्रयत्न करा""छान!"
- "ट्यूटोरियल %1$d/%2$d"
- "सर्व तयार आहे!"
- "होम वर जाण्यासाठी वरती स्वाइप करा"
- "तुम्ही तुमचा फोन वापरण्यास सुरुवात करू शकता"
- "सिस्टम नेव्हिगेशन सेटिंग्ज"
+ "ट्युटोरियल %1$d/%2$d""शेअर करा""स्क्रीनशॉट""अॅप किंवा तुमच्या संस्थेद्वारे ही क्रिया करण्याची अनुमती नाही"
- "नेव्हिगेशन ट्यूटोरियल वगळायचे आहे का?"
+ "नेव्हिगेशन ट्युटोरियल वगळायचे आहे का?""तुम्हाला हे नंतर %1$s ॲपमध्ये मिळेल""रद्द करा""वगळा"
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 1e2d43db1a..74b9d086e8 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -45,10 +45,12 @@
"Cadangan apl didayakan""Cadangan apl dilumpuhkan""Apl yang diramalkan: %1$s"
- "Pastikan anda meleret dari hujung sebelah kanan atau sebelah kiri."
- "Pastikan anda meleret dari tepi sebelah kanan atau kiri ke tengah skrin dan lepaskan."
- "Anda belajar cara meleret dari kanan untuk kembali. Seterusnya, ketahui cara menukar apl."
- "Anda telah melengkapkan gerak isyarat undur."
+ "Pastikan anda meleret dari hujung sebelah kiri."
+ "Pastikan anda meleret dari tepi sebelah kiri ke tengah skrin dan lepaskan."
+ "Itu sahaja! Sekarang, cuba leret dari tepi sebelah kanan."
+ "Pastikan anda meleret dari hujung sebelah kanan."
+ "Pastikan anda meleret dari tepi sebelah kanan ke tengah skrin dan lepaskan."
+ "Anda telah melengkapkan gerak isyarat undur. Seterusnya, ketahui cara kembali ke Laman Utama.""Pastikan anda tidak meleret terlalu dekat dengan bahagian bawah skrin.""Utk mengubah kepekaan gerak isyarat undur, pergi ke Tetapan""Leret untuk kembali"
@@ -56,27 +58,22 @@
"Pastikan anda meleret ke atas dari tepi sebelah bawah skrin.""Pastikan anda tidak menjeda sebelum melepaskan gerak isyarat tersebut.""Pastikan anda meleret terus ke atas."
- "Anda telah melengkapkan gerak isyarat pergi ke Laman Utama. Seterusnya, ketahui cara kembali."
- "Anda telah melengkapkan gerak isyarat pergi ke Laman Utama."
+ "Anda telah melengkapkan gerak isyarat kembali ke Laman Utama. Seterusnya, ketahui cara menukar apl.""Leret untuk kembali ke laman utama""Leret ke atas dari bahagian bawah skrin. Gerak isyarat ini sentiasa membawa anda ke Skrin utama.""Pastikan anda meleret ke atas dari tepi sebelah bawah skrin.""Cuba tahan tetingkap untuk tempoh yang lebih lama sebelum melepaskan.""Pastikan anda meleret ke atas, kemudian menjeda."
- "Anda mempelajari cara menggunakan gerak isyarat. Untuk mematikan gerak isyarat, pergi ke Tetapan."
- "Anda telah melengkapkan gerak isyarat menukar apl."
+ "Anda telah melengkapkan gerak isyarat menukar apl. Telefon anda sudah bersedia untuk digunakan!""Leret untuk menukar apl"
- "Untuk beralih antara apl, leret ke atas dari bahagian bawah skrin anda, tahan, kemudian lepaskan."
+ "Leret ke atas dari bahagian bawah skrin anda, tahan, kemudian lepaskan.""Selesai"
- "Selesai"
+ "Seterusnya"
+ "Selesai""Tetapan""Cuba lagi""Bagus!""Tutorial %1$d/%2$d"
- "Siap!"
- "Leret ke atas untuk kembali ke Laman Utama"
- "Anda sudah sedia untuk mula menggunakan telefon anda"
- "Tetapan navigasi sistem""Kongsi""Tangkapan skrin""Tindakan ini tidak dibenarkan oleh apl atau organisasi anda"
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 14c3576f2f..919ad6efa7 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -23,7 +23,7 @@
"အလွတ်ပုံစံ""မကြာမီကဖွင့်ထားသည်များ မရှိပါ""အက်ပ်အသုံးပြုမှု ဆက်တင်များ"
- "အားလုံးရှင်းရန်"
+ "အားလုံးကို ရှင်းရန်""လတ်တလောသုံး အက်ပ်များ""%1$s၊ %2$s""< ၁ မိနစ်"
@@ -45,10 +45,12 @@
"အက်ပ်အကြံပြုချက်များ ဖွင့်ထားသည်""အက်ပ်အကြံပြုချက်များကို ပိတ်ထားသည်""ကြိုတင်မှန်းဆထားသော အက်ပ်− %1$s"
- "ညာ သို့မဟုတ် ဘယ်ဘက်အစွန် ခပ်လှမ်းလှမ်းမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ။"
- "စခရင်၏ ညာ သို့မဟုတ် ဘက်ဘက်အစွန်မှ အလယ်သို့ ပွတ်ဆွဲပြီး လွှတ်လိုက်ကြောင်း သေချာပါစေ။"
- "နောက်ပြန်သွားရန် ညာဘက်မှပွတ်ဆွဲနည်းကို သိသွားပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"
- "နောက်ဆုတ်လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။"
+ "ဘယ်ဘက်အစွန် ခပ်လှမ်းလှမ်းမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ။"
+ "ဘယ်ဘက်အစွန်မှ ဖန်သားပြင်အလယ်သို့ ပွတ်ဆွဲပြီး လွှတ်လိုက်ကြောင်း သေချာပါစေ။"
+ "ရပါပြီ။ ညာဘက်အစွန်မှနေ၍ ယခု ပွတ်ဆွဲကြည့်ပါ။"
+ "ညာဘက်အစွန် ခပ်လှမ်းလှမ်းမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ။"
+ "ညာဘက်အစွန်မှ ဖန်သားပြင်အလယ်သို့ ပွတ်ဆွဲပြီး လွှတ်လိုက်ကြောင်း သေချာပါစေ။"
+ "နောက်ဆုတ်လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။ နောက်အဆင့်တွင် ပင်မစာမျက်နှာသို့ သွားနည်းကို လေ့လာပါ။""ဖန်သားပြင် အောက်ခြေနှင့် အလွန်နီးကပ်စွာ ပွတ်ဆွဲခြင်းမရှိကြောင်း သေချာပါစေ။""နောက်ဆုတ်လက်ဟန်၏ အာရုံခံစွမ်းကိုပြောင်းရန် ‘ဆက်တင်များ’ သို့ သွားပါ""နောက်ပြန်သွားရန် ပွတ်ဆွဲပါ"
@@ -56,27 +58,22 @@
"ဖန်သားပြင် အောက်ခြေအစွန်မှ အပေါ်သို့ ပွတ်ဆွဲကြောင်း သေချာပါစေ။""လက်မလွှတ်ခင် ခဏရပ်ခြင်းမရှိကြောင်း သေချာပါစေ။""အပေါ်တည့်တည့်သို့ ပွတ်ဆွဲကြောင်း သေချာပါစေ။"
- "ပင်မစာမျက်နှာသို့သွားသည့် လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။ နောက်အဆင့်တွင် နောက်သို့ပြန်သွားနည်းကို လေ့လာပါ။"
- "ပင်မစာမျက်နှာသို့သွားသည့် လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။"
+ "ပင်မစာမျက်နှာသို့သွားသည့် လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။""ပင်မစာမျက်နှာသို့သွားရန် ပွတ်ဆွဲပါ""သင့်ဖန်သားပြင် အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ။ ဤလက်ဟန်ဖြင့် ပင်မစာမျက်နှာသို့ အမြဲပြန်သွားနိုင်သည်။""ဖန်သားပြင် အောက်ခြေအစွန်မှ အပေါ်သို့ ပွတ်ဆွဲကြောင်း သေချာပါစေ။""မလွှတ်ခင် ဝင်းဒိုးကို အချိန်ကြာကြာ ဖိထားကြည့်ပါ။""အပေါ်တည့်တည့်သို့ ပွတ်ဆွဲပြီးနောက် ခဏရပ်ကြောင်း သေချာပါစေ။"
- "လက်ဟန်များသုံးနည်းကို သင်သိသွားပါပြီ။ လက်ဟန်များကို ပိတ်ရန် ဆက်တင်များသို့ သွားပါ။"
- "အက်ပ်များပြောင်းသည့် လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။"
+ "အက်ပ်များပြောင်းသည့် လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။ သင့်ဖုန်းကို သုံးရန် အဆင်သင့်ဖြစ်ပါပြီ။""အက်ပ်များပြောင်းရန် ပွတ်ဆွဲပါ"
- "အက်ပ်တစ်ခုမှတစ်ခုသို့ ပြောင်းရန် စခရင်အောက်ခြေမှ အပေါ်သို့ ပွတ်ဆွဲ၍ ဖိထားပြီးနောက် လွှတ်ပါ။"
+ "သင့်ဖန်သားပြင် အောက်ခြေမှ အပေါ်သို့ ပွတ်ဆွဲပါ၊ ဖိထားပြီးနောက် လွှတ်လိုက်ပါ။""အားလုံးအဆင်သင့်ဖြစ်ပါပြီ"
- "ပြီးပြီ"
+ "ရှေ့သို့"
+ "ပြီးပြီ""ဆက်တင်များ""ထပ်စမ်းကြည့်ရန်""ကောင်းသည်။""ရှင်းလင်းပို့ချချက် %1$d/%2$d"
- "အားလုံး အဆင်သင့်ပါ။"
- "ပင်မစာမျက်နှာသို့သွားရန် အပေါ်သို့ ပွတ်ဆွဲပါ"
- "သင့်ဖုန်းကို စတင်အသုံးပြုရန် အသင့်ဖြစ်ပါပြီ"
- "စနစ် လမ်းညွှန် ဆက်တင်များ""မျှဝေရန်""ဖန်သားပြင်ဓာတ်ပုံ""ဤလုပ်ဆောင်ချက်ကို အက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 16988c583f..6e7e4a3cf7 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -45,10 +45,12 @@
"Appforslag er på""Appforslag er slått av""Foreslått app: %1$s"
- "Sørg for at du sveiper fra kanten helt til høyre eller venstre."
- "Sørg for at du sveiper fra den høyre eller venstre kanten til midten av skjermen og slipper."
- "Du har lært hvordan du sveiper fra høyre for å gå tilbake. I neste trinn lærer du å bytte app."
- "Du har fullført bevegelsen for å gå tilbake."
+ "Sørg for at du sveiper fra kanten helt til venstre."
+ "Sørg for at du sveiper fra den venstre kanten til midten av skjermen og slipper."
+ "Så enkelt er det! Prøv nå å sveipe fra den høyre kanten."
+ "Sørg for at du sveiper fra kanten helt til høyre."
+ "Sørg for at du sveiper fra den høyre kanten til midten av skjermen og slipper."
+ "Du har fullført bevegelsen for å gå tilbake. I neste trinn ser du hvordan du går til startskjermen.""Sørg for at du ikke sveiper for nær bunnen av skjermen.""Gå til Innstillinger for å endre tilbakebevegelsefølsomheten""Sveip for å gå tilbake"
@@ -56,27 +58,22 @@
"Sørg for at du sveiper opp fra den nederste kanten av skjermen.""Sørg for at du ikke setter på pause før du slipper.""Sørg for at du sveiper rett opp."
- "Du har fullført bevegelsen for å gå til startskjermen. I neste trinn ser du hvordan du går tilbake."
- "Du har fullført bevegelsen for å gå til startskjermen."
+ "Du har fullført bevegelsen for å gå til startskjermen. I neste trinn lærer du hvordan du bytter app.""Sveip for å gå til startskjermen""Sveip opp fra bunnen av skjermen. Denne bevegelsen tar deg alltid til startskjermen.""Sørg for at du sveiper opp fra den nederste kanten av skjermen.""Prøv å holde vinduet lenger før du slipper.""Sørg for at du sveiper rett opp, og så stopper du."
- "Du har lært hvordan du bruker bevegelser. For å slå av bevegelser, gå til Innstillinger."
- "Du har fullført bevegelsen for å bytte app."
+ "Du har fullført bevegelsen for å bytte app. Du er klar til å bruke telefonen.""Sveip for å bytte app"
- "For å bytte mellom apper, sveip opp fra bunnen av skjermen, hold, og slipp"
+ "Sveip opp fra bunnen av skjermen, hold og slipp.""Ferdig"
- "Ferdig"
+ "Neste"
+ "Ferdig""Innstillinger""Prøv igjen""Bra!""Veiledning %1$d/%2$d"
- "Alt er klart!"
- "Sveip opp for å gå til startskjermen"
- "Du er klar til å begynne å bruke telefonen"
- "Innstillinger for systemnavigasjon""Del""Skjermdump""Appen eller organisasjonen din tillater ikke denne handlingen"
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 91cae4775f..99ad8143e9 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -23,7 +23,7 @@
"फ्रिफर्म""हालसालैको कुनै पनि वस्तु छैन""एपको उपयोगका सेटिङहरू"
- "सबै मेटाउनुहोस्"
+ "सबै खाली गर्नुहोस्""हालसालैका एपहरू""%1$s, %2$s""< १ मिनेट"
@@ -31,57 +31,86 @@
"एपसम्बन्धी सुझावहरू""सबै एपहरू""तपाईंलाई चाहिने एपहरू"
- "आफ्नो होम स्क्रिनको पुछारको रोमा एपसम्बन्धी सिफारिस प्राप्त गर्नुहोस्"
- "आफ्नो होम स्क्रिनको मन पर्ने नामक पङ्क्तिमा एपसम्बन्धी सिफारिस प्राप्त गर्नुहोस्"
- "आफूले सबैभन्दा बढी प्रयोग गर्ने एप होम स्क्रिनबाट सजिलै चलाउनुहोस्। सिफारिस गरिने एपहरूको क्रम तपाईंले एप प्रयोग गर्ने समयतालिकाअनुसार बदलिने छ। फेदको रोमा रहेका एपहरू तपाईंको होम स्क्रिनको सिरानमा सर्ने छन्।"
+ "तपाईंको गृह स्क्रिनको पुछारको पङ्क्तिमा सिफारिस गरिएका एपहरू प्राप्त गर्नुहोस्"
+ "आफ्नो होम स्क्रिनको मन पर्ने नामक पङ्क्तिमा सिफारिस गरिएका एपहरू प्राप्त गर्नुहोस्"
+ "गृह स्क्रिनबाटै आफूले सबैभन्दा बढी प्रयोग गर्ने एप सजिलै चलाउनुहोस्। सिफारिस गरिने एपहरूको क्रम तपाईंले एप प्रयोग गर्ने समयतालिकाअनुसार बदलिने छ। फेदको पङ्क्तिमा रहेका एपहरू तपाईंको गृह स्क्रिनको सिरानमा सर्ने छन्।""आफूले सबैभन्दा बढी प्रयोग गर्ने एपहरू गृह स्क्रिनबाटै सजिलैसँग खोल्नुहोस्। सिफारिस गरिने एपहरूको क्रम तपाईंको दिनचर्याअनुसार बदलिने छ। मन पर्ने नामक पङ्क्तिमा रहेका एपहरू सारेर होम स्क्रिनमा लगिने छन्।""गृह स्क्रिनबाटै आफूले सबैभन्दा बढी प्रयोग गर्ने एप सजिलै चलाउनुहोस्। सिफारिस गरिने एपहरूको क्रम तपाईंले एप प्रयोग गर्ने समयतालिकाअनुसार बदलिने छ। फेदको पङ्क्तिमा रहेका एपहरू एउटा नयाँ फोल्डरमा सर्ने छन्।"
- "एपसम्बन्धी सिफारिस प्राप्त गर्नुहोस्"
+ "सिफारिस गरिएका एपहरू प्राप्त गर्नुहोस्""पर्दैन धन्यवाद""सेटिङ""सबैभन्दा बढी प्रयोग हुने एपहरू यहाँ देखिन्छन् र यी एपहरूको क्रम तपाईंले एप प्रयोग गर्ने समयतालिकाअनुसार बदलिरहन्छ"
- "एपसम्बन्धी सिफारिस प्राप्त गर्न फेदको रोमा रहेका एपहरू ड्र्याग गरी हटाउनुहोस्"
+ "सिफारिस गरिएका एपहरू प्राप्त गर्न फेदको पङ्क्तिमा रहेका एपहरू ड्र्याग गरी हटाउनुहोस्""खाली ठाउँमा सिफारिस गरिएका एपहरू थपिए""सिफारिस गरिएका एपहरू देखाउने सुविधा सक्षम पारिएका छन्""सिफारिस गरिएका एपहरू देखाउने सुविधा असक्षम पारिएको छ""पूर्वानुमान गरिएको एप: %1$s"
- "स्क्रिनको सबैभन्दा दायाँ किनारा वा सबैभन्दा बायाँ किनाराबाट स्वाइप गर्नुहोस्।"
- "स्क्रिनको दायाँ वा बायाँ किनाराबाट मध्य भागसम्म स्वाइप गर्नुहोस् अनि औँला उठाउनुहोस्।"
- "तपाईंले स्क्रिनको दायाँ किनाराबाट स्वाइप गरेर अघिल्लो स्क्रिनमा फर्कने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"
- "तपाईंले \'पछाडि जानुहोस्\' नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो।"
- "स्क्रिनको फेदको धेरै नजिकसम्म स्वाइप नगर्नुहोस्।"
- "\'पछाडि\' नामक इसाराको संवेदनशीलता बदल्न सेटिङमा जानुहोस्"
- "पछाडि जान स्वाइप गर्नुहोस्"
- "यसअघिको स्क्रिनमा फर्कन स्क्रिनको बायाँ वा दायाँ किनाराबाट मध्य भागसम्म स्वाइप गर्नुहोस्।"
- "स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्।"
- "औँला उठाउनुअघि नरोकिनुहोस्।"
- "सीधै माथितिर स्वाइप गर्नुहोस्।"
- "तपाईंले \'होम स्क्रिनमा जानुहोस्\' नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो। अब पछाडि जाने तरिका सिक्नुहोस्।"
- "तपाईंले \'होम स्क्रिनमा जानुहोस्\' नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो।"
- "होम स्क्रिनमा जान स्वाइप गर्नुहोस्"
- "स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्। यो इसारा प्रयोग गर्दा सधैँ होम स्क्रिन खुल्छ।"
- "स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्।"
- "स्क्रिनबाट औँला उठाउनुअघि एपको विन्डोमा केही बेर छोइराख्नुहोस्।"
- "सीधै माथितिर स्वाइप गर्नुहोस् अनि रोकिनुहोस्।"
- "तपाईंले इसाराहरू प्रयोग गर्ने तरिका सिक्नुभयो। इसारा अफ गर्न सेटिङमा जानुहोस्।"
- "तपाईंले \'एउटा एपबाट अर्को एपमा जानुहोस्\' नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो।"
- "एउटा एपबाट अर्को एपमा जान स्वाइप गर्नुहोस्"
- "एउटा एपबाट अर्कोमा जान स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्, छोइराख्नुहोस् अनि औँला उठाउनुहोस्।"
- "सबै तयार छ"
- "सम्पन्न भयो"
- "सेटिङ"
- "फेरि प्रयास गर्नुहोस्"
- "राम्रो!"
- "ट्युटोरियल %1$d/%2$d"
- "सबै तयार भयो!"
- "होममा जान माथितिर स्वाइप गर्नुहोस्"
- "तपाईं आफ्नो फोन चलाउन थाल्न सक्नुहुन्छ"
- "सिस्टम नेभिगेसनसम्बन्धी सेटिङ"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "सेयर गर्नुहोस्""स्क्रिनसट""यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"
- "नेभिगेसन ट्युटोरियल स्किप गर्ने हो?"
- "तपाईं पछि %1$s नामक एपमा गई यो ट्युटोरियल भेट्टाउन सक्नुहुन्छ"
- "रद्द गर्नुहोस्"
- "स्किप गर्नु…"
+
+
+ "तपाईं पछि %1$s एपमा गई यो ट्युटोरियल भेट्टाउन सक्नुहुन्छ"
+
+
+
+
diff --git a/quickstep/res/values-night/colors.xml b/quickstep/res/values-night/colors.xml
new file mode 100644
index 0000000000..af6e0647a1
--- /dev/null
+++ b/quickstep/res/values-night/colors.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ #99000000
+
+ #000000
+
+ #202124
+ #3c4043
+
+ #FF000000
+
+
\ No newline at end of file
diff --git a/quickstep/res/values-night/styles.xml b/quickstep/res/values-night/styles.xml
index 1bd3f5d138..e6b345010d 100644
--- a/quickstep/res/values-night/styles.xml
+++ b/quickstep/res/values-night/styles.xml
@@ -21,7 +21,7 @@
@android:color/transparentfalsefalse
- #FF000000
+ @android:color/transparent
\ No newline at end of file
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index a7084fb097..be9329f000 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -42,13 +42,15 @@
"De meestgebruikte apps worden hier weergegeven en kunnen veranderen op basis van je routines""Sleep apps weg van de onderste rij om app-suggesties te ontvangen""App-suggesties toegevoegd aan lege ruimte"
- "App-suggesties staan aan"
- "App-suggesties staan uit"
+ "App-suggesties zijn ingeschakeld"
+ "App-suggesties zijn uitgeschakeld""Voorspelde app: %1$s"
- "Swipe helemaal vanaf de rechter- of linkerrand."
- "Swipe vanaf de rechter- of linkerrand naar het midden van het scherm en laat los."
- "Je weet nu hoe je vanaf rechts kunt swipen om terug te gaan. Ontdek nu hoe je tussen apps schakelt."
- "Je weet nu hoe je het gebaar Terug maakt."
+ "Swipe helemaal vanaf de linkerrand."
+ "Swipe vanaf de linkerrand naar het midden van het scherm en laat los."
+ "Dat is alles. Swipe nu vanaf de rechterrand."
+ "Swipe helemaal vanaf de rechterrand."
+ "Swipe vanaf de rechterrand naar het midden van het scherm en laat los."
+ "Je hebt het gebaar Terug voltooid. Ontdek nu hoe je naar het startscherm gaat.""Swipe niet te dicht bij de onderkant van het scherm.""Open Instellingen om de gevoeligheid van Terug te wijzigen""Swipe om terug te gaan"
@@ -56,27 +58,22 @@
"Swipe vanaf de onderrand van het scherm omhoog.""Pauzeer niet voordat je loslaat.""Swipe recht omhoog."
- "Je weet nu hoe je weer naar het startscherm gaat. Ontdek als volgende hoe je weer teruggaat."
- "Je weet nu hoe je teruggaat naar het startscherm."
+ "Je hebt het gebaar Naar startscherm voltooid. Ontdek nu hoe je tussen apps schakelt.""Swipe om naar het startscherm te gaan""Swipe omhoog vanaf de onderkant van het scherm. Met dit gebaar ga je altijd naar het startscherm.""Swipe vanaf de onderrand van het scherm omhoog.""Houd het venster langer vast voordat je loslaat.""Swipe recht omhoog en pauzeer dan."
- "Je weet nu hoe je gebaren gebruikt. Als je gebaren wilt uitzetten, kun je dat via Instellingen doen."
- "Je weet nu hoe je het gebaar Schakelen tussen apps maakt."
+ "Je hebt het gebaar Schakelen tussen apps voltooid. Je kunt nu je telefoon gebruiken.""Swipe om tussen apps te schakelen"
- "Swipe omhoog vanaf de onderkant van het scherm, houd vast en laat los om tussen apps te schakelen."
+ "Swipe omhoog vanaf de onderkant van het scherm, houd vast en laat dan los.""Klaar"
- "Klaar"
+ "Volgende"
+ "Klaar""Instellingen"
- "Probeer opnieuw"
+ "Opnieuw""Dat gaat lekker.""Tutorial %1$d/%2$d"
- "Klaar"
- "Swipe omhoog om naar het startscherm te gaan"
- "Je bent klaar om je telefoon te gebruiken"
- "Navigatie-instellingen van systeem""Delen""Screenshot""Deze actie wordt niet toegestaan door de app of je organisatie"
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 9488021139..8c3697296f 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -45,10 +45,12 @@
"ଆପ୍ ପରାମର୍ଶଗୁଡ଼ିକୁ ସକ୍ଷମ କରାଯାଇଛି""ଆପ୍ ପରାମର୍ଶଗୁଡ଼ିକୁ ଅକ୍ଷମ କରାଯାଇଛି""ପୂର୍ବାନୁମାନ କରାଯାଇଥିବା ଆପ୍: %1$s"
- "ଆପଣ ସ୍କ୍ରିନର ଏକଦମ୍-ଡାହାଣ ବା ବାମ ଧାରରୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"
- "ଆପଣ ସ୍କ୍ରିନର ଡାହାଣ ବା ବାମ ଧାରରୁ ମଝିକୁ ସ୍ୱାଇପ୍ କରି ଛାଡ଼ି ଦେଉଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"
- "ଆପଣ ଡାହାଣରୁ ସ୍ୱାଇପ୍ କରି ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣିଲେ। ତା\'ପରେ, ଆପକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"
- "ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"
+ "ଆପଣ ଦୂର-ବାମ ଧାରରୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"
+ "ଆପଣ ସ୍କ୍ରିନର ବାମ ଧାରରୁ ମଝିକୁ ସ୍ୱାଇପ୍ କରି ଛାଡ଼ି ଦେଉଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"
+ "କେବଳ ଏତିକି! ବର୍ତ୍ତମାନ ଡାହାଣ ଧାରରୁ ସ୍ୱାଇପ୍ କରି ଦେଖନ୍ତୁ।"
+ "ଆପଣ ଦୂର-ଡାହାଣ ଧାରରୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"
+ "ଆପଣ ସ୍କ୍ରିନର ଡାହାଣ ଧାରରୁ ମଝିକୁ ସ୍ୱାଇପ୍ କରି ଛାଡ଼ି ଦେଉଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"
+ "ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ମୂଳପୃଷ୍ଠାକୁ କିପରି ଯିବେ ଜାଣନ୍ତୁ।""ଆପଣ ସ୍କ୍ରିନର ତଳଭାଗର ଅତି ନିକଟରୁ ସ୍ୱାଇପ୍ କରୁନଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।""ପଛକୁ ଫେରିବା ଜେଶ୍ଚରର ସମ୍ବେଦନଶୀଳତା ବଦଳାଇବାକୁ ସେଟିଂସକୁ ଯାଆନ୍ତୁ""ପଛକୁ ଫେରିବା ପାଇଁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"
@@ -56,27 +58,22 @@
"ଆପଣ ସ୍କ୍ରିନର ତଳ ଧାରରୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।""ଆପଣ ଛାଡ଼ିବା ପୂର୍ବରୁ ବିରତ କରୁନଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।""ଆପଣ ସିଧା ଉପରକୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"
- "ଆପଣ \'ମୂଳପୃଷ୍ଠାକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣନ୍ତୁ।"
- "ଆପଣ \'ମୂଳପୃଷ୍ଠାକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"
+ "ଆପଣ \'ମୂଳପୃଷ୍ଠାକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ଆପଗୁଡ଼ିକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ଜାଣନ୍ତୁ।""ମୂଳପୃଷ୍ଠାକୁ ଯିବା ପାଇଁ ସ୍ୱାଇପ୍ କରନ୍ତୁ""ଆପଣଙ୍କ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ। ଏହି ଜେଶ୍ଚର୍ ସର୍ବଦା ଆପଣଙ୍କୁ ମୂଳସ୍କ୍ରିନକୁ ନେଇଥାଏ।""ଆପଣ ସ୍କ୍ରିନର ତଳ ଧାରରୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।""ୱିଣ୍ଡୋକୁ ରିଲିଜ୍ କରିବା ପୂର୍ବରୁ ଅଧିକ ସମୟ ଧରି ରଖିବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ।""ଆପଣ ସିଧା ଉପରକୁ ସ୍ୱାଇପ୍ କରି ତା\'ପରେ ବିରତ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"
- "ଜେଶ୍ଚରଗୁଡ଼ିକୁ କିପରି ବ୍ୟବହାର କରାଯିବ ଆପଣ ତାହା ଶିଖିଛନ୍ତି। ଜେଶ୍ଚରଗୁଡ଼ିକୁ ବନ୍ଦ କରିବାକୁ, ସେଟିଂସକୁ ଯାଆନ୍ତୁ।"
- "ଆପଣ \'ଆପଗୁଡ଼ିକୁ ସ୍ୱିଚ୍ କରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"
+ "ଆପଣ \'ଆପଗୁଡ଼ିକୁ ସ୍ୱିଚ୍ କରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ଆପଣ ଆପଣଙ୍କ ଫୋନ୍ ବ୍ୟବହାର କରିବାକୁ ପ୍ରସ୍ତୁତ ଅଛନ୍ତି!""ଆପଗୁଡ଼ିକୁ ସ୍ୱିଚ୍ କରିବା ପାଇଁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"
- "ଆପଗୁଡ଼ିକ ମଧ୍ୟରେ ସ୍ୱିଚ୍ କରିବାକୁ, ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ, ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ୍ କରନ୍ତୁ।"
+ "ଆପଣଙ୍କ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ, ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ୍ କରନ୍ତୁ।""ସବୁ ପ୍ରସ୍ତୁତ"
- "ହୋଇଗଲା"
+ "ପରବର୍ତ୍ତୀ"
+ "ହୋଇଗଲା""ସେଟିଂସ୍""ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ""ବଢ଼ିଆ!""ଟ୍ୟୁଟୋରିଆଲ୍ %1$d/%2$d"
- "ସମ୍ପୂର୍ଣ୍ଣ ଭାବେ ପ୍ରସ୍ତୁତ!"
- "ମୂଳପୃଷ୍ଠାକୁ ଯିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"
- "ଆପଣ ଆପଣଙ୍କ ଫୋନ୍ ବ୍ୟବହାର କରିବା ପାଇଁ ପ୍ରସ୍ତୁତ ଅଛନ୍ତି"
- "ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ସେଟିଂସ୍""ସେୟାର୍ କରନ୍ତୁ""ସ୍କ୍ରିନସଟ୍""ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 89b21194f5..227c060230 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -45,10 +45,12 @@
"ਐਪ ਸੁਝਾਵਾਂ ਨੂੰ ਚਾਲੂ ਕੀਤਾ ਗਿਆ""ਐਪ ਸੁਝਾਵਾਂ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ""ਪੂਰਵ ਅਨੁਮਾਨਿਤ ਐਪ: %1$s"
- "ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸੱਜੇ ਜਾਂ ਖੱਬੇ ਪਾਸੇ ਦੇ ਬਿਲਕੁਲ ਕਿਨਾਰੇ ਤੋਂ ਸਵਾਈਪ ਕਰਦੇ ਹੋ।"
- "ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸੱਜੇ ਜਾਂ ਖੱਬੇ ਕਿਨਾਰੇ ਤੋਂ ਸਕ੍ਰੀਨ ਦੇ ਵਿਚਕਾਰ ਤੱਕ ਸਵਾਈਪ ਕਰਦੇ ਹੋ ਅਤੇ ਛੱਡ ਦਿੰਦੇ ਹੋ।"
- "ਤੁਸੀਂ ਪਿੱਛੇ ਜਾਣ ਲਈ ਸੱਜੇ ਪਾਸੇ ਤੋਂ ਸਵਾਈਪ ਕਰਨ ਦਾ ਤਰੀਕਾ ਜਾਣਿਆ। ਅੱਗੇ, ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਦਾ ਤਰੀਕਾ ਜਾਣੋ।"
- "ਤੁਸੀਂ \'ਵਾਪਸ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"
+ "ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਦੂਰ-ਖੱਬੇ ਕਿਨਾਰੇ ਤੋਂ ਸਵਾਈਪ ਕਰਦੇ ਹੋ।"
+ "ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਖੱਬੇ ਕਿਨਾਰੇ ਤੋਂ ਸਕ੍ਰੀਨ ਦੇ ਵਿਚਕਾਰ ਤੱਕ ਸਵਾਈਪ ਕਰਦੇ ਹੋ ਅਤੇ ਛੱਡ ਦਿੰਦੇ ਹੋ।"
+ "ਹੋ ਗਿਆ! ਹੁਣ ਸੱਜੇ ਕਿਨਾਰੇ ਤੋਂ ਸਵਾਈਪ ਕਰਕੇ ਦੇੇਖੋ।"
+ "ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਦੂਰ-ਸੱਜੇ ਕਿਨਾਰੇ ਤੋਂ ਸਵਾਈਪ ਕਰਦੇ ਹੋ।"
+ "ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸੱਜੇ ਕਿਨਾਰੇ ਤੋਂ ਸਕ੍ਰੀਨ ਦੇ ਵਿਚਕਾਰ ਤੱਕ ਸਵਾਈਪ ਕਰਦੇ ਹੋ ਅਤੇ ਛੱਡ ਦਿੰਦੇ ਹੋ।"
+ "ਤੁਸੀਂ \'ਵਾਪਸ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ। ਅੱਗੇ, ਜਾਣੋ ਕਿ ਹੋਮ \'ਤੇ ਕਿਵੇਂ ਜਾਣਾ ਹੈ।""ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਹਿੱਸੇ ਦੇ ਬਹੁਤ ਨੇੜੇ ਸਵਾਈਪ ਨਾ ਕਰੋ।""ਪਿੱਛੇ ਜਾਣ ਦੇ ਸੰਕੇਤ ਦੀ ਸੰਵੇਦਨਸ਼ੀਲਤਾ ਬਦਲਣ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ""ਪਿੱਛੇ ਜਾਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"
@@ -56,27 +58,22 @@
"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਕਿਨਾਰੇ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਦੇ ਹੋ।""ਪੱਕਾ ਕਰੋ ਕਿ ਸਕ੍ਰੀਨ ਨੂੰ ਛੱਡਣ ਤੋਂ ਪਹਿਲਾਂ ਰੁਕੋ ਨਾ।""ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਿੱਧੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਦੇ ਹੋ।"
- "ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ। ਅੱਗੇ, ਜਾਣੋ ਕਿ ਪਿੱਛੇ ਕਿਵੇਂ ਜਾਣਾ ਹੈ।"
- "ਤੁਸੀਂ \'ਹੋਮ \'ਤੇ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"
+ "ਤੁਸੀਂ ਹੋਮ \'ਤੇ ਜਾਓ ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ। ਅੱਗੇ, ਜਾਣੋ ਕਿ ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਿਵੇਂ ਕਰਨੀ ਹੈ।""ਹੋਮ \'ਤੇ ਜਾਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"
- "ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ। ਇਹ ਇਸ਼ਾਰਾ ਹਮੇਸ਼ਾਂ ਤੁਹਾਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲੈ ਜਾਂਦਾ ਹੈ।"
+ "ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ। ਇਹ ਸੰਕੇਤ ਹਮੇਸ਼ਾਂ ਤੁਹਾਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲੈ ਜਾਂਦਾ ਹੈ।""ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਕਿਨਾਰੇ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਦੇ ਹੋ।""ਛੱਡਣ ਤੋਂ ਪਹਿਲਾਂ ਵਿੰਡੋ ਨੂੰ ਕੁਝ ਸਮੇਂ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।""ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਿੱਧੇ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਦੇ ਹੋ, ਫਿਰ ਰੋਕੋ।"
- "ਤੁਸੀਂ ਇਸ਼ਾਰੇ ਵਰਤਣ ਬਾਰੇ ਜਾਣਿਆ। ਇਸ਼ਾਰੇ ਬੰਦ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"
- "ਤੁਸੀਂ \'ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਰੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ।"
+ "ਤੁਸੀਂ ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ। ਤੁਸੀਂ ਆਪਣੇ ਫ਼ੋਨ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਤਿਆਰ ਹੋ!""ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਸਵਾਈਪ ਕਰੋ"
- "ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ, ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ ਅਤੇ ਫਿਰ ਛੱਡੋ।"
+ "ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ, ਅਤੇ ਫਿਰ ਛੱਡੋ।""ਪੂਰੀ ਤਰ੍ਹਾਂ ਤਿਆਰ"
- "ਹੋ ਗਿਆ"
+ "ਅੱਗੇ"
+ "ਹੋ ਗਿਆ""ਸੈਟਿੰਗਾਂ""ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ""ਵਧੀਆ!""ਟਿਊਟੋਰੀਅਲ %1$d/%2$d"
- "ਪੂਰੀ ਤਰ੍ਹਾਂ ਤਿਆਰ!"
- "ਹੋਮ \'ਤੇ ਜਾਣ ਲਈ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"
- "ਤੁਸੀਂ ਆਪਣਾ ਫ਼ੋਨ ਵਰਤਣ ਲਈ ਤਿਆਰ ਹੋ"
- "ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਸੈਟਿੰਗਾਂ""ਸਾਂਝਾ ਕਰੋ""ਸਕ੍ਰੀਨਸ਼ਾਟ""ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 893db91b6c..61d9b9377a 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -45,38 +45,35 @@
"Włączono sugestie aplikacji""Sugestie aplikacji są wyłączone""Przewidywana aplikacja: %1$s"
- "Pamiętaj, aby przesuwać palcem od samej prawej lub lewej krawędzi."
- "Pamiętaj, aby przesuwać palcem od prawej lub lewej krawędzi do środka ekranu i podnieść palec."
- "Wiesz już, jak przesuwać palcem, aby przejść wstecz. Poćwicz teraz przełączanie aplikacji."
- "Gest przejścia wstecz został opanowany."
+ "Pamiętaj, aby przesuwać palcem od samej lewej krawędzi."
+ "Pamiętaj, aby przesuwać palcem od lewej krawędzi do środka ekranu, a potem podnieść palec."
+ "Dobrze. Teraz przesuń palcem od prawej krawędzi."
+ "Pamiętaj, aby przesuwać palcem od samej prawej krawędzi."
+ "Pamiętaj, aby przesuwać palcem od prawej krawędzi do środka ekranu, a potem podnieść palec."
+ "Gest przejścia wstecz został opanowany. Poćwicz teraz przechodzenie na ekran główny.""Pamiętaj, aby nie przesuwać palcem zbyt blisko dolnej części ekranu.""Czułość gestu cofania możesz zmienić w Ustawieniach"
- "Przesuń palcem, aby przejść wstecz"
+ "Przesuwanie palcem, aby przejść wstecz""Aby wrócić do ostatniego ekranu, przesuń palcem od lewej lub prawej krawędzi do środka ekranu.""Pamiętaj, aby przesuwać palcem od dolnej krawędzi ekranu.""Pamiętaj, aby przed podniesieniem palca nie było przerwy.""Pamiętaj, aby przesuwać palcem prosto do góry."
- "Potrafisz już przejść na ekran główny. Poćwicz teraz powrót do wcześniejszego ekranu."
- "Gest przechodzenia na ekran główny został opanowany."
- "Przesuń palcem, aby przejść na ekran główny"
+ "Gest przechodzenia na ekran główny został opanowany. Poćwicz teraz przełączanie aplikacji."
+ "Przesuwanie palcem, aby przejść na ekran główny""Przesuń palcem z dołu ekranu. Ten gest zawsze powoduje przejście na ekran główny.""Pamiętaj, aby przesuwać palcem od dolnej krawędzi ekranu.""Przytrzymaj okno dłużej, zanim podniesiesz palec.""Pamiętaj, aby przesuwać palcem prosto do góry, a potem przerwać ruch."
- "Wiesz już, jak używać gestów. Aby wyłączyć gesty, przejdź do Ustawień."
- "Gest przełączania aplikacji został opanowany."
- "Przesuń palcem, aby przełączać aplikacje"
- "Aby przełączać się między aplikacjami, przesuń palcem od dołu ekranu, przytrzymaj i puść."
+ "Gest przełączania aplikacji został opanowany. Możesz już używać telefonu."
+ "Przesuwanie palcem, aby przełączać aplikacje"
+ "Przesuń palcem od dołu ekranu, przytrzymaj i puść.""Wszystko gotowe"
- "Gotowe"
+ "Dalej"
+ "Gotowe""Ustawienia""Spróbuj ponownie""Super!""Samouczek %1$d/%2$d"
- "Wszystko gotowe"
- "Aby przejść na stronę główną, przesuń palcem w górę"
- "Teraz możesz zacząć używać telefonu"
- "Ustawienia nawigacji w systemie""Udostępnij""Zrzut ekranu""Nie możesz wykonać tego działania, bo nie zezwala na to aplikacja lub Twoja organizacja"
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index c1cd2bbb92..0feead77b1 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -45,10 +45,12 @@
"Sugestões de apps ativadas""As sugestões de apps estão desativadas""App prevista: %1$s"
- "Deslize rapidamente a partir da extremidade mais à direita ou mais à esquerda."
- "Deslize rapidamente a partir da extremidade esquerda ou direita até ao centro do ecrã e solte."
- "Aprendeu a deslizar a partir da direita para retroceder. A seguir, saiba como alternar entre apps."
- "Concluiu o gesto para retroceder."
+ "Garanta que desliza rapidamente com o dedo a partir da extremidade esquerda."
+ "Garanta que desliza rapidamente com o dedo do limite esquerdo até ao centro do ecrã e solta."
+ "Já está! Agora deslize rapidamente do limite direito."
+ "Garanta que desliza rapidamente com o dedo a partir da extremidade direita."
+ "Garanta que desliza rapidamente com o dedo do limite direito até ao centro do ecrã e solta."
+ "Concluiu o gesto para retroceder. A seguir, saiba como aceder à Página inicial.""Garanta que não desliza rapidamente com o dedo demasiado perto da parte inferior do ecrã.""Altere a sensibilidade do gesto para voltar nas Definições.""Deslize rapidamente com o dedo para retroceder"
@@ -56,27 +58,22 @@
"Garanta que desliza rapidamente com o dedo a partir do limite inferior do ecrã.""Garanta que não faz uma pausa antes de soltar.""Garanta que desliza rapidamente com o dedo para cima."
- "Concluiu o gesto para aceder ao ecrã principal. A seguir, saiba como retroceder."
- "Concluiu o gesto para aceder ao ecrã principal."
- "Deslize rapidamente com o dedo para aceder ao ecrã principal"
+ "Concluiu o gesto para aceder à Página inicial. A seguir, saiba como alternar entre apps."
+ "Deslize rapidamente com o dedo para aceder à Página inicial""Deslize rapidamente para cima a partir da parte inferior. Este gesto abre sempre o ecrã principal."
- "Deslize rapidamente com o dedo a partir do limite inferior do ecrã."
+ "Garanta que desliza rapidamente com o dedo a partir do limite inferior do ecrã.""Experimente premir a janela durante mais tempo antes de soltar.""Garanta que desliza rapidamente com o dedo para cima e, em seguida, faz uma pausa."
- "Aprendeu a utilizar gestos. Para desativar os gestos, aceda às Definições."
- "Concluiu o gesto para alternar entre apps."
+ "Concluiu o gesto para alternar entre apps. Já pode utilizar o seu telemóvel!""Deslize rapidamente com o dedo para alternar entre apps"
- "Para alternar entre apps, deslize para cima sem soltar a partir da parte inferior do ecrã e solte."
+ "Deslize rapidamente para cima a partir da parte inferior do ecrã sem soltar e, em seguida, solte.""Está tudo pronto"
- "Concluído"
+ "Seguinte"
+ "Concluído""Definições""Tente novamente""Boa!""Tutorial %1$d/%2$d"
- "Tudo pronto!"
- "Deslize rapidamente para cima para aceder ao ecrã principal"
- "Já pode começar a utilizar o seu telemóvel"
- "Definições de navegação do sistema""Partilhar""Fazer captura de ecrã""Esta ação não é permitida pela app ou a sua entidade."
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 422d13af89..f533bbcbc3 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -45,10 +45,12 @@
"O recurso \"sugestões de apps\" está ativado""O recurso \"sugestões de apps\" está desativado""App previsto: %1$s"
- "Deslize da borda direita ou esquerda."
- "Deslize da borda direita ou esquerda até o meio da tela e solte."
- "Você aprendeu a deslizar da direita para voltar. A seguir, aprenda a trocar de app."
- "Você concluiu o gesto para voltar."
+ "Deslize da borda esquerda."
+ "Deslize da borda esquerda até o meio da tela e solte."
+ "Pronto! Agora tente deslizar da borda direita."
+ "Deslize da borda direita."
+ "Deslize da borda direita até o meio da tela e solte."
+ "Você concluiu o gesto para voltar. A seguir, aprenda a acessar a tela inicial.""Não deslize perto demais da parte inferior da tela.""Mude a sensibilidade do gesto de voltar nas configurações""Deslize para voltar"
@@ -56,27 +58,22 @@
"Deslize da borda inferior da tela para cima.""Não pare antes de soltar.""Deslize para cima."
- "Você concluiu o gesto para acessar a tela inicial. A seguir, aprenda a voltar."
- "Você concluiu o gesto para acessar a tela inicial."
+ "Você concluiu o gesto para acessar a tela inicial. A seguir, aprenda a trocar de app.""Deslizar para voltar à tela inicial""Deslize de baixo para cima na tela. Esse gesto sempre leva você para a tela inicial.""Deslize da borda inferior da tela para cima.""Mantenha a janela pressionada por mais tempo antes de soltar.""Deslize para cima e pare."
- "Você aprendeu a usar gestos. Para desativá-los, acesse as Configurações."
- "Você concluiu o gesto para trocar de app."
+ "Você concluiu o gesto para trocar de app. Você já pode usar o smartphone.""Deslizar para trocar de app"
- "Para mudar de app, deslize de baixo para cima na tela, mantenha-a pressionada por um tempo e solte."
+ "Deslize de baixo para cima na tela, mantenha-a pressionada e depois solte.""Tudo pronto"
- "Concluído"
+ "Próxima"
+ "Concluído""Configurações""Tentar novamente""Muito bem!""Tutorial %1$d/%2$d"
- "Tudo pronto!"
- "Deslize para cima para acessar a tela inicial"
- "Você já pode começar a usar seu smartphone"
- "Configurações de navegação do sistema""Compartilhar""Capturar tela""Essa ação não é permitida pelo app ou pela organização"
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index a5e97e0519..37d2935683 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -45,10 +45,12 @@
"Sugestiile de aplicații au fost activate""Sugestiile de aplicații au fost dezactivate""Aplicația estimată: %1$s"
- "Glisați dinspre marginea dreaptă îndepărtată sau dinspre marginea stângă îndepărtată."
- "Glisați dinspre marginea dreaptă sau stângă spre mijlocul ecranului și eliberați."
- "Ați învățat cum să glisați dinspre dreapta pentru a reveni. În continuare, aflați cum să comutați aplicațiile."
- "Ați finalizat gestul „înapoi”."
+ "Glisați dinspre marginea stângă îndepărtată."
+ "Glisați dinspre marginea stângă spre mijlocul ecranului și eliberați."
+ "Atât! Acum încercați să glisați dinspre marginea dreaptă."
+ "Glisați dinspre marginea dreaptă îndepărtată."
+ "Glisați dinspre marginea dreaptă spre mijlocul ecranului și eliberați."
+ "Ați finalizat gestul „Înapoi”. În continuare, aflați cum să accesați pagina de pornire.""Nu glisați prea aproape de partea de jos a ecranului.""Schimbați sensibilitatea gestului „Înapoi” accesând Setările""Glisați pentru a reveni"
@@ -56,27 +58,22 @@
"Glisați în sus dinspre marginea de jos a ecranului.""Nu întrerupeți gestul înainte de a elibera.""Glisați direct în sus."
- "Ați finalizat gestul „accesați ecranul de pornire”. În continuare, aflați cum să reveniți."
- "Ați finalizat gestul „accesați ecranul de pornire”."
- "Glisați pentru a accesa ecranul de pornire"
+ "Ați finalizat gestul „Pagina de pornire”. În continuare, aflați cum să comutați aplicațiile."
+ "Glisați pentru a accesa pagina de pornire""Glisați în sus din partea de jos a ecranului. Cu acest gest accesați întotdeauna ecranul de pornire.""Glisați în sus dinspre marginea de jos a ecranului.""Încercați să țineți fereastra mai mult înainte s-o eliberați.""Glisați direct în sus, apoi întrerupeți."
- "Ați învățat cum să folosiți gesturi. Pentru a dezactiva gesturile, accesați Setările."
- "Ați finalizat gestul „comutați între aplicații”."
+ "Ați finalizat gestul „schimbați aplicațiile”. Sunteți gata să vă folosiți telefonul!""Glisați pentru a comuta între aplicații"
- "Ca să comutați între aplicații, glisați în sus din partea de jos a ecranului, așteptați și eliberați."
+ "Glisați în sus din partea de jos a ecranului, așteptați, apoi eliberați.""Gata"
- "Gata"
+ "Înainte"
+ "Gata""Setări""Reîncercați""Bravo!""Tutorialul %1$d / %2$d"
- "Gata!"
- "Glisați în sus pentru a accesa ecranul de pornire"
- "Sunteți gata să folosiți telefonul"
- "Setările de navigare ale sistemului""Distribuiți""Captură de ecran""Această acțiune nu este permisă de aplicație sau de organizația dvs."
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 7c4d485012..8d4c40a210 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -33,22 +33,24 @@
"Ваши рекомендуемые приложения""Рекомендуемые приложения будут появляться в нижнем ряду на главном экране""Рекомендуемые приложения будут появляться в разделе избранных на главном экране"
- "Приложения, которыми вы часто пользуетесь, будут доступны прямо на главном экране. Их список может меняться с учетом ваших предпочтений. Приложения из нижнего ряда будут перемещены выше на главном экране."
+ "Быстрый доступ к часто используемым приложениям на главном экране. Список меняется с учетом ваших привычек. Приложения из нижнего ряда будут перемещены вверх на главный экран.""Включите функцию для быстрого доступа к часто используемым приложениям на главном экране. Список меняется с учетом ваших действий. Приложения из раздела избранных будут перемещены на главный экран."
- "Приложения, которыми вы часто пользуетесь, будут доступны прямо на главном экране. Их список может меняться с учетом ваших предпочтений. Приложения из нижнего ряда будут перемещены в новую папку."
+ "Быстрый доступ к часто используемым приложениям на главном экране. Список меняется с учетом ваших привычек. Приложения из нижнего ряда будут перемещены в новую папку.""Показывать рекомендации""Отмена""Настройки""Здесь появляются часто используемые приложения. Список меняется с учетом ваших привычек."
- "Перетащите приложения из нижнего ряда, чтобы получить рекомендации."
+ "Перетащите приложения из нижнего ряда, чтобы получить рекомендации""Рекомендуемые приложения будут появляться на свободных местах.""Функция \"Рекомендуемые приложения\" включена.""Функция \"Рекомендуемые приложения\" отключена.""Рекомендуемое приложение: %1$s"
- "Проведите справа налево или слева направо от самого края экрана."
- "Проведите от правого или левого края экрана до середины дисплея и отпустите палец."
- "Теперь вы знаете, как вернуться, проведя справа налево. Далее мы расскажем, как переключаться между приложениями."
- "Вы выполнили жест для перехода назад."
+ "Проведите слева направо от самого края экрана."
+ "Проведите от левого края экрана до середины дисплея и отпустите палец."
+ "Готово! Теперь попробуйте провести от правого края экрана."
+ "Проведите справа налево от самого края экрана."
+ "Проведите от правого края экрана до середины дисплея и отпустите палец."
+ "Вы выполнили жест \"Назад\". Далее мы расскажем, как переходить на главный экран.""Проведите пальцем не слишком близко к нижнему краю экрана.""Уровень чувствительности можно изменить в настройках.""Возврат к предыдущему экрану"
@@ -56,27 +58,22 @@
"Проведите снизу вверх от самого края экрана.""Не приостанавливайтесь перед тем, как отпустить палец.""Проведите по экрану ровно вверх."
- "Вы выполнили жест для перехода на главный экран. Далее мы расскажем, как вернуться назад."
- "Вы выполнили жест для перехода на главный экран."
+ "Вы выполнили жест \"На главный экран\". Далее мы расскажем, как переключаться между приложениями.""Переход на главный экран""Проведите вверх от нижнего края дисплея. Этот жест открывает главный экран.""Проведите снизу вверх от самого края экрана.""Прежде чем отпускать палец, задержите его на дисплее подольше.""Проведите по экрану ровно вверх, а затем задержите палец в крайнем положении."
- "Теперь вы знаете, как использовать жесты. Чтобы отключить их, перейдите в настройки."
- "Вы выполнили жест для переключения между приложениями."
+ "Вы выполнили жест \"Переключение между приложениями\". Теперь вы готовы начать работу с телефоном.""Переключение между приложениями"
- "Чтобы переключиться между приложениями‚ проведите по экрану снизу вверх, задержите палец, а затем отпустите."
+ "Проведите вверх от нижнего края экрана, задержите палец в крайнем положении, а затем отпустите.""Готово"
- "Готово"
+ "Далее"
+ "Готово""Настройки""Повторите попытку""Поздравляем!""Руководство (шаг %1$d из %2$d)"
- "Готово!"
- "Чтобы перейти на главный экран, проведите вверх."
- "Теперь вы можете использовать телефон."
- "Системные настройки навигации""Поделиться""Скриншот""Это действие заблокировано приложением или организацией."
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 5f322e6af2..d526e139ee 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -45,10 +45,12 @@
"යෙදුම් යෝජනා සබලිතයි""යෙදුම් යෝජනා අබල කර ඇත""පුරෝකථනය කළ යෙදුම: %1$s"
- "ඔබ ඈත දකුණු හෝ ඈත වම් දාරයේ ස්වයිප් කරන බව සහතික කර ගන්න."
- "ඔබ දකුණු හෝ වම් දාරයේ සිට තිරයේ මැදට ස්වයිප් කර අත හරින බව සහතික කර ගන්න."
- "ආපසු යාමට දකුණේ සිට ස්වයිප් කරන්නේ කෙසේදැයි ඔබ දැන ගත්තේය. ඊළඟට, යෙදුම් මාරු කරන ආකාරය දැන ගන්න."
- "ඔබ ආපසු යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි."
+ "ඔබ ඈත වම් දාරයෙන් ස්වයිප් කරන බවට සහතික කර ගන්න."
+ "ඔබ වම් දාරයේ සිට තිරයේ මැදට ස්වයිප් කර අත හරින බව සහතික කර ගන්න."
+ "එච්චරයි! දැන් දකුණු දාරයෙන් ස්වයිප් කිරීම උත්සාහ කරන්න."
+ "ඔබ ඈත දකුණු දාරයෙන් ස්වයිප් කරන බවට සහතික කර ගන්න."
+ "ඔබ දකුණු දාරයේ සිට තිරයේ මැදට ස්වයිප් කර අත හරින බව සහතික කර ගන්න."
+ "ඔබ ආපසු යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි. ඊළඟට, මුල් පිටුවට යන ආකාරය දැන ගන්න.""ඔබ තිරයේ පහළට ඉතාම සමීපව ස්වයිප් නොකරන බවට සහතික කර ගන්න.""ආපසු ඉංගිතයෙහි සංවේදීතාව වෙනස් කිරීමට, සැකසීම් වෙත යන්න""ආපසු යාමට ස්වයිප් කරන්න"
@@ -56,27 +58,22 @@
"ඔබ තිරයේ පහළ දාරයේ සිට ඉහළට ස්වයිප් කරන බව සහතික කර ගන්න.""යාමට ඉඩ හැරීමට පෙර ඔබ විරාමයක් නොගන්නා බව සහතික කර ගන්න.""ඔබ කෙලින්ම ඉහළට ස්වයිප් කරන බව සහතික කර ගන්න."
- "ඔබ මුල් පිටුවට යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි. ඊළඟට, ආපසු යන ආකාරය දැන ගන්න."
- "ඔබ මුල් පිටුවට යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි."
+ "ඔබ මුල් පිටුවට යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි. ඊළඟට, යෙදුම් මාරු කරන ආකාරය දැන ගන්න.""මුල් පිටුවට යාමට ස්වයිප් කරන්න""ඔබගේ තිරයේ පහළින් උඩට ස්වයිප් කරන්න.මෙම ඉංගිතය සැම විටම ඔබව මුල් තිරයට ගෙන යයි.""ඔබ තිරයේ පහළ දාරයේ සිට ඉහළට ස්වයිප් කරන බව සහතික කර ගන්න.""මුදා හැරීමට පෙර කවුළුව වැඩි වේලාවක් රඳවා තබා ගැනීමට උත්සාහ කරන්න.""ඔබ කෙලින්ම ඉහළට ස්වයිප් කර, අනතුරුව විරාම කරන බව සහතික කර ගන්න."
- "ඔබ ඉංගිත භාවිත කරන ආකාරය දැන ගෙන ඇත. ඉංගිත ක්රියාවිරහිත කිරීමට, සැකසීම් වෙත යන්න."
- "ඔබ යෙදුම් මාරු කිරීමේ ඉංගිතය සම්පූර්ණ කර ඇත."
+ "ඔබ යෙදුම් මාරු කිරීමේ ඉංගිතය සම්පූර්ණ කළේය. ඔබ ඔබගේ දුරකථනය භාවිත කිරීමට සූදානම්ය!""යෙදුම් මාරු කිරීමට ස්වයිප් කරන්න"
- "යෙදුම් අතර මාරු වීමට, ඔබගේ තිරයේ පහළම සිට උඩට ස්වයිප් කර, අල්ලාගෙන සිට, අනතුරුව මුදා හරින්න."
+ "ඔබගේ තිරයේ පහළින් උඩට ස්වයිප් කර, අල්ලාගෙන සිට, අනතුරුව මුදා හරින්න.""සියල්ල සකසා ඇත"
- "නිමයි"
+ "ඊළඟ"
+ "නිමයි""සැකසීම්""නැවත උත්සාහ කරන්න""කදිමයි!""නිබන්ධනය %1$d/%2$d"
- "සියල්ල සූදානම්!"
- "මුල් පිටුවට යාමට ඉහළට ස්වයිප් කරන්න"
- "ඔබ ඔබගේ දුරකථනය භාවිත කිරීම පටන් ගැනීමට සූදානම්"
- "පද්ධති සංචාලන සැකසීම්""බෙදා ගන්න""තිර රුව""මෙම ක්රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 799e94174b..24a4ac974f 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -45,10 +45,12 @@
"Návrhy aplikácií zapnuté""Návrhy aplikácií vypnuté""Predpovedaná aplikácia: %1$s"
- "Musite potiahnuť z úplne krajného pravého alebo ľavého okraja."
- "Musíte potiahnuť z pravého alebo ľavého okraja do stredu obrazovky a potom uvoľniť."
- "Naučili ste sa prejsť späť potiahnutím sprava. V ďalšom kroku sa naučíte prepínať aplikácie."
- "Dokončili ste gesto na prechod späť."
+ "Musite potiahnuť z úplne krajného ľavého okraja."
+ "Musíte potiahnuť z ľavého okraja do stredu obrazovky a uvoľniť."
+ "Hotovo! Teraz skúste potiahnuť z pravého okraja."
+ "Musite potiahnuť z úplne krajného pravého okraja."
+ "Musíte potiahnuť z pravého okraja do stredu obrazovky a uvoľniť."
+ "Dokončili ste gesto na prejdenie späť. V ďalšom kroku sa naučíte, ako prejsť na plochu.""Nesmiete potiahnuť príliš blízko dolnej časti obrazovky.""Ak chcete zmeniť citlivosť gesta Späť, prejdite do Nastavení""Prejdite späť potiahnutím"
@@ -56,27 +58,22 @@
"Musíte potiahnuť nahor z dolného okraja obrazovky.""Pred uvoľnením nesmiete zastať.""Musíte potiahnuť priamo hore."
- "Dokončili ste gesto na prechod na plochu. V ďalšom kroku sa naučíte, ako sa vrátiť späť."
- "Dokončili ste gesto na prechod na plochu."
+ "Dokončili ste gesto na prechod na plochu. V ďalšom kroku sa naučíte, ako prepínať aplikácie.""Prechod na plochu potiahnutím"
- "Potiahnite nahor zdola obrazovky. Týmto gestom sa vždy vrátite na plochu."
+ "Potiahnite nahor z dolného okraja obrazovky. Týmto gestom sa vždy vrátite na plochu.""Musíte potiahnuť nahor z dolného okraja obrazovky.""Skúste okno pred uvoľnením podržať dlhšie.""Musite potiahnuť priamo hore a potom zastať."
- "Naučili ste sa používať gestá. Ak ich chcete vypnúť, prejdite do Nastavení."
- "Dokončili ste gesto na prepnutie aplikácií."
+ "Dokončili ste gesto na prepnutie aplikácií. Môžete začať používať telefón.""Prepínanie aplikácií potiahnutím"
- "Aplikácie môžete prepínať potiahnutím obrazovky zdola nahor, pridržaním a následným uvoľnením."
+ "Potiahnite nahor z dolnej časti obrazovky, pridržte a uvoľnite.""Hotovo"
- "Hotovo"
+ "Ďalej"
+ "Hotovo""Nastavenia""Skúste to znova""Výborne!""Návod %1$d/%2$d"
- "Hotovo"
- "Potiahnutím nahor prejdete na plochu"
- "Telefón môžete začať používať"
- "Nastavenia navigácie systémom""Zdieľať""Snímka obrazovky""Aplikácia alebo vaša organizácia túto akciu nepovoľuje"
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 7e40277af4..fdc8a6a4b4 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -33,50 +33,47 @@
"Predvidene aplikacije""Oglejte si predlagane aplikacije v spodnji vrstici začetnega zaslona""Prejemajte predloge aplikacij v vrstici s priljubljenimi na začetnem zaslonu"
- "Preprosto dostopajte do najpogosteje uporabljenih aplikacij kar na začetnem zaslonu. Predlogi se spreminjajo na podlagi dejanj, ki jih pogosto izvajate. Aplikacije iz spodnje vrstice se premaknejo na začetni zaslon."
+ "Preprosto dostopajte do najpogosteje uporabljenih aplikacij kar na začetnem zaslonu. Predlogi se spreminjajo na podlagi dejanj, ki jih pogosto izvajate. Aplikacije se iz spodnje vrstice premaknejo na začetni zaslon.""Preprosto dostopajte do najpogosteje uporabljenih aplikacij kar na začetnem zaslonu. Predlogi se spreminjajo na podlagi dejanj, ki jih pogosto izvajate. Aplikacije v vrstici s priljubljenimi bodo premaknjene na začetni zaslon."
- "Preprosto dostopajte do najpogosteje uporabljenih aplikacij kar na začetnem zaslonu. Predlogi se spreminjajo na podlagi dejanj, ki jih pogosto izvajate. Aplikacije iz spodnje vrstice se premaknejo v novo mapo."
+ "Preprosto dostopajte do najpogosteje uporabljenih aplikacij kar na začetnem zaslonu. Predlogi se spreminjajo na podlagi dejanj, ki jih pogosto izvajate. Aplikacije se iz spodnje vrstice premaknejo v novo mapo.""Prikaži predlagane aplikacije""Ne, hvala""Nastavitve""Tukaj so navedene najpogosteje uporabljene aplikacije in spremembe na podlagi rutin"
- "Če si želite ogledati predlagane aplikacije, povlecite aplikacije iz spodnje vrstice."
+ "Če si želite ogledati predlagane aplikacije, povlecite aplikacije iz spodnje vrstice""Predlagane aplikacije so bile dodane v prazni prostor"
- "Predlogi aplikacij so omogočeni."
- "Predlogi aplikacij so onemogočeni."
+ "Predlogi aplikacij so omogočeni"
+ "Predlogi aplikacij so onemogočeni""Predvidena aplikacija: %1$s"
- "Pazite, da povlečete s skrajno desnega ali skrajno levega roba."
- "Pazite, da povlečete z desnega ali levega roba do sredine zaslona in dvignete prst."
- "Naučili ste se, kako povlečete z desne za vrnitev. Zdaj se naučite preklapljanja med aplikacijami."
- "Izvedli ste potezo za pomik nazaj."
+ "Pazite, da ne povlečete s skrajno levega roba."
+ "Pazite, da povlečete z levega roba do sredine zaslona in dvignete prst."
+ "To je vse. Zdaj preizkusite vlečenje z levega roba."
+ "Pazite, da ne povlečete s skrajno desnega roba."
+ "Pazite, da povlečete z desnega roba do sredine zaslona in dvignete prst."
+ "Izvedli ste potezo za nazaj. Zdaj se naučite, kako se pomaknete na začetni zaslon.""Pazite, da ne povlečete preblizu dna zaslona.""Občutljivost poteze za nazaj lahko spremenite v nastavitvah."
- "Povlecite za vrnitev"
+ "Povlecite za vrnitev.""Če se želite vrniti na zadnji zaslon, povlecite z levega ali desnega roba do sredine zaslona.""Pazite, da povlečete s spodnjega roba zaslona navzgor.""Pazite, da ne zaustavite prsta, preden ga dvignete.""Pazite, da povlečete naravnost navzgor."
- "Izvedli ste potezo za pomik na začetni zaslon. Zdaj se naučite, kako se pomaknete nazaj."
- "Izvedli ste potezo za pomik na začetni zaslon."
- "Povlecite za pomik na začetni zaslon"
+ "Izvedli ste potezo za pomik na začetni zaslon. Zdaj se naučite preklapljanja med aplikacijami."
+ "Vlečenje za pomik na začetni zaslon""Z dna zaslona s prstom povlecite navzgor. S to potezo lahko vedno odprete začetni zaslon.""Pazite, da povlečete s spodnjega roba zaslona navzgor.""Poskusite okno pridržati dalj časa, preden ga izpustite.""Pazite, da povlečete naravnost navzgor in nato zaustavite prst."
- "Naučili ste se uporabljati poteze. Poteze lahko izklopite v nastavitvah."
- "Izvedli ste potezo za preklapljanje med aplikacijami."
- "Povlecite za preklapljanje med aplikacijami"
- "Za preklapljanje med aplikacijami povlecite navzgor z dna zaslona, pridržite in nato izpustite."
+ "Izvedli ste potezo za preklapljanje med aplikacijami. Pripravljeni ste na uporabo telefona."
+ "Vlečenje za preklapljanje med aplikacijami"
+ "Povlecite navzgor z dna zaslona, pridržite, nato izpustite.""Zdaj znate"
- "Končano"
+ "Naprej"
+ "Končano""Nastavitve""Poskusite znova""Odlično!""Vadnica %1$d/%2$d"
- "Končano"
- "Povlecite navzgor za začetni zaslon"
- "Pripravljeni ste, da začnete uporabljati telefon"
- "Nastavitve krmarjenja po sistemu""Deli""Posnetek zaslona""Aplikacija ali vaša organizacija ne dovoljuje tega dejanja"
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 86528d2777..36e0afc371 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -45,10 +45,12 @@
"Aplikacionet e sugjeruara janë aktivizuar""Sugjerimet e aplikacioneve janë çaktivizuar""Aplikacioni i parashikuar: %1$s"
- "Sigurohu që të rrëshqasësh shpejt nga skaji më i djathtë ose më i majtë."
- "Sigurohu që të rrëshqasësh shpejt nga skaji i djathtë ose i majtë drejt mesit të ekranit dhe lëshoje."
- "Ke mësuar si të rrëshqasësh shpejt nga e djathta për t\'u kthyer prapa. Në vijim do të mësosh se si t\'i ndërrosh aplikacionet."
- "E ke përfunduar gjestin e kthimit prapa."
+ "Sigurohu që të rrëshqasësh shpejt nga skaji sa më majtas."
+ "Sigurohu që të rrëshqasësh shpejt nga skaji i majtë drejt mesit të ekranit dhe lëshoje."
+ "Kaq ishte! Tani provo të rrëshqasësh shpejt nga skaji i djathtë."
+ "Sigurohu që të rrëshqasësh shpejt nga skaji sa më djathtas."
+ "Sigurohu që të rrëshqasësh shpejt nga skaji i djathtë drejt mesit të ekranit dhe lëshoje."
+ "E ke përfunduar gjestin e kthimit prapa. Në vijim do të mësosh si të shkosh tek ekrani bazë.""Sigurohu që të mos rrëshqasësh shumë afër fundit të ekranit.""Për të ndryshuar ndjeshmërinë e gjestit të kthimit prapa, shko te \"Cilësimet\"""Rrëshqit shpejt për t\'u kthyer prapa"
@@ -56,27 +58,22 @@
"Sigurohu që të rrëshqasësh shpejt lart nga skaji i poshtëm i ekranit.""Sigurohu që të mos ndalosh para se ta lëshosh.""Sigurohu që të rrëshqasësh shpejt drejt lart."
- "E ke përfunduar gjestin e kalimit tek ekrani bazë. Në vijim do të mësosh si të kthehesh prapa."
- "E ke përfunduar gjestin e kalimit tek ekrani bazë."
+ "E ke përfunduar gjestin e kalimit tek ekrani bazë. Në vijim do të mësosh se si t\'i ndërrosh aplikacionet.""Rrëshqit shpejt për të kaluar tek ekrani bazë""Rrëshqit shpejt lart nga fundi i ekranit tënd. Ky gjest të dërgon gjithmonë tek ekrani bazë.""Sigurohu që të rrëshqasësh shpejt lart nga skaji i poshtëm i ekranit.""Provo ta mbash shtypur dritaren për një kohë më të gjatë para se ta lëshosh.""Sigurohu që të rrëshqasësh shpejt drejt lart dhe më pas ndalo."
- "Ke mësuar si të përdorësh gjestet. Për t\'i çaktivizuar gjestet, shko te \"Cilësimet\"."
- "E ke përfunduar gjestin e ndërrimit të aplikacioneve."
+ "E ke përfunduar gjestin e ndërrimit të aplikacioneve. Je gati për të përdorur telefonin!""Rrëshqit shpejt për të ndërruar aplikacionet"
- "Për të ndërruar mes aplikacioneve, rrëshqit shpejt lart nga fundi i ekranit tënd, mbaj dhe pastaj lësho."
+ "Rrëshqit shpejt lart nga fundi i ekranit, mbaje të shtypur dhe më pas lëshoje.""Plotësisht gati"
- "U krye"
+ "Para"
+ "U krye""Cilësimet""Provo përsëri""Bukur!""Udhëzuesi %1$d/%2$d"
- "Plotësisht gati!"
- "Rrëshqit shpejt lart për të shkuar tek \"Ekrani bazë\""
- "Je gati për të filluar përdorimin e telefonit tënd"
- "Cilësimet e navigimit të sistemit""Ndaj""Pamja e ekranit""Ky veprim nuk lejohet nga aplikacioni ose organizata jote"
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index f2ffa0a41e..8a462f982d 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -45,38 +45,35 @@
"Предлози апликација су омогућени""Предлози апликација су онемогућени""Предвиђамо апликацију: %1$s"
- "Обавезно превуците од саме десне или леве ивице."
- "Обавезно превуците од десне или леве ивице до средине екрана и отпустите."
- "Научили сте како да превлачите здесна да бисте се вратили уназад. Сада научите да замените апликације."
- "Довршили сте покрет за повратак."
+ "Обавезно превуците од саме леве ивице."
+ "Обавезно превуците од леве ивице до средине екрана и отпустите."
+ "То је све! Сада пробајте да превучете од десне ивице."
+ "Обавезно превуците од саме десне ивице."
+ "Обавезно превуците од десне ивице до средине екрана и отпустите."
+ "Довршили сте покрет за повратак. Сада сазнајте како да одете на почетну страницу.""Никако не превлачите превише близу дна екрана.""Осетљивост пок. за назад можете да промените у Подешавањима"
- "Превуците да бисте се вратили уназад"
+ "Превуците да бисте се вратили""Да бисте се вратили на последњи екран, превуците од леве или десне ивице до средине екрана.""Обавезно превуците нагоре од доње ивице екрана.""Никако не стајте пре отпуштања.""Обавезно превуците право нагоре."
- "Довршили сте покрет за повратак на почетну страницу. Сада сазнајте како да се вратите."
- "Довршили сте покрет за повратак на почетну страницу."
+ "Довршили сте покрет за повратак на почетну страницу. Сада сазнајте како да промените апликације.""Превуците да бисте отишли на почетну страницу""Превуците нагоре од дна екрана. Овај покрет вас увек води на почетни екран.""Обавезно превуците нагоре од доње ивице екрана.""Пробајте да држите прозор дуже пре отпуштања.""Обавезно превуците право нагоре, па застаните."
- "Научили сте како да користите покрете. Да бисте искључили покрете, идите на подешавања."
- "Довршили сте покрет за промену апликација."
- "Превуците да бисте заменили апликације"
- "За прелазак са једне апликације на другу превуците нагоре од дна екрана, задржите, па пустите."
+ "Довршили сте покрет за промену апликација. Спремни сте за коришћење телефона!"
+ "Превуците да бисте променили апликације"
+ "Превуците нагоре од дна екрана, задржите, па пустите.""То је то"
- "Готово"
+ "Даље"
+ "Готово""Подешавања""Пробајте поново""Свака част!""Водич %1$d/%2$d"
- "Готово!"
- "Превуците нагоре да бисте отворили почетни екран"
- "Спремни сте да почнете да користите телефон"
- "Подешавања кретања кроз систем""Дели""Снимак екрана""Апликација или организација не дозвољавају ову радњу"
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 931e4588b7..bf6985030c 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -45,10 +45,12 @@
"Appförslag har aktiverats""Appförslag har inaktiverats""Appförslag: %1$s"
- "Se till att du sveper ända från högerkanten eller vänsterkanten."
- "Se till att du sveper från den högra eller vänstra kanten till mitten av skärmen och sedan släpper."
- "Nu kan du svepa från höger för att gå tillbaka. Nu ska du få lära dig hur du byter mellan appar."
- "Du är klar med rörelsen för att gå tillbaka."
+ "Se till att du sveper ända från vänsterkanten."
+ "Se till att du sveper från den vänstra kanten till mitten av skärmen och sedan släpper."
+ "Så där ja! Nu kan du testa att svepa från högerkanten."
+ "Se till att du sveper ända från högerkanten."
+ "Se till att du sveper från den högra kanten till mitten av skärmen och sedan släpper."
+ "Du är klar med rörelsen för att gå tillbaka. Nu ska du få lära dig hur du öppnar startskärmen.""Se till att du inte sveper för nära skärmens nederkant.""Öppna inställningarna om du vill ändra rörelsens känslighet""Svep för att återgå"
@@ -56,32 +58,27 @@
"Se till att du sveper från nederkanten på skärmen.""Se till att du sveper i en jämn rörelse innan du släpper.""Se till att du sveper rakt uppåt."
- "Du är klar med rörelsen för att öppna startskärmen. Nu ska du få lära dig hur du går tillbaka."
- "Du är klar med rörelsen för att öppna startskärmen."
+ "Du är klar med rörelsen för att öppna startskärmen. Nu ska du få lära dig hur du byter mellan appar.""Svep för att öppna startskärmen"
- "Svep uppåt från skärmens nederkant. Du kan alltid återgå till startskärmen med den här rörelsen."
+ "Svep uppåt från skärmens nederkant. Du kan alltid återgå startskärmen med den här rörelsen.""Se till att du sveper från nederkanten på skärmen.""Testa att trycka längre på fönstret innan du släpper.""Se till att du sveper rakt uppåt och sedan pausar."
- "Du har lärt dig hur du använder rörelser. Om du vill inaktivera rörelser öppnar du inställningarna."
- "Du är klar med rörelsen för att byta mellan appar."
+ "Du är klar med rörelsen för att byta mellan appar. Nu kan du börja använda telefonen!""Svep för att byta mellan appar"
- "Byt mellan appar genom att svepa uppåt från skärmens nederkant. Håll fingret nedtryckt och släpp."
+ "Svep uppåt från skärmens nederkant. Håll fingret nedtryckt och släpp sedan.""Klart"
- "Klar"
+ "Nästa"
+ "Klar""Inställningar""Försök igen""Bra!""Självstudie %1$d/%2$d"
- "Klart!"
- "Svep uppåt för att öppna startskärmen"
- "Nu kan du börja använda telefonen"
- "Systemnavigeringsinställningar""Dela""Skärmbild""Appen eller organisationen tillåter inte den här åtgärden""Vill du hoppa över självstudierna?"
- "Du hittar det här igen i %1$s-appen"
+ "Du kan hitta det här igen i %1$s-appen""Avbryt""Hoppa över"
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 22aa3ef29f..b761caee7d 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -45,10 +45,12 @@
"Mapendekezo ya programu yamewashwa""Umezima mapendekezo ya programu""Programu iliyotabiriwa: %1$s"
- "Hakikisha unatelezesha kidole kuanzia ukingo wa kulia kabisa au ukingo wa kushoto kabisa."
- "Hakikisha unatelezesha kidole kuanzia ukingo wa kulia au kushoto kuelekea katikati ya skrini na uachilie."
- "Umejifunza jinsi ya kutelezesha kidole kuanzia kulia ili kurudi nyuma. Sasa jifunze jinsi ya kubadilisha programu."
- "Umekamilisha ishara ya kurudi nyuma."
+ "Hakikisha unatelezesha kidole kuanzia ukingo wa mbali wa kushoto."
+ "Hakikisha unatelezesha kidole kuanzia ukingo wa kushoto kuelekea katikati ya skrini na uachilie."
+ "Ni hivyo tu! Sasa jaribu kutelezesha kidole kuanzia ukingo wa kuilia."
+ "Hakikisha unatelezesha kidole kuanzia ukingo wa mbali wa kulia."
+ "Hakikisha unatelezesha kidole kuanzia ukingo wa kulia kuelekea katikati ya skrini na uachilie."
+ "Umekamilisha ishara ya kurudi nyuma. Inayofuata, jifunze jinsi ya kwenda kwenye Skrini ya kwanza.""Hakikisha hutelezeshi kidole karibu sana na sehemu ya chini ya skrini.""Kubadilisha hisi ya ishara ya nyuma, nenda kwenye Mipangilio""Telezesha kidole ili urudi nyuma"
@@ -56,27 +58,22 @@
"Hakikisha unatelezesha kidole juu kuanzia ukingo wa chini wa skrini.""Hakikisha kuwa husimamishi kabla ya kuachilia.""Hakikisha unatelezesha kidole kuelekea juu."
- "Umekamilisha ishara ya kwenda kwenye Skrini ya kwanza. Sasa jifunze jinsi ya kurudi nyuma."
- "Umekamilisha ishara ya kwenda kwenye Skrini ya kwanza."
+ "Umekamilisha ishara ya kwenda kwenye Skrini ya kwanza. Hatua inayofuata, jifunze jinsi ya kubadilisha programu.""Telezesha kidole ili uende kwenye skrini ya kwanza""Telezesha kidole juu kuanzia chini ya skrini yako. Ishara hii kila wakati hukupeleka kwenye Skrini ya kwanza.""Hakikisha unatelezesha kidole juu kuanzia ukingo wa chini wa skrini.""Jaribu kushikilia dirisha kwa muda mrefu kabla ya kuachilia.""Hakikisha unatelezesha kidole kuelekea juu, kisha usimamishe."
- "Umejifunza jinsi ya kutumia ishara. Ili uzime ishara, nenda kwenye Mipangilio."
- "Umekamilisha ishara ya kubadilisha programu."
+ "Umekamilisha ishara ya kubadilisha programu. Uko tayari kutumia simu yako!""Telezesha kidole ili ubadilishe programu"
- "Ili ubadili kati ya programu, telezesha kidole juu kuanzia sehemu ya chini ya skrini yako, ushikilie, kisha uachilie."
+ "Telezesha kidole juu kuanzia sehemu ya chini ya skrini yako, ushikilie, kisha uachilie.""Kila kitu kiko tayari"
- "Nimemaliza"
+ "Endelea"
+ "Nimemaliza""Mipangilio""Jaribu tena""Safi!""Mafunzo ya %1$d kati ya %2$d"
- "Tayari!"
- "Telezesha kidole juu ili uende kwenye skrini ya kwanza"
- "Uko tayari kuanza kutumia simu yako"
- "Mipangilio ya usogezaji kwenye mfumo""Shiriki""Picha ya skrini""Kitendo hiki hakiruhusiwi na programu au shirika lako"
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000000..5d9e0596b5
--- /dev/null
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -0,0 +1,19 @@
+
+
+ 25dp
+
diff --git a/quickstep/res/values-sw720dp/dimens.xml b/quickstep/res/values-sw720dp/dimens.xml
new file mode 100644
index 0000000000..2831a6f7f5
--- /dev/null
+++ b/quickstep/res/values-sw720dp/dimens.xml
@@ -0,0 +1,21 @@
+
+
+ 44dp
+ 44dp
+ 44dp
+
diff --git a/quickstep/res/values-sw900dp/dimens.xml b/quickstep/res/values-sw900dp/dimens.xml
new file mode 100644
index 0000000000..3efa5e3ecf
--- /dev/null
+++ b/quickstep/res/values-sw900dp/dimens.xml
@@ -0,0 +1,23 @@
+
+
+
+ 76dp
+
+
+ 0dp
+
\ No newline at end of file
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index e7cc31d97f..089c95de7b 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -35,7 +35,7 @@
"உங்கள் முகப்புத் திரையின் \'பிடித்தவை\' வரிசையில் ஆப்ஸ் பரிந்துரைகளைப் பெறலாம்""அதிகமாகப் பயன்படுத்திய ஆப்ஸை முகப்புத் திரையிலேயே அணுகலாம். உங்கள் வழக்கங்களின் அடிப்படையில் பரிந்துரைகள் மாறும். கடைசி வரிசையிலுள்ள ஆப்ஸ் உங்கள் முகப்புத் திரைக்கு நகர்த்தப்படும்.""அதிகமாகப் பயன்படுத்திய ஆப்ஸை முகப்புத் திரையிலேயே எளிதாக அணுகலாம். உங்கள் வழக்கங்களின் அடிப்படையில் பரிந்துரைகள் மாறும். பிடித்தவை வரிசையில் உள்ள ஆப்ஸ் உங்கள் முகப்புத் திரைக்கு நகர்த்தப்படும்."
- "அதிகமாகப் பயன்படுத்திய ஆப்ஸை முகப்புத் திரையிலேயே அணுகலாம். உங்கள் வழக்கங்களின் அடிப்படையில் பரிந்துரைகள் மாறும். கடைசி வரிசையிலுள்ள ஆப்ஸ் புதிய ஃபோல்டருக்கு நகர்த்தப்படும்."
+ "அதிகமாகப் பயன்படுத்திய ஆப்ஸை முகப்புத் திரையிலேயே அணுகலாம். உங்கள் வழக்கங்களின் அடிப்படையில் பரிந்துரைகள் மாறும். கடைசி வரிசையிலுள்ள ஆப்ஸ் புதிய கோப்புறைக்கு நகர்த்தப்படும்.""ஆப்ஸ் பரிந்துரைகளைப் பெறுக""வேண்டாம்""அமைப்புகள்"
@@ -45,10 +45,12 @@
"ஆப்ஸ் பரிந்துரைகள் இயக்கப்பட்டுள்ளன""ஆப்ஸ் பரிந்துரைகள் முடக்கப்பட்டுள்ளன""கணித்த ஆப்ஸ்: %1$s"
- "வலது அல்லது இடது ஓரத்தின் விளிம்பிலிருந்து ஸ்வைப் செய்வதை உறுதிசெய்க."
- "வலது அல்லது இடது ஓரத்திலிருந்து திரையின் மையப் பகுதிக்கு ஸ்வைப் செய்தபிறகு விடுவிப்பதை உறுதிசெய்க."
- "பின்செல்வதற்கு எப்படி வலதுபுறத்திலிருந்து ஸ்வைப் செய்வதென்று கற்றுக்கொண்டீர்கள். அடுத்து ஆப்ஸுக்கிடையே எப்படி மாறுவது என்பதை அறிக."
- "பின்செல் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள்."
+ "இடது ஓரத்தின் விளிம்பிலிருந்து ஸ்வைப் செய்கிறீர்கள் என்பதை உறுதிசெய்துகொள்ளுங்கள்."
+ "இடது ஓரத்திலிருந்து திரையின் மையப் பகுதிக்கு ஸ்வைப் செய்தபிறகு விடுவிப்பதை உறுதிசெய்துகொள்ளுங்கள்."
+ "அவ்வளவுதான்! இப்போது வலது ஓரத்திலிருந்து ஸ்வைப் செய்க."
+ "வலது ஓரத்தின் விளிம்பிலிருந்து ஸ்வைப் செய்கிறீர்கள் என்பதை உறுதிசெய்துகொள்ளுங்கள்."
+ "வலது ஓரத்திலிருந்து திரையின் மையப் பகுதிக்கு ஸ்வைப் செய்தபிறகு விடுவிப்பதை உறுதிசெய்துகொள்ளுங்கள்."
+ "பின்செல் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள். அடுத்து, முகப்புக்குச் செல்வது எப்படி என்பதை அறிக.""திரையின் கீழ்பகுதிக்கு மிக நெருக்கமாக ஸ்வைப் செய்யவில்லை என்பதை உறுதிசெய்துகொள்ளுங்கள்.""பின்செல் சைகையின் உணர்திறனை மாற்ற அமைப்புகளுக்குச் செல்க""பின்செல்ல ஸ்வைப் செய்யுங்கள்"
@@ -56,27 +58,22 @@
"திரையின் கீழ் ஓரத்திலிருந்து மேல்நோக்கி ஸ்வைப் செய்வதை உறுதிசெய்துகொள்ளுங்கள்.""விடுவிப்பதற்கு முன்பாக இடைநிறுத்தவில்லை என்பதை உறுதிசெய்துகொள்ளுங்கள்.""மேல்நோக்கி நேராக ஸ்வைப் செய்வதை உறுதிசெய்துகொள்ளுங்கள்."
- "முகப்புக்குச் செல் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள். அடுத்து, பின்செல்வது எப்படி என்பதை அறிக."
- "முகப்புக்குச் செல் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள்."
+ "முகப்புக்குச் செல் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள். அடுத்து, ஆப்ஸுக்கிடையே மாறுவது எப்படி என்பதை அறிக.""முகப்புக்குச் செல்ல ஸ்வைப் செய்யுங்கள்""திரையின் கீழிருந்து மேலாக ஸ்வைப் செய்க. இந்தச் சைகை எப்போதும் முகப்புத் திரைக்கு அழைத்துச் செல்லும்.""திரையின் கீழ் ஓரத்திலிருந்து மேல்நோக்கி ஸ்வைப் செய்வதை உறுதிசெய்துகொள்ளுங்கள்.""விடுவிப்பதற்கு முன்பாக நீண்டநேரம் சாளரத்தை அழுத்திப் பிடித்திருங்கள்.""மேல்நோக்கி நேராக ஸ்வைப் செய்தபிறகு இடைநிறுத்துவதை உறுதிசெய்துகொள்ளுங்கள்."
- "சைகைகளை எப்படி உபயோகிப்பது என்று கற்றுக்கொண்டீர்கள். சைகைகளை முடக்க அமைப்புகளுக்குச் செல்லுங்கள்."
- "ஆப்ஸுக்கிடையே மாறும் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள்."
+ "ஆப்ஸுக்கிடையே மாறும் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள். உங்கள் மொபைலைப் பயன்படுத்தத் தயாராகிவிட்டீர்கள்!""ஆப்ஸுக்கிடையே மாற ஸ்வைப் செய்யுங்கள்"
- "ஆப்ஸுக்கு இடையே மாற, திரையின் கீழிலிருந்து மேலாக ஸ்வைப் செய்து, பிடித்திருந்து, பிறகு விடுவிக்கவும்."
+ "திரையின் கீழிலிருந்து மேலாக ஸ்வைப் செய்து, சில விநாடிகள் பிடித்திருந்து, பிறகு விரலை எடுங்கள்.""எல்லாம் தயார்"
- "முடிந்தது"
+ "அடுத்து"
+ "முடிந்தது""அமைப்புகள்""மீண்டும் முயல்க""அருமை!""பயிற்சி %1$d/%2$d"
- "அனைத்தையும் அமைத்துவிட்டீர்கள்!"
- "முகப்புத் திரைக்குச் செல்ல மேல்நோக்கி ஸ்வைப் செய்யுங்கள்"
- "மொபைலைப் பயன்படுத்தத் தயாராகிவிட்டீர்கள்"
- "சிஸ்டம் வழிசெலுத்தல் அமைப்புகள்""பகிர்""ஸ்கிரீன்ஷாட்""ஆப்ஸோ உங்கள் நிறுவனமோ இந்த செயலை அனுமதிப்பதில்லை"
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index ef8f3bad48..c73c83ebb5 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -31,52 +31,49 @@
"యాప్ సలహాలు""అన్ని యాప్లు""మీ సూచించబడిన యాప్లు"
- "మీ మొదటి స్క్రీన్ దిగువ వరుసలో యాప్ సలహాలను పొందండి"
+ "మీ హోమ్ స్క్రీన్ దిగువ వరుసలో యాప్ సలహాలను పొందండి""మీ హోమ్ స్క్రీన్లోని ఇష్టమైన వాటి వరుసలో యాప్ సూచనలు పొందండి"
- "మీరు ఎక్కువగా ఉపయోగించే యాప్లను నేరుగా మొదటి స్క్రీన్లోనే సులభంగా యాక్సెస్ చేయండి. మీ రోజువారీ యాక్టివిటీలను బట్టి సూచనలు మారతాయి. దిగువ వరుసలోని యాప్లు మీ మొదటి స్క్రీన్ పైకి చేరుకుంటాయి."
- "మీరు ఎక్కువగా ఉపయోగించే యాప్లను నేరుగా మొదటి స్క్రీన్లోనే సులభంగా యాక్సెస్ చేయండి. మీ రోజువారీ యాక్టివిటీలను బట్టి సూచనలు మారతాయి. ఇష్టమైన వాటి వరుసలోని యాప్లు మీ మొదటి స్క్రీన్కు చేరుకుంటాయి."
- "మీరు ఎక్కువగా ఉపయోగించే యాప్లను నేరుగా మొదటి స్క్రీన్లోనే సులభంగా యాక్సెస్ చేయండి. మీ రోజువారీ యాక్టివిటీలను బట్టి సూచనలు మారతాయి. దిగువ వరుసలోని యాప్లు కొత్త ఫోల్డర్కు తరలించబడతాయి."
+ "మీరు ఎక్కువగా ఉపయోగించే యాప్లను నేరుగా హోమ్ స్క్రీన్లోనే సులభంగా యాక్సెస్ చేయండి. మీ రోజువారీ కార్యకలాపాలను బట్టి సూచనలు మారతాయి. దిగువ వరుసలోని యాప్లు మీ హోమ్ స్క్రీన్ పైకి చేరుకుంటాయి."
+ "మీరు ఎక్కువగా ఉపయోగించే యాప్లను నేరుగా హోమ్ స్క్రీన్లోనే సులభంగా యాక్సెస్ చేయండి. మీ రోజువారీ కార్యకలాపాలను బట్టి సూచనలు మారతాయి. ఇష్టమైన వాటి వరుసలోని యాప్లు మీ హోమ్ స్క్రీన్కు చేరుకుంటాయి."
+ "మీరు ఎక్కువగా ఉపయోగించే యాప్లను నేరుగా హోమ్ స్క్రీన్లోనే సులభంగా యాక్సెస్ చేయండి. మీ రోజువారీ కార్యకలాపాలను బట్టి సూచనలు మారతాయి. దిగువ వరుసలోని యాప్లు కొత్త ఫోల్డర్కు తరలించబడతాయి.""యాప్ సూచనలను పొందండి""వద్దు""సెట్టింగ్లు"
- "ఎక్కువగా ఉపయోగించిన యాప్లు ఇక్కడ కనిపిస్తాయి, అవి రోజువారీ యాక్టివిటీలను బట్టి మారుతూ ఉంటాయి"
+ "ఎక్కువగా ఉపయోగించిన యాప్లు ఇక్కడ కనిపిస్తాయి, అవి రోజువారీ కార్యకలాపాలను బట్టి మారుతూ ఉంటాయి""యాప్ సలహాలను పొందడానికి దిగువ వరుస నుండి యాప్లను లాగండి""యాప్ సూచనలు ఖాళీ స్పేస్కు జోడించబడ్డాయి""యాప్ సలహాలు ఎనేబుల్ చేయబడ్డాయి""యాప్ సూచనలు డిజేబుల్ చేయబడ్డాయి""సూచించబడిన యాప్: %1$s"
- "కుడి వైపు చిట్ట చివరి లేదా ఎడమ వైపు చిట్ట చివరి అంచు నుండి స్వైప్ చేస్తున్నారని నిర్ధారించుకోండి."
- "మీరు కుడి లేదా ఎడమ అంచు నుండి స్క్రీన్ మధ్యలోకి స్వైప్ చేశారని నిర్ధారించుకోని, మీ వేలిని ఎత్తండి."
- "వెనుకకు వెళ్లడానికి కుడి నుండి స్వైప్ ఎలానో మీకు తెలుసు. తర్వాత, యాప్ల మధ్య ఎలా మారాలో తెలుసుకోండి."
- "మీరు తిరిగి వెనక్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు."
+ "మీరు చాలా-ఎడమ అంచు నుండి స్వైప్ చేశారని నిర్ధారించుకోండి."
+ "మీరు ఎడమ అంచు నుండి స్క్రీన్ మధ్యలోకి స్వైప్ చేశారని నిర్ధారించుకోని, ఆపై మీ వేలిని ఎత్తండి."
+ "అంతే! ఇప్పుడు కుడి అంచు నుండి స్వైప్ చేయడానికి ట్రై చేయండి."
+ "మీరు చాలా-కుడి అంచు నుండి స్వైప్ చేశారని నిర్ధారించుకోండి."
+ "మీరు కుడి అంచు నుండి స్క్రీన్ మధ్యలోకి స్వైప్ చేశారని నిర్ధారించుకోని, ఆపై మీ వేలిని ఎత్తండి."
+ "మీరు తిరిగి వెళ్లే సంజ్ఞను పూర్తి చేశారు. తర్వాత, మొదటి ట్యాబ్కు ఎలా వెళ్లాలో తెలుసుకోండి.""మీరు స్క్రీన్ దిగువకు చాలా దగ్గరగా స్వైప్ చేయలేదని నిర్ధారించుకోండి.""వెనుక సంజ్ఞ సున్నితత్వం మార్చడానికి, సెట్టింగ్లకు వెళ్లండి""వెనుకకు వెళ్ళడం కోసం స్వైప్ చేయండి""మునుపటి స్క్రీన్కు తిరిగి వెళ్లడానికి, ఎడమ లేదా కుడి అంచు నుండి స్క్రీన్ మధ్యలోకి స్వైప్ చేయండి."
- "మీరు స్క్రీన్ దిగువ అంచు నుండి పైకి స్వయిప్ చేస్తున్నారని నిర్ధారించుకోండి."
+ "మీరు స్క్రీన్ దిగువ అంచు నుండి పైకి స్వైప్ చేశారని నిర్ధారించుకోండి.""బయలుదేరే ముందు మీరు పాజ్ చేయకుండా చూసుకోండి.""మీరు నేరుగా పైకి స్వైప్ చేశారని నిర్ధారించుకోండి."
- "మీరు మొదటి స్క్రీన్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు. తర్వాత, వెనుకకు ఎలా వెళ్లాలో తెలుసుకోండి."
- "మీరు మొదటి ట్యాబ్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు."
- "మొదటి స్క్రీన్కు వెళ్లడానికి స్వైప్ చేయండి"
- "స్క్రీన్ కింది నుండి పైకి స్వైప్ చేయండి. ఈ సంజ్ఞ ఎప్పుడూ మిమ్మల్ని మొదటి స్క్రీన్కు తీసుకెళ్తుంది."
- "మీరు స్క్రీన్ దిగువ అంచు నుండి పైకి స్వయిప్ చేస్తున్నారని నిర్ధారించుకోండి."
+ "మీరు మొదటి ట్యాబ్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు. తర్వాత, యాప్ల మధ్య ఎలా మార్చాలో తెలుసుకోండి."
+ "వర్చువల్ హోమ్కి వెళ్లడానికి స్వైప్ చేయండి"
+ "మీ స్క్రీన్ కింది నుండి పైకి స్వైప్ చేయి. ఈ సంజ్ఞ ఎప్పుడూ మిమ్మల్ని మొదటి స్క్రీన్కు తీసుకెళ్తుంది."
+ "మీరు స్క్రీన్ దిగువ అంచు నుండి పైకి స్వైప్ చేశారని నిర్ధారించుకోండి.""రిలీజ్ చేయడానికి ముందు విండోను ఎక్కువసేపు పట్టుకోడానికి ట్రై చేయండి.""మీరు నేరుగా స్వైప్ చేశారని నిర్ధారించుకోండి, ఆపై పాజ్ చేయండి."
- "మీరు సంజ్ఞలను ఎలా ఉపయోగించాలో నేర్చుకున్నారు. సంజ్ఞలను ఆఫ్ చేయడానికి, సెట్టింగ్లకు వెళ్లండి."
- "మీరు \'యాప్ల మధ్య మార్పు\' సంజ్ఞను పూర్తి చేశారు."
+ "మీరు \'యాప్ల మధ్య మార్పు\' సంజ్ఞను పూర్తి చేశారు. మీరు మీ ఫోన్ను ఉపయోగించడానికి సిద్ధంగా ఉన్నారు!""యాప్ల మధ్య మార్చడం కోసం స్వైప్ చేయండి"
- "యాప్ల మధ్య మారడానికి, మీ స్క్రీన్ కింది వైపు నుండి పైకి స్వైప్ చేసి, పట్టుకుని, తర్వాత వదలండి."
+ "మీ స్క్రీన్ కింది వైపు నుండి పైకి స్వైప్ చేసి, హోల్డ్ చేసి, తర్వాత రిలీజ్ చేయండి.""అంతా సిద్ధంగా ఉంది"
- "పూర్తయింది"
+ "తర్వాత"
+ "పూర్తయింది""సెట్టింగ్లు""మళ్లీ ట్రై చేయండి""పనితీరు బాగుంది!""ట్యుటోరియల్ %1$d/%2$d"
- "అంతా సెట్ అయింది!"
- "మొదటి స్క్రీన్కు వెళ్లడానికి పైకి స్వైప్ చేయండి"
- "మీరు మీ ఫోన్ను ఉపయోగించడానికి సిద్ధంగా ఉన్నారు"
- "సిస్టమ్ నావిగేషన్ సెట్టింగ్లు""షేర్ చేయండి""స్క్రీన్షాట్""ఈ చర్యను యాప్ గానీ, మీ సంస్థ గానీ అనుమతించవు"
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 52b2878564..d7061089f2 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -42,46 +42,43 @@
"แอปที่ใช้มากที่สุดจะปรากฎที่นี่และจะเปลี่ยนไปตามการใช้งานประจำ""ลากแอปออกจากแถวล่างเพื่อดูแอปแนะนำ""เพิ่มคำแนะนำเกี่ยวกับแอปในพื้นที่ว่างแล้ว"
- "เปิดใช้แอปแนะนำแล้ว"
+ "เปิดใช้คำแนะนำเกี่ยวกับแอปแล้ว""ปิดใช้คำแนะนำเกี่ยวกับแอปอยู่""แอปที่คาดว่าจะใช้: %1$s"
- "ตรวจสอบว่าปัดจากขอบด้านขวาสุดหรือซ้ายสุด"
- "ตรวจสอบว่าปัดจากขอบด้านขวาหรือซ้ายไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"
- "คุณรู้วิธีปัดจากด้านขวาเพื่อย้อนกลับแล้ว ต่อไปดูวิธีสลับแอป"
- "คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว"
+ "ตรวจสอบว่าปัดจากขอบด้านซ้ายสุด"
+ "ตรวจสอบว่าปัดจากขอบด้านซ้ายไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"
+ "เท่านี้ก็เรียบร้อย คราวนี้ให้ลองปัดจากขอบด้านขวา"
+ "ตรวจสอบว่าปัดจากขอบด้านขวาสุด"
+ "ตรวจสอบว่าปัดจากขอบด้านขวาไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"
+ "คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว ต่อไปดูวิธีไปที่หน้าแรก""ตรวจสอบว่าไม่ได้ปัดใกล้กับด้านล่างของหน้าจอมากเกินไป""เปลี่ยนความไวของท่าทางสัมผัสเพื่อย้อนกลับได้ที่การตั้งค่า""ปัดเพื่อย้อนกลับ""หากต้องการย้อนกลับไปที่หน้าจอล่าสุด ให้ปัดจากขอบด้านซ้ายหรือขวาไปตรงกลางหน้าจอ"
- "ปัดขึ้นจากขอบด้านล่างของหน้าจอ"
+ "ตรวจสอบว่าปัดขึ้นจากขอบด้านล่างของหน้าจอ""ตรวจสอบว่าไม่มีการหยุดชั่วคราวก่อนยกนิ้วขึ้น""ตรวจสอบว่าปัดขึ้นในแนวตรง"
- "คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว ต่อไปดูวิธีย้อนกลับ"
- "คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว"
+ "คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว ต่อไปดูวิธีสลับแอป""ปัดเพื่อไปที่หน้าแรก""ปัดขึ้นจากด้านล่างของหน้าจอ ท่าทางสัมผัสนี้จะนำคุณไปที่หน้าจอหลักเสมอ"
- "ปัดขึ้นจากขอบด้านล่างของหน้าจอ"
+ "ตรวจสอบว่าปัดขึ้นจากขอบด้านล่างของหน้าจอ""ลองแตะหน้าต่างค้างไว้นานขึ้นก่อนปล่อยนิ้ว""ตรวจสอบว่าปัดขึ้นในแนวตรง แล้วหยุดชั่วคราว"
- "คุณรู้วิธีใช้ท่าทางสัมผัสแล้ว หากต้องการปิดท่าทางสัมผัส ให้ไปที่การตั้งค่า"
- "คุณทำท่าทางสัมผัสเพื่อสลับแอปเสร็จแล้ว"
+ "คุณทำท่าทางสัมผัสเพื่อสลับแอปเสร็จแล้ว คุณพร้อมใช้โทรศัพท์แล้ว""ปัดเพื่อสลับแอป"
- "หากต้องการสลับระหว่างแอปต่างๆ ให้ปัดขึ้นจากด้านล่างของหน้าจอ ค้างไว้ แล้วปล่อย"
+ "ปัดขึ้นจากด้านล่างของหน้าจอค้างไว้ แล้วปล่อย""เรียบร้อย"
- "เสร็จสิ้น"
+ "ถัดไป"
+ "เสร็จสิ้น""การตั้งค่า""ลองอีกครั้ง""ดีมาก""บทแนะนำ %1$d/%2$d"
- "เรียบร้อยแล้ว"
- "ปัดขึ้นเพื่อไปที่หน้าแรก"
- "คุณเริ่มใช้โทรศัพท์ได้แล้ว"
- "การตั้งค่าการนำทางของระบบ""แชร์""ภาพหน้าจอ""แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้""ข้ามบทแนะนำการนำทางไหม"
- "คุณดูบทแนะนำนี้ได้ภายหลังในแอป \"%1$s\""
+ "คุณดูบทแนะนำนี้ได้ภายหลังในแอป %1$s""ยกเลิก""ข้าม"
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 412449b41a..5056481ccf 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -45,10 +45,12 @@
"Naka-enable ang mga iminumungkahing app""Naka-disable ang mga iminumungkahing app""Hinulaang app: %1$s"
- "Tiyaking magsa-swipe ka mula sa dulong kanan o dulong kaliwang gilid."
- "Tiyaking mag-swipe mula sa kanan o kaliwang gilid papunta sa gitna ng screen at iangat ang daliri."
- "Natuto kang mag-swipe mula sa kanan para bumalik. Sunod, alamin kung paano magpalipat-lipat ng app."
- "Nakumpleto mo na ang galaw para bumalik."
+ "Tiyaking magsa-swipe ka mula sa pinakadulo sa kaliwa."
+ "Tiyaking mag-swipe mula sa kaliwang gilid papunta sa gitna ng screen, saka iangat ang iyong daliri."
+ "Iyon lang! Subukang mag-swipe mula sa kaliwang gilid."
+ "Tiyaking magsa-swipe ka mula sa pinakadulo sa kanan."
+ "Tiyaking mag-swipe mula sa kanang gilid papunta sa gitna ng screen, saka iangat ang iyong daliri."
+ "Nakumpleto mo na ang galaw para bumalik. Susunod, alamin kung paano pumunta sa Home.""Tiyaking hindi ka magsa-swipe nang masyadong malapit sa ibaba ng screen.""Pumunta sa Settings para baguhin ang sensitivity ng pagbalik""Mag-swipe para bumalik"
@@ -56,27 +58,22 @@
"Tiyaking magsa-swipe ka pataas mula sa pinakaibaba ng screen.""Tiyaking hindi ka magpo-pause bago iangat ang iyong daliri.""Tiyaking magsa-swipe ka nang diretso pataas."
- "Nakumpleto mo na ang galaw para pumunta sa Home. Susunod, alamin kung paano bumalik."
- "Nakumpleto mo na ang galaw para pumunta sa Home."
+ "Nakumpleto mo na ang galaw para pumunta sa Home. Susunod, alamin kung paano magpalipat-lipat sa mga app.""Mag-swipe para pumunta sa home""Mag-swipe pataas mula sa ibaba ng iyong screen. Dadalhin ka palagi ng galaw na ito sa Home screen.""Tiyaking magsa-swipe ka pataas mula sa pinakaibaba ng screen.""Subukang pindutin nang mas matagal ang window bago ito bitawan.""Tiyaking magsa-swipe ka nang diretso pataas, pagkatapos ay mag-pause."
- "Alam mo na kung paano gumamit ng mga galaw. Para i-off ang mga galaw, pumunta sa Mga Setting."
- "Nakumpleto mo na ang galaw para magpalipat-lipat sa mga app."
+ "Nakumpleto mo na ang galaw para magpalipat-lipat sa mga app. Handa ka nang gamitin ang iyong telepono!""Mag-swipe para lumipat ng app"
- "Para lumipat ng app, mag-swipe pataas mula sa ibaba ng iyong screen, mag-hold, at iangat ang daliri."
+ "Mag-swipe pataas mula sa ibaba ng iyong screen, mag-hold, pagkatapos ay bitawan ito.""Handa na ang lahat"
- "Tapos na"
+ "Susunod"
+ "Tapos na""Mga Setting""Subukan ulit""Magaling!""Tutorial %1$d/%2$d"
- "Handa na ang lahat!"
- "Mag-swipe pataas para pumunta sa Home"
- "Handa mo nang simulan ang paggamit sa iyong telepono"
- "Mga setting ng navigation ng system""Ibahagi""Screenshot""Hindi pinapayagan ng app o ng iyong organisasyon ang pagkilos na ito"
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 58d78e0efd..a22247b2de 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -45,42 +45,39 @@
"Uygulama önerileri etkinleştirildi""Uygulama önerileri devre dışı bırakıldı""Tahmin edilen uygulama: %1$s"
- "En sağ veya en sol kenardan kaydırdığınızdan emin olun."
- "Ekranın sağ veya sol kenarından ortasına doğru sürükleyip bıraktığınızdan emin olun."
- "Geri dönmek için sağdan kaydırmayı öğrendiniz. Sırada uygulamalar arasında geçiş yapma var."
- "Geri dön hareketini tamamladınız."
+ "Ekranın en solundan kaydırdığınızdan emin olun."
+ "Sol kenardan ekranın ortasına doğru kaydırıp bıraktığınızdan emin olun."
+ "İşte oldu. Şimdi sağ kenardan kaydırmayı deneyin."
+ "Ekranın en sağından kaydırdığınızdan emin olun."
+ "Sağ kenardan ekranın ortasına doğru kaydırıp bıraktığınızdan emin olun."
+ "Geri dön hareketini tamamladınız. Sırada, Ana ekrana gitmeyi öğrenmek var.""Ekranın alt kısmına çok yakın bir şekilde kaydırmadığınızdan emin olun.""Geri hareketinin hassasiyetini değiştirmek için Ayarlar\'a gidin"
- "Geri dönmek için kaydırma"
+ "Geri dönmek için kaydırın""Son ekrana geri gitmek için sol veya sağ kenardan ekranın ortasına doğru kaydırın.""Ekranın alt kenarından yukarı kaydırdığınızdan emin olun.""Bırakmadan önce parmağınızı duraklatmadığınızdan emin olun.""Düz bir şekilde yukarı kaydırdığınızdan emin olun."
- "Ana ekrana git hareketini tamamladınız. Şimdi nasıl geri döneceğinizi öğreneceksiniz."
- "Ana ekrana git hareketini tamamladınız."
+ "Ana ekrana git hareketini tamamladınız. Sırada, uygulamalar arasında geçiş yapmayı öğrenmek var.""Ana ekrana gitmek için kaydırma""Ekranın alt kısmından yukarıya doğru kaydırın. Bu hareket sizi her zaman Ana ekrana götürür.""Ekranın alt kenarından yukarı kaydırdığınızdan emin olun.""Bırakmadan önce pencereyi daha uzun süre tutmayı deneyin.""Düz bir şekilde yukarı kaydırıp ardından parmağınızı duraklattığınızdan emin olun."
- "Hareketleri nasıl kullanacağınızı öğrendiniz. Hareketleri kapatmak için Ayarlar\'a gidin."
- "Uygulamalar arasında geçiş yapma hareketini tamamladınız."
+ "Uygulamalar arasında geçiş yapma hareketini tamamladınız. Telefonunuzu kullanmaya hazırsınız.""Uygulamalar arasında geçiş yapmak için kaydırma"
- "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."
+ "Ekranınızın alt tarafından yukarı doğru kaydırın, tutun ve sonra bırakın.""Hepsi bu kadar"
- "Bitti"
+ "Sonraki"
+ "Bitti""Ayarlar""Tekrar deneyin""Güzel!"
- "Eğitim %1$d/%2$d"
- "İşlem tamam!"
- "Ana ekrana gitmek için yukarı kaydırın"
- "Telefonunuzu kullanmaya hazırsınız"
- "Sistem gezinme ayarları"
+ "Eğitici %1$d/%2$d""Paylaş""Ekran görüntüsü""Uygulamanız veya kuruluşunuz bu işleme izin vermiyor"
- "Gezinme eğitimi atlansın mı?"
+ "Gezinme eğitici içeriği atlansın mı?""Bunu daha sonra %1$s uygulamasında bulabilirsiniz""İptal""Atla"
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 544cec7e0f..c63cec4c0a 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -45,10 +45,12 @@
"Рекомендовані додатки ввімкнено""Рекомендовані додатки вимкнено""Передбачений додаток: %1$s"
- "Проведіть пальцем саме від правого або лівого краю екрана."
- "Проведіть пальцем від правого або лівого краю до середини екрана й підніміть палець."
- "Тепер ви знаєте, як повернутися на попередній екран, провівши пальцем справа наліво. Дізнайтеся, як переключатися між додатками."
- "Ви виконали жест \"Назад\"."
+ "Проведіть пальцем саме від лівого краю екрана."
+ "Проведіть пальцем від лівого краю до середини екрана й підніміть палець."
+ "Це й усе! Тепер проведіть пальцем від правого краю."
+ "Проведіть пальцем саме від правого краю екрана."
+ "Проведіть пальцем від правого краю до середини екрана й підніміть палець."
+ "Ви виконали жест \"Назад\". Далі дізнайтеся, як перейти на головний екран.""Не проводьте пальцем надто близько до нижнього краю екрана.""Щоб змінити чутливість жесту \"Назад\", відкрийте налаштування""Щоб повернутися, проведіть пальцем по екрану"
@@ -56,27 +58,22 @@
"Проведіть пальцем угору від нижнього краю екрана.""Не робіть паузу перед тим, як відірвати палець від екрана.""Проводьте пальцем вертикально вгору."
- "Ви виконали жест переходу на головний екран. Тепер дізнайтеся, як повернутися."
- "Ви виконали жест переходу на головний екран."
+ "Ви виконали жест переходу на головний екран. Тепер дізнайтеся, як переходити між додатками.""Проведіть пальцем, щоб перейти на головний екран""Проведіть пальцем по екрану знизу вгору. Цей жест завжди повертатиме вас на головний екран.""Проведіть пальцем угору від нижнього краю екрана.""Спробуйте втримувати вікно довше, перш ніж відпустити.""Проведіть пальцем вертикально вгору, а тоді зробіть паузу."
- "Ви вивчили жести. Щоб вимкнути їх, перейдіть у налаштування."
- "Ви виконали жест переходу в інший додаток."
+ "Ви виконали жест переходу в інший додаток. Усе готово! Почніть користуватися телефоном.""Проведіть пальцем, щоб перейти в інший додаток"
- "Щоб переключатися між додатками, проведіть знизу вгору по екрану, утримуйте палець, а потім відпустіть."
+ "Проведіть пальцем вгору від низу екрана, утримуйте палець на екрані, а потім відпустіть.""Усе готово!"
- "Готово"
+ "Далі"
+ "Готово""Налаштування""Спробуйте ще""Чудово!""Навчальний посібник %1$d/%2$d"
- "Готово."
- "Щоб перейти на головний екран, проведіть пальцем угору"
- "Тепер ви можете користуватися телефоном"
- "Системні налаштування навігації""Поділитися""Знімок екрана""Ця дія заборонена додатком або адміністратором організації"
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 2e8bde9b64..5ce95ad7c1 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -45,10 +45,12 @@
"ایپ کی تجاویز فعال ہیں""ایپ کی تجاویز غیر فعال ہیں""پیشن گوئی کردہ ایپ: %1$s"
- "یقینی بنائیں کہ آپ دائیں یا بائیں کنارے سے دور سے سوئپ کریں۔"
- "یقینی بنائیں کہ آپ دائیں یا بائیں کنارے سے اسکرین کے وسط تک سوائپ کریں اور پھر اپنی انگلی اٹھا لیں۔"
- "آپ نے واپس جانے کے لیے دائیں کنارے سے سوائپ کرنے کا طریقہ سیکھ لیا۔ اس کے بعد ایپس سوئچ کرنے کا طریقہ جانیں۔"
- "آپ نے واپس جائیں اشارے کو مکمل کر لیا۔"
+ "اس بات کو یقینی بنائیں کہ آپ بائیں کنارے سے دور سے سوائپ کریں۔"
+ "یقینی طور پر بائیں کنارے سے اسکرین کے وسط تک سوائپ کریں اور پھر اپنی انگلی اٹھا لیں۔"
+ "بس اتنا ہی! اب دائیں کنارے سے سوائپ کرنا شروع کریں۔"
+ "اس بات کو یقینی بنائیں کہ آپ دائیں کنارے سے دور سے سوائپ کریں۔"
+ "یقینی طور پر دائیں کنارے سے اسکرین کے وسط تک سوائپ کریں اور پھر اپنی انگلی اٹھا لیں۔"
+ "آپ نے واپس جائیں اشارے کو مکمل کر لیا۔ اس کے بعد آپ ہوم پر جانے کا طریقہ جانیں۔""اس بات کو یقینی بنائیں کہ آپ اسکرین کے نچلے حصے سے زیادہ قریب سے سوائپ نہ کریں۔""پچھلے اشارے کی حساسیت تبدیل کرنے کے لیے ترتیبات پر جائیں""واپس جانے کے لیے سوائپ کریں"
@@ -56,27 +58,22 @@
"اس بات کو یقینی بنائیں کہ آپ اسکرین کے نچلے کنارے سے اوپر کی طرف سوائپ کریں۔""اس بات کو یقینی بنائیں کہ آپ اپنی انگلی اوپر اٹھانے سے پہلے موقوف نہ کریں۔""اس بات کو یقینی بنائیں کہ آپ سیدھا اوپر کی طرف سوائپ کریں۔"
- "آپ نے ہوم پر جانے کا اشارہ مکمل کر لیا۔ اس کے بعد واپس جانے کا طریقہ جانیں۔"
- "آپ نے ہوم پر جانے کا اشارہ مکمل کر لیا۔"
+ "آپ نے ہوم پر جانے کا اشارہ مکمل کر لیا۔ اس کے بعد ایپس سوئچ کرنے کا طریقہ جانیں۔""ہوم پر جانے کے لیے سوائپ کریں""اپنی اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں۔ یہ اشارہ آپ کو ہمیشہ ہوم اسکرین پر لے جاتا ہے۔""اس بات کو یقینی بنائیں کہ آپ اسکرین کے نچلے کنارے سے اوپر کی طرف سوائپ کریں۔""انگلی اٹھانے سے پہلے ونڈو کو زیادہ دیر تک پکڑنے کی کوشش کریں۔""اس بات کو یقینی بنائیں کہ آپ سیدھا اوپر کی طرف سوائپ کریں، پھر موقوف کریں۔"
- "آپ نے اشاروں کو استعمال کرنے کا طریقہ سیکھ لیا۔ اشاروں کو آف کرنے کے لیے ترتیبات پر جائیں۔"
- "آپ نے ایپس کو سوئچ کرنے کا اشارہ مکمل کر لیا۔"
+ "آپ نے ایپ کو سوئچ کرنے کا اشارہ مکمل کر لیا۔ آپ اپنا فون استعمال کرنے کے لیے تیار ہیں!""ایپس سوئچ کرنے کے لیے سوائپ کریں"
- "ایپس کے مابین سوئچ کرنے کے لیے، اپنی اسکرین کے نچلے حصے سے اوپر کی جانب سوائپ کریں، پکڑے رکھیں، پھر چھوڑ دیں۔"
+ "اپنی اسکرین کے نچلے حصے سے اوپر کی طرف سوائپ کریں، پکڑ کر رکھیں، پھر چھوڑ دیں۔""سب ہو گیا"
- "ہو گیا"
+ "آگے"
+ "ہو گیا""ترتیبات""پھر کوشش کریں""عمدہ!""ٹیوٹوریل %1$d/%2$d"
- "سب کچھ تیار ہے!"
- "ہوم پر جانے کے لیے اوپر سوائپ کریں"
- "آپ اپنا فون استعمال شروع کرنے کے لیے تیار ہیں"
- "سسٹم نیویگیشن کی ترتیبات""اشتراک کریں""اسکرین شاٹ""ایپ یا آپ کی تنظیم کی جانب سے اس کارروائی کی اجازت نہیں ہے"
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 8b194de80f..7272eddf51 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -45,38 +45,35 @@
"Ilova tavsiyalari yoqildi""Endi ilova takliflari chiqmaydi""Taklif etilgan ilova: %1$s"
- "Ekran chetidan boshlab oʻngdan yoki chapdan suring."
- "Ekranning oʻng yoki chap chetidan oʻrtasiga suring va qoʻyib yuboring."
- "Ortga qaytish uchun oʻngdan surishni oʻrgandingiz. Endi ilovalarni almashtirishni oʻrganamiz."
- "Ortga qaytish ishorasi darsini tamomladingiz."
+ "Barmoqni chapdagi eng chekkadan suring."
+ "Barmoqni ekranning chap chetidan oʻrtasigacha suring va ekrandan uzing."
+ "Tamom! Endi oʻng chetidan surishga urining."
+ "Barmoqni oʻngdagi eng chekkadan suring."
+ "Barmoqni ekranning oʻng chetidan oʻrtasigacha suring va ekrandan uzing."
+ "Ortga qaytish ishorasi darsini tamomladingiz. Endi Bosh sahifaga qaytishni oʻrganamiz.""Barmoqni ekran pastiga yaqin surmaslikka harakat qiling.""Orqaga ishorasi sezuvchanligi Sozlamalardan oʻzgartiriladi"
- "Orqaga qaytish"
+ "Ortga qaytish uchun suring""Ortga qaytish uchun barmoqni ekranning yon chekkalaridan oʻrtasigacha suring.""Barmoqni ekranning pastki chetidan yuqoriga suring.""Barmoqni ekrandan pauzasiz qoʻyib uzing.""Barmoqni tik tepaga suring."
- "Bosh ekranni ochish ishorasi darsini tamomladingiz. Endi orqaga qaytishni oʻrganamiz."
- "Bosh ekranni ochish ishorasi darsini tamomladingiz."
+ "Bosh ekranni ochish ishorasi darsini tamomladingiz. Endi ilovalarni almashtirishni oʻrganamiz.""Svayp bilan bosh ekranni ochish""Ekranning pastidan tepaga qarab suring. Bu ishora doim Bosh ekranni ochadi.""Barmoqni ekranning pastki chetidan yuqoriga suring.""Barmoqni uzishdan oldin oynani biroz bosib turing.""Avval tik tepaga surib, keyin pauza qiling."
- "Ishoralardan qanday foydalanishni oʻrganib oldingiz. Ishoralarni oʻchirish uchun Sozlamalarga kiring."
- "Ilovalarni almashtirish darsini tamomladingiz."
- "Ilovalar orasida almashish"
- "Ilovalarni ochish uchun ekranning pastidan tepaga qarab suring, biroz ushlab turing va qoʻyib yuboring"
+ "Ilovalarni almashtirish darsini tamomladingiz. Endi telefondan foydalana olasiz!"
+ "Svayp bilan ilovalarni almashtirish"
+ "Ekranning pastidan tepasiga suring, bosib turing va qoʻyib yuboring.""Tayyor"
- "Tayyor"
+ "Keyingisi"
+ "Tayyor""Sozlamalar""Qayta urinish""Yaxshi!""Darslik: %1$d/%2$d"
- "Hammasi tayyor!"
- "Boshiga qaytish uchun tepaga suring"
- "Telefoningiz xizmatga tayyor"
- "Tizim navigatsiya sozlamalari""Ulashish""Skrinshot""Bu amal ilova yoki tashkilotingiz tomonidan taqiqlangan"
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 7bd0c70420..fc3ef3ffff 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -45,38 +45,35 @@
"Đã bật tính năng Ứng dụng đề xuất""Tính năng Ứng dụng đề xuất bị tắt""Ứng dụng dự đoán: %1$s"
- "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."
- "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."
- "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."
- "Bạn đã thực hiện xong cử chỉ quay lại."
+ "Hãy vuốt từ mép ngoài cùng bên trái."
+ "Hãy vuốt từ mép trái tới chính giữa màn hình rồi nhấc ngón tay."
+ "Vậy là xong! Bây giờ, hãy thử vuốt từ mép phải."
+ "Hãy vuốt từ mép ngoài cùng bên phải."
+ "Hãy vuốt từ mép phải tới chính giữa màn hình rồi nhấc ngón tay."
+ "Bạn đã thực hiện xong cử chỉ quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đến Màn hình chính.""Hãy nhớ không được vuốt quá gần phần cuối màn hình.""Để thay đổi độ nhạy của cử chỉ quay lại, hãy vào mục Cài đặt"
- "Vuốt để quay lại"
+ "Hãy vuốt để quay lại""Để 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.""Hãy vuốt lên từ mép dưới cùng của màn hình.""Hãy nhớ không được tạm dừng trước khi nhấc ngón tay.""Hãy vuốt thẳng lên."
- "Bạn đã thực hiện xong cử chỉ chuyển đến Màn hình chính. Tiếp theo, hãy tìm hiểu cách quay lại."
- "Bạn đã thực hiện xong cử chỉ chuyển đến Màn hình chính."
+ "Bạn đã thực hiện xong cử chỉ chuyển đến Màn hình chính. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng.""Vuốt để chuyển đến Màn hình chính""Vuốt lên từ cuối màn hình. Cử chỉ này luôn đưa bạn đến Màn hình chính.""Hãy vuốt lên từ mép dưới cùng của màn hình.""Hãy thử giữ cửa sổ lâu hơn trước khi thả tay ra.""Hãy vuốt thẳng lên, sau đó tạm dừng."
- "Bạn đã tìm hiểu cách sử dụng cử chỉ. Để tắt cử chỉ, hãy chuyển đến phần Cài đặt."
- "Bạn đã thực hiện xong cử chỉ chuyển đổi ứng dụng."
+ "Bạn đã thực hiện xong cử chỉ chuyển đổi ứng dụng. Bạn đã sẵn sàng sử dụng điện thoại!""Vuốt để chuyển đổi ứng dụng"
- "Để chuyển đổi giữa các ứng dụng, hãy vuốt lên từ cuối màn hình, giữ rồi thả ra."
+ "Vuốt lên từ cuối màn hình, giữ rồi thả tay ra.""Đã hoàn tất"
- "Xong"
+ "Tiếp theo"
+ "Xong""Cài đặt""Thử lại""Tuyệt vời!""Hướng dẫn %1$d/%2$d"
- "Đã hoàn tất!"
- "Vuốt lên để chuyển đến Màn hình chính"
- "Vậy là bạn đã sẵn sàng sử dụng điện thoại của mình"
- "Chế độ cài đặt di chuyển trên hệ thống""Chia sẻ""Chụp ảnh màn hình""Ứng dụng hoặc tổ chức của bạn không cho phép thực hiện hành động này"
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 9e641dec30..fe5e553d98 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -45,38 +45,35 @@
"已启用应用建议""已停用应用建议""预测的应用:%1$s"
- "请从最右侧或最左侧边缘开始滑动。"
- "请从右侧或左侧边缘滑动到屏幕中间位置后再松开手指。"
- "您已了解如何使用“从右侧向左滑动”手势返回。接下来了解如何切换应用。"
- "您完成了“返回”手势教程。"
- "请确保滑动时手的位置不要太靠近屏幕底部。"
+ "请从最左侧边缘开始滑动。"
+ "请从左侧边缘滑动到屏幕中间位置后再松开手指。"
+ "大功告成!现在试着从右侧边缘开始滑动。"
+ "请从最右侧边缘开始滑动。"
+ "请从右侧边缘滑动到屏幕中间位置后再松开手指。"
+ "您完成了“返回”手势教程。接下来了解如何转到主屏幕。"
+ "滑动时,手的位置不要太靠近屏幕底部。""如要调节“返回”手势的灵敏度,请转到“设置”""滑动即可返回""如要返回上一个屏幕,请从左侧或右侧边缘滑动到屏幕中间位置。"
- "请确保从屏幕底部边缘向上滑动。"
- "松开手指前,请确保不要停下来。"
- "请确保直接向上滑动。"
- "您完成了“转到主屏幕”手势教程。接下来了解如何返回。"
- "您完成了“转到主屏幕”手势教程。"
- "上滑可转到主屏幕"
+ "请从屏幕底部边缘向上滑动。"
+ "在松开手指前请勿停下来。"
+ "请向上滑动。"
+ "您完成了“转到主屏幕”手势教程。接下来了解如何切换应用。"
+ "滑动即可转到主屏幕""从屏幕底部向上滑动。这个手势会一律将您转到主屏幕。"
- "请确保从屏幕底部边缘向上滑动。"
+ "请从屏幕底部边缘向上滑动。""请尝试按住窗口较长时间,然后再松开手指。"
- "请确保直接向上滑动,然后停住。"
- "您已了解如何使用手势了。如要关闭手势,请转到“设置”。"
- "您完成了“切换应用”手势教程。"
+ "请向上滑动,然后停住。"
+ "您完成了“切换应用”手势教程。您现在可以使用手机了!""滑动即可切换应用"
- "如需在应用之间切换,请从屏幕底部向上滑动后按住,然后松开。"
+ "从屏幕底部向上滑动后按住,然后松开。""大功告成"
- "完成"
+ "继续"
+ "完成""设置""重试""很好!""教程 %1$d/%2$d"
- "大功告成!"
- "向上滑动即可转到主屏幕"
- "您可以开始使用手机了"
- "系统导航设置""分享""屏幕截图""该应用或您所在的单位不允许执行此操作"
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index d1e8392d55..5522a67f05 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -45,10 +45,12 @@
"已啟用應用程式建議""已停用應用程式建議""預測應用程式:%1$s"
- "請從螢幕右側或左側邊緣滑動。"
- "請從螢幕右側或左側邊緣往中央滑動,然後放開手指。"
- "您已瞭解如何透過「由右向左滑動」手勢返回。接下來一起瞭解如何切換應用程式。"
- "您已完成「返回」手勢的教學課程。"
+ "請從螢幕左側邊緣滑動。"
+ "請從螢幕左側邊緣往中央滑動,然後放開手指。"
+ "大功告成!現在試試從螢幕右側邊緣滑動。"
+ "請從螢幕右側邊緣滑動。"
+ "請從螢幕右側邊緣往中央滑動,然後放開手指"
+ "您已完成「返回」手勢的教學課程。接下來一起瞭解如何返回主畫面。""滑動時,手的位置不要太接近螢幕底部。""如要變更「返回」手勢的敏感度,請前往「設定」""滑動即可返回"
@@ -56,27 +58,22 @@
"請從螢幕底部邊緣向上滑動。""放開手指前請勿停下來。""請向上滑動。"
- "您已完成「返回主畫面」手勢的教學課程。接著,一起來瞭解如何返回上一個畫面。"
- "您已完成「返回主畫面」手勢的教學課程。"
- "向上滑動即可返回主畫面"
+ "您已完成「返回主畫面」手勢的教學課程。接下來一起瞭解如何切換應用程式。"
+ "向上滑動即可返回主畫面。""從螢幕底部向上滑動。這個手勢在所有畫面下都可讓您返回主畫面。""請從螢幕底部邊緣向上滑動。""請嘗試按住視窗更長時間,然後再放開。""請向上滑動,然後停住。"
- "您已學會如何使用手勢。如要關閉手勢,請前往「設定」。"
- "您已完成「切換應用程式」手勢的教學課程。"
+ "您已完成「切換應用程式」手勢的教學課程。現在可以開始使用手機了!""滑動即可切換應用程式"
- "如要切換應用程式,請從螢幕底部向上滑動並按住,然後放開。"
+ "從螢幕底部向上滑動並按住,然後放開。""大功告成"
- "完成"
+ "繼續"
+ "完成""設定""再試一次"
- "做得好!"
+ "很好!""教學課程 %1$d/%2$d"
- "設定完成!"
- "向上滑動即可前往主畫面"
- "您可以開始使用手機了"
- "系統導覽設定""分享""螢幕截圖""應用程式或您的機構不允許此操作"
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index db1035401a..20af2b4f88 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -31,24 +31,26 @@
"應用程式建議""所有應用程式""系統預測你會使用的應用程式"
- "在主畫面底部顯示應用程式建議"
+ "在主畫面的底部取得應用程式建議""在主畫面的收藏列取得應用程式建議"
- "你可以輕鬆地在主畫面上找到自己常用的應用程式。應用程式建議會依據你的日常使用習慣而有所不同。系統會將底部列出的應用程式上移到主畫面。"
- "你可以輕鬆地在主畫面上找到自己常用的應用程式。系統會根據你的日常使用習慣提供不同的應用程式建議,並在主畫面顯示收藏列中的應用程式。"
- "你可以輕鬆地在主畫面上找到自己常用的應用程式。應用程式建議會根據日常安排有所不同。系統會將底部列出的應用程式移到新的資料夾。"
+ "在主畫面上輕鬆存取最常使用的應用程式。應用程式建議會依據你的日常使用習慣而有所不同。系統會將底部列出的應用程式上移到主畫面。"
+ "在主畫面上輕鬆存取最常使用的應用程式。系統會根據你的日常使用習慣提供不同的應用程式建議,並在主畫面顯示收藏列中的應用程式。"
+ "在主畫面上輕鬆存取最常使用的應用程式。應用程式建議會根據日常安排有所不同。系統會將底部列出的應用程式移到新的資料夾。""取得應用程式建議""不用了,謝謝""設定""最常使用的應用程式會顯示在這裡,顯示的項目會根據日常安排有所不同"
- "將底部列中顯示的應用程式拖曳出來,即可取得應用程式建議"
+ "將應用程式從底部列向外拖曳,即可取得應用程式建議""應用程式建議已新增到空白位置""應用程式建議功能已啟用""應用程式建議功能已停用""預測的應用程式:%1$s"
- "請從螢幕右側或左側邊緣滑動。"
- "請從螢幕右側或左側邊緣往中央滑動,然後放開手指。"
- "你已瞭解如何透過「由右向左滑動」手勢返回。接著,一起來瞭解如何切換應用程式。"
- "你已完成「返回」手勢的教學課程。"
+ "請從螢幕左側邊緣滑動。"
+ "請從螢幕左側邊緣往中央滑動,然後放開手指。"
+ "大功告成!現在請試著從螢幕右側邊緣滑動。"
+ "請從螢幕右側邊緣滑動。"
+ "請從螢幕右側邊緣往中央滑動,然後放開手指。"
+ "你已完成「返回」手勢的教學課程。接著,一起來瞭解如何返回主畫面。""滑動時,手的位置不要太接近螢幕底部。""如要變更「返回」手勢的敏感度,請前往「設定」""滑動即可返回"
@@ -56,29 +58,24 @@
"請從螢幕底部邊緣向上滑動。""放開手指前請勿停下來。""請向上滑動。"
- "你已完成「返回主畫面」手勢的教學課程。接著,一起來瞭解如何返回上一個畫面。"
- "你已完成「返回主畫面」手勢的教學課程。"
+ "你已完成「返回主畫面」手勢的教學課程。接著,一起來瞭解如何切換應用程式。""使用滑動手勢返回主畫面""從螢幕底部向上滑動,即可返回主畫面。""請從螢幕底部邊緣向上滑動。""請按住視窗久一點,然後再放開。""請向上滑動,然後停住。"
- "你已瞭解如何使用手勢了。如要關閉手勢,請前往「設定」。"
- "你已完成「切換應用程式」手勢的教學課程。"
+ "你已完成「切換應用程式」手勢的教學課程。現在可以開始使用手機了!""使用滑動手勢切換應用程式"
- "如要切換不同的應用程式,請從螢幕底部向上滑動並按住,然後放開手指。"
+ "從螢幕底部向上滑動並按住,然後放開。""大功告成"
- "完成"
+ "繼續"
+ "完成""設定""重試""很好!""教學課程 %1$d/%2$d"
- "設定完成!"
- "向上滑動即可前往主畫面"
- "你可以開始使用手機了"
- "系統操作機制設定""分享"
- "螢幕截圖"
+ "擷取螢幕畫面""這個應用程式或貴機構不允許執行這個動作""要略過手勢操作教學課程嗎?""你之後可以在「%1$s」應用程式找到這些說明"
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index bbfb840e4a..2ffaecf9c5 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -45,10 +45,12 @@
"Iziphakamiso zohlelo lokusebenza zinikwe amandla""Iziphakamiso zohlelo lokusebenza zikhutshaziwe""Uhlelo lokusebenza olubikezelwe: %1$s"
- "Qiniseka ukuthi uswayipha kusuka onqenqemeni olukude ngakwesokudla noma olukude ngakwesokunxele."
- "Qiniseka ukuthi uswayipha kusuka kunqenqema ongakwesokudla noma ongakwesokunxele kuya maphakathi nesikrini bese uyadedela."
- "Ufunde indlela yokuswayipha kusuka kwesokudla ukuze ubuyele emuva. Ngokulandelayo, funda indlela yokushintsha ama-app."
- "Ukuqedile ukuthinta kokubuyela emuva."
+ "Qiniseka ukuthi uswayiphela ekudeni emngceleni ongakwesobunxele."
+ "Qiniseka ukuthi uswayipha kusuka emngceleni okwesobunxele kuya phakathi kwesikrini bese uyadedela."
+ "Yilokho nje! Manje zama ukuswayipha kusuka kwesokudla."
+ "Qiniseka ukuthi uswayiphela ekudeni emngceleni ongakwesokudla."
+ "Qiniseka ukuthi uswayipha kusuka emngceleni okwesokudla kuya phakathi kwesikrini bese uyadedela."
+ "Ukuqedile ukuthinta kokubuyela emuva. Ngokulandelayo, funda indlela yokuya Ekhaya.""Qiniseka ukuba awuswayipheli eduze kakhulu naphansi kwesikrini.""Ukuze ushintshe ukuzwela kokuthinta emuva, iya Kumasethingi""Swayipha ukuze uye emuva"
@@ -56,27 +58,22 @@
"Qiniseka ukuthi uswayiphela phezulu kusuka emngceleni ophansi wesikrini.""Qiniseka ukuthi awumisi ngaphambi kokudedela.""Qiniseka ukuthi uswayiphela ngqo phezulu."
- "Ukuqedile ukuthinta kokuya Ekhaya. Ngokulandelayo, funda indlela yokuya emuva."
- "Ukuqedile ukuthinta kokuya Ekhaya."
+ "Ukuqedile ukuthinta kokuya Ekhaya. Ngokulandelayo, funda indlela yokushintsha ama-app.""Swayipha ukuze uye ekhaya""Swayiphela phezulu kusuka phansi kwesikrini sakho.Lokhu kuthinta kuhlala kukusa esikrinini sasekhaya.""Qiniseka ukuthi uswayiphela phezulu kusuka emngceleni ophansi wesikrini.""Zama ukubamba iwindi isikhashana ngaphambi kokulidedela.""Qiniseka ukuthi uswayiphela ngqo phezulu bese uyamisa."
- "Ufunde ukusebenzisa ukuthinta. Ukuze uvale ukuthinta, iya kokuthi Amasethingi."
- "Ukuqedile ukuthinta kokushintsha ama-app."
+ "Ukuqedile ukuthinta kokushintsha ama-app. Ukulungele ukusebenzisa ifoni yakho!""Swayipha ukuze ushintshe ama-app"
- "Ukuze ushintshe phakathi kwama-app, swayiphela phezulu kusuka ngezansi kwesikrini sakho, bese uyadedela."
+ "Swayiphela phezulu kusuka ngezansi kwesikrini sakho, ubambe, bese udedele.""Konke kusethiwe"
- "Kwenziwe"
+ "Okulandelayo"
+ "Kwenziwe""Amasethingi""Zama futhi""Kuhle!""Okokufundisa %1$d/%2$d"
- "Konke kusethiwe!"
- "Swayiphela phezulu ukuze uye Ekhaya"
- "Usulungele ukuqala ukusebenzisa ifoni yakho"
- "Amasethingi wokuzulazula isistimu""Yabelana""Isithombe-skrini""Lesi senzo asivunyelwanga uhlelo lokusebenza noma inhlangano yakho"
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 167c7c3d0f..671a617f01 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -14,8 +14,6 @@
limitations under the License.
-->
- #FFFFFFFF
- #99000000#fff#39000000
@@ -26,6 +24,59 @@
#3cffffff
- #101010
- #E0E0E0
+ @color/overview_scrim_dark
+ #E0E0E0
+ #ffffff
+
+ #99000000
+ #EBffffff
+ #99000000
+
+
+ #FFFFFFFF
+
+ #f9f9f9
+ #A0C2F9
+ #6DA1FF
+
+ #3C4043
+ #FF000000
+ #B7F29F
+ #202124
+
+
+ #8AB4F8
+ #F28B82
+ #FDD663
+ #81C995
+ #3C4043
+
+
+ #f1f3f4
+ #e8eaed
+ #dadce0
+ #bdc1c6
+ #e8eaed
+ #dadce0
+ #dadce0
+
+
+ #dadce0
+ #e8eaed
+ #f8f9fa
+ #9aa0a6
+ #bdc1c6
+ #bdc1c6
+
+
+ #f1f3f4
+ #6e7175
+ #9a9a9a
+ #e8eaed
+ #80868b
+ #bdc1c6
+
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index d67b23be0a..31c0f5f2ab 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -30,6 +30,7 @@
determines how many thumbnails will be fetched in the background. -->
312
+ 20200
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 6cc64e0aa7..5ea94e906e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -16,7 +16,8 @@
48dp
- 32dp
+ 48dp
+ 32dp2dp
@@ -26,24 +27,35 @@
22dp4dp2dp
+ 234dp
+ 8dp48dp16dp50dp16dp
+ 12dp
+ 4dp
+ 0.748dp
- 28dp
- 8dp
+ 32dp
+ 36dp
+ 28dp
+ 19.37dp
+ 22dp
+ 19.1dp
+ 10dp
+ 8dp16dp
- 77dp
- 90dp
- 54dp
- 42dp
- 90dp
- 110dp
+ 60dp
+ 52dp
+ 36dp
+ 16dp
+ 36dp
+ 38dp2.25dp
@@ -51,7 +63,6 @@
1dp5dp
- 16dp70dp10dp
@@ -108,17 +121,57 @@
136dp
- 40dp
- 16dp24dp
- 18dp
+ 140dp
+ 72dp
+ 18dp
+ 80dp
+
+
+ 44dp
+ 100dp
+ 36dp
+ 32dp
+ 4dp
+ 26dp
+ 18dp
+ 126dp
+
+
+ 56dp
+ 100dp
+ 28dp
+ 20dp
+
+
+ 60dp
+ 100dp
+ 50dp
+ 100dp
+ 36dp
+
+
+ 32dp
+ 24dp
+ 8dp
+ 22dp
+ 8dp
+ 4dp
+ 36dp
+ 22dp
+
+
+ 44dp
+ 100dp
+ 218dp40dp24dp32dp
- 52dp24dp
+ 348dp
+ 10dp8dp
@@ -148,13 +201,34 @@
80dp
+
+ 95dp
+
+ 0dp
+
+ 0dp
+
+
+ 40dp
+ 20dp
+ 20dp
+ 10dp
+
- 60dp
- 44dp
+ @*android:dimen/taskbar_frame_height
+ 48dp48dp54dp
-
- 8dp16dp16dp
+ 8dp
+ 44dp
+ 40dp
+ 42dp
+ 35dp
+ 24dp
+ 220dp
+ 6dp
+ 25dp
+ 4dp
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 4aee2a9ccb..6caed1cf7d 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -39,6 +39,9 @@
Recent apps
+
+ Task Closed
+
%1$s, %2$s
@@ -53,8 +56,6 @@
App suggestions
-
- All appsYour predicted apps
@@ -191,6 +192,12 @@
ShareScreenshot
+
+ Split
+
+ Tap another app to use splitscreen
+
+ App does not support split-screen.This action isn\'t allowed by the app or your organization
@@ -203,4 +210,30 @@
CancelSkip
+
+
+ Rotate screen
+
+
+
+ Taskbar education appeared
+
+ Taskbar education closed
+
+ Use the taskbar to switch apps
+
+ Drag to the side to use two apps at once
+
+ Touch & hold to hide the taskbar
+
+ Next
+
+ Back
+
+ Close
+
+ Done
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 07c448df9e..2efe72e651 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -115,7 +115,7 @@
@android:color/transparentfalsetrue
- #FFFFFFFF
+ @android:color/transparent
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
deleted file mode 100644
index 9df9ab1682..0000000000
--- a/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import static com.android.launcher3.util.LauncherUIHelper.doLayout;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-
-import com.android.quickstep.fallback.FallbackRecentsView;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.android.controller.ActivityController;
-import org.robolectric.annotation.LooperMode;
-import org.robolectric.annotation.LooperMode.Mode;
-import org.robolectric.shadows.ShadowLooper;
-import org.robolectric.util.ReflectionHelpers;
-
-
-@RunWith(RobolectricTestRunner.class)
-@LooperMode(Mode.PAUSED)
-@org.junit.Ignore
-public class RecentsActivityTest {
-
- @Test
- public void testRecentsActivityCreates() {
- ActivityController controller =
- Robolectric.buildActivity(RecentsActivity.class);
-
- RecentsActivity launcher = controller.setup().get();
- doLayout(launcher);
-
- // TODO: Ensure that LauncherAppState is not created
- }
-
- @Test
- public void testRecents_showCurrentTask() {
- ActivityController controller =
- Robolectric.buildActivity(RecentsActivity.class);
-
- RecentsActivity activity = controller.setup().get();
- doLayout(activity);
-
- FallbackRecentsView frv = activity.getOverviewPanel();
-
- RunningTaskInfo placeholderTask = new RunningTaskInfo();
- placeholderTask.taskId = 22;
- frv.showCurrentTask(placeholderTask);
- doLayout(activity);
-
- ThumbnailData thumbnailData = new ThumbnailData();
- ReflectionHelpers.setField(thumbnailData, "thumbnail",
- Bitmap.createBitmap(300, 500, Config.ARGB_8888));
- frv.switchToScreenshot(thumbnailData, () -> { });
- ShadowLooper.idleMainLooper();
- }
-}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index de0416b693..4269f2d906 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -22,21 +22,25 @@ import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.NO_OFFSET;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
+import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.app.ActivityOptions;
-import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.ServiceConnection;
+import android.graphics.Insets;
+import android.hardware.SensorManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
import android.os.CancellationSignal;
-import android.os.IBinder;
import android.view.View;
+import android.view.WindowInsets;
import android.window.SplashScreen;
import androidx.annotation.Nullable;
@@ -53,9 +57,10 @@ import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.taskbar.TaskbarManager;
-import com.android.launcher3.taskbar.TaskbarStateHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.ActivityOptionsWrapper;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.OverviewCommandHelper;
@@ -65,18 +70,24 @@ import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
-import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.util.LauncherUnfoldAnimationController;
+import com.android.quickstep.util.ProxyScreenStatusProvider;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.quickstep.util.SplitSelectStateController;
+import com.android.quickstep.util.TISBindHelper;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.SplitPlaceholderView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.unfold.UnfoldTransitionFactory;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
+import com.android.systemui.unfold.config.UnfoldTransitionConfig;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
import java.util.stream.Stream;
@@ -98,45 +109,61 @@ public abstract class BaseQuickstepLauncher extends Launcher
private OverviewActionsView mActionsView;
+ private TISBindHelper mTISBindHelper;
private @Nullable TaskbarManager mTaskbarManager;
private @Nullable OverviewCommandHelper mOverviewCommandHelper;
private @Nullable LauncherTaskbarUIController mTaskbarUIController;
- private final ServiceConnection mTisBinderConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
- mTaskbarManager = ((TISBinder) iBinder).getTaskbarManager();
- mTaskbarManager.setLauncher(BaseQuickstepLauncher.this);
-
- mOverviewCommandHelper = ((TISBinder) iBinder).getOverviewCommandHelper();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName componentName) { }
- };
- private final TaskbarStateHandler mTaskbarStateHandler = new TaskbarStateHandler(this);
// Will be updated when dragging from taskbar.
private @Nullable DragOptions mNextWorkspaceDragOptions = null;
- private SplitPlaceholderView mSplitPlaceholderView;
+
+ private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
+ private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this);
addMultiWindowModeChangedListener(mDepthController);
+ initUnfoldTransitionProgressProvider();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (mLauncherUnfoldAnimationController != null) {
+ mLauncherUnfoldAnimationController.onResume();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ if (mLauncherUnfoldAnimationController != null) {
+ mLauncherUnfoldAnimationController.onPause();
+ }
+
+ super.onPause();
}
@Override
public void onDestroy() {
mAppTransitionManager.onActivityDestroyed();
+ if (mUnfoldTransitionProgressProvider != null) {
+ mUnfoldTransitionProgressProvider.destroy();
+ }
SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
-
- unbindService(mTisBinderConnection);
+ mTISBindHelper.onDestroy();
if (mTaskbarManager != null) {
- mTaskbarManager.setLauncher(null);
+ mTaskbarManager.clearActivity(this);
}
+
+ if (mLauncherUnfoldAnimationController != null) {
+ mLauncherUnfoldAnimationController.onDestroy();
+ }
+
super.onDestroy();
}
@@ -272,32 +299,64 @@ public abstract class BaseQuickstepLauncher extends Launcher
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),
+ getStateManager(), getDepthController());
+ overviewPanel.init(mActionsView, controller);
mActionsView.setDp(getDeviceProfile());
mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
mAppTransitionManager = new QuickstepTransitionManager(this);
mAppTransitionManager.registerRemoteAnimations();
+ mAppTransitionManager.registerRemoteTransitions();
- bindService(new Intent(this, TouchInteractionService.class), mTisBinderConnection, 0);
+ mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
+ }
+ private void onTISConnected(TISBinder binder) {
+ mTaskbarManager = binder.getTaskbarManager();
+ mTaskbarManager.setActivity(this);
+ mOverviewCommandHelper = binder.getOverviewCommandHelper();
+ }
+
+ @Override
+ public void runOnBindToTouchInteractionService(Runnable r) {
+ mTISBindHelper.runOnBindToTouchInteractionService(r);
+ }
+
+ private void initUnfoldTransitionProgressProvider() {
+ final UnfoldTransitionConfig config = UnfoldTransitionFactory.createConfig(this);
+ if (config.isEnabled()) {
+ mUnfoldTransitionProgressProvider =
+ UnfoldTransitionFactory.createUnfoldTransitionProgressProvider(
+ this,
+ config,
+ ProxyScreenStatusProvider.INSTANCE,
+ getSystemService(DeviceStateManager.class),
+ getSystemService(SensorManager.class),
+ getMainThreadHandler(),
+ getMainExecutor()
+ );
+
+ mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController(
+ this,
+ getWindowManager(),
+ mUnfoldTransitionProgressProvider
+ );
+ }
}
public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) {
mTaskbarUIController = taskbarUIController;
}
- public T getActionsView() {
- return (T) mActionsView;
+ public @Nullable LauncherTaskbarUIController getTaskbarUIController() {
+ return mTaskbarUIController;
}
- public SplitPlaceholderView getSplitPlaceholderView() {
- return mSplitPlaceholderView;
+ public T getActionsView() {
+ return (T) mActionsView;
}
@Override
@@ -312,19 +371,15 @@ public abstract class BaseQuickstepLauncher extends Launcher
out.add(getDepthController());
out.add(new RecentsViewStateController(this));
out.add(new BackButtonAlphaHandler(this));
- out.add(getTaskbarStateHandler());
}
public DepthController getDepthController() {
return mDepthController;
}
- public @Nullable LauncherTaskbarUIController getTaskbarUIController() {
- return mTaskbarUIController;
- }
-
- public TaskbarStateHandler getTaskbarStateHandler() {
- return mTaskbarStateHandler;
+ @Nullable
+ public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() {
+ return mUnfoldTransitionProgressProvider;
}
@Override
@@ -374,14 +429,6 @@ public abstract class BaseQuickstepLauncher extends Launcher
? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
}
- @Override
- public float getNormalTaskbarScale() {
- if (mTaskbarUIController != null) {
- return mTaskbarUIController.getTaskbarScaleOnHome();
- }
- return super.getNormalTaskbarScale();
- }
-
@Override
public void onDragLayerHierarchyChanged() {
onLauncherStateOrFocusChanged();
@@ -436,8 +483,8 @@ public abstract class BaseQuickstepLauncher extends Launcher
}
@Override
- public void finishBindingItems(int pageBoundFirst) {
- super.finishBindingItems(pageBoundFirst);
+ public void finishBindingItems(IntSet pagesBoundFirst) {
+ super.finishBindingItems(pagesBoundFirst);
// Instantiate and initialize WellbeingModel now that its loading won't interfere with
// populating workspace.
// TODO: Find a better place for this
@@ -505,4 +552,35 @@ public abstract class BaseQuickstepLauncher extends Launcher
public void setHintUserWillBeActive() {
addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
}
+
+ @Override
+ public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
+ super.onDisplayInfoChanged(context, info, flags);
+ // When changing screens, force moving to rest state similar to StatefulActivity.onStop, as
+ // StatefulActivity isn't called consistently.
+ if ((flags & CHANGE_ACTIVE_SCREEN) != 0) {
+ getStateManager().moveToRestState();
+ }
+ }
+
+ @Override
+ public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+ super.dump(prefix, fd, writer, args);
+ if (mDepthController != null) {
+ mDepthController.dump(prefix, writer);
+ }
+ }
+
+ @Override
+ public void updateWindowInsets(WindowInsets.Builder updatedInsetsBuilder,
+ WindowInsets oldInsets) {
+ // Override the tappable insets to be 0 on the bottom for gesture nav (otherwise taskbar
+ // would count towards it). This is used for the bottom protection in All Apps for example.
+ if (SysUINavigationMode.getMode(this) == NO_BUTTON) {
+ Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
+ Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
+ oldTappableInsets.right, 0);
+ updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
index 5fc79f078f..35151f1a68 100644
--- a/quickstep/src/com/android/launcher3/LauncherInitListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -17,11 +17,8 @@ package com.android.launcher3;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.Intent;
import android.os.Build;
import android.os.CancellationSignal;
-import android.os.Handler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RemoteAnimationProvider;
@@ -78,11 +75,4 @@ public class LauncherInitListener extends ActivityInitListener {
mRemoteAnimationProvider = null;
super.unregister();
}
-
- @Override
- public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
- Context context, Handler handler, long duration) {
- mRemoteAnimationProvider = animProvider;
- super.registerAndStartActivity(intent, animProvider, context, handler, duration);
- }
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index b557779a26..6e2fadd7d3 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -28,18 +28,24 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.Utilities.mapBoundToRange;
import static com.android.launcher3.Utilities.postAsyncCallback;
+import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
+import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_BACK_SWIPE_HOME_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
+import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
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.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
+import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
@@ -51,20 +57,24 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.CancellationSignal;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.util.Pair;
import android.util.Size;
import android.view.SurfaceControl;
@@ -86,8 +96,12 @@ import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.taskbar.LauncherTaskbarUIController;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.ActivityOptionsWrapper;
+import com.android.launcher3.util.DynamicResource;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.FloatingIconView;
@@ -97,7 +111,9 @@ import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.util.MultiValueUpdateListener;
+import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.WorkspaceRevealAnim;
import com.android.quickstep.views.FloatingWidgetView;
@@ -159,6 +175,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
public static final int RECENTS_LAUNCH_DURATION = 336;
private static final int LAUNCHER_RESUME_START_DELAY = 100;
private static final int CLOSING_TRANSITION_DURATION_MS = 250;
+ public static final int SPLIT_LAUNCH_DURATION = 370;
+ public static final int SPLIT_DIVIDER_ANIM_DURATION = 100;
public static final int CONTENT_ALPHA_DURATION = 217;
protected static final int CONTENT_SCALE_DURATION = 350;
@@ -269,7 +287,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY;
RemoteAnimationAdapterCompat adapterCompat =
- new RemoteAnimationAdapterCompat(runner, duration, statusBarTransitionDelay);
+ new RemoteAnimationAdapterCompat(runner, duration, statusBarTransitionDelay,
+ mLauncher.getIApplicationThread());
return new ActivityOptionsWrapper(
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat), onEndCallback);
}
@@ -422,6 +441,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
4 - rotationChange);
}
}
+ if (mDeviceProfile.isTaskbarPresentInApps) {
+ // Animate to above the taskbar.
+ bounds.bottom -= target.contentInsets.bottom;
+ }
return bounds;
}
@@ -506,7 +529,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
final boolean scrimEnabled = ENABLE_SCRIM_FOR_APP_LAUNCH.get();
if (scrimEnabled) {
- int scrimColor = Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
+ boolean useTaskbarColor = mDeviceProfile.isTaskbarPresentInApps;
+ int scrimColor = useTaskbarColor
+ ? mLauncher.getResources().getColor(R.color.taskbar_background)
+ : Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
int scrimColorTrans = ColorUtils.setAlphaComponent(scrimColor, 0);
int[] colors = isAppOpening
? new int[]{scrimColorTrans, scrimColor}
@@ -519,6 +545,30 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
colors);
scrim.setDuration(CONTENT_SCRIM_DURATION);
scrim.setInterpolator(DEACCEL_1_5);
+
+ if (useTaskbarColor) {
+ // Hide the taskbar background color since it would duplicate the scrim.
+ scrim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ LauncherTaskbarUIController taskbarUIController =
+ mLauncher.getTaskbarUIController();
+ if (taskbarUIController != null) {
+ taskbarUIController.forceHideBackground(true);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ LauncherTaskbarUIController taskbarUIController =
+ mLauncher.getTaskbarUIController();
+ if (taskbarUIController != null) {
+ taskbarUIController.forceHideBackground(false);
+ }
+ }
+ });
+ }
+
launcherAnimator.play(scrim);
}
}
@@ -611,10 +661,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
AnimOpenProperties prop = new AnimOpenProperties(mLauncher.getResources(), mDeviceProfile,
windowTargetBounds, launcherIconBounds, v, dragLayerBounds[0], dragLayerBounds[1],
hasSplashScreen, floatingView.isDifferentFromAppIcon());
- int left = (int) (prop.cropCenterXStart - prop.cropWidthStart / 2);
- int top = (int) (prop.cropCenterYStart - prop.cropHeightStart / 2);
- int right = (int) (left + prop.cropWidthStart);
- int bottom = (int) (top + prop.cropHeightStart);
+ int left = prop.cropCenterXStart - prop.cropWidthStart / 2;
+ int top = prop.cropCenterYStart - prop.cropHeightStart / 2;
+ int right = left + prop.cropWidthStart;
+ int bottom = top + prop.cropHeightStart;
// Set the crop here so we can calculate the corner radius below.
crop.set(left, top, right, bottom);
@@ -633,6 +683,10 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
if (v instanceof BubbleTextView) {
((BubbleTextView) v).setStayPressed(false);
}
+ LauncherTaskbarUIController taskbarController = mLauncher.getTaskbarUIController();
+ if (taskbarController != null) {
+ taskbarController.showEdu();
+ }
openingTargets.release();
}
});
@@ -641,7 +695,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
? Math.max(crop.width(), crop.height()) / 2f
: 0f;
final float finalWindowRadius = mDeviceProfile.isMultiWindowMode
- ? 0 : getWindowCornerRadius(mLauncher.getResources());
+ ? 0 : getWindowCornerRadius(mLauncher);
final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
@@ -804,7 +858,13 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
// Since we added a start delay, call update here to init the FloatingIconView properly.
listener.onUpdate(0, true /* initOnly */);
- animatorSet.playTogether(appAnimator, getBackgroundAnimator(appTargets));
+ // If app targets are translucent, do not animate the background as it causes a visible
+ // flicker when it resets itself at the end of its animation.
+ if (appTargetsAreTranslucent) {
+ animatorSet.play(appAnimator);
+ } else {
+ animatorSet.playTogether(appAnimator, getBackgroundAnimator());
+ }
return animatorSet;
}
@@ -832,7 +892,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
}
final float finalWindowRadius = mDeviceProfile.isMultiWindowMode
- ? 0 : getWindowCornerRadius(mLauncher.getResources());
+ ? 0 : getWindowCornerRadius(mLauncher);
final FloatingWidgetView floatingView = FloatingWidgetView.getFloatingWidgetView(mLauncher,
v, widgetBackgroundBounds,
new Size(windowTargetBounds.width(), windowTargetBounds.height()),
@@ -941,11 +1001,20 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
}
});
- animatorSet.playTogether(appAnimator, getBackgroundAnimator(appTargets));
+ // If app targets are translucent, do not animate the background as it causes a visible
+ // flicker when it resets itself at the end of its animation.
+ if (appTargetsAreTranslucent) {
+ animatorSet.play(appAnimator);
+ } else {
+ animatorSet.playTogether(appAnimator, getBackgroundAnimator());
+ }
return animatorSet;
}
- private ObjectAnimator getBackgroundAnimator(RemoteAnimationTargetCompat[] appTargets) {
+ /**
+ * Returns animator that controls depth/blur of the background.
+ */
+ private ObjectAnimator getBackgroundAnimator() {
// When launching an app from overview that doesn't map to a task, we still want to just
// blur the wallpaper instead of the launcher surface as well
boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW;
@@ -1015,7 +1084,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
new RemoteAnimationAdapterCompat(
new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
false /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */,
+ mLauncher.getIApplicationThread()));
if (KEYGUARD_ANIMATION.get()) {
mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
@@ -1025,7 +1095,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
new LauncherAnimationRunner(
mHandler, mKeyguardGoingAwayRunner,
true /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */,
+ mLauncher.getIApplicationThread()));
}
new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
@@ -1043,8 +1114,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */);
mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition(
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
- false /* startAtFrontOfQueue */));
- mLauncherOpenTransition.addHomeOpenCheck();
+ false /* startAtFrontOfQueue */), mLauncher.getIApplicationThread());
+ mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName());
SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
}
}
@@ -1085,7 +1156,16 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
}
private boolean launcherIsATargetWithMode(RemoteAnimationTargetCompat[] targets, int mode) {
- return taskIsATargetWithMode(targets, mLauncher.getTaskId(), mode);
+ for (RemoteAnimationTargetCompat target : targets) {
+ if (target.mode == mode && target.taskInfo != null
+ // Compare component name instead of task-id because transitions will promote
+ // the target up to the root task while getTaskId returns the leaf.
+ && target.taskInfo.topActivity != null
+ && target.taskInfo.topActivity.equals(mLauncher.getComponentName())) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -1105,7 +1185,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1);
unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 :
- QuickStepContract.getWindowCornerRadius(mLauncher.getResources());
+ QuickStepContract.getWindowCornerRadius(mLauncher);
unlockAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -1135,10 +1215,181 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
}
/**
- * Animator that controls the transformations of the windows the targets that are closing.
+ * Returns view on launcher that corresponds to the closing app in the list of app targets
*/
- private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets) {
+ private @Nullable View findLauncherView(RemoteAnimationTargetCompat[] appTargets) {
+ for (RemoteAnimationTargetCompat appTarget : appTargets) {
+ if (appTarget.mode == MODE_CLOSING) {
+ View launcherView = findLauncherView(appTarget);
+ if (launcherView != null) {
+ return launcherView;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns view on launcher that corresponds to the {@param runningTaskTarget}.
+ */
+ private @Nullable View findLauncherView(RemoteAnimationTargetCompat runningTaskTarget) {
+ if (runningTaskTarget == null || runningTaskTarget.taskInfo == null) {
+ return null;
+ }
+
+ final ComponentName[] taskInfoActivities = new ComponentName[] {
+ runningTaskTarget.taskInfo.baseActivity,
+ runningTaskTarget.taskInfo.origActivity,
+ runningTaskTarget.taskInfo.realActivity,
+ runningTaskTarget.taskInfo.topActivity};
+
+ String packageName = null;
+ for (ComponentName component : taskInfoActivities) {
+ if (component != null && component.getPackageName() != null) {
+ packageName = component.getPackageName();
+ break;
+ }
+ }
+
+ if (packageName == null) {
+ return null;
+ }
+
+ // Find the associated item info for the launch cookie (if available), note that predicted
+ // apps actually have an id of -1, so use another default id here
+ final ArrayList launchCookies = runningTaskTarget.taskInfo.launchCookies == null
+ ? new ArrayList<>()
+ : runningTaskTarget.taskInfo.launchCookies;
+
+ int launchCookieItemId = NO_MATCHING_ID;
+ for (IBinder cookie : launchCookies) {
+ Integer itemId = ObjectWrapper.unwrap(cookie);
+ if (itemId != null) {
+ launchCookieItemId = itemId;
+ break;
+ }
+ }
+
+ return mLauncher.getFirstMatchForAppClose(launchCookieItemId,
+ packageName, UserHandle.of(runningTaskTarget.taskInfo.userId));
+ }
+
+ private @NonNull RectF getDefaultWindowTargetRect() {
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ final int halfIconSize = dp.iconSizePx / 2;
+ float primaryDimension = orientationHandler
+ .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
+ float secondaryDimension = orientationHandler
+ .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
+ final float targetX = primaryDimension / 2f;
+ final float targetY = secondaryDimension - dp.hotseatBarSizePx;
+ return new RectF(targetX - halfIconSize, targetY - halfIconSize,
+ targetX + halfIconSize, targetY + halfIconSize);
+ }
+
+ /**
+ * Closing animator that animates the window into its final location on the workspace.
+ */
+ private void getClosingWindowAnimators(AnimatorSet animation,
+ RemoteAnimationTargetCompat[] targets, View launcherView, PointF velocityPxPerS) {
+ FloatingIconView floatingIconView = null;
+ FloatingWidgetView floatingWidget = null;
+ RectF targetRect = new RectF();
+
+ RemoteAnimationTargetCompat runningTaskTarget = null;
+ boolean isTransluscent = false;
+ for (RemoteAnimationTargetCompat target : targets) {
+ if (target.mode == MODE_CLOSING) {
+ runningTaskTarget = target;
+ isTransluscent = runningTaskTarget.isTranslucent;
+ break;
+ }
+ }
+
+ // Get floating view and target rect.
+ if (launcherView instanceof LauncherAppWidgetHostView) {
+ Size windowSize = new Size(mDeviceProfile.availableWidthPx,
+ mDeviceProfile.availableHeightPx);
+ int fallbackBackgroundColor =
+ FloatingWidgetView.getDefaultBackgroundColor(mLauncher, runningTaskTarget);
+ floatingWidget = FloatingWidgetView.getFloatingWidgetView(mLauncher,
+ (LauncherAppWidgetHostView) launcherView, targetRect, windowSize,
+ mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher),
+ isTransluscent, fallbackBackgroundColor);
+ } else if (launcherView != null) {
+ floatingIconView = getFloatingIconView(mLauncher, launcherView,
+ true /* hideOriginal */, targetRect, false /* isOpening */);
+ } else {
+ targetRect.set(getDefaultWindowTargetRect());
+ }
+
+ final RectF startRect = new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
+ RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mLauncher,
+ mDeviceProfile);
+
+ // Hook up floating views to the closing window animators.
+ final int rotationChange = getRotationChange(targets);
+ Rect windowTargetBounds = getWindowTargetBounds(targets, rotationChange);
+ if (floatingIconView != null) {
+ anim.addAnimatorListener(floatingIconView);
+ floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
+ floatingIconView.setFastFinishRunnable(anim::end);
+ FloatingIconView finalFloatingIconView = floatingIconView;
+
+ // We want the window alpha to be 0 once this threshold is met, so that the
+ // FolderIconView can be seen morphing into the icon shape.
+ final float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
+
+ RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect,
+ windowTargetBounds) {
+ @Override
+ public void onUpdate(RectF currentRectF, float progress) {
+ finalFloatingIconView.update(1f, 255 /* fgAlpha */, currentRectF, progress,
+ windowAlphaThreshold, getCornerRadius(progress), false);
+
+ super.onUpdate(currentRectF, progress);
+ }
+ };
+ anim.addOnUpdateListener(runner);
+ } else if (floatingWidget != null) {
+ anim.addAnimatorListener(floatingWidget);
+ floatingWidget.setOnTargetChangeListener(anim::onTargetPositionChanged);
+ floatingWidget.setFastFinishRunnable(anim::end);
+
+ final float floatingWidgetAlpha = isTransluscent ? 0 : 1;
+ FloatingWidgetView finalFloatingWidget = floatingWidget;
+ RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect,
+ windowTargetBounds) {
+ @Override
+ public void onUpdate(RectF currentRectF, float progress) {
+ final float fallbackBackgroundAlpha =
+ 1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
+ final float foregroundAlpha =
+ mapBoundToRange(progress, 0.5f, 1, 0, 1, EXAGGERATED_EASE);
+ finalFloatingWidget.update(currentRectF, floatingWidgetAlpha, foregroundAlpha,
+ fallbackBackgroundAlpha, 1 - progress);
+
+ super.onUpdate(currentRectF, progress);
+ }
+ };
+ anim.addOnUpdateListener(runner);
+ }
+
+ // Use a fixed velocity to start the animation.
+ animation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ anim.start(mLauncher, velocityPxPerS);
+ }
+ });
+ }
+
+ /**
+ * Closing window animator that moves the window down and offscreen.
+ */
+ private Animator getFallbackClosingWindowAnimators(RemoteAnimationTargetCompat[] appTargets) {
final int rotationChange = getRotationChange(appTargets);
SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer);
Matrix matrix = new Matrix();
@@ -1147,7 +1398,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
int duration = CLOSING_TRANSITION_DURATION_MS;
float windowCornerRadius = mDeviceProfile.isMultiWindowMode
- ? 0 : getWindowCornerRadius(mLauncher.getResources());
+ ? 0 : getWindowCornerRadius(mLauncher);
float startShadowRadius = areAllTargetsTranslucent(appTargets) ? 0 : mMaxShadowRadius;
closingAnimator.setDuration(duration);
closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
@@ -1277,7 +1528,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
LauncherAnimationRunner.AnimationResult result) {
if (mLauncher.isDestroyed()) {
AnimatorSet anim = new AnimatorSet();
- anim.play(getClosingWindowAnimators(appTargets, wallpaperTargets));
+ anim.play(getFallbackClosingWindowAnimators(appTargets));
result.setAnimation(anim, mLauncher.getApplicationContext());
return;
}
@@ -1304,9 +1555,34 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
if (anim == null) {
anim = new AnimatorSet();
- anim.play(mFromUnlock
- ? getUnlockWindowAnimator(appTargets, wallpaperTargets)
- : getClosingWindowAnimators(appTargets, wallpaperTargets));
+
+ final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
+ || launcherIsATargetWithMode(appTargets, MODE_OPENING);
+
+ View launcherView = findLauncherView(appTargets);
+ boolean playFallBackAnimation = (launcherView == null
+ && launcherIsForceInvisibleOrOpening)
+ || mLauncher.getWorkspace().isOverlayShown();
+
+ boolean playWorkspaceReveal = true;
+ if (mFromUnlock) {
+ anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
+ } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
+ && !playFallBackAnimation) {
+ // Use a fixed velocity to start the animation.
+ float velocityPxPerS = DynamicResource.provider(mLauncher)
+ .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
+ PointF velocity = new PointF(0, -velocityPxPerS);
+ getClosingWindowAnimators(anim, appTargets, launcherView, velocity);
+ if (!mLauncher.isInState(LauncherState.ALL_APPS)) {
+ anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
+ true /* animateOverviewScrim */, launcherView).getAnimators());
+ // We play StaggeredWorkspaceAnim as a part of the closing window animation.
+ playWorkspaceReveal = false;
+ }
+ } else {
+ anim.play(getFallbackClosingWindowAnimators(appTargets));
+ }
// Normally, we run the launcher content animation when we are transitioning
// home, but if home is already visible, then we don't want to animate the
@@ -1316,8 +1592,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
// targets list because it is already visible). In that case, we force
// invisibility on touch down, and only reset it after the animation to home
// is initialized.
- if (launcherIsATargetWithMode(appTargets, MODE_OPENING)
- || mLauncher.isForceInvisible()) {
+ if (launcherIsForceInvisibleOrOpening) {
addCujInstrumentation(
anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
// Only register the content animation for cancellation when state changes
@@ -1334,7 +1609,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
}
});
} else {
- anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
+ if (playWorkspaceReveal) {
+ anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
+ }
}
}
}
@@ -1483,4 +1760,101 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
mTransitionManager.mTaskStartParams.put(taskId, Pair.create(supportedType, color));
}
}
+
+ /**
+ * RectFSpringAnim update listener to be used for app to home animation.
+ */
+ private class SpringAnimRunner implements RectFSpringAnim.OnUpdateListener {
+ private final RemoteAnimationTargetCompat[] mAppTargets;
+ private final Matrix mMatrix = new Matrix();
+ private final Point mTmpPos = new Point();
+ private final Rect mCurrentRect = new Rect();
+ private final float mStartRadius;
+ private final float mEndRadius;
+ private final SurfaceTransactionApplier mSurfaceApplier;
+ private final Rect mWindowTargetBounds = new Rect();
+
+ private final Rect mTmpRect = new Rect();
+
+ SpringAnimRunner(RemoteAnimationTargetCompat[] appTargets, RectF targetRect,
+ Rect windowTargetBounds) {
+ mAppTargets = appTargets;
+ mStartRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
+ mEndRadius = Math.max(1, targetRect.width()) / 2f;
+ mSurfaceApplier = new SurfaceTransactionApplier(mDragLayer);
+ mWindowTargetBounds.set(windowTargetBounds);
+ }
+
+ public float getCornerRadius(float progress) {
+ return Utilities.mapRange(progress, mStartRadius, mEndRadius);
+ }
+
+ @Override
+ public void onUpdate(RectF currentRectF, float progress) {
+ SurfaceParams[] params = new SurfaceParams[mAppTargets.length];
+ for (int i = mAppTargets.length - 1; i >= 0; i--) {
+ RemoteAnimationTargetCompat target = mAppTargets[i];
+ SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
+
+ if (target.localBounds != null) {
+ mTmpPos.set(target.localBounds.left, target.localBounds.top);
+ } else {
+ mTmpPos.set(target.position.x, target.position.y);
+ }
+
+ if (target.mode == MODE_CLOSING) {
+ currentRectF.round(mCurrentRect);
+
+ // Scale the target window to match the currentRectF.
+ final float scale;
+
+ // We need to infer the crop (we crop the window to match the currentRectF).
+ if (mWindowTargetBounds.height() > mWindowTargetBounds.width()) {
+ scale = Math.min(1f, currentRectF.width() / mWindowTargetBounds.width());
+
+ int unscaledHeight = (int) (mCurrentRect.height() * (1f / scale));
+ int croppedHeight = mWindowTargetBounds.height() - unscaledHeight;
+ mTmpRect.set(0, 0, mWindowTargetBounds.width(),
+ mWindowTargetBounds.height() - croppedHeight);
+ } else {
+ scale = Math.min(1f, currentRectF.height() / mWindowTargetBounds.height());
+
+ int unscaledWidth = (int) (mCurrentRect.width() * (1f / scale));
+ int croppedWidth = mWindowTargetBounds.width() - unscaledWidth;
+ mTmpRect.set(0, 0, mWindowTargetBounds.width() - croppedWidth,
+ mWindowTargetBounds.height());
+ }
+
+ // Match size and position of currentRect.
+ mMatrix.setScale(scale, scale);
+ mMatrix.postTranslate(mCurrentRect.left, mCurrentRect.top);
+
+ builder.withMatrix(mMatrix)
+ .withWindowCrop(mTmpRect)
+ .withAlpha(getWindowAlpha(progress))
+ .withCornerRadius(getCornerRadius(progress) / scale);
+ } else if (target.mode == MODE_OPENING) {
+ mMatrix.setTranslate(mTmpPos.x, mTmpPos.y);
+ builder.withMatrix(mMatrix)
+ .withAlpha(1f);
+ }
+ params[i] = builder.build();
+ }
+ mSurfaceApplier.scheduleApply(params);
+ }
+
+ protected float getWindowAlpha(float progress) {
+ // Alpha interpolates between [1, 0] between progress values [start, end]
+ final float start = 0f;
+ final float end = 0.85f;
+
+ if (progress <= start) {
+ return 1f;
+ }
+ if (progress >= end) {
+ return 0f;
+ }
+ return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 63a569a65c..1b0f967a1f 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -282,8 +282,7 @@ public class AppsDividerView extends View implements StateListener items) {
mPendingPredictedItems = null;
mPredictedApps.clear();
- items.stream()
+ mPredictedApps.addAll(items.stream()
.filter(itemInfo -> itemInfo instanceof WorkspaceItemInfo)
- .map(itemInfo -> (WorkspaceItemInfo) itemInfo)
- .forEach(mPredictedApps::add);
+ .map(itemInfo -> (WorkspaceItemInfo) itemInfo).collect(Collectors.toList()));
applyPredictionApps();
}
@@ -249,8 +249,7 @@ public class PredictionRowView extends LinearLayout implements
@Override
public void setInsets(Rect insets, DeviceProfile grid) {
- int leftRightPadding = grid.desiredWorkspaceLeftRightMarginPx
- + grid.cellLayoutPaddingLeftRightPx;
+ int leftRightPadding = grid.allAppsLeftRightPadding;
setPadding(leftRightPadding, getPaddingTop(), leftRightPadding, getPaddingBottom());
}
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index a6844e48b7..680012ce28 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -15,18 +15,22 @@
*/
package com.android.launcher3.hybridhotseat;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent
- .LAUNCHER_HOTSEAT_EDU_ONLY_TIP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_ONLY_TIP;
import android.content.Intent;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.Gravity;
import android.view.View;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.FolderInfo;
@@ -47,6 +51,8 @@ import java.util.stream.IntStream;
*/
public class HotseatEduController {
+ private static final String TAG = "HotseatEduController";
+
public static final String SETTINGS_ACTION =
"android.settings.ACTION_CONTENT_SUGGESTIONS_SETTINGS";
@@ -188,8 +194,12 @@ public class HotseatEduController {
.getInt(LauncherSettings.Settings.EXTRA_VALUE);
mNewScreens = IntArray.wrap(pageId);
}
- for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) {
- View child = mHotseat.getChildAt(i, 0);
+ boolean isPortrait = !mLauncher.getDeviceProfile().isVerticalBarLayout();
+ int hotseatItemsNum = mLauncher.getDeviceProfile().numShownHotseatIcons;
+ for (int i = 0; i < hotseatItemsNum; i++) {
+ int x = isPortrait ? i : 0;
+ int y = isPortrait ? 0 : hotseatItemsNum - i - 1;
+ View child = mHotseat.getChildAt(x, y);
if (child == null || child.getTag() == null) continue;
ItemInfo tag = (ItemInfo) child.getTag();
if (tag.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) continue;
@@ -229,8 +239,7 @@ public class HotseatEduController {
R.string.hotseat_prediction_settings, null,
() -> mLauncher.startActivity(getSettingsIntent()));
} else {
- new ArrowTipView(mLauncher).show(
- mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
+ showHotseatArrowTip(true, mLauncher.getString(R.string.hotseat_tip_no_empty_slots));
}
}
@@ -251,15 +260,50 @@ public class HotseatEduController {
if (requiresMigration && canMigrateToFirstPage) {
showDialog();
} else {
- new ArrowTipView(mLauncher).show(mLauncher.getString(
+ if (showHotseatArrowTip(requiresMigration, mLauncher.getString(
requiresMigration ? R.string.hotseat_tip_no_empty_slots
- : R.string.hotseat_auto_enrolled),
- mHotseat.getTop());
- mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ONLY_TIP);
+ : R.string.hotseat_auto_enrolled))) {
+ mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ONLY_TIP);
+ }
finishOnboarding();
}
}
+ /**
+ * Finds a child suitable child in hotseat and shows arrow tip pointing at it.
+ *
+ * @param usePinned used to determine target view. If true, will use the first matching pinned
+ * item. Otherwise, will use the first predicted child
+ * @param message String to be shown inside the arrowView
+ * @return whether suitable child was found and tip was shown
+ */
+ private boolean showHotseatArrowTip(boolean usePinned, String message) {
+ int childCount = mHotseat.getShortcutsAndWidgets().getChildCount();
+ boolean isPortrait = !mLauncher.getDeviceProfile().isVerticalBarLayout();
+
+ BubbleTextView tipTargetView = null;
+ for (int i = childCount - 1; i > -1; i--) {
+ int x = isPortrait ? i : 0;
+ int y = isPortrait ? 0 : i;
+ View v = mHotseat.getShortcutsAndWidgets().getChildAt(x, y);
+ if (v instanceof BubbleTextView && v.getTag() instanceof WorkspaceItemInfo) {
+ ItemInfo info = (ItemInfo) v.getTag();
+ boolean isPinned = info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+ if (isPinned == usePinned) {
+ tipTargetView = (BubbleTextView) v;
+ break;
+ }
+ }
+ }
+ if (tipTargetView == null) {
+ Log.e(TAG, "Unable to find suitable view for ArrowTip");
+ return false;
+ }
+ Rect bounds = Utilities.getViewBounds(tipTargetView);
+ new ArrowTipView(mLauncher).show(message, Gravity.END, bounds.centerX(), bounds.top);
+ return true;
+ }
+
void showDialog() {
if (mPredictedApps == null || mPredictedApps.isEmpty()) {
return;
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index 14b0c5dd62..119ae907f7 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -28,17 +28,20 @@ import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.views.AbstractSlideInView;
@@ -77,6 +80,11 @@ public class HotseatEduDialog extends AbstractSlideInView implements I
mContent = this;
}
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ setTranslationShift(TRANSLATION_SHIFT_CLOSED);
+ }
@Override
protected void onFinishInflate() {
@@ -84,8 +92,9 @@ public class HotseatEduDialog extends AbstractSlideInView implements I
mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
mSampleHotseat = findViewById(R.id.sample_prediction);
+ Context context = getContext();
DeviceProfile grid = mActivityContext.getDeviceProfile();
- Rect padding = grid.getHotseatLayoutPadding();
+ Rect padding = grid.getHotseatLayoutPadding(context);
mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1);
@@ -97,6 +106,15 @@ public class HotseatEduDialog extends AbstractSlideInView implements I
mDismissBtn = findViewById(R.id.no_thanks);
mDismissBtn.setOnClickListener(this::onDismiss);
+ LinearLayout buttonContainer = findViewById(R.id.button_container);
+ int adjustedMarginEnd = ApiWrapper.getHotseatEndOffset(context)
+ - buttonContainer.getPaddingEnd();
+ if (InvariantDeviceProfile.INSTANCE.get(context)
+ .getDeviceProfile(context).isTaskbarPresent && adjustedMarginEnd > 0) {
+ ((LinearLayout.LayoutParams) buttonContainer.getLayoutParams()).setMarginEnd(
+ adjustedMarginEnd);
+ }
+
// update ui to reflect which migration method is going to be used
if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) {
((TextView) findViewById(R.id.hotseat_edu_content)).setText(
@@ -200,9 +218,9 @@ public class HotseatEduDialog extends AbstractSlideInView implements I
}
AbstractFloatingView.closeAllOpenViews(mActivityContext);
attachToContainer();
- mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN);
animateOpen();
populatePreview(predictions);
+ mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN);
}
/**
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 85e5ab0a9b..85d9f01735 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -55,8 +55,8 @@ import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OnboardingPrefs;
-import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.Snackbar;
import java.util.ArrayList;
@@ -152,37 +152,14 @@ public class HotseatPredictionController implements DragController.DragListener,
*/
public void showEdu() {
mLauncher.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
- if (mPredictedItems.isEmpty()) {
- // launcher has empty predictions set
- Snackbar.show(mLauncher, R.string.hotsaet_tip_prediction_disabled,
- R.string.hotseat_prediction_settings, null,
- () -> mLauncher.startActivity(getSettingsIntent()));
- } else if (getPredictedIcons().size() >= (mHotSeatItemsCount + 1) / 2) {
- showDiscoveryTip();
- } else {
- HotseatEduController eduController = new HotseatEduController(mLauncher);
- eduController.setPredictedApps(mPredictedItems.stream()
- .map(i -> (WorkspaceItemInfo) i)
- .collect(Collectors.toList()));
- eduController.showEdu();
- }
+ HotseatEduController eduController = new HotseatEduController(mLauncher);
+ eduController.setPredictedApps(mPredictedItems.stream()
+ .map(i -> (WorkspaceItemInfo) i)
+ .collect(Collectors.toList()));
+ eduController.showEdu();
}));
}
- /**
- * Shows educational tip for hotseat if user does not go through Tips app.
- */
- private void showDiscoveryTip() {
- if (getPredictedIcons().isEmpty()) {
- new ArrowTipView(mLauncher).show(
- mLauncher.getString(R.string.hotseat_tip_no_empty_slots), mHotseat.getTop());
- } else {
- Snackbar.show(mLauncher, R.string.hotseat_tip_gaps_filled,
- R.string.hotseat_prediction_settings, null,
- () -> mLauncher.startActivity(getSettingsIntent()));
- }
- }
-
/**
* Returns if hotseat client has predictions
*/
@@ -200,6 +177,7 @@ public class HotseatPredictionController implements DragController.DragListener,
}
int predictionIndex = 0;
+ int numViewsAnimated = 0;
ArrayList newItems = new ArrayList<>();
// make sure predicted icon removal and filling predictions don't step on each other
if (mIconRemoveAnimators != null && mIconRemoveAnimators.isRunning()) {
@@ -233,7 +211,11 @@ public class HotseatPredictionController implements DragController.DragListener,
(WorkspaceItemInfo) mPredictedItems.get(predictionIndex++);
if (isPredictedIcon(child) && child.isEnabled()) {
PredictedAppIcon icon = (PredictedAppIcon) child;
- icon.applyFromWorkspaceItem(predictedItem);
+ boolean animateIconChange = icon.shouldAnimateIconChange(predictedItem);
+ icon.applyFromWorkspaceItem(predictedItem, animateIconChange, numViewsAnimated);
+ if (animateIconChange) {
+ numViewsAnimated++;
+ }
icon.finishBinding(mPredictionLongClickListener);
} else {
newItems.add(predictedItem);
@@ -262,10 +244,6 @@ public class HotseatPredictionController implements DragController.DragListener,
} else {
removeOutlineDrawings();
}
-
- if (mLauncher.getTaskbarUIController() != null) {
- mLauncher.getTaskbarUIController().onHotseatUpdated();
- }
}
private void removeOutlineDrawings() {
@@ -496,6 +474,28 @@ public class HotseatPredictionController implements DragController.DragListener,
.log(LAUNCHER_HOTSEAT_RANKED);
}
+ /**
+ * Called when app/shortcut icon is removed by system. This is used to prune visible stale
+ * predictions while while waiting for AppAPrediction service to send new batch of predictions.
+ *
+ * @param matcher filter matching items that have been removed
+ */
+ public void onModelItemsRemoved(ItemInfoMatcher matcher) {
+ if (mPredictedItems.removeIf(matcher::matchesInfo)) {
+ fillGapsWithPrediction(true);
+ }
+ }
+
+ /**
+ * Called when user completes adding item requiring a config activity to the hotseat
+ */
+ public void onDeferredDrop(int cellX, int cellY) {
+ View child = mHotseat.getChildAt(cellX, cellY);
+ if (child instanceof PredictedAppIcon) {
+ removeIconWithoutNotify((PredictedAppIcon) child);
+ }
+ }
+
private class PinPrediction extends SystemShortcut {
private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) {
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
index 080633a653..56945ba0a6 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
@@ -16,33 +16,25 @@
package com.android.launcher3.hybridhotseat;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
+import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
+import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
+import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
-import android.app.prediction.AppTargetId;
-import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Workspace;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.shortcuts.ShortcutKey;
import java.util.ArrayList;
-import java.util.Locale;
/**
* Model helper for app predictions in workspace
*/
public class HotseatPredictionModel {
- private static final String APP_LOCATION_HOTSEAT = "hotseat";
- private static final String APP_LOCATION_WORKSPACE = "workspace";
-
private static final String BUNDLE_KEY_PIN_EVENTS = "pin_events";
private static final String BUNDLE_KEY_CURRENT_ITEMS = "current_items";
@@ -54,15 +46,15 @@ public class HotseatPredictionModel {
ArrayList events = new ArrayList<>();
ArrayList workspaceItems = dataModel.getAllWorkspaceItems();
for (ItemInfo item : workspaceItems) {
- AppTarget target = getAppTargetFromInfo(context, item);
- if (target != null && !isTrackedForPrediction(item)) continue;
- events.add(wrapAppTargetWithLocation(target, AppTargetEvent.ACTION_PIN, item));
+ AppTarget target = getAppTargetFromItemInfo(context, item);
+ if (target != null && !isTrackedForHotseatPrediction(item)) continue;
+ events.add(wrapAppTargetWithItemLocation(target, AppTargetEvent.ACTION_PIN, item));
}
ArrayList currentTargets = new ArrayList<>();
FixedContainerItems hotseatItems = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION);
if (hotseatItems != null) {
for (ItemInfo itemInfo : hotseatItems.items) {
- AppTarget target = getAppTargetFromInfo(context, itemInfo);
+ AppTarget target = getAppTargetFromItemInfo(context, itemInfo);
if (target != null) currentTargets.add(target);
}
}
@@ -70,56 +62,4 @@ public class HotseatPredictionModel {
bundle.putParcelableArrayList(BUNDLE_KEY_CURRENT_ITEMS, currentTargets);
return bundle;
}
-
- /**
- * Creates and returns for {@link AppTarget} object given an {@link ItemInfo}. Returns null
- * if item is not supported prediction
- */
- public static AppTarget getAppTargetFromInfo(Context context, ItemInfo info) {
- if (info == null) return null;
- if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
- && info instanceof LauncherAppWidgetInfo
- && ((LauncherAppWidgetInfo) info).providerName != null) {
- ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
- return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
- cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
- } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- && info.getTargetComponent() != null) {
- ComponentName cn = info.getTargetComponent();
- return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
- cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
- } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
- && info instanceof WorkspaceItemInfo) {
- ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
- //TODO: switch to using full shortcut info
- return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
- shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
- } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
- return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
- context.getPackageName(), info.user).build();
- }
- return null;
- }
-
- /**
- * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
- * location using {@link ItemInfo}
- */
- public static AppTargetEvent wrapAppTargetWithLocation(
- AppTarget target, int action, ItemInfo info) {
- String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
- info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
- ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
- info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
- return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
- }
-
- /**
- * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors
- */
- public static boolean isTrackedForPrediction(ItemInfo info) {
- return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
- info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
- && info.screenId == Workspace.FIRST_SCREEN_ID);
- }
}
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index eed493d4cf..7c29c5b4c6 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -22,6 +22,7 @@ import static android.app.prediction.AppTargetEvent.ACTION_UNPIN;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_PREDICTION_PINNED;
@@ -30,10 +31,13 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_REMOVE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_FOLDER_CREATED;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
+import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
+import static com.android.launcher3.model.PredictionHelper.isTrackedForWidgetPrediction;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.annotation.TargetApi;
@@ -61,7 +65,6 @@ import com.android.launcher3.logger.LauncherAtom.FolderContainer;
import com.android.launcher3.logger.LauncherAtom.HotseatContainer;
import com.android.launcher3.logger.LauncherAtom.WorkspaceContainer;
import com.android.launcher3.logging.StatsLogManager.EventEnum;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer;
@@ -140,6 +143,9 @@ public class AppEventProducer implements StatsLogConsumer {
if (isTrackedForHotseatPrediction(mLastDragItem)) {
sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
}
+ if (isTrackedForWidgetPrediction(atomInfo)) {
+ sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION);
+ }
mLastDragItem = null;
} else if (event == LAUNCHER_ITEM_DROP_FOLDER_CREATED) {
if (isTrackedForHotseatPrediction(atomInfo)) {
@@ -157,10 +163,18 @@ public class AppEventProducer implements StatsLogConsumer {
if (mLastDragItem != null && isTrackedForHotseatPrediction(mLastDragItem)) {
sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_HOTSEAT_PREDICTION);
}
+ if (mLastDragItem != null && isTrackedForWidgetPrediction(mLastDragItem)) {
+ sendEvent(mLastDragItem, ACTION_UNPIN, CONTAINER_WIDGETS_PREDICTION);
+ }
} else if (event == LAUNCHER_HOTSEAT_PREDICTION_PINNED) {
if (isTrackedForHotseatPrediction(atomInfo)) {
sendEvent(atomInfo, ACTION_PIN, CONTAINER_HOTSEAT_PREDICTION);
}
+ } else if (event == LAUNCHER_ONRESUME) {
+ AppTarget target = new AppTarget.Builder(new AppTargetId("launcher:launcher"),
+ mContext.getPackageName(), Process.myUserHandle())
+ .build();
+ sendEvent(target, atomInfo, ACTION_LAUNCH, CONTAINER_PREDICTION);
}
}
@@ -257,9 +271,6 @@ public class AppEventProducer implements StatsLogConsumer {
case ALL_APPS_CONTAINER: {
return "all-apps";
}
- case SEARCH_RESULT_CONTAINER: {
- return "search-results";
- }
case PREDICTED_HOTSEAT_CONTAINER: {
return "predictions/hotseat";
}
@@ -279,6 +290,16 @@ public class AppEventProducer implements StatsLogConsumer {
}
return "folder";
}
+ case SEARCH_RESULT_CONTAINER:
+ return "search-results";
+ case EXTENDED_CONTAINERS: {
+ switch(ci.getExtendedContainers().getContainerCase()) {
+ case DEVICE_SEARCH_RESULT_CONTAINER:
+ case CORRECTED_DEVICE_SEARCH_RESULT_CONTAINER:
+ return "search-results";
+ }
+ }
+ default: // fall out
}
return "";
}
@@ -296,19 +317,4 @@ public class AppEventProducer implements StatsLogConsumer {
return TextUtils.isEmpty(componentNameString)
? null : ComponentName.unflattenFromString(componentNameString);
}
-
- /**
- * Helper method to determine if {@link ItemInfo} should be tracked and reported to predictors
- */
- private static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
- ContainerInfo ci = info.getContainerInfo();
- switch (ci.getContainerCase()) {
- case HOTSEAT:
- return true;
- case WORKSPACE:
- return ci.getWorkspace().getPageIndex() == 0;
- default:
- return false;
- }
- }
}
diff --git a/quickstep/src/com/android/launcher3/model/PredictionHelper.java b/quickstep/src/com/android/launcher3/model/PredictionHelper.java
new file mode 100644
index 0000000000..738dd83cbc
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/model/PredictionHelper.java
@@ -0,0 +1,130 @@
+/*
+ * 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.logger.LauncherAtom.ContainerInfo.ContainerCase.WORKSPACE;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
+import android.content.ComponentName;
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.shortcuts.ShortcutKey;
+
+import java.util.Locale;
+
+/** Helper class with methods for converting launcher items to form usable by predictors */
+public final class PredictionHelper {
+ private static final String APP_LOCATION_HOTSEAT = "hotseat";
+ private static final String APP_LOCATION_WORKSPACE = "workspace";
+
+ /**
+ * Creates and returns an {@link AppTarget} object for an {@link ItemInfo}. Returns null
+ * if item type is not supported in predictions
+ */
+ @Nullable
+ public static AppTarget getAppTargetFromItemInfo(Context context, ItemInfo info) {
+ if (info == null) return null;
+ if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+ && info instanceof LauncherAppWidgetInfo
+ && ((LauncherAppWidgetInfo) info).providerName != null) {
+ ComponentName cn = ((LauncherAppWidgetInfo) info).providerName;
+ return new AppTarget.Builder(new AppTargetId("widget:" + cn.getPackageName()),
+ cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ && info.getTargetComponent() != null) {
+ ComponentName cn = info.getTargetComponent();
+ return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()),
+ cn.getPackageName(), info.user).setClassName(cn.getClassName()).build();
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+ && info instanceof WorkspaceItemInfo) {
+ ShortcutKey shortcutKey = ShortcutKey.fromItemInfo(info);
+ //TODO: switch to using full shortcut info
+ return new AppTarget.Builder(new AppTargetId("shortcut:" + shortcutKey.getId()),
+ shortcutKey.componentName.getPackageName(), shortcutKey.user).build();
+ } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+ return new AppTarget.Builder(new AppTargetId("folder:" + info.id),
+ context.getPackageName(), info.user).build();
+ }
+ return null;
+ }
+
+ /**
+ * Creates and returns {@link AppTargetEvent} from an {@link AppTarget}, action, and item
+ * location using {@link ItemInfo}
+ */
+ public static AppTargetEvent wrapAppTargetWithItemLocation(
+ AppTarget target, int action, ItemInfo info) {
+ String location = String.format(Locale.ENGLISH, "%s/%d/[%d,%d]/[%d,%d]",
+ info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
+ ? APP_LOCATION_HOTSEAT : APP_LOCATION_WORKSPACE,
+ info.screenId, info.cellX, info.cellY, info.spanX, info.spanY);
+ return new AppTargetEvent.Builder(target, action).setLaunchLocation(location).build();
+ }
+
+ /**
+ * Helper method to determine if {@link ItemInfo} should be tracked and reported to hotseat
+ * predictors
+ */
+ public static boolean isTrackedForHotseatPrediction(ItemInfo info) {
+ return info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT || (
+ info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP
+ && info.screenId == Workspace.FIRST_SCREEN_ID);
+ }
+
+ /**
+ * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported to
+ * hotseat predictors
+ */
+ public static boolean isTrackedForHotseatPrediction(LauncherAtom.ItemInfo info) {
+ LauncherAtom.ContainerInfo ci = info.getContainerInfo();
+ switch (ci.getContainerCase()) {
+ case HOTSEAT:
+ return true;
+ case WORKSPACE:
+ return ci.getWorkspace().getPageIndex() == 0;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Helper method to determine if {@link ItemInfo} should be tracked and reported to widget
+ * predictors
+ */
+ public static boolean isTrackedForWidgetPrediction(ItemInfo info) {
+ return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+ && info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP;
+ }
+
+ /**
+ * Helper method to determine if {@link LauncherAtom.ItemInfo} should be tracked and reported
+ * to widget predictors
+ */
+ public static boolean isTrackedForWidgetPrediction(LauncherAtom.ItemInfo info) {
+ return info.getItemCase() == LauncherAtom.ItemInfo.ItemCase.WIDGET
+ && info.getContainerInfo().getContainerCase() == WORKSPACE;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index a9c2a5e51d..4d0695631c 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -25,7 +25,13 @@ import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICA
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.Utilities.getDevicePrefs;
import static com.android.launcher3.hybridhotseat.HotseatPredictionModel.convertDataModelToAppTargetBundle;
+import static com.android.launcher3.model.PredictionHelper.getAppTargetFromItemInfo;
+import static com.android.launcher3.model.PredictionHelper.wrapAppTargetWithItemLocation;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static java.util.stream.Collectors.toCollection;
+
+import android.app.StatsManager;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionManager;
import android.app.prediction.AppPredictor;
@@ -37,15 +43,17 @@ import android.content.SharedPreferences;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
+import android.util.StatsEvent;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
@@ -54,11 +62,13 @@ import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
-import com.android.launcher3.util.Executors;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.PersistedItemArray;
+import com.android.quickstep.logging.SettingsChangeLogger;
import com.android.quickstep.logging.StatsLogCompatManager;
+import com.android.systemui.shared.system.SysUiStatsLog;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -68,10 +78,11 @@ import java.util.stream.IntStream;
/**
* Model delegate which loads prediction items
*/
-public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChangeListener {
+public class QuickstepModelDelegate extends ModelDelegate {
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";
private static final String LAST_SNAPSHOT_TIME_MILLIS = "LAST_SNAPSHOT_TIME_MILLIS";
+ private static final String BUNDLE_KEY_ADDED_APP_WIDGETS = "added_app_widgets";
private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20;
private static final boolean IS_DEBUG = false;
@@ -86,15 +97,18 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
private final InvariantDeviceProfile mIDP;
private final AppEventProducer mAppEventProducer;
+ private final StatsManager mStatsManager;
+ private final Context mContext;
protected boolean mActive = false;
public QuickstepModelDelegate(Context context) {
+ mContext = context;
mAppEventProducer = new AppEventProducer(context, this::onAppTargetEvent);
mIDP = InvariantDeviceProfile.INSTANCE.get(context);
- mIDP.addOnChangeListener(this);
StatsLogCompatManager.LOGS_CONSUMER.add(mAppEventProducer);
+ mStatsManager = context.getSystemService(StatsManager.class);
}
@Override
@@ -150,17 +164,82 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
}
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
for (ItemInfo info : itemsIdMap) {
- FolderInfo parent = info.container > 0
- ? (FolderInfo) itemsIdMap.get(info.container) : null;
+ FolderInfo parent = getContainer(info, itemsIdMap);
StatsLogCompatManager.writeSnapshot(info.buildProto(parent), instanceId);
}
additionalSnapshotEvents(instanceId);
prefs.edit().putLong(LAST_SNAPSHOT_TIME_MILLIS, now).apply();
}
+
+ // Only register for launcher snapshot logging if this is the primary ModelDelegate
+ // instance, as there will be additional instances that may be destroyed at any time.
+ if (mIsPrimaryInstance) {
+ registerSnapshotLoggingCallback();
+ }
}
protected void additionalSnapshotEvents(InstanceId snapshotInstanceId){}
+ /**
+ * Registers a callback to log launcher workspace layout using Statsd pulled atom.
+ */
+ protected void registerSnapshotLoggingCallback() {
+ if (mStatsManager == null) {
+ Log.d(TAG, "Failed to get StatsManager");
+ }
+
+ try {
+ mStatsManager.setPullAtomCallback(
+ SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT,
+ null /* PullAtomMetadata */,
+ MODEL_EXECUTOR,
+ (i, eventList) -> {
+ InstanceId instanceId = new InstanceIdSequence().newInstanceId();
+ IntSparseArrayMap itemsIdMap;
+ synchronized (mDataModel) {
+ itemsIdMap = mDataModel.itemsIdMap.clone();
+ }
+
+ for (ItemInfo info : itemsIdMap) {
+ FolderInfo parent = getContainer(info, itemsIdMap);
+ LauncherAtom.ItemInfo itemInfo = info.buildProto(parent);
+ Log.d(TAG, itemInfo.toString());
+ StatsEvent statsEvent = StatsLogCompatManager.buildStatsEvent(itemInfo,
+ instanceId);
+ eventList.add(statsEvent);
+ }
+ Log.d(TAG,
+ String.format(
+ "Successfully logged %d workspace items with instanceId=%d",
+ itemsIdMap.size(), instanceId.getId()));
+ additionalSnapshotEvents(instanceId);
+ SettingsChangeLogger.INSTANCE.get(mContext).logSnapshot(instanceId);
+ return StatsManager.PULL_SUCCESS;
+ }
+ );
+ Log.d(TAG, "Successfully registered for launcher snapshot logging!");
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to register launcher snapshot logging callback with StatsManager",
+ e);
+ }
+ }
+
+ private static FolderInfo getContainer(ItemInfo info, IntSparseArrayMap itemsIdMap) {
+ if (info.container > 0) {
+ ItemInfo containerInfo = itemsIdMap.get(info.container);
+
+ if (!(containerInfo instanceof FolderInfo)) {
+ Log.e(TAG, String.format(
+ "Item info: %s found with invalid container: %s",
+ info,
+ containerInfo));
+ } else {
+ return (FolderInfo) containerInfo;
+ }
+ }
+ return null;
+ }
+
@Override
public void validateData() {
super.validateData();
@@ -177,9 +256,10 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
super.destroy();
mActive = false;
StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
-
+ if (mIsPrimaryInstance) {
+ mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+ }
destroyPredictors();
- mIDP.removeOnChangeListener(this);
}
private void destroyPredictors() {
@@ -217,6 +297,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
registerWidgetsPredictor(apm.createAppPredictionSession(
new AppPredictionContext.Builder(context)
.setUiSurface("widgets")
+ .setExtras(getBundleForWidgetsOnWorkspace(context, mDataModel))
.setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION)
.build()));
}
@@ -224,7 +305,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
private void registerPredictor(PredictorState state, AppPredictor predictor) {
state.predictor = predictor;
state.predictor.registerPredictionUpdates(
- Executors.MODEL_EXECUTOR, t -> handleUpdate(state, t));
+ MODEL_EXECUTOR, t -> handleUpdate(state, t));
state.predictor.requestPredictionUpdate();
}
@@ -239,7 +320,7 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
private void registerWidgetsPredictor(AppPredictor predictor) {
mWidgetsRecommendationState.predictor = predictor;
mWidgetsRecommendationState.predictor.registerPredictionUpdates(
- Executors.MODEL_EXECUTOR, targets -> {
+ MODEL_EXECUTOR, targets -> {
if (mWidgetsRecommendationState.setTargets(targets)) {
// No diff, skip
return;
@@ -250,19 +331,44 @@ public class QuickstepModelDelegate extends ModelDelegate implements OnIDPChange
mWidgetsRecommendationState.predictor.requestPredictionUpdate();
}
- @Override
- public void onIdpChanged(InvariantDeviceProfile profile) {
- // Reinitialize everything
- Executors.MODEL_EXECUTOR.execute(this::recreatePredictors);
- }
-
private void onAppTargetEvent(AppTargetEvent event, int client) {
- PredictorState state = client == CONTAINER_PREDICTION ? mAllAppsState : mHotseatState;
+ PredictorState state;
+ switch(client) {
+ case CONTAINER_PREDICTION:
+ state = mAllAppsState;
+ break;
+ case CONTAINER_WIDGETS_PREDICTION:
+ state = mWidgetsRecommendationState;
+ break;
+ case CONTAINER_HOTSEAT_PREDICTION:
+ default:
+ state = mHotseatState;
+ break;
+ }
if (state.predictor != null) {
state.predictor.notifyAppTargetEvent(event);
+ Log.d(TAG, "notifyAppTargetEvent action=" + event.getAction()
+ + " launchLocation=" + event.getLaunchLocation());
}
}
+ private Bundle getBundleForWidgetsOnWorkspace(Context context, BgDataModel dataModel) {
+ Bundle bundle = new Bundle();
+ ArrayList widgetEvents =
+ dataModel.getAllWorkspaceItems().stream()
+ .filter(PredictionHelper::isTrackedForWidgetPrediction)
+ .map(item -> {
+ AppTarget target = getAppTargetFromItemInfo(context, item);
+ if (target == null) return null;
+ return wrapAppTargetWithItemLocation(
+ target, AppTargetEvent.ACTION_PIN, item);
+ })
+ .filter(Objects::nonNull)
+ .collect(toCollection(ArrayList::new));
+ bundle.putParcelableArrayList(BUNDLE_KEY_ADDED_APP_WIDGETS, widgetEvents);
+ return bundle;
+ }
+
static class PredictorState {
public final FixedContainerItems items;
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index 154b78b1b9..e489cb3a71 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -377,7 +377,7 @@ public final class WellbeingModel extends BgObjectWithLooper {
/**
* Shortcut factory for generating wellbeing action
*/
- public static final SystemShortcut.Factory SHORTCUT_FACTORY =
+ public static final SystemShortcut.Factory SHORTCUT_FACTORY =
(activity, info) -> (info.getTargetComponent() == null) ? null : INSTANCE.get(activity)
.getShortcutForApp(
info.getTargetComponent().getPackageName(), info.user.getIdentifier(),
diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
index 3d891e8748..4be83dc0b0 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
@@ -83,7 +83,7 @@ public final class WidgetsPredictionUpdateTask extends BaseModelUpdateTask {
}
} else {
Map widgetItems =
- allWidgets.values().stream().flatMap(List::stream)
+ allWidgets.values().stream().flatMap(List::stream).distinct()
.collect(Collectors.toMap(widget -> (ComponentKey) widget,
widget -> widget));
for (AppTarget app : mTargets) {
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index bb58f451ce..3242d42f93 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -44,6 +44,7 @@ import com.android.launcher3.states.StateAnimationConfig;
import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.WallpaperManagerCompat;
+import java.io.PrintWriter;
import java.util.function.Consumer;
/**
@@ -96,7 +97,11 @@ public class DepthController implements StateHandler,
public void onDraw() {
View view = mLauncher.getDragLayer();
ViewRootImpl viewRootImpl = view.getViewRootImpl();
- setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
+ boolean applied = setSurface(
+ viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
+ if (!applied) {
+ dispatchTransactionSurface(mDepth);
+ }
view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this));
}
};
@@ -133,14 +138,27 @@ public class DepthController implements StateHandler,
* @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
*/
private float mDepth;
+ /**
+ * Last blur value, in pixels, that was applied.
+ * For debugging purposes.
+ */
+ private int mCurrentBlur;
/**
* 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;
+ // Hints that there is potentially content behind Launcher and that we shouldn't optimize by
+ // marking the launcher surface as opaque. Only used in certain Launcher states.
+ private boolean mHasContentBehindLauncher;
+
private View.OnAttachStateChangeListener mOnAttachListener;
public DepthController(Launcher l) {
@@ -184,6 +202,10 @@ public class DepthController implements StateHandler,
mLauncher.getScrimView().addOpaquenessListener(mOpaquenessListener);
}
+ public void setHasContentBehindLauncher(boolean hasContentBehindLauncher) {
+ mHasContentBehindLauncher = hasContentBehindLauncher;
+ }
+
/**
* Sets if the underlying activity is started or not
*/
@@ -198,20 +220,22 @@ public class DepthController implements StateHandler,
/**
* Sets the specified app target surface to apply the blur to.
+ * @return true when surface was valid and transaction was dispatched.
*/
- public void setSurface(SurfaceControl surface) {
+ public boolean setSurface(SurfaceControl surface) {
// Set launcher as the SurfaceControl when we don't need an external target anymore.
if (surface == null) {
ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl();
surface = viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null;
}
-
if (mSurface != surface) {
mSurface = surface;
if (surface != null) {
dispatchTransactionSurface(mDepth);
+ return true;
}
}
+ return false;
}
@Override
@@ -225,6 +249,8 @@ public class DepthController implements StateHandler,
setDepth(toDepth);
} else if (toState == LauncherState.OVERVIEW) {
dispatchTransactionSurface(mDepth);
+ } else if (toState == LauncherState.BACKGROUND_APP) {
+ mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener);
}
}
@@ -263,9 +289,8 @@ public class DepthController implements StateHandler,
if (Float.compare(mDepth, depthF) == 0) {
return;
}
- if (dispatchTransactionSurface(depthF)) {
- mDepth = depthF;
- }
+ dispatchTransactionSurface(depthF);
+ mDepth = depthF;
}
public void onOverlayScrollChanged(float progress) {
@@ -292,16 +317,25 @@ public class DepthController implements StateHandler,
}
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;
+ boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque();
+ boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg;
- int blur = opaque || isOverview || !mCrossWindowBlursEnabled
- || mBlurDisabledForAppLaunch ? 0 : (int) (depth * mMaxBlurRadius);
+ mCurrentBlur = !mCrossWindowBlursEnabled || mBlurDisabledForAppLaunch || hasOpaqueBg
+ ? 0 : (int) (depth * mMaxBlurRadius);
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
- .setBackgroundBlurRadius(mSurface, blur)
- .setOpaque(mSurface, opaque);
+ .setBackgroundBlurRadius(mSurface, mCurrentBlur)
+ .setOpaque(mSurface, isSurfaceOpaque);
+
+ // Set early wake-up flags when we know we're executing an expensive operation, this way
+ // SurfaceFlinger will adjust its internal offsets to avoid jank.
+ boolean wantsEarlyWakeUp = depth > 0 && depth < 1;
+ if (wantsEarlyWakeUp && !mInEarlyWakeUp) {
+ transaction.setEarlyWakeupStart();
+ mInEarlyWakeUp = true;
+ } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) {
+ transaction.setEarlyWakeupEnd();
+ mInEarlyWakeUp = false;
+ }
AttachedSurfaceControl rootSurfaceControl =
mLauncher.getRootView().getRootSurfaceControl();
@@ -328,4 +362,18 @@ public class DepthController implements StateHandler,
mwAnimation.setAutoCancel(true);
mwAnimation.start();
}
+
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + this.getClass().getSimpleName());
+ writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius);
+ writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled);
+ writer.println(prefix + "\tmSurface=" + mSurface);
+ writer.println(prefix + "\tmOverlayScrollProgress=" + mOverlayScrollProgress);
+ writer.println(prefix + "\tmDepth=" + mDepth);
+ writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur);
+ writer.println(prefix + "\tmBlurDisabledForAppLaunch=" + mBlurDisabledForAppLaunch);
+ writer.println(prefix + "\tmInEarlyWakeUp=" + mInEarlyWakeUp);
+ writer.println(prefix + "\tmIgnoreStateChangesDuringMultiWindowAnimation="
+ + mIgnoreStateChangesDuringMultiWindowAnimation);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java b/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java
deleted file mode 100644
index 540f748313..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/ButtonProvider.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.taskbar;
-
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
-import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
-
-import android.annotation.DrawableRes;
-import android.view.View;
-import android.widget.ImageView;
-
-import com.android.launcher3.R;
-import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
-
-/**
- * Creates Buttons for Taskbar for 3 button nav.
- * Can add animations and state management for buttons in this class as things progress.
- */
-public class ButtonProvider {
-
- private final int mMarginLeftRight;
- private final TaskbarActivityContext mContext;
-
- public ButtonProvider(TaskbarActivityContext context) {
- mContext = context;
- mMarginLeftRight = context.getResources()
- .getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
- }
-
- public View getBack() {
- // Back button
- return getButtonForDrawable(R.drawable.ic_sysbar_back, BUTTON_BACK);
- }
-
- public View getDown() {
- // Ime down button
- return getButtonForDrawable(R.drawable.ic_sysbar_back, BUTTON_BACK);
- }
-
- public View getHome() {
- // Home button
- return getButtonForDrawable(R.drawable.ic_sysbar_home, BUTTON_HOME);
- }
-
- public View getRecents() {
- // Recents button
- return getButtonForDrawable(R.drawable.ic_sysbar_recent, BUTTON_RECENTS);
- }
-
- public View getImeSwitcher() {
- // IME Switcher Button
- return getButtonForDrawable(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH);
- }
-
- private View getButtonForDrawable(@DrawableRes int drawableId, @TaskbarButton int buttonType) {
- ImageView buttonView = new ImageView(mContext);
- buttonView.setImageResource(drawableId);
- buttonView.setBackgroundResource(R.drawable.taskbar_icon_click_feedback_roundrect);
- buttonView.setPadding(mMarginLeftRight, 0, mMarginLeftRight, 0);
- buttonView.setOnClickListener(view -> mContext.onNavigationButtonClick(buttonType));
- return buttonView;
- }
-
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
new file mode 100644
index 0000000000..f1e67479f5
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
+import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
+
+import android.animation.Animator;
+
+import com.android.launcher3.statemanager.StateManager;
+import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * A data source which integrates with the fallback RecentsActivity instance (for 3P launchers).
+ */
+public class FallbackTaskbarUIController extends TaskbarUIController {
+
+ private final RecentsActivity mRecentsActivity;
+
+ private final StateManager.StateListener mStateListener =
+ new StateManager.StateListener() {
+ @Override
+ public void onStateTransitionStart(RecentsState toState) {
+ animateToRecentsState(toState);
+
+ // Handle tapping on live tile.
+ RecentsView recentsView = mRecentsActivity.getOverviewPanel();
+ recentsView.setTaskLaunchListener(toState == RecentsState.DEFAULT
+ ? (() -> animateToRecentsState(RecentsState.BACKGROUND_APP)) : null);
+ }
+ };
+
+ public FallbackTaskbarUIController(RecentsActivity recentsActivity) {
+ mRecentsActivity = recentsActivity;
+ }
+
+ @Override
+ protected void init(TaskbarControllers taskbarControllers) {
+ super.init(taskbarControllers);
+
+ mRecentsActivity.setTaskbarUIController(this);
+ mRecentsActivity.getStateManager().addStateListener(mStateListener);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mRecentsActivity.setTaskbarUIController(null);
+ mRecentsActivity.getStateManager().removeStateListener(mStateListener);
+ }
+
+ /**
+ * Creates an animation to animate the taskbar for the given state (but does not start it).
+ * Currently this animation just force stashes the taskbar in Overview.
+ */
+ public Animator createAnimToRecentsState(RecentsState toState, long duration) {
+ boolean forceStashed = toState.hasOverviewActions();
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ // Set both FLAG_IN_STASHED_LAUNCHER_STATE and FLAG_IN_APP to ensure the state is respected.
+ // For all other states, just use the current stashed-in-app setting (e.g. if long clicked).
+ controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, forceStashed);
+ controller.updateStateForFlag(FLAG_IN_APP, !forceStashed);
+ return controller.applyStateWithoutStart(duration);
+ }
+
+ private void animateToRecentsState(RecentsState toState) {
+ Animator anim = createAnimToRecentsState(toState, TASKBAR_STASH_DURATION);
+ if (anim != null) {
+ anim.start();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java b/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java
deleted file mode 100644
index 287caab44b..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/ImeBarView.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.taskbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.RelativeLayout;
-
-import com.android.launcher3.views.ActivityContext;
-
-public class ImeBarView extends RelativeLayout {
-
- private ButtonProvider mButtonProvider;
- private View mImeView;
-
- public ImeBarView(Context context) {
- this(context, null);
- }
-
- public ImeBarView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public ImeBarView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- public void init(ButtonProvider buttonProvider) {
- mButtonProvider = buttonProvider;
-
- ActivityContext context = getActivityContext();
- RelativeLayout.LayoutParams imeParams = new RelativeLayout.LayoutParams(
- context.getDeviceProfile().iconSizePx,
- context.getDeviceProfile().iconSizePx
- );
- RelativeLayout.LayoutParams downParams = new RelativeLayout.LayoutParams(imeParams);
-
- imeParams.addRule(ALIGN_PARENT_END);
- imeParams.setMarginEnd(context.getDeviceProfile().iconSizePx);
- downParams.setMarginStart(context.getDeviceProfile().iconSizePx);
- downParams.addRule(ALIGN_PARENT_START);
-
- // Down Arrow
- View downView = mButtonProvider.getDown();
- downView.setLayoutParams(downParams);
- downView.setRotation(-90);
- addView(downView);
-
- // IME switcher button
- mImeView = mButtonProvider.getImeSwitcher();
- mImeView.setLayoutParams(imeParams);
- addView(mImeView);
- }
-
- public void setImeSwitcherVisibility(boolean show) {
- mImeView.setVisibility(show ? VISIBLE : GONE);
- }
-
- private T getActivityContext() {
- return ActivityContext.lookupContext(getContext());
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index c2d107c22d..5e8db69f2b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -15,13 +15,18 @@
*/
package com.android.launcher3.taskbar;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.view.MotionEvent;
+import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_RESUMED;
+import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
-import androidx.annotation.Nullable;
+import android.animation.Animator;
+import android.annotation.ColorInt;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.TaskTransitionSpec;
+import android.view.WindowManagerGlobal;
+
+import androidx.annotation.NonNull;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
@@ -29,188 +34,116 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.InstanceIdSequence;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.OnboardingPrefs;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsAnimationCallbacks;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Stream;
/**
* A data source which integrates with a Launcher instance
- * TODO: Rename to have Launcher prefix
*/
-
public class LauncherTaskbarUIController extends TaskbarUIController {
+ private static final String TAG = "TaskbarUIController";
+
private final BaseQuickstepLauncher mLauncher;
- private final TaskbarStateHandler mTaskbarStateHandler;
- private final TaskbarAnimationController mTaskbarAnimationController;
- private final TaskbarHotseatController mHotseatController;
- private final TaskbarActivityContext mContext;
- final TaskbarDragLayer mTaskbarDragLayer;
- final TaskbarView mTaskbarView;
+ private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
+ this::onStashedInAppChanged;
- private @Nullable Animator mAnimator;
- private boolean mIsAnimatingToLauncher;
+ // Initialized in init.
+ private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
+ private TaskbarKeyguardController mKeyguardController;
+ private final TaskbarLauncherStateController
+ mTaskbarLauncherStateController = new TaskbarLauncherStateController();
- public LauncherTaskbarUIController(
- BaseQuickstepLauncher launcher, TaskbarActivityContext context) {
- mContext = context;
- mTaskbarDragLayer = context.getDragLayer();
- mTaskbarView = mTaskbarDragLayer.findViewById(R.id.taskbar_view);
+ private final DeviceProfile.OnDeviceProfileChangeListener mProfileChangeListener =
+ new DeviceProfile.OnDeviceProfileChangeListener() {
+ @Override
+ public void onDeviceProfileChanged(DeviceProfile dp) {
+ mControllers.taskbarViewController.onRotationChanged(
+ mLauncher.getDeviceProfile());
+ }
+ };
+ public LauncherTaskbarUIController(BaseQuickstepLauncher launcher) {
mLauncher = launcher;
- mTaskbarStateHandler = mLauncher.getTaskbarStateHandler();
- mTaskbarAnimationController = new TaskbarAnimationController(mLauncher,
- createTaskbarAnimationControllerCallbacks());
- mHotseatController = new TaskbarHotseatController(
- mLauncher, mTaskbarView::updateHotseatItems);
}
@Override
- protected void onCreate() {
- mTaskbarStateHandler.setAnimationController(mTaskbarAnimationController);
- mTaskbarAnimationController.init();
- mHotseatController.init();
- setTaskbarViewVisible(!mLauncher.hasBeenResumed());
- alignRealHotseatWithTaskbar();
+ protected void init(TaskbarControllers taskbarControllers) {
+ super.init(taskbarControllers);
+
+ mTaskbarLauncherStateController.init(mControllers, mLauncher);
+ mTaskbarOverrideBackgroundAlpha = mControllers.taskbarDragLayerController
+ .getOverrideBackgroundAlpha();
+
mLauncher.setTaskbarUIController(this);
+ mKeyguardController = taskbarControllers.taskbarKeyguardController;
+
+ onLauncherResumedOrPaused(mLauncher.hasBeenResumed(), true /* fromInit */);
+
+ onStashedInAppChanged(mLauncher.getDeviceProfile());
+ mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
+ mLauncher.addOnDeviceProfileChangeListener(mProfileChangeListener);
}
@Override
protected void onDestroy() {
- if (mAnimator != null) {
- // End this first, in case it relies on properties that are about to be cleaned up.
- mAnimator.end();
- }
- mTaskbarStateHandler.setAnimationController(null);
- mTaskbarAnimationController.cleanup();
- mHotseatController.cleanup();
- setTaskbarViewVisible(true);
- mLauncher.getHotseat().setIconsAlpha(1f);
+ super.onDestroy();
+ onLauncherResumedOrPaused(false);
+ mTaskbarLauncherStateController.onDestroy();
+
+ mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
mLauncher.setTaskbarUIController(null);
+ mLauncher.removeOnDeviceProfileChangeListener(mProfileChangeListener);
+ updateTaskTransitionSpec(true);
}
@Override
protected boolean isTaskbarTouchable() {
- return !mIsAnimatingToLauncher;
- }
-
- private TaskbarAnimationControllerCallbacks createTaskbarAnimationControllerCallbacks() {
- return new TaskbarAnimationControllerCallbacks() {
- @Override
- public void updateTaskbarBackgroundAlpha(float alpha) {
- mTaskbarDragLayer.setTaskbarBackgroundAlpha(alpha);
- }
-
- @Override
- public void updateTaskbarVisibilityAlpha(float alpha) {
- mTaskbarView.setAlpha(alpha);
- }
-
- @Override
- public void updateImeBarVisibilityAlpha(float alpha) {
- mTaskbarDragLayer.updateImeBarVisibilityAlpha(alpha);
- }
-
- @Override
- public void updateTaskbarScale(float scale) {
- mTaskbarView.setScaleX(scale);
- mTaskbarView.setScaleY(scale);
- }
-
- @Override
- public void updateTaskbarTranslationY(float translationY) {
- if (translationY < 0) {
- // Resize to accommodate the max translation we'll reach.
- mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize
- + mLauncher.getHotseat().getTaskbarOffsetY());
- } else {
- mContext.setTaskbarWindowHeight(mContext.getDeviceProfile().taskbarSize);
- }
- mTaskbarView.setTranslationY(translationY);
- }
- };
+ return !mTaskbarLauncherStateController.isAnimatingToLauncher();
}
/**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
public void onLauncherResumedOrPaused(boolean isResumed) {
- long duration = QuickstepTransitionManager.CONTENT_ALPHA_DURATION;
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- if (isResumed) {
- mAnimator = createAnimToLauncher(null, duration);
- } else {
- mAnimator = createAnimToApp(duration);
- }
- mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimator = null;
+ onLauncherResumedOrPaused(isResumed, false /* fromInit */);
+ }
+
+ private void onLauncherResumedOrPaused(boolean isResumed, boolean fromInit) {
+ if (mKeyguardController.isScreenOff()) {
+ if (!isResumed) {
+ return;
+ } else {
+ // Resuming implicitly means device unlocked
+ mKeyguardController.setScreenOn();
}
- });
- mAnimator.start();
+ }
+
+ mTaskbarLauncherStateController.updateStateForFlag(FLAG_RESUMED, isResumed);
+ mTaskbarLauncherStateController.applyState(
+ fromInit ? 0 : QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
}
/**
- * Create Taskbar animation when going from an app to Launcher.
+ * Create Taskbar animation when going from an app to Launcher as part of recents transition.
* @param toState If known, the state we will end up in when reaching Launcher.
+ * @param callbacks callbacks to track the recents animation lifecycle. The state change is
+ * automatically reset once the recents animation finishes
*/
- public Animator createAnimToLauncher(@Nullable LauncherState toState, long duration) {
- PendingAnimation anim = new PendingAnimation(duration);
- anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(0, duration));
- if (toState != null) {
- mTaskbarStateHandler.setStateWithAnimation(toState, new StateAnimationConfig(), anim);
- }
-
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mIsAnimatingToLauncher = true;
- mTaskbarView.setHolesAllowedInLayout(true);
- mTaskbarView.updateHotseatItemsVisibility();
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mIsAnimatingToLauncher = false;
- setTaskbarViewVisible(false);
- }
- });
-
- return anim.buildAnim();
- }
-
- private Animator createAnimToApp(long duration) {
- PendingAnimation anim = new PendingAnimation(duration);
- anim.add(mTaskbarAnimationController.createAnimToBackgroundAlpha(1, duration));
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mTaskbarView.updateHotseatItemsVisibility();
- setTaskbarViewVisible(true);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mTaskbarView.setHolesAllowedInLayout(false);
- }
- });
- return anim.buildAnim();
- }
-
- @Override
- protected void onImeVisible(TaskbarDragLayer containerView, boolean isVisible) {
- mTaskbarAnimationController.animateToVisibilityForIme(isVisible ? 0 : 1);
- }
-
- /**
- * Should be called when one or more items in the Hotseat have changed.
- */
- public void onHotseatUpdated() {
- mHotseatController.onHotseatUpdated();
+ public Animator createAnimToLauncher(@NonNull LauncherState toState,
+ @NonNull RecentsAnimationCallbacks callbacks, long duration) {
+ return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
}
/**
@@ -218,58 +151,99 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
* @return Whether any Taskbar item could handle the given MotionEvent if given the chance.
*/
public boolean isEventOverAnyTaskbarItem(MotionEvent ev) {
- return mTaskbarView.isEventOverAnyItem(ev);
+ return mControllers.taskbarViewController.isEventOverAnyItem(ev)
+ || mControllers.navbarButtonsViewController.isEventOverAnyItem(ev);
}
public boolean isDraggingItem() {
- return mTaskbarView.isDraggingItem();
+ return mControllers.taskbarDragController.isDragging();
}
- /**
- * Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat.
- */
@Override
- public void alignRealHotseatWithTaskbar() {
- Rect hotseatBounds = new Rect();
- DeviceProfile grid = mLauncher.getDeviceProfile();
- int hotseatHeight = grid.workspacePadding.bottom + grid.taskbarSize;
- int taskbarOffset = mLauncher.getHotseat().getTaskbarOffsetY();
- int hotseatTopDiff = hotseatHeight - grid.taskbarSize - taskbarOffset;
- int hotseatBottomDiff = taskbarOffset;
+ protected void onStashedInAppChanged() {
+ onStashedInAppChanged(mLauncher.getDeviceProfile());
+ }
- RectF hotseatBoundsF = mTaskbarView.getHotseatBounds();
- Utilities.scaleRectFAboutPivot(hotseatBoundsF, getTaskbarScaleOnHome(),
- mTaskbarView.getPivotX(), mTaskbarView.getPivotY());
- hotseatBoundsF.round(hotseatBounds);
- mLauncher.getHotseat().setPadding(hotseatBounds.left,
- hotseatBounds.top + hotseatTopDiff,
- mTaskbarView.getWidth() - hotseatBounds.right,
- mTaskbarView.getHeight() - hotseatBounds.bottom + hotseatBottomDiff);
+ private void onStashedInAppChanged(DeviceProfile deviceProfile) {
+ boolean taskbarStashedInApps = mControllers.taskbarStashController.isStashedInApp();
+ deviceProfile.isTaskbarPresentInApps = !taskbarStashedInApps;
+ updateTaskTransitionSpec(taskbarStashedInApps);
+ }
+
+ private void updateTaskTransitionSpec(boolean taskbarIsHidden) {
+ try {
+ if (taskbarIsHidden) {
+ // Clear custom task transition settings when the taskbar is stashed
+ WindowManagerGlobal.getWindowManagerService().clearTaskTransitionSpec();
+ } else {
+ // Adjust task transition spec to account for taskbar being visible
+ @ColorInt int taskAnimationBackgroundColor =
+ mLauncher.getColor(R.color.taskbar_background);
+
+ TaskTransitionSpec customTaskAnimationSpec = new TaskTransitionSpec(
+ taskAnimationBackgroundColor,
+ Set.of(ITYPE_EXTRA_NAVIGATION_BAR)
+ );
+ WindowManagerGlobal.getWindowManagerService()
+ .setTaskTransitionSpec(customTaskAnimationSpec);
+ }
+ } catch (RemoteException e) {
+ // This shouldn't happen but if it does task animations won't look good until the
+ // taskbar stashing state is changed.
+ Log.e(TAG, "Failed to update task transition spec to account for new taskbar state",
+ e);
+ }
}
/**
- * Returns the ratio of the taskbar icon size on home vs in an app.
+ * Sets whether the background behind the taskbar/nav bar should be hidden.
*/
- public float getTaskbarScaleOnHome() {
- DeviceProfile inAppDp = mContext.getDeviceProfile();
- DeviceProfile onHomeDp = mLauncher.getDeviceProfile();
- return (float) onHomeDp.cellWidthPx / inAppDp.cellWidthPx;
+ public void forceHideBackground(boolean forceHide) {
+ mTaskbarOverrideBackgroundAlpha.updateValue(forceHide ? 0 : 1);
}
- void setTaskbarViewVisible(boolean isVisible) {
- mTaskbarView.setIconsVisibility(isVisible);
- mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f);
+ @Override
+ public Stream getAppIconsForEdu() {
+ return Arrays.stream(mLauncher.getAppsView().getAppsStore().getApps());
}
/**
- * Contains methods that TaskbarAnimationController can call to interface with
- * TaskbarController.
+ * Starts the taskbar education flow, if the user hasn't seen it yet.
*/
- protected interface TaskbarAnimationControllerCallbacks {
- void updateTaskbarBackgroundAlpha(float alpha);
- void updateTaskbarVisibilityAlpha(float alpha);
- void updateImeBarVisibilityAlpha(float alpha);
- void updateTaskbarScale(float scale);
- void updateTaskbarTranslationY(float translationY);
+ public void showEdu() {
+ if (!FeatureFlags.ENABLE_TASKBAR_EDU.get()
+ || Utilities.IS_RUNNING_IN_TEST_HARNESS
+ || mLauncher.getOnboardingPrefs().getBoolean(OnboardingPrefs.TASKBAR_EDU_SEEN)) {
+ return;
+ }
+ mLauncher.getOnboardingPrefs().markChecked(OnboardingPrefs.TASKBAR_EDU_SEEN);
+
+ mControllers.taskbarEduController.showEdu();
+ }
+
+ /**
+ * Manually ends the taskbar education flow.
+ */
+ public void hideEdu() {
+ if (!FeatureFlags.ENABLE_TASKBAR_EDU.get()) {
+ return;
+ }
+
+ mControllers.taskbarEduController.hideEdu();
+ }
+
+ @Override
+ public void onTaskbarIconLaunched(WorkspaceItemInfo item) {
+ InstanceId instanceId = new InstanceIdSequence().newInstanceId();
+ mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
+ instanceId);
+ }
+
+ @Override
+ public void setSystemGestureInProgress(boolean inProgress) {
+ super.setSystemGestureInProgress(inProgress);
+ // Launcher's ScrimView will draw the background throughout the gesture. But once the
+ // gesture ends, start drawing taskbar's background again since launcher might stop drawing.
+ forceHideBackground(inProgress);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
new file mode 100644
index 0000000000..50637a12ce
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -0,0 +1,612 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
+import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_KEYGUARD;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.annotation.DrawableRes;
+import android.annotation.IdRes;
+import android.annotation.LayoutRes;
+import android.content.pm.ActivityInfo.Config;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.Region.Op;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.util.Property;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnHoverListener;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AlphaUpdateListener;
+import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.AnimatedFloat;
+import com.android.systemui.shared.rotation.FloatingRotationButton;
+import com.android.systemui.shared.rotation.RotationButton;
+import com.android.systemui.shared.rotation.RotationButtonController;
+
+import java.util.ArrayList;
+import java.util.function.IntPredicate;
+
+/**
+ * Controller for managing nav bar buttons in taskbar
+ */
+public class NavbarButtonsViewController {
+
+ private final Rect mTempRect = new Rect();
+
+ private static final int FLAG_SWITCHER_SUPPORTED = 1 << 0;
+ private static final int FLAG_IME_VISIBLE = 1 << 1;
+ private static final int FLAG_ROTATION_BUTTON_VISIBLE = 1 << 2;
+ private static final int FLAG_A11Y_VISIBLE = 1 << 3;
+ private static final int FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE = 1 << 4;
+ private static final int FLAG_KEYGUARD_VISIBLE = 1 << 5;
+ private static final int FLAG_KEYGUARD_OCCLUDED = 1 << 6;
+ private static final int FLAG_DISABLE_HOME = 1 << 7;
+ private static final int FLAG_DISABLE_RECENTS = 1 << 8;
+ private static final int FLAG_DISABLE_BACK = 1 << 9;
+ private static final int FLAG_NOTIFICATION_SHADE_EXPANDED = 1 << 10;
+ private static final int FLAG_SCREEN_PINNING_ACTIVE = 1 << 11;
+
+ private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
+
+ private final ArrayList mPropertyHolders = new ArrayList<>();
+ private final ArrayList mAllButtons = new ArrayList<>();
+ private int mState;
+
+ private final TaskbarActivityContext mContext;
+ private final FrameLayout mNavButtonsView;
+ private final ViewGroup mNavButtonContainer;
+ // Used for IME+A11Y buttons
+ private final ViewGroup mEndContextualContainer;
+ private final ViewGroup mStartContextualContainer;
+ private final int mLightIconColor;
+ private final int mDarkIconColor;
+
+ private final AnimatedFloat mTaskbarNavButtonTranslationY = new AnimatedFloat(
+ this::updateNavButtonTranslationY);
+ private final AnimatedFloat mTaskbarNavButtonTranslationYForIme = new AnimatedFloat(
+ this::updateNavButtonTranslationY);
+ // Only applies to mTaskbarNavButtonTranslationY
+ private final AnimatedFloat mNavButtonTranslationYMultiplier = new AnimatedFloat(
+ this::updateNavButtonTranslationY);
+ private final AnimatedFloat mTaskbarNavButtonDarkIntensity = new AnimatedFloat(
+ this::updateNavButtonDarkIntensity);
+ private final AnimatedFloat mNavButtonDarkIntensityMultiplier = new AnimatedFloat(
+ this::updateNavButtonDarkIntensity);
+ private final RotationButtonListener mRotationButtonListener = new RotationButtonListener();
+
+ private final Rect mFloatingRotationButtonBounds = new Rect();
+
+ // Initialized in init.
+ private TaskbarControllers mControllers;
+ private View mA11yButton;
+ private int mSysuiStateFlags;
+ private View mBackButton;
+ private FloatingRotationButton mFloatingRotationButton;
+
+ public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
+ mContext = context;
+ mNavButtonsView = navButtonsView;
+ mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
+ mEndContextualContainer = mNavButtonsView.findViewById(R.id.end_contextual_buttons);
+ mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
+
+ mLightIconColor = context.getColor(R.color.taskbar_nav_icon_light_color);
+ mDarkIconColor = context.getColor(R.color.taskbar_nav_icon_dark_color);
+ }
+
+ /**
+ * Initializes the controller
+ */
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
+ mNavButtonTranslationYMultiplier.value = 1;
+
+ boolean isThreeButtonNav = mContext.isThreeButtonNav();
+ // IME switcher
+ View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
+ isThreeButtonNav ? mStartContextualContainer : 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)));
+
+ mPropertyHolders.add(new StatePropertyHolder(
+ mControllers.taskbarViewController.getTaskbarIconAlpha()
+ .getProperty(ALPHA_INDEX_KEYGUARD),
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
+ && (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0,
+ MultiValueAlpha.VALUE, 1, 0));
+
+ mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
+ .getKeyguardBgTaskbar(),
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0, AnimatedFloat.VALUE, 1, 0));
+
+ // Force nav buttons (specifically back button) to be visible during setup wizard.
+ boolean isInSetup = !mContext.isUserSetupComplete();
+ boolean alwaysShowButtons = isThreeButtonNav || isInSetup;
+
+ // Make sure to remove nav bar buttons translation when notification shade is expanded or
+ // IME is showing (add separate translation for IME).
+ int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE;
+ mPropertyHolders.add(new StatePropertyHolder(mNavButtonTranslationYMultiplier,
+ flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
+ 0, 1));
+ // Center nav buttons in new height for IME.
+ float transForIme = (mContext.getDeviceProfile().taskbarSize
+ - mContext.getTaskbarHeightForIme()) / 2f;
+ // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
+ float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
+ mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
+ flags -> (flags & FLAG_IME_VISIBLE) != 0, AnimatedFloat.VALUE, transForIme,
+ defaultButtonTransY));
+
+ if (alwaysShowButtons) {
+ initButtons(mNavButtonContainer, mEndContextualContainer,
+ mControllers.navButtonController);
+
+ if (isInSetup) {
+ // Since setup wizard only has back button enabled, it looks strange to be
+ // end-aligned, so start-align instead.
+ FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams)
+ mNavButtonContainer.getLayoutParams();
+ navButtonsLayoutParams.setMarginStart(navButtonsLayoutParams.getMarginEnd());
+ navButtonsLayoutParams.setMarginEnd(0);
+ navButtonsLayoutParams.gravity = Gravity.START;
+ mNavButtonContainer.requestLayout();
+
+ // TODO(b/210906568) Dark intensity is currently not propagated during setup, so set
+ // it based on dark theme for now.
+ int mode = mContext.getResources().getConfiguration().uiMode
+ & Configuration.UI_MODE_NIGHT_MASK;
+ boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
+ mTaskbarNavButtonDarkIntensity.updateValue(isDarkTheme ? 0 : 1);
+ }
+
+ // Animate taskbar background when any of these flags are enabled
+ int flagsToShowBg = FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE
+ | FLAG_NOTIFICATION_SHADE_EXPANDED;
+ mPropertyHolders.add(new StatePropertyHolder(
+ mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
+ flags -> (flags & flagsToShowBg) != 0, AnimatedFloat.VALUE, 1, 0));
+
+ // Rotation button
+ RotationButton rotationButton = new RotationButtonImpl(
+ addButton(mEndContextualContainer, R.id.rotate_suggestion,
+ R.layout.taskbar_contextual_button));
+ rotationButton.hide();
+ mControllers.rotationButtonController.setRotationButton(rotationButton, null);
+ } else {
+ mFloatingRotationButton = new FloatingRotationButton(mContext,
+ R.string.accessibility_rotate_button,
+ R.layout.rotate_suggestion,
+ R.id.rotate_suggestion,
+ R.dimen.floating_rotation_button_min_margin,
+ R.dimen.rounded_corner_content_padding,
+ R.dimen.floating_rotation_button_taskbar_left_margin,
+ R.dimen.floating_rotation_button_taskbar_bottom_margin,
+ R.dimen.floating_rotation_button_diameter,
+ R.dimen.key_button_ripple_max_width);
+ mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
+ mRotationButtonListener);
+
+ 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(imeDownButton,
+ flags -> (flags & FLAG_IME_VISIBLE) != 0));
+ }
+
+ applyState();
+ mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
+ }
+
+ 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 -> {
+ // Show only if not disabled, and if not on the keyguard or otherwise only when
+ // the bouncer or a lockscreen app is showing above the keyguard
+ boolean showingOnKeyguard = (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
+ (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0 ||
+ (flags & FLAG_KEYGUARD_OCCLUDED) != 0;
+ return (flags & FLAG_DISABLE_BACK) == 0
+ && ((flags & FLAG_KEYGUARD_VISIBLE) == 0 || showingOnKeyguard);
+ }));
+ boolean isRtl = Utilities.isRtl(mContext.getResources());
+ mPropertyHolders.add(new StatePropertyHolder(
+ mBackButton, flags -> (flags & FLAG_IME_VISIBLE) != 0, View.ROTATION,
+ isRtl ? 90 : -90, 0));
+ // Translate back button to be at end/start of other buttons for keyguard
+ int navButtonSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.taskbar_nav_buttons_size);
+ mPropertyHolders.add(new StatePropertyHolder(
+ mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
+ || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
+ VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
+
+
+ // home and recents buttons
+ View homeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer,
+ navButtonController, R.id.home);
+ mPropertyHolders.add(new StatePropertyHolder(homeButton,
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
+ (flags & FLAG_DISABLE_HOME) == 0));
+ View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
+ navContainer, navButtonController, R.id.recent_apps);
+ mPropertyHolders.add(new StatePropertyHolder(recentsButton,
+ flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
+ (flags & FLAG_DISABLE_RECENTS) == 0));
+
+ // A11y button
+ mA11yButton = addButton(R.drawable.ic_sysbar_accessibility_button, BUTTON_A11Y,
+ endContainer, navButtonController, R.id.accessibility_button,
+ R.layout.taskbar_contextual_button);
+ mPropertyHolders.add(new StatePropertyHolder(mA11yButton,
+ flags -> (flags & FLAG_A11Y_VISIBLE) != 0
+ && (flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0));
+ }
+
+ private void parseSystemUiFlags(int sysUiStateFlags) {
+ mSysuiStateFlags = sysUiStateFlags;
+ boolean isImeVisible = (sysUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0;
+ boolean isImeSwitcherShowing = (sysUiStateFlags & SYSUI_STATE_IME_SWITCHER_SHOWING) != 0;
+ boolean a11yVisible = (sysUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
+ boolean isHomeDisabled = (sysUiStateFlags & SYSUI_STATE_HOME_DISABLED) != 0;
+ boolean isRecentsDisabled = (sysUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
+ boolean isBackDisabled = (sysUiStateFlags & SYSUI_STATE_BACK_DISABLED) != 0;
+ int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+ | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+ boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0;
+ boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
+
+ // TODO(b/202218289) we're getting IME as not visible on lockscreen from system
+ updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
+ updateStateForFlag(FLAG_SWITCHER_SUPPORTED, isImeSwitcherShowing);
+ updateStateForFlag(FLAG_A11Y_VISIBLE, a11yVisible);
+ updateStateForFlag(FLAG_DISABLE_HOME, isHomeDisabled);
+ updateStateForFlag(FLAG_DISABLE_RECENTS, isRecentsDisabled);
+ updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled);
+ updateStateForFlag(FLAG_NOTIFICATION_SHADE_EXPANDED, isNotificationShadeExpanded);
+ updateStateForFlag(FLAG_SCREEN_PINNING_ACTIVE, isScreenPinningActive);
+
+ if (mA11yButton != null) {
+ // Only used in 3 button
+ boolean a11yLongClickable =
+ (sysUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+ mA11yButton.setLongClickable(a11yLongClickable);
+ }
+ }
+
+ public void updateStateForSysuiFlags(int systemUiStateFlags, boolean skipAnim) {
+ if (systemUiStateFlags == mSysuiStateFlags) {
+ return;
+ }
+ parseSystemUiFlags(systemUiStateFlags);
+ applyState();
+ if (skipAnim) {
+ mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
+ }
+ }
+
+ /**
+ * Should be called when we need to show back button for bouncer
+ */
+ public void setBackForBouncer(boolean isBouncerVisible) {
+ updateStateForFlag(FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE, isBouncerVisible);
+ applyState();
+ }
+
+ /**
+ * Slightly misnamed, but should be called when keyguard OR AOD is showing.
+ * We consider keyguardVisible when it's showing bouncer OR is occlucded by another app
+ */
+ public void setKeyguardVisible(boolean isKeyguardVisible, boolean isKeyguardOccluded) {
+ updateStateForFlag(FLAG_KEYGUARD_VISIBLE, isKeyguardVisible || isKeyguardOccluded);
+ updateStateForFlag(FLAG_KEYGUARD_OCCLUDED, isKeyguardOccluded);
+ applyState();
+ }
+
+ /**
+ * Returns true if IME bar is visible
+ */
+ public boolean isImeVisible() {
+ return (mState & FLAG_IME_VISIBLE) != 0;
+ }
+
+ /**
+ * Returns true if the home button is disabled
+ */
+ public boolean isHomeDisabled() {
+ return (mState & FLAG_DISABLE_HOME) != 0;
+ }
+
+ /**
+ * Returns true if the recents (overview) button is disabled
+ */
+ public boolean isRecentsDisabled() {
+ return (mState & FLAG_DISABLE_RECENTS) != 0;
+ }
+
+ /**
+ * Adds the bounds corresponding to all visible buttons to provided region
+ */
+ public void addVisibleButtonsRegion(TaskbarDragLayer parent, Region outRegion) {
+ int count = mAllButtons.size();
+ for (int i = 0; i < count; i++) {
+ View button = mAllButtons.get(i);
+ if (button.getVisibility() == View.VISIBLE) {
+ parent.getDescendantRectRelativeToSelf(button, mTempRect);
+ outRegion.op(mTempRect, Op.UNION);
+ }
+ }
+ }
+
+ /** Use to set the translationY for the all nav+contextual buttons */
+ public AnimatedFloat getTaskbarNavButtonTranslationY() {
+ return mTaskbarNavButtonTranslationY;
+ }
+
+ /** Use to set the dark intensity for the all nav+contextual buttons */
+ public AnimatedFloat getTaskbarNavButtonDarkIntensity() {
+ return mTaskbarNavButtonDarkIntensity;
+ }
+
+ /** Use to determine whether to use the dark intensity requested by the underlying app */
+ public AnimatedFloat getNavButtonDarkIntensityMultiplier() {
+ return mNavButtonDarkIntensityMultiplier;
+ }
+
+ /**
+ * Does not call {@link #applyState()}. Don't forget to!
+ */
+ private void updateStateForFlag(int flag, boolean enabled) {
+ if (enabled) {
+ mState |= flag;
+ } else {
+ mState &= ~flag;
+ }
+ }
+
+ private void applyState() {
+ int count = mPropertyHolders.size();
+ for (int i = 0; i < count; i++) {
+ mPropertyHolders.get(i).setState(mState);
+ }
+ }
+
+ private void updateNavButtonTranslationY() {
+ float normalTranslationY = mTaskbarNavButtonTranslationY.value
+ * mNavButtonTranslationYMultiplier.value;
+ float otherTranslationY = mTaskbarNavButtonTranslationYForIme.value;
+ mNavButtonsView.setTranslationY(normalTranslationY + otherTranslationY);
+ }
+
+ private void updateNavButtonDarkIntensity() {
+ float darkIntensity = mTaskbarNavButtonDarkIntensity.value
+ * mNavButtonDarkIntensityMultiplier.value;
+ int iconColor = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, mLightIconColor,
+ mDarkIconColor);
+ for (ImageView button : mAllButtons) {
+ button.setImageTintList(ColorStateList.valueOf(iconColor));
+ }
+ }
+
+ private ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
+ ViewGroup parent, TaskbarNavButtonController navButtonController, @IdRes int id) {
+ return addButton(drawableId, buttonType, parent, navButtonController, id,
+ R.layout.taskbar_nav_button);
+ }
+
+ private ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
+ ViewGroup parent, TaskbarNavButtonController navButtonController, @IdRes int id,
+ @LayoutRes int layoutId) {
+ ImageView buttonView = addButton(parent, id, layoutId);
+ buttonView.setImageResource(drawableId);
+ buttonView.setOnClickListener(view -> navButtonController.onButtonClick(buttonType));
+ buttonView.setOnLongClickListener(view ->
+ navButtonController.onButtonLongClick(buttonType));
+ return buttonView;
+ }
+
+ private ImageView addButton(ViewGroup parent, @IdRes int id, @LayoutRes int layoutId) {
+ ImageView buttonView = (ImageView) mContext.getLayoutInflater()
+ .inflate(layoutId, parent, false);
+ buttonView.setId(id);
+ parent.addView(buttonView);
+ mAllButtons.add(buttonView);
+ return buttonView;
+ }
+
+ public boolean isEventOverAnyItem(MotionEvent ev) {
+ return mFloatingRotationButtonBounds.contains((int) ev.getX(), (int) ev.getY());
+ }
+
+ public void onConfigurationChanged(@Config int configChanges) {
+ if (mFloatingRotationButton != null) {
+ mFloatingRotationButton.onConfigurationChanged(configChanges);
+ }
+ }
+
+ public void onDestroy() {
+ mPropertyHolders.clear();
+ mControllers.rotationButtonController.unregisterListeners();
+ if (mFloatingRotationButton != null) {
+ mFloatingRotationButton.hide();
+ }
+ }
+
+ private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
+ @Override
+ public void onVisibilityChanged(boolean isVisible) {
+ if (isVisible) {
+ mFloatingRotationButton.getCurrentView()
+ .getBoundsOnScreen(mFloatingRotationButtonBounds);
+ } else {
+ mFloatingRotationButtonBounds.setEmpty();
+ }
+ }
+ }
+
+ private class RotationButtonImpl implements RotationButton {
+
+ private final ImageView mButton;
+ private AnimatedVectorDrawable mImageDrawable;
+
+ RotationButtonImpl(ImageView button) {
+ mButton = button;
+ }
+
+ @Override
+ public void setRotationButtonController(RotationButtonController rotationButtonController) {
+ // TODO(b/187754252) UI polish, different icons based on light/dark context, etc
+ mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
+ .getDrawable(rotationButtonController.getIconResId());
+ mButton.setImageDrawable(mImageDrawable);
+ mButton.setContentDescription(mButton.getResources()
+ .getString(R.string.accessibility_rotate_button));
+ mImageDrawable.setCallback(mButton);
+ }
+
+ @Override
+ public View getCurrentView() {
+ return mButton;
+ }
+
+ @Override
+ public boolean show() {
+ mButton.setVisibility(View.VISIBLE);
+ mState |= FLAG_ROTATION_BUTTON_VISIBLE;
+ applyState();
+ return true;
+ }
+
+ @Override
+ public boolean hide() {
+ mButton.setVisibility(View.GONE);
+ mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
+ applyState();
+ return true;
+ }
+
+ @Override
+ public boolean isVisible() {
+ return mButton.getVisibility() == View.VISIBLE;
+ }
+
+ @Override
+ public void updateIcon(int lightIconColor, int darkIconColor) {
+ // TODO(b/187754252): UI Polish
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener onClickListener) {
+ mButton.setOnClickListener(onClickListener);
+ }
+
+ @Override
+ public void setOnHoverListener(OnHoverListener onHoverListener) {
+ mButton.setOnHoverListener(onHoverListener);
+ }
+
+ @Override
+ public AnimatedVectorDrawable getImageDrawable() {
+ return mImageDrawable;
+ }
+
+ @Override
+ public void setDarkIntensity(float darkIntensity) {
+ // TODO(b/187754252) UI polish
+ }
+
+ @Override
+ public boolean acceptRotationProposal() {
+ return mButton.isAttachedToWindow();
+ }
+ }
+
+ private static class StatePropertyHolder {
+
+ private final float mEnabledValue, mDisabledValue;
+ private final ObjectAnimator mAnimator;
+ private final IntPredicate mEnableCondition;
+
+ private boolean mIsEnabled = true;
+
+ StatePropertyHolder(View view, IntPredicate enableCondition) {
+ this(view, enableCondition, LauncherAnimUtils.VIEW_ALPHA, 1, 0);
+ mAnimator.addListener(new AlphaUpdateListener(view));
+ }
+
+ StatePropertyHolder(T target, IntPredicate enabledCondition,
+ Property property, float enabledValue, float disabledValue) {
+ mEnableCondition = enabledCondition;
+ mEnabledValue = enabledValue;
+ mDisabledValue = disabledValue;
+ mAnimator = ObjectAnimator.ofFloat(target, property, enabledValue, disabledValue);
+ }
+
+ public void setState(int flags) {
+ boolean isEnabled = mEnableCondition.test(flags);
+ if (mIsEnabled != isEnabled) {
+ mIsEnabled = isEnabled;
+ mAnimator.cancel();
+ mAnimator.setFloatValues(mIsEnabled ? mEnabledValue : mDisabledValue);
+ mAnimator.start();
+ }
+ }
+
+ public void endAnimation() {
+ if (mAnimator.isRunning()) {
+ mAnimator.end();
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
new file mode 100644
index 0000000000..6db58397c3
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.ColorInt;
+import androidx.core.content.ContextCompat;
+
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
+
+public class StashedHandleView extends View {
+
+ private static final long COLOR_CHANGE_DURATION = 120;
+
+ private final @ColorInt int mStashedHandleLightColor;
+ private final @ColorInt int mStashedHandleDarkColor;
+ private final Rect mSampledRegion = new Rect();
+ private final int[] mTmpArr = new int[2];
+
+ private @Nullable ObjectAnimator mColorChangeAnim;
+
+ public StashedHandleView(Context context) {
+ this(context, null);
+ }
+
+ public StashedHandleView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public StashedHandleView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public StashedHandleView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ mStashedHandleLightColor = ContextCompat.getColor(context,
+ R.color.taskbar_stashed_handle_light_color);
+ mStashedHandleDarkColor = ContextCompat.getColor(context,
+ R.color.taskbar_stashed_handle_dark_color);
+ }
+
+ /**
+ * Updates mSampledRegion to be the location of the stashedHandleBounds relative to the screen.
+ * @see #getSampledRegion()
+ */
+ public void updateSampledRegion(Rect stashedHandleBounds) {
+ getLocationOnScreen(mTmpArr);
+ mSampledRegion.set(stashedHandleBounds);
+ mSampledRegion.offset(mTmpArr[0], mTmpArr[1]);
+ }
+
+ public Rect getSampledRegion() {
+ return mSampledRegion;
+ }
+
+ /**
+ * Updates the handle color.
+ * @param isRegionDark Whether the background behind the handle is dark, and thus the handle
+ * should be light (and vice versa).
+ * @param animate Whether to animate the change, or apply it immediately.
+ */
+ public void updateHandleColor(boolean isRegionDark, boolean animate) {
+ int newColor = isRegionDark ? mStashedHandleLightColor : mStashedHandleDarkColor;
+ if (mColorChangeAnim != null) {
+ mColorChangeAnim.cancel();
+ }
+ if (animate) {
+ mColorChangeAnim = ObjectAnimator.ofArgb(this,
+ LauncherAnimUtils.VIEW_BACKGROUND_COLOR, newColor);
+ mColorChangeAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mColorChangeAnim = null;
+ }
+ });
+ mColorChangeAnim.setDuration(COLOR_CHANGE_DURATION);
+ mColorChangeAnim.start();
+ } else {
+ setBackgroundColor(newColor);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
new file mode 100644
index 0000000000..22ca63f963
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.RevealOutlineAnimation;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.AnimatedFloat;
+import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
+
+/**
+ * Handles properties/data collection, then passes the results to our stashed handle View to render.
+ */
+public class StashedHandleViewController {
+
+ public static final int ALPHA_INDEX_STASHED = 0;
+ public static final int ALPHA_INDEX_HOME_DISABLED = 1;
+ private static final int NUM_ALPHA_CHANNELS = 2;
+
+ /**
+ * The SharedPreferences key for whether the stashed handle region is dark.
+ */
+ private static final String SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY =
+ "stashed_handle_region_is_dark";
+
+ private final TaskbarActivityContext mActivity;
+ private final SharedPreferences mPrefs;
+ private final StashedHandleView mStashedHandleView;
+ private final int mStashedHandleWidth;
+ private final int mStashedHandleHeight;
+ private final RegionSamplingHelper mRegionSamplingHelper;
+ private final MultiValueAlpha mTaskbarStashedHandleAlpha;
+ private final AnimatedFloat mTaskbarStashedHandleHintScale = new AnimatedFloat(
+ this::updateStashedHandleHintScale);
+
+ // Initialized in init.
+ private TaskbarControllers mControllers;
+
+ // The bounds we want to clip to in the settled state when showing the stashed handle.
+ private final Rect mStashedHandleBounds = new Rect();
+ private float mStashedHandleRadius;
+
+ // When the reveal animation is cancelled, we can assume it's about to create a new animation,
+ // which should start off at the same point the cancelled one left off.
+ private float mStartProgressForNextRevealAnim;
+ private boolean mWasLastRevealAnimReversed;
+
+ public StashedHandleViewController(TaskbarActivityContext activity,
+ StashedHandleView stashedHandleView) {
+ mActivity = activity;
+ mPrefs = Utilities.getPrefs(mActivity);
+ mStashedHandleView = stashedHandleView;
+ mTaskbarStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, NUM_ALPHA_CHANNELS);
+ mTaskbarStashedHandleAlpha.setUpdateVisibility(true);
+ mStashedHandleView.updateHandleColor(
+ mPrefs.getBoolean(SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY, false),
+ false /* animate */);
+ final Resources resources = mActivity.getResources();
+ mStashedHandleWidth = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
+ mStashedHandleHeight = resources.getDimensionPixelSize(
+ R.dimen.taskbar_stashed_handle_height);
+ mRegionSamplingHelper = new RegionSamplingHelper(mStashedHandleView,
+ new RegionSamplingHelper.SamplingCallback() {
+ @Override
+ public void onRegionDarknessChanged(boolean isRegionDark) {
+ mStashedHandleView.updateHandleColor(isRegionDark, true /* animate */);
+ mPrefs.edit().putBoolean(SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY,
+ isRegionDark).apply();
+ }
+
+ @Override
+ public Rect getSampledRegion(View sampledView) {
+ return mStashedHandleView.getSampledRegion();
+ }
+ }, Executors.UI_HELPER_EXECUTOR);
+ }
+
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ mStashedHandleView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize;
+
+ mTaskbarStashedHandleAlpha.getProperty(ALPHA_INDEX_STASHED).setValue(0);
+ mTaskbarStashedHandleHintScale.updateValue(1f);
+
+ final int stashedTaskbarHeight = mControllers.taskbarStashController.getStashedHeight();
+ mStashedHandleView.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ final int stashedCenterX = view.getWidth() / 2;
+ final int stashedCenterY = view.getHeight() - stashedTaskbarHeight / 2;
+ mStashedHandleBounds.set(
+ stashedCenterX - mStashedHandleWidth / 2,
+ stashedCenterY - mStashedHandleHeight / 2,
+ stashedCenterX + mStashedHandleWidth / 2,
+ stashedCenterY + mStashedHandleHeight / 2);
+ mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
+ mStashedHandleRadius = view.getHeight() / 2f;
+ outline.setRoundRect(mStashedHandleBounds, mStashedHandleRadius);
+ }
+ });
+
+ mStashedHandleView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) -> {
+ final int stashedCenterX = view.getWidth() / 2;
+ final int stashedCenterY = view.getHeight() - stashedTaskbarHeight / 2;
+
+ view.setPivotX(stashedCenterX);
+ view.setPivotY(stashedCenterY);
+ });
+ }
+
+ public void onDestroy() {
+ mRegionSamplingHelper.stopAndDestroy();
+ }
+
+ public MultiValueAlpha getStashedHandleAlpha() {
+ return mTaskbarStashedHandleAlpha;
+ }
+
+ public AnimatedFloat getStashedHandleHintScale() {
+ return mTaskbarStashedHandleHintScale;
+ }
+
+ /**
+ * Creates and returns a {@link RevealOutlineAnimation} Animator that updates the stashed handle
+ * shape and size. When stashed, the shape is a thin rounded pill. When unstashed, the shape
+ * morphs into the size of where the taskbar icons will be.
+ */
+ public Animator createRevealAnimToIsStashed(boolean isStashed) {
+ final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
+ mStashedHandleRadius, mStashedHandleRadius,
+ mControllers.taskbarViewController.getIconLayoutBounds(), mStashedHandleBounds);
+
+ boolean isReversed = !isStashed;
+ boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
+ mWasLastRevealAnimReversed = isReversed;
+ if (changingDirection) {
+ mStartProgressForNextRevealAnim = 1f - mStartProgressForNextRevealAnim;
+ }
+
+ ValueAnimator revealAnim = handleRevealProvider.createRevealAnimator(mStashedHandleView,
+ isReversed, mStartProgressForNextRevealAnim);
+ revealAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStartProgressForNextRevealAnim = ((ValueAnimator) animation).getAnimatedFraction();
+ }
+ });
+ return revealAnim;
+ }
+
+ public void onIsStashed(boolean isStashed) {
+ mRegionSamplingHelper.setWindowVisible(isStashed);
+ if (isStashed) {
+ mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
+ mRegionSamplingHelper.start(mStashedHandleView.getSampledRegion());
+ } else {
+ mRegionSamplingHelper.stop();
+ }
+ }
+
+ protected void updateStashedHandleHintScale() {
+ mStashedHandleView.setScaleX(mTaskbarStashedHandleHintScale.value);
+ mStashedHandleView.setScaleY(mTaskbarStashedHandleHintScale.value);
+ }
+
+ /**
+ * Should be called when the home button is disabled, so we can hide this handle as well.
+ */
+ public void setIsHomeButtonDisabled(boolean homeDisabled) {
+ mTaskbarStashedHandleAlpha.getProperty(ALPHA_INDEX_HOME_DISABLED).setValue(
+ homeDisabled ? 0 : 1);
+ }
+
+ public boolean isStashedHandleVisible() {
+ return mStashedHandleView.getVisibility() == View.VISIBLE;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 4ba0ee0d41..5308a8f3e8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -17,29 +17,37 @@ package com.android.launcher3.taskbar;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
+import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
+import android.content.res.Resources;
+import android.graphics.Insets;
import android.graphics.PixelFormat;
-import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
import android.os.Process;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
+import android.view.RoundedCorner;
import android.view.View;
import android.view.WindowManager;
+import android.widget.FrameLayout;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -47,30 +55,27 @@ import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DragSource;
-import com.android.launcher3.DropTarget;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
-import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.dragndrop.DragView;
-import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.FolderInfo;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.util.ViewCache;
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
/**
* The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
@@ -88,59 +93,97 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
private final DeviceProfile mDeviceProfile;
private final LayoutInflater mLayoutInflater;
private final TaskbarDragLayer mDragLayer;
- private final TaskbarIconController mIconController;
- private final MyDragController mDragController;
+ private final TaskbarControllers mControllers;
private final WindowManager mWindowManager;
+ private final @Nullable RoundedCorner mLeftCorner, mRightCorner;
+ private final int mTaskbarHeightForIme;
private WindowManager.LayoutParams mWindowLayoutParams;
+ private boolean mIsFullscreen;
+ // The size we should return to when we call setTaskbarWindowFullscreen(false)
+ private int mLastRequestedNonFullscreenHeight;
private final SysUINavigationMode.Mode mNavMode;
- private final TaskbarNavButtonController mNavButtonController;
+ private final ViewCache mViewCache = new ViewCache();
private final boolean mIsSafeModeEnabled;
-
- @NonNull
- private TaskbarUIController mUIController = TaskbarUIController.DEFAULT;
-
- private final View.OnClickListener mOnTaskbarIconClickListener;
- private final View.OnLongClickListener mOnTaskbarIconLongClickListener;
+ private final boolean mIsUserSetupComplete;
+ private boolean mIsDestroyed = false;
+ // The flag to know if the window is excluded from magnification region computation.
+ private boolean mIsExcludeFromMagnificationRegion = false;
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
- TaskbarNavButtonController buttonController) {
+ TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
+ unfoldTransitionProgressProvider) {
super(windowContext, Themes.getActivityThemeRes(windowContext));
mDeviceProfile = dp;
- mNavButtonController = buttonController;
+
mNavMode = SysUINavigationMode.getMode(windowContext);
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
() -> getPackageManager().isSafeMode());
+ mIsUserSetupComplete = SettingsCache.INSTANCE.get(this).getValue(
+ Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
- mOnTaskbarIconLongClickListener =
- new TaskbarDragController(this)::startSystemDragOnLongClick;
- mOnTaskbarIconClickListener = this::onTaskbarIconClicked;
-
- float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size);
+ final Resources resources = getResources();
+ float taskbarIconSize = resources.getDimension(R.dimen.taskbar_icon_size);
+ mDeviceProfile.updateIconSize(1, resources);
float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
- mDeviceProfile.updateIconSize(iconScale, getResources());
+ mDeviceProfile.updateIconSize(iconScale, resources);
+
+ mTaskbarHeightForIme = resources.getDimensionPixelSize(R.dimen.taskbar_ime_size);
mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
- mDragLayer = (TaskbarDragLayer) mLayoutInflater
- .inflate(R.layout.taskbar, null, false);
- mIconController = new TaskbarIconController(this, mDragLayer);
- mDragController = new MyDragController(this);
+
+ // Inflate views.
+ mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(
+ R.layout.taskbar, null, false);
+ TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
+ TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
+ FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
+ StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
Display display = windowContext.getDisplay();
Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
? windowContext.getApplicationContext()
: windowContext.getApplicationContext().createDisplayContext(display);
mWindowManager = c.getSystemService(WindowManager.class);
+ mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
+ mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
+
+ // Construct controllers.
+ mControllers = new TaskbarControllers(this,
+ new TaskbarDragController(this),
+ buttonController,
+ new NavbarButtonsViewController(this, navButtonsView),
+ new RotationButtonController(this,
+ c.getColor(R.color.taskbar_nav_icon_light_color),
+ c.getColor(R.color.taskbar_nav_icon_dark_color),
+ R.drawable.ic_sysbar_rotate_button_ccw_start_0,
+ R.drawable.ic_sysbar_rotate_button_ccw_start_90,
+ R.drawable.ic_sysbar_rotate_button_cw_start_0,
+ R.drawable.ic_sysbar_rotate_button_cw_start_90,
+ () -> getDisplay().getRotation()),
+ new TaskbarDragLayerController(this, mDragLayer),
+ new TaskbarViewController(this, taskbarView),
+ new TaskbarScrimViewController(this, taskbarScrimView),
+ new TaskbarUnfoldAnimationController(unfoldTransitionProgressProvider,
+ mWindowManager),
+ new TaskbarKeyguardController(this),
+ new StashedHandleViewController(this, stashedHandleView),
+ new TaskbarStashController(this),
+ new TaskbarEduController(this),
+ new TaskbarAutohideSuspendController(this),
+ new TaskbarPopupController());
}
- public void init() {
+ public void init(TaskbarSharedState sharedState) {
+ mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
mWindowLayoutParams = new WindowManager.LayoutParams(
MATCH_PARENT,
- mDeviceProfile.taskbarSize,
- TYPE_APPLICATION_OVERLAY,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ mLastRequestedNonFullscreenHeight,
+ TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
mWindowLayoutParams.setTitle(WINDOW_TITLE);
mWindowLayoutParams.packageName = getPackageName();
@@ -148,31 +191,40 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
mWindowLayoutParams.setFitInsetsTypes(0);
mWindowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mWindowLayoutParams.setSystemApplicationOverlay(true);
+ mWindowLayoutParams.privateFlags =
+ WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
WindowManagerWrapper wmWrapper = WindowManagerWrapper.getInstance();
wmWrapper.setProvidesInsetsTypes(
mWindowLayoutParams,
new int[] { ITYPE_EXTRA_NAVIGATION_BAR, ITYPE_BOTTOM_TAPPABLE_ELEMENT }
);
+ // Adjust the frame by the rounded corners (ie. leaving just the bar as the inset) when
+ // the IME is showing
+ mWindowLayoutParams.providedInternalImeInsets = Insets.of(0,
+ getDefaultTaskbarWindowHeight() - mTaskbarHeightForIme, 0, 0);
+
+ // Initialize controllers after all are constructed.
+ mControllers.init(sharedState);
+ updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
- mIconController.init(mOnTaskbarIconClickListener, mOnTaskbarIconLongClickListener);
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
}
- /**
- * Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset).
- */
- public void setTaskbarWindowHeight(int height) {
- if (mWindowLayoutParams.height == height) {
- return;
- }
- mWindowLayoutParams.height = height;
- mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
+ public void onConfigurationChanged(@Config int configChanges) {
+ mControllers.onConfigurationChanged(configChanges);
}
- public boolean canShowNavButtons() {
- return ENABLE_THREE_BUTTON_TASKBAR && mNavMode == Mode.THREE_BUTTONS;
+ public boolean isThreeButtonNav() {
+ return mNavMode == Mode.THREE_BUTTONS;
+ }
+
+ public int getLeftCornerRadius() {
+ return mLeftCorner == null ? 0 : mLeftCorner.getRadius();
+ }
+
+ public int getRightCornerRadius() {
+ return mRightCorner == null ? 0 : mRightCorner.getRadius();
}
@Override
@@ -192,59 +244,223 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
@Override
public Rect getFolderBoundingBox() {
- return mDragLayer.getFolderBoundingBox();
+ return mControllers.taskbarDragLayerController.getFolderBoundingBox();
}
@Override
- public DragController getDragController() {
- return mDragController;
+ public TaskbarDragController getDragController() {
+ return mControllers.taskbarDragController;
+ }
+
+ @Override
+ public ViewCache getViewCache() {
+ return mViewCache;
+ }
+
+ @Override
+ public boolean supportsIme() {
+ // Currently we don't support IME because we have FLAG_NOT_FOCUSABLE. We can remove that
+ // flag when opening a floating view that needs IME (such as Folder), but then that means
+ // Taskbar will be below IME and thus users can't click the back button.
+ return false;
+ }
+
+ @Override
+ public View.OnClickListener getItemOnClickListener() {
+ return this::onTaskbarIconClicked;
+ }
+
+ /**
+ * Change from hotseat/predicted hotseat to taskbar container.
+ */
+ @Override
+ public void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) {
+ if (!itemInfoBuilder.hasContainerInfo()) {
+ return;
+ }
+ LauncherAtom.ContainerInfo oldContainer = itemInfoBuilder.getContainerInfo();
+
+ if (oldContainer.hasPredictedHotseatContainer()) {
+ LauncherAtom.PredictedHotseatContainer predictedHotseat =
+ oldContainer.getPredictedHotseatContainer();
+ LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
+ LauncherAtom.TaskBarContainer.newBuilder();
+
+ if (predictedHotseat.hasIndex()) {
+ taskbarBuilder.setIndex(predictedHotseat.getIndex());
+ }
+ if (predictedHotseat.hasCardinality()) {
+ taskbarBuilder.setCardinality(predictedHotseat.getCardinality());
+ }
+
+ itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setTaskBarContainer(taskbarBuilder));
+ } else if (oldContainer.hasHotseat()) {
+ LauncherAtom.HotseatContainer hotseat = oldContainer.getHotseat();
+ LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
+ LauncherAtom.TaskBarContainer.newBuilder();
+
+ if (hotseat.hasIndex()) {
+ taskbarBuilder.setIndex(hotseat.getIndex());
+ }
+
+ itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setTaskBarContainer(taskbarBuilder));
+ } else if (oldContainer.hasFolder() && oldContainer.getFolder().hasHotseat()) {
+ LauncherAtom.FolderContainer.Builder folderBuilder = oldContainer.getFolder()
+ .toBuilder();
+ LauncherAtom.HotseatContainer hotseat = folderBuilder.getHotseat();
+ LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
+ LauncherAtom.TaskBarContainer.newBuilder();
+
+ if (hotseat.hasIndex()) {
+ taskbarBuilder.setIndex(hotseat.getIndex());
+ }
+
+ folderBuilder.setTaskbar(taskbarBuilder);
+ folderBuilder.clearHotseat();
+ itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+ .setFolder(folderBuilder));
+ }
}
/**
* Sets a new data-source for this taskbar instance
*/
public void setUIController(@NonNull TaskbarUIController uiController) {
- mUIController.onDestroy();
- mUIController = uiController;
- mIconController.setUIController(mUIController);
- mUIController.onCreate();
+ mControllers.uiController.onDestroy();
+ mControllers.uiController = uiController;
+ mControllers.uiController.init(mControllers);
+ }
+
+ /**
+ * Sets the flag indicating setup UI is visible
+ */
+ public void setSetupUIVisible(boolean isVisible) {
+ mControllers.taskbarStashController.setSetupUIVisible(isVisible);
}
/**
* Called when this instance of taskbar is no longer needed
*/
public void onDestroy() {
+ mIsDestroyed = true;
setUIController(TaskbarUIController.DEFAULT);
- mIconController.onDestroy();
+ mControllers.onDestroy();
mWindowManager.removeViewImmediate(mDragLayer);
}
- void onNavigationButtonClick(@TaskbarButton int buttonType) {
- mNavButtonController.onButtonClick(buttonType);
+ public void updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit) {
+ mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
+ fromInit);
+ mControllers.taskbarViewController.setImeIsVisible(
+ mControllers.navbarButtonsViewController.isImeVisible());
+ int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+ | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+ onNotificationShadeExpandChanged((systemUiStateFlags & shadeExpandedFlags) != 0, fromInit);
+ mControllers.taskbarViewController.setRecentsButtonDisabled(
+ mControllers.navbarButtonsViewController.isRecentsDisabled());
+ mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
+ mControllers.navbarButtonsViewController.isHomeDisabled());
+ mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
+ mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
+ mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
+ fromInit);
+ mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
}
/**
- * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
+ * Hides the taskbar icons and background when the notication shade is expanded.
*/
- public void setImeIsVisible(boolean isImeVisible) {
- mIconController.setImeIsVisible(isImeVisible);
+ private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
+ float alpha = isExpanded ? 0 : 1;
+ AnimatorSet anim = new AnimatorSet();
+ anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().getProperty(
+ TaskbarViewController.ALPHA_INDEX_NOTIFICATION_EXPANDED).animateToValue(alpha));
+ if (!isThreeButtonNav()) {
+ anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar()
+ .animateToValue(alpha));
+ }
+ anim.start();
+ if (skipAnim) {
+ anim.end();
+ }
}
- /**
- * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
- * instantiating at all, which is what's responsible for sending sysui state flags over.
- *
- * @param vis IME visibility flag
- */
- public void updateImeStatus(int displayId, int vis, boolean showImeSwitcher) {
- mIconController.updateImeStatus(displayId, vis, showImeSwitcher);
+ public void onRotationProposal(int rotation, boolean isValid) {
+ mControllers.rotationButtonController.onRotationProposal(rotation, isValid);
+ }
+
+ public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
+ if (displayId != getDisplayId()) {
+ return;
+ }
+ mControllers.rotationButtonController.onDisable2FlagChanged(state2);
+ }
+
+ public void onSystemBarAttributesChanged(int displayId, int behavior) {
+ mControllers.rotationButtonController.onBehaviorChanged(displayId, behavior);
+ }
+
+ public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+ if (!isUserSetupComplete()) {
+ return;
+ }
+ mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
+ .updateValue(darkIntensity);
}
/**
* Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
*/
- protected void setTaskbarWindowFullscreen(boolean fullscreen) {
- setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : getDeviceProfile().taskbarSize);
+ public void setTaskbarWindowFullscreen(boolean fullscreen) {
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
+ mIsFullscreen = fullscreen;
+ setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
+ }
+
+ public boolean isTaskbarWindowFullscreen() {
+ return mIsFullscreen;
+ }
+
+ /**
+ * Updates the TaskbarContainer height (pass {@link #getDefaultTaskbarWindowHeight()} to reset).
+ */
+ public void setTaskbarWindowHeight(int height) {
+ if (mWindowLayoutParams.height == height || mIsDestroyed) {
+ return;
+ }
+ if (height == MATCH_PARENT) {
+ height = mDeviceProfile.heightPx;
+ } else {
+ mLastRequestedNonFullscreenHeight = height;
+ if (mIsFullscreen) {
+ // We still need to be fullscreen, so defer any change to our height until we call
+ // setTaskbarWindowFullscreen(false). For example, this could happen when dragging
+ // from the gesture region, as the drag will cancel the gesture and reset launcher's
+ // state, which in turn normally would reset the taskbar window height as well.
+ return;
+ }
+ }
+ mWindowLayoutParams.height = height;
+ mWindowLayoutParams.providedInternalImeInsets =
+ Insets.of(0, height - mTaskbarHeightForIme, 0, 0);
+ mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
+ }
+
+ /**
+ * Returns the default height of the window, including the static corner radii above taskbar.
+ */
+ public int getDefaultTaskbarWindowHeight() {
+ return mDeviceProfile.taskbarSize + Math.max(getLeftCornerRadius(), getRightCornerRadius());
+ }
+
+ /**
+ * Returns the bottom insets taskbar provides to the IME when IME is visible.
+ */
+ public int getTaskbarHeightForIme() {
+ return mTaskbarHeightForIme;
}
protected void onTaskbarIconClicked(View view) {
@@ -260,10 +476,11 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
getDragLayer().post(() -> {
folder.animateOpen();
+ getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN);
folder.iterateOverItems((itemInfo, itemView) -> {
- itemView.setOnClickListener(mOnTaskbarIconClickListener);
- itemView.setOnLongClickListener(mOnTaskbarIconLongClickListener);
+ mControllers.taskbarViewController
+ .setClickAndLongClickListenersForIcon(itemView);
// To play haptic when dragging, like other Taskbar items do.
itemView.setHapticFeedbackEnabled(true);
return false;
@@ -271,7 +488,9 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
});
} else if (tag instanceof WorkspaceItemInfo) {
WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
- if (!(info.isDisabled() && ItemClickHandler.handleDisabledItemClicked(info, this))) {
+ if (info.isDisabled()) {
+ ItemClickHandler.handleDisabledItemClicked(info, this);
+ } else {
Intent intent = new Intent(info.getIntent())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
@@ -295,6 +514,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
getSystemService(LauncherApps.class).startMainActivity(
intent.getComponent(), info.user, intent.getSourceBounds(), null);
}
+
+ mControllers.uiController.onTaskbarIconLaunched(info);
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
.show();
@@ -308,26 +529,44 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ
AbstractFloatingView.closeAllOpenViews(this);
}
- private static class MyDragController extends DragController {
- MyDragController(TaskbarActivityContext activity) {
- super(activity);
+ /**
+ * Called when we detect a long press in the nav region before passing the gesture slop.
+ * @return Whether taskbar handled the long press, and thus should cancel the gesture.
+ */
+ public boolean onLongPressToUnstashTaskbar() {
+ return mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
+ }
+
+ /**
+ * Called when we detect a motion down or up/cancel in the nav region while stashed.
+ * @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
+ */
+ public void startTaskbarUnstashHint(boolean animateForward) {
+ mControllers.taskbarStashController.startUnstashHint(animateForward);
+ }
+
+ protected boolean isUserSetupComplete() {
+ return mIsUserSetupComplete;
+ }
+
+ /**
+ * Called when we determine the touchable region.
+ *
+ * @param exclude {@code true} then the magnification region computation will omit the window.
+ */
+ public void excludeFromMagnificationRegion(boolean exclude) {
+ if (mIsExcludeFromMagnificationRegion == exclude) {
+ return;
}
- @Override
- protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view,
- DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source,
- ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale,
- float dragViewScaleOnDrop, DragOptions options) {
- return null;
- }
-
- @Override
- protected void exitDrag() {
- }
-
- @Override
- protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
- return null;
+ mIsExcludeFromMagnificationRegion = exclude;
+ if (exclude) {
+ mWindowLayoutParams.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
+ } else {
+ mWindowLayoutParams.privateFlags &=
+ ~WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
}
+ mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java
deleted file mode 100644
index e20ddf88ce..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAnimationController.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import static com.android.launcher3.LauncherState.TASKBAR;
-
-import android.animation.Animator;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.taskbar.LauncherTaskbarUIController.TaskbarAnimationControllerCallbacks;
-import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.SystemUiProxy;
-import com.android.systemui.shared.system.QuickStepContract;
-
-/**
- * Works with TaskbarController to update the TaskbarView's visual properties based on factors such
- * as LauncherState, whether Launcher is in the foreground, etc.
- */
-public class TaskbarAnimationController {
-
- private static final long IME_VISIBILITY_ALPHA_DURATION = 120;
-
- private final BaseQuickstepLauncher mLauncher;
- private final TaskbarAnimationControllerCallbacks mTaskbarCallbacks;
-
- // Background alpha.
- private final AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
- this::onTaskbarBackgroundAlphaChanged);
-
- // Overall visibility.
- private final AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat(
- this::updateVisibilityAlpha);
- private final AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
- this::updateVisibilityAlphaForIme);
-
- // Scale.
- private final AnimatedFloat mTaskbarScaleForLauncherState = new AnimatedFloat(
- this::updateScale);
-
- // TranslationY.
- private final AnimatedFloat mTaskbarTranslationYForLauncherState = new AnimatedFloat(
- this::updateTranslationY);
-
- public TaskbarAnimationController(BaseQuickstepLauncher launcher,
- TaskbarAnimationControllerCallbacks taskbarCallbacks) {
- mLauncher = launcher;
- mTaskbarCallbacks = taskbarCallbacks;
- }
-
- protected void init() {
- mTaskbarBackgroundAlpha.updateValue(mLauncher.hasBeenResumed() ? 0f : 1f);
- boolean isVisibleForLauncherState = (mLauncher.getStateManager().getState()
- .getVisibleElements(mLauncher) & TASKBAR) != 0;
- mTaskbarVisibilityAlphaForLauncherState.updateValue(isVisibleForLauncherState ? 1f : 0f);
- boolean isImeVisible = (SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags()
- & QuickStepContract.SYSUI_STATE_IME_SHOWING) != 0;
- mTaskbarVisibilityAlphaForIme.updateValue(isImeVisible ? 0f : 1f);
-
- onTaskbarBackgroundAlphaChanged();
- updateVisibilityAlpha();
- }
-
- protected void cleanup() {
- setNavBarButtonAlpha(1f);
- }
-
- protected AnimatedFloat getTaskbarVisibilityForLauncherState() {
- return mTaskbarVisibilityAlphaForLauncherState;
- }
-
- protected AnimatedFloat getTaskbarScaleForLauncherState() {
- return mTaskbarScaleForLauncherState;
- }
-
- protected AnimatedFloat getTaskbarTranslationYForLauncherState() {
- return mTaskbarTranslationYForLauncherState;
- }
-
- protected Animator createAnimToBackgroundAlpha(float toAlpha, long duration) {
- return mTaskbarBackgroundAlpha.animateToValue(mTaskbarBackgroundAlpha.value, toAlpha)
- .setDuration(duration);
- }
-
- protected void animateToVisibilityForIme(float toAlpha) {
- mTaskbarVisibilityAlphaForIme.animateToValue(mTaskbarVisibilityAlphaForIme.value, toAlpha)
- .setDuration(IME_VISIBILITY_ALPHA_DURATION).start();
- }
-
- private void onTaskbarBackgroundAlphaChanged() {
- mTaskbarCallbacks.updateTaskbarBackgroundAlpha(mTaskbarBackgroundAlpha.value);
- updateVisibilityAlpha();
- updateScale();
- updateTranslationY();
- }
-
- private void updateVisibilityAlpha() {
- // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
- // assumption being that Taskbar should always be visible regardless of the current
- // LauncherState if Launcher is paused.
- float alphaDueToIme = mTaskbarVisibilityAlphaForIme.value;
- float alphaDueToLauncher = Math.max(mTaskbarBackgroundAlpha.value,
- mTaskbarVisibilityAlphaForLauncherState.value);
- float taskbarAlpha = alphaDueToLauncher * alphaDueToIme;
- mTaskbarCallbacks.updateTaskbarVisibilityAlpha(taskbarAlpha);
-
- // Make the nav bar invisible if taskbar is visible.
- setNavBarButtonAlpha(1f - taskbarAlpha);
- }
-
- private void updateVisibilityAlphaForIme() {
- updateVisibilityAlpha();
- float taskbarAlphaDueToIme = mTaskbarVisibilityAlphaForIme.value;
- mTaskbarCallbacks.updateImeBarVisibilityAlpha(1f - taskbarAlphaDueToIme);
- }
-
- private void updateScale() {
- // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
- // assumption being that Taskbar should always be at scale 1f regardless of the current
- // LauncherState if Launcher is paused.
- float scale = mTaskbarScaleForLauncherState.value;
- scale = Utilities.mapRange(mTaskbarBackgroundAlpha.value, scale, 1f);
- mTaskbarCallbacks.updateTaskbarScale(scale);
- }
-
- private void updateTranslationY() {
- // We use mTaskbarBackgroundAlpha as a proxy for whether Launcher is resumed/paused, the
- // assumption being that Taskbar should always be at translationY 0f regardless of the
- // current LauncherState if Launcher is paused.
- float translationY = mTaskbarTranslationYForLauncherState.value;
- translationY = Utilities.mapRange(mTaskbarBackgroundAlpha.value, translationY, 0f);
- mTaskbarCallbacks.updateTaskbarTranslationY(translationY);
- }
-
- private void setNavBarButtonAlpha(float navBarAlpha) {
- SystemUiProxy.INSTANCE.get(mLauncher).setNavBarButtonAlpha(navBarAlpha, false);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
new file mode 100644
index 0000000000..e42f83de6a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import androidx.annotation.IntDef;
+
+import com.android.quickstep.SystemUiProxy;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Normally Taskbar will auto-hide when entering immersive (fullscreen) apps. This controller allows
+ * us to suspend that behavior in certain cases (e.g. opening a Folder or dragging an icon).
+ */
+public class TaskbarAutohideSuspendController {
+
+ public static final int FLAG_AUTOHIDE_SUSPEND_FULLSCREEN = 1 << 0;
+ public static final int FLAG_AUTOHIDE_SUSPEND_DRAGGING = 1 << 1;
+ @IntDef(flag = true, value = {
+ FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
+ FLAG_AUTOHIDE_SUSPEND_DRAGGING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AutohideSuspendFlag {}
+
+ private final SystemUiProxy mSystemUiProxy;
+
+ private @AutohideSuspendFlag int mAutohideSuspendFlags = 0;
+
+ public TaskbarAutohideSuspendController(TaskbarActivityContext activity) {
+ mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
+ }
+
+ public void onDestroy() {
+ mSystemUiProxy.notifyTaskbarAutohideSuspend(false);
+ }
+
+ /**
+ * Adds or removes the given flag, then notifies system UI proxy whether to suspend auto-hide.
+ */
+ public void updateFlag(@AutohideSuspendFlag int flag, boolean enabled) {
+ if (enabled) {
+ mAutohideSuspendFlags |= flag;
+ } else {
+ mAutohideSuspendFlags &= ~flag;
+ }
+ mSystemUiProxy.notifyTaskbarAutohideSuspend(mAutohideSuspendFlags != 0);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
new file mode 100644
index 0000000000..c43fbf9b20
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.content.pm.ActivityInfo.Config;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.shared.rotation.RotationButtonController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Hosts various taskbar controllers to facilitate passing between one another.
+ */
+public class TaskbarControllers {
+
+ public final TaskbarActivityContext taskbarActivityContext;
+ public final TaskbarDragController taskbarDragController;
+ public final TaskbarNavButtonController navButtonController;
+ public final NavbarButtonsViewController navbarButtonsViewController;
+ public final RotationButtonController rotationButtonController;
+ public final TaskbarDragLayerController taskbarDragLayerController;
+ public final TaskbarScrimViewController taskbarScrimViewController;
+ public final TaskbarViewController taskbarViewController;
+ public final TaskbarUnfoldAnimationController taskbarUnfoldAnimationController;
+ public final TaskbarKeyguardController taskbarKeyguardController;
+ public final StashedHandleViewController stashedHandleViewController;
+ public final TaskbarStashController taskbarStashController;
+ public final TaskbarEduController taskbarEduController;
+ public final TaskbarAutohideSuspendController taskbarAutohideSuspendController;
+ public final TaskbarPopupController taskbarPopupController;
+
+ /** Do not store this controller, as it may change at runtime. */
+ @NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
+
+ private boolean mAreAllControllersInitialized;
+ private final List mPostInitCallbacks = new ArrayList<>();
+
+ public TaskbarControllers(TaskbarActivityContext taskbarActivityContext,
+ TaskbarDragController taskbarDragController,
+ TaskbarNavButtonController navButtonController,
+ NavbarButtonsViewController navbarButtonsViewController,
+ RotationButtonController rotationButtonController,
+ TaskbarDragLayerController taskbarDragLayerController,
+ TaskbarViewController taskbarViewController,
+ TaskbarScrimViewController taskbarScrimViewController,
+ TaskbarUnfoldAnimationController taskbarUnfoldAnimationController,
+ TaskbarKeyguardController taskbarKeyguardController,
+ StashedHandleViewController stashedHandleViewController,
+ TaskbarStashController taskbarStashController,
+ TaskbarEduController taskbarEduController,
+ TaskbarAutohideSuspendController taskbarAutoHideSuspendController,
+ TaskbarPopupController taskbarPopupController) {
+ this.taskbarActivityContext = taskbarActivityContext;
+ this.taskbarDragController = taskbarDragController;
+ this.navButtonController = navButtonController;
+ this.navbarButtonsViewController = navbarButtonsViewController;
+ this.rotationButtonController = rotationButtonController;
+ this.taskbarDragLayerController = taskbarDragLayerController;
+ this.taskbarViewController = taskbarViewController;
+ this.taskbarScrimViewController = taskbarScrimViewController;
+ this.taskbarUnfoldAnimationController = taskbarUnfoldAnimationController;
+ this.taskbarKeyguardController = taskbarKeyguardController;
+ this.stashedHandleViewController = stashedHandleViewController;
+ this.taskbarStashController = taskbarStashController;
+ this.taskbarEduController = taskbarEduController;
+ this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController;
+ this.taskbarPopupController = taskbarPopupController;
+ }
+
+ /**
+ * Initializes all controllers. Note that controllers can now reference each other through this
+ * TaskbarControllers instance, but should be careful to only access things that were created
+ * in constructors for now, as some controllers may still be waiting for init().
+ */
+ public void init(TaskbarSharedState sharedState) {
+ mAreAllControllersInitialized = false;
+
+ taskbarDragController.init(this);
+ navbarButtonsViewController.init(this);
+ rotationButtonController.init();
+ taskbarDragLayerController.init(this);
+ taskbarViewController.init(this);
+ taskbarScrimViewController.init(this);
+ taskbarUnfoldAnimationController.init(this);
+ taskbarKeyguardController.init(navbarButtonsViewController);
+ stashedHandleViewController.init(this);
+ taskbarStashController.init(this, sharedState);
+ taskbarEduController.init(this);
+
+ mAreAllControllersInitialized = true;
+ for (Runnable postInitCallback : mPostInitCallbacks) {
+ postInitCallback.run();
+ }
+ mPostInitCallbacks.clear();
+ }
+
+ public void onConfigurationChanged(@Config int configChanges) {
+ navbarButtonsViewController.onConfigurationChanged(configChanges);
+ }
+
+ /**
+ * Cleans up all controllers.
+ */
+ public void onDestroy() {
+ navbarButtonsViewController.onDestroy();
+ uiController.onDestroy();
+ rotationButtonController.onDestroy();
+ taskbarDragLayerController.onDestroy();
+ taskbarKeyguardController.onDestroy();
+ taskbarUnfoldAnimationController.onDestroy();
+ taskbarViewController.onDestroy();
+ stashedHandleViewController.onDestroy();
+ taskbarAutohideSuspendController.onDestroy();
+ }
+
+ /**
+ * If all controllers are already initialized, runs the given callback immediately. Otherwise,
+ * queues it to run after calling init() on all controllers. This should likely be used in any
+ * case where one controller is telling another controller to do something inside init().
+ */
+ public void runAfterInit(Runnable callback) {
+ if (mAreAllControllersInitialized) {
+ callback.run();
+ } else {
+ mPostInitCallbacks.add(callback);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index ee44927ce4..b3a9f8db7c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -15,25 +15,42 @@
*/
package com.android.launcher3.taskbar;
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-
import android.content.ClipData;
import android.content.ClipDescription;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.view.DragEvent;
+import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.InstanceIdSequence;
+import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
+import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragDriver;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.graphics.DragPreviewProvider;
+import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ClipDescriptionCompat;
import com.android.systemui.shared.system.LauncherAppsCompat;
@@ -41,52 +58,213 @@ import com.android.systemui.shared.system.LauncherAppsCompat;
/**
* Handles long click on Taskbar items to start a system drag and drop operation.
*/
-public class TaskbarDragController {
+public class TaskbarDragController extends DragController {
- private final Context mContext;
private final int mDragIconSize;
+ private final int[] mTempXY = new int[2];
- public TaskbarDragController(Context context) {
- mContext = context;
- Resources resources = mContext.getResources();
+ // Initialized in init.
+ TaskbarControllers mControllers;
+
+ // Where the initial touch was relative to the dragged icon.
+ private int mRegistrationX;
+ private int mRegistrationY;
+
+ private boolean mIsSystemDragInProgress;
+
+ public TaskbarDragController(TaskbarActivityContext activity) {
+ super(activity);
+ Resources resources = mActivity.getResources();
mDragIconSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_drag_icon_size);
}
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ }
+
/**
* Attempts to start a system drag and drop operation for the given View, using its tag to
* generate the ClipDescription and Intent.
* @return Whether {@link View#startDragAndDrop} started successfully.
*/
- protected boolean startSystemDragOnLongClick(View view) {
+ protected boolean startDragOnLongClick(View view) {
if (!(view instanceof BubbleTextView)) {
return false;
}
BubbleTextView btv = (BubbleTextView) view;
- View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view) {
+
+ mActivity.setTaskbarWindowFullscreen(true);
+ btv.post(() -> {
+ startInternalDrag(btv);
+ btv.getIcon().setIsDisabled(true);
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, true);
+ });
+ return true;
+ }
+
+ private void startInternalDrag(BubbleTextView btv) {
+ float iconScale = btv.getIcon().getAnimatedScale();
+
+ // Clear the pressed state if necessary
+ btv.clearFocus();
+ btv.setPressed(false);
+ btv.clearPressedBackground();
+
+ final DragPreviewProvider previewProvider = new DragPreviewProvider(btv);
+ final Drawable drawable = previewProvider.createDrawable();
+ final float scale = previewProvider.getScaleAndPosition(drawable, mTempXY);
+ int dragLayerX = mTempXY[0];
+ int dragLayerY = mTempXY[1];
+
+ Rect dragRect = new Rect();
+ btv.getSourceVisualDragBounds(dragRect);
+ 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;
+ }
+ };
+ if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()) {
+ PopupContainerWithArrow popupContainer =
+ mControllers.taskbarPopupController.showForIcon(btv);
+ if (popupContainer != null) {
+ dragOptions.preDragCondition = popupContainer.createPreDragCondition();
+ }
+ }
+
+ startDrag(
+ drawable,
+ /* view = */ null,
+ /* originalView = */ btv,
+ dragLayerX,
+ dragLayerY,
+ (View target, DropTarget.DragObject d, boolean success) -> {} /* DragSource */,
+ (WorkspaceItemInfo) btv.getTag(),
+ /* dragVisualizeOffset = */ null,
+ dragRect,
+ scale * iconScale,
+ scale,
+ dragOptions);
+ }
+
+ @Override
+ protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view,
+ DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source,
+ ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale,
+ float dragViewScaleOnDrop, DragOptions options) {
+ mOptions = options;
+
+ mRegistrationX = mMotionDown.x - dragLayerX;
+ mRegistrationY = mMotionDown.y - dragLayerY;
+
+ final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
+ final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
+
+ mLastDropTarget = null;
+
+ mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext());
+ mDragObject.originalView = originalView;
+ mDragObject.deferDragViewCleanupPostAnimation = false;
+
+ mIsInPreDrag = mOptions.preDragCondition != null
+ && !mOptions.preDragCondition.shouldStartDrag(0);
+
+ float scalePx = mDragIconSize - dragRegion.width();
+ final DragView dragView = mDragObject.dragView = new TaskbarDragView(
+ mActivity,
+ drawable,
+ mRegistrationX,
+ mRegistrationY,
+ initialDragViewScale,
+ dragViewScaleOnDrop,
+ scalePx);
+ dragView.setItemInfo(dragInfo);
+ mDragObject.dragComplete = false;
+
+ mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft);
+ mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop);
+
+ mDragDriver = DragDriver.create(this, mOptions, /* secondaryEventConsumer = */ ev -> {});
+ if (!mOptions.isAccessibleDrag) {
+ mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
+ }
+
+ mDragObject.dragSource = source;
+ mDragObject.dragInfo = dragInfo;
+ mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
+
+ if (dragRegion != null) {
+ dragView.setDragRegion(new Rect(dragRegion));
+ }
+
+ dragView.show(mLastTouch.x, mLastTouch.y);
+ mDistanceSinceScroll = 0;
+
+ if (!mIsInPreDrag) {
+ callOnDragStart();
+ } else if (mOptions.preDragCondition != null) {
+ mOptions.preDragCondition.onPreDragStart(mDragObject);
+ }
+
+ handleMoveEvent(mLastTouch.x, mLastTouch.y);
+
+ return dragView;
+ }
+
+ @Override
+ protected void callOnDragStart() {
+ super.callOnDragStart();
+ // Pre-drag has ended, start the global system drag.
+ AbstractFloatingView.closeAllOpenViews(mActivity);
+ startSystemDrag((BubbleTextView) mDragObject.originalView);
+ }
+
+ private void startSystemDrag(BubbleTextView btv) {
+ View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(btv) {
+
@Override
public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
shadowSize.set(mDragIconSize, mDragIconSize);
- // TODO: should be based on last touch point on the icon.
- shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y / 2);
+ // The registration point was taken before the icon scaled to mDragIconSize, so
+ // offset the registration to where the touch is on the new size.
+ int offsetX = (mDragIconSize - mDragObject.dragView.getDragRegionWidth()) / 2;
+ int offsetY = (mDragIconSize - mDragObject.dragView.getDragRegionHeight()) / 2;
+ shadowTouchPoint.set(mRegistrationX + offsetX, mRegistrationY + offsetY);
}
@Override
public void onDrawShadow(Canvas canvas) {
canvas.save();
- float scale = (float) mDragIconSize / btv.getIconSize();
+ float scale = mDragObject.dragView.getScaleX();
canvas.scale(scale, scale);
- btv.getIcon().draw(canvas);
+ mDragObject.dragView.draw(canvas);
canvas.restore();
}
};
- Object tag = view.getTag();
+ Object tag = btv.getTag();
ClipDescription clipDescription = null;
Intent intent = null;
if (tag instanceof WorkspaceItemInfo) {
WorkspaceItemInfo item = (WorkspaceItemInfo) tag;
- LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
+ LauncherApps launcherApps = mActivity.getSystemService(LauncherApps.class);
clipDescription = new ClipDescription(item.title,
new String[] {
item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
@@ -115,29 +293,97 @@ public class TaskbarDragController {
}
if (clipDescription != null && intent != null) {
+ // Need to share the same InstanceId between launcher3 and WM Shell (internal).
+ InstanceId internalInstanceId = new InstanceIdSequence(
+ com.android.launcher3.logging.InstanceId.INSTANCE_ID_MAX).newInstanceId();
+ com.android.launcher3.logging.InstanceId launcherInstanceId =
+ new com.android.launcher3.logging.InstanceId(internalInstanceId.getId());
+
+ intent.putExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID, internalInstanceId);
+
ClipData clipData = new ClipData(clipDescription, new ClipData.Item(intent));
- view.setOnDragListener(getDraggedViewDragListener());
- return view.startDragAndDrop(clipData, shadowBuilder, null /* localState */,
- View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE);
+ if (btv.startDragAndDrop(clipData, shadowBuilder, null /* localState */,
+ View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_OPAQUE)) {
+ onSystemDragStarted();
+
+ mActivity.getStatsLogManager().logger().withItemInfo(mDragObject.dragInfo)
+ .withInstanceId(launcherInstanceId)
+ .log(StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED);
+ }
}
- return false;
}
- /**
- * Hide the original Taskbar item while it is being dragged.
- */
- private View.OnDragListener getDraggedViewDragListener() {
- return (view, dragEvent) -> {
+ private void onSystemDragStarted() {
+ mIsSystemDragInProgress = true;
+ mActivity.getDragLayer().setOnDragListener((view, dragEvent) -> {
switch (dragEvent.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
- view.setVisibility(INVISIBLE);
+ // Return true to tell system we are interested in events, so we get DRAG_ENDED.
return true;
case DragEvent.ACTION_DRAG_ENDED:
- view.setVisibility(VISIBLE);
- view.setOnDragListener(null);
+ mIsSystemDragInProgress = false;
+ maybeOnDragEnd();
return true;
}
return false;
- };
+ });
+ }
+
+ @Override
+ public boolean isDragging() {
+ return super.isDragging() || mIsSystemDragInProgress;
+ }
+
+ private void maybeOnDragEnd() {
+ if (!isDragging()) {
+ ((BubbleTextView) mDragObject.originalView).getIcon().setIsDisabled(false);
+ mControllers.taskbarAutohideSuspendController.updateFlag(
+ TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, false);
+ }
+ }
+
+ @Override
+ protected void callOnDragEnd() {
+ super.callOnDragEnd();
+ maybeOnDragEnd();
+ }
+
+ @Override
+ protected float getX(MotionEvent ev) {
+ // We will resize to fill the screen while dragging, so use screen coordinates. This ensures
+ // we start at the correct position even though touch down is on the smaller DragLayer size.
+ return ev.getRawX();
+ }
+
+ @Override
+ protected float getY(MotionEvent ev) {
+ // We will resize to fill the screen while dragging, so use screen coordinates. This ensures
+ // we start at the correct position even though touch down is on the smaller DragLayer size.
+ return ev.getRawY();
+ }
+
+ @Override
+ protected Point getClampedDragLayerPos(float x, float y) {
+ // No need to clamp, as we will take up the entire screen.
+ mTmpPoint.set(Math.round(x), Math.round(y));
+ return mTmpPoint;
+ }
+
+ @Override
+ protected void exitDrag() {
+ if (mDragObject != null) {
+ mActivity.getDragLayer().removeView(mDragObject.dragView);
+ }
+ }
+
+ @Override
+ public void addDropTarget(DropTarget target) {
+ // No-op as Taskbar currently doesn't support any drop targets internally.
+ // Note: if we do add internal DropTargets, we'll still need to ignore Folder.
+ }
+
+ @Override
+ protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
+ return null;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 45ec911527..b42a60ceea 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -18,14 +18,17 @@ package com.android.launcher3.taskbar;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
-import android.graphics.Rect;
+import android.graphics.Path;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
import com.android.systemui.shared.system.ViewTreeObserverWrapper;
@@ -37,14 +40,16 @@ import com.android.systemui.shared.system.ViewTreeObserverWrapper.OnComputeInset
*/
public class TaskbarDragLayer extends BaseDragLayer {
- private final int mFolderMargin;
private final Paint mTaskbarBackgroundPaint;
-
- private TaskbarIconController.Callbacks mControllerCallbacks;
- private TaskbarView mTaskbarView;
-
+ private final Path mInvertedLeftCornerPath, mInvertedRightCornerPath;
private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets;
+ // Initialized in init.
+ private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks;
+ private float mLeftCornerRadius, mRightCornerRadius;
+
+ private float mTaskbarBackgroundOffset;
+
public TaskbarDragLayer(@NonNull Context context) {
this(context, null);
}
@@ -61,25 +66,47 @@ public class TaskbarDragLayer extends BaseDragLayer {
public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, 1 /* alphaChannelCount */);
- mFolderMargin = getResources().getDimensionPixelSize(R.dimen.taskbar_folder_margin);
mTaskbarBackgroundPaint = new Paint();
mTaskbarBackgroundPaint.setColor(getResources().getColor(R.color.taskbar_background));
+ mTaskbarBackgroundPaint.setAlpha(0);
+ mTaskbarBackgroundPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+ mTaskbarBackgroundPaint.setStyle(Paint.Style.FILL);
+
+ // Will be set in init(), but this ensures they are always non-null.
+ mInvertedLeftCornerPath = new Path();
+ mInvertedRightCornerPath = new Path();
+ }
+
+ public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
+ mControllerCallbacks = callbacks;
+
+ // Create the paths for the inverted rounded corners above the taskbar. Start with a filled
+ // square, and then subtracting out a circle from the appropriate corner.
+ mLeftCornerRadius = mActivity.getLeftCornerRadius();
+ mRightCornerRadius = mActivity.getRightCornerRadius();
+ Path square = new Path();
+ square.addRect(0, 0, mLeftCornerRadius, mLeftCornerRadius, Path.Direction.CW);
+ Path circle = new Path();
+ circle.addCircle(mLeftCornerRadius, 0, mLeftCornerRadius, Path.Direction.CW);
+ mInvertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE);
+ square.reset();
+ square.addRect(0, 0, mRightCornerRadius, mRightCornerRadius, Path.Direction.CW);
+ circle.reset();
+ circle.addCircle(0, 0, mRightCornerRadius, Path.Direction.CW);
+ mInvertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE);
+
recreateControllers();
}
@Override
public void recreateControllers() {
- mControllers = new TouchController[0];
- }
-
- public void init(TaskbarIconController.Callbacks callbacks, TaskbarView taskbarView) {
- mControllerCallbacks = callbacks;
- mTaskbarView = taskbarView;
+ mControllers = new TouchController[] {mActivity.getDragController()};
}
private void onComputeTaskbarInsets(InsetsInfo insetsInfo) {
if (mControllerCallbacks != null) {
mControllerCallbacks.updateInsetsTouchability(insetsInfo);
+ mControllerCallbacks.updateContentInsets(insetsInfo.contentInsets);
}
}
@@ -108,12 +135,6 @@ public class TaskbarDragLayer extends BaseDragLayer {
return true;
}
- public void updateImeBarVisibilityAlpha(float alpha) {
- if (mControllerCallbacks != null) {
- mControllerCallbacks.updateImeBarVisibilityAlpha(alpha);
- }
- }
-
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
@@ -124,21 +145,25 @@ public class TaskbarDragLayer extends BaseDragLayer {
@Override
protected void dispatchDraw(Canvas canvas) {
- canvas.drawRect(0, canvas.getHeight() - mTaskbarView.getHeight(), canvas.getWidth(),
- canvas.getHeight(), mTaskbarBackgroundPaint);
+ float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight()
+ * (1f - mTaskbarBackgroundOffset);
+ canvas.save();
+ canvas.translate(0, canvas.getHeight() - backgroundHeight);
+
+ // Draw the background behind taskbar content.
+ canvas.drawRect(0, 0, canvas.getWidth(), backgroundHeight, mTaskbarBackgroundPaint);
+
+ // Draw the inverted rounded corners above the taskbar.
+ canvas.translate(0, -mLeftCornerRadius);
+ canvas.drawPath(mInvertedLeftCornerPath, mTaskbarBackgroundPaint);
+ canvas.translate(0, mLeftCornerRadius);
+ canvas.translate(canvas.getWidth() - mRightCornerRadius, -mRightCornerRadius);
+ canvas.drawPath(mInvertedRightCornerPath, mTaskbarBackgroundPaint);
+
+ canvas.restore();
super.dispatchDraw(canvas);
}
- /**
- * @return Bounds (in our coordinates) where an opened Folder can display.
- */
- protected Rect getFolderBoundingBox() {
- Rect boundingBox = new Rect(0, 0, getWidth(), getHeight() - mTaskbarView.getHeight());
- boundingBox.inset(mFolderMargin, mFolderMargin);
- return boundingBox;
- }
-
-
/**
* Sets the alpha of the background color behind all the Taskbar contents.
* @param alpha 0 is fully transparent, 1 is fully opaque.
@@ -147,4 +172,19 @@ public class TaskbarDragLayer extends BaseDragLayer {
mTaskbarBackgroundPaint.setAlpha((int) (alpha * 255));
invalidate();
}
+
+ /**
+ * Sets the translation of the background color behind all the Taskbar contents.
+ * @param offset 0 is fully onscreen, 1 is fully offscreen.
+ */
+ protected void setTaskbarBackgroundOffset(float offset) {
+ mTaskbarBackgroundOffset = offset;
+ invalidate();
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
+ return super.dispatchTouchEvent(ev);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
new file mode 100644
index 0000000000..a918016cc6
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_CONTENT;
+import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
+import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
+
+import android.content.res.Resources;
+import android.graphics.Rect;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.AlphaUpdateListener;
+import com.android.quickstep.AnimatedFloat;
+import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
+
+/**
+ * Handles properties/data collection, then passes the results to TaskbarDragLayer to render.
+ */
+public class TaskbarDragLayerController {
+
+ private final TaskbarActivityContext mActivity;
+ private final TaskbarDragLayer mTaskbarDragLayer;
+ private final int mFolderMargin;
+
+ // 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);
+ private final AnimatedFloat mNotificationShadeBgTaskbar = new AnimatedFloat(
+ this::updateBackgroundAlpha);
+ private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
+ // Used to hide our background color when someone else (e.g. ScrimView) is handling it.
+ private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha);
+
+ // Translation property for taskbar background.
+ private final AnimatedFloat mBgOffset = new AnimatedFloat(this::updateBackgroundOffset);
+
+ // Initialized in init.
+ private TaskbarControllers mControllers;
+ private AnimatedFloat mNavButtonDarkIntensityMultiplier;
+
+ private float mLastSetBackgroundAlpha;
+
+ public TaskbarDragLayerController(TaskbarActivityContext activity,
+ TaskbarDragLayer taskbarDragLayer) {
+ mActivity = activity;
+ mTaskbarDragLayer = taskbarDragLayer;
+ final Resources resources = mTaskbarDragLayer.getResources();
+ mFolderMargin = resources.getDimensionPixelSize(R.dimen.taskbar_folder_margin);
+ }
+
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ mTaskbarDragLayer.init(new TaskbarDragLayerCallbacks());
+
+ mNavButtonDarkIntensityMultiplier = mControllers.navbarButtonsViewController
+ .getNavButtonDarkIntensityMultiplier();
+
+ mBgTaskbar.value = 1;
+ mKeyguardBgTaskbar.value = 1;
+ mNotificationShadeBgTaskbar.value = 1;
+ mImeBgTaskbar.value = 1;
+ mBgOverride.value = 1;
+ updateBackgroundAlpha();
+ }
+
+ public void onDestroy() {
+ mTaskbarDragLayer.onDestroy();
+ }
+
+ /**
+ * @return Bounds (in TaskbarDragLayer coordinates) where an opened Folder can display.
+ */
+ public Rect getFolderBoundingBox() {
+ Rect boundingBox = new Rect(0, 0, mTaskbarDragLayer.getWidth(),
+ mTaskbarDragLayer.getHeight() - mActivity.getDeviceProfile().taskbarSize);
+ boundingBox.inset(mFolderMargin, mFolderMargin);
+ return boundingBox;
+ }
+
+ public AnimatedFloat getTaskbarBackgroundAlpha() {
+ return mBgTaskbar;
+ }
+
+ public AnimatedFloat getNavbarBackgroundAlpha() {
+ return mBgNavbar;
+ }
+
+ public AnimatedFloat getKeyguardBgTaskbar() {
+ return mKeyguardBgTaskbar;
+ }
+
+ public AnimatedFloat getNotificationShadeBgTaskbar() {
+ return mNotificationShadeBgTaskbar;
+ }
+
+ public AnimatedFloat getImeBgTaskbar() {
+ return mImeBgTaskbar;
+ }
+
+ public AnimatedFloat getOverrideBackgroundAlpha() {
+ return mBgOverride;
+ }
+
+ public AnimatedFloat getTaskbarBackgroundOffset() {
+ return mBgOffset;
+ }
+
+ private void updateBackgroundAlpha() {
+ final float bgNavbar = mBgNavbar.value;
+ final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
+ * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value;
+ mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar);
+ mTaskbarDragLayer.setTaskbarBackgroundAlpha(mLastSetBackgroundAlpha);
+
+ updateNavBarDarkIntensityMultiplier();
+ }
+
+ private void updateBackgroundOffset() {
+ mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value);
+
+ updateNavBarDarkIntensityMultiplier();
+ }
+
+ private void updateNavBarDarkIntensityMultiplier() {
+ // Zero out the app-requested dark intensity when we're drawing our own background.
+ float effectiveBgAlpha = mLastSetBackgroundAlpha * (1 - mBgOffset.value);
+ mNavButtonDarkIntensityMultiplier.updateValue(1 - effectiveBgAlpha);
+ }
+
+ /**
+ * Callbacks for {@link TaskbarDragLayer} to interact with its controller.
+ */
+ public class TaskbarDragLayerCallbacks {
+
+ /**
+ * Called to update the touchable insets.
+ * @see InsetsInfo#setTouchableInsets(int)
+ */
+ public void updateInsetsTouchability(InsetsInfo insetsInfo) {
+ insetsInfo.touchableRegion.setEmpty();
+ // Always have nav buttons be touchable
+ mControllers.navbarButtonsViewController.addVisibleButtonsRegion(
+ mTaskbarDragLayer, insetsInfo.touchableRegion);
+ boolean insetsIsTouchableRegion = true;
+
+ if (mTaskbarDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
+ // Let touches pass through us.
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+ } else if (mControllers.navbarButtonsViewController.isImeVisible()) {
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+ } else if (!mControllers.uiController.isTaskbarTouchable()) {
+ // Let touches pass through us.
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+ } else if (mControllers.taskbarViewController.areIconsVisible()
+ || AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) != null) {
+ // Taskbar has some touchable elements, take over the full taskbar area
+ insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen()
+ ? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT);
+ insetsIsTouchableRegion = false;
+ } else {
+ insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+ }
+ mActivity.excludeFromMagnificationRegion(insetsIsTouchableRegion);
+ }
+
+ /**
+ * Called to update the {@link InsetsInfo#contentInsets}. This is reported to apps but our
+ * internal launcher will ignore these insets.
+ */
+ public void updateContentInsets(Rect outContentInsets) {
+ int contentHeight = mControllers.taskbarStashController
+ .getContentHeightToReportToApps();
+ outContentInsets.top = mTaskbarDragLayer.getHeight() - contentHeight;
+ }
+
+ /**
+ * Called when a child is removed from TaskbarDragLayer.
+ */
+ public void onDragLayerViewRemoved() {
+ if (AbstractFloatingView.getAnyView(mActivity, TYPE_ALL) == null) {
+ mActivity.setTaskbarWindowFullscreen(false);
+ }
+ }
+
+ /**
+ * Returns how tall the background should be drawn at the bottom of the screen.
+ */
+ public int getTaskbarBackgroundHeight() {
+ return mActivity.getDeviceProfile().taskbarSize;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java
new file mode 100644
index 0000000000..cf28eff0c2
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragView.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.graphics.drawable.Drawable;
+
+import com.android.launcher3.R;
+import com.android.launcher3.dragndrop.DragView;
+
+/**
+ * A DragView drawn/used by the Taskbar. Note that this is only for the internal drag-and-drop,
+ * while the pre-drag is still in progress (i.e. when the long press popup is still open). After
+ * that ends, we switch to a system drag and drop view instead.
+ */
+public class TaskbarDragView extends DragView {
+ public TaskbarDragView(TaskbarActivityContext launcher, Drawable drawable, int registrationX,
+ int registrationY, float initialScale, float scaleOnDrop, float finalScaleDps) {
+ super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop,
+ finalScaleDps);
+ }
+
+ @Override
+ public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
+ Runnable onAnimationEnd = () -> {
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
+ mActivity.getDragLayer().removeView(this);
+ };
+
+ duration = Math.max(duration,
+ getResources().getInteger(R.integer.config_dropAnimMinDuration));
+
+ animate()
+ .translationX(toTouchX - mRegistrationX)
+ .translationY(toTouchY - mRegistrationY)
+ .scaleX(mScaleOnDrop)
+ .scaleY(mScaleOnDrop)
+ .withEndAction(onAnimationEnd)
+ .setDuration(duration)
+ .start();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
new file mode 100644
index 0000000000..fd5c2ea6b2
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.Keyframe;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.content.res.Resources;
+import android.text.TextUtils;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.uioverrides.PredictedAppIcon;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Handles the Taskbar Education flow. */
+public class TaskbarEduController {
+
+ private static final long WAVE_ANIM_DELAY = 250;
+ private static final long WAVE_ANIM_STAGGER = 50;
+ private static final long WAVE_ANIM_EACH_ICON_DURATION = 633;
+ private static final long WAVE_ANIM_SLOT_MACHINE_DURATION = 1085;
+ // The fraction of each icon's animation at which we reach the top point of the wave.
+ private static final float WAVE_ANIM_FRACTION_TOP = 0.4f;
+ // The fraction of each icon's animation at which we reach the bottom, before overshooting.
+ private static final float WAVE_ANIM_FRACTION_BOTTOM = 0.9f;
+ private static final TimeInterpolator WAVE_ANIM_TO_TOP_INTERPOLATOR = FAST_OUT_SLOW_IN;
+ private static final TimeInterpolator WAVE_ANIM_TO_BOTTOM_INTERPOLATOR = ACCEL_2;
+ private static final TimeInterpolator WAVE_ANIM_OVERSHOOT_INTERPOLATOR = DEACCEL;
+ private static final TimeInterpolator WAVE_ANIM_OVERSHOOT_RETURN_INTERPOLATOR = ACCEL_DEACCEL;
+ private static final float WAVE_ANIM_ICON_SCALE = 1.2f;
+ // How many icons to cycle through in the slot machine (+ the original icon at each end).
+ private static final int WAVE_ANIM_SLOT_MACHINE_NUM_ICONS = 3;
+
+ private final TaskbarActivityContext mActivity;
+ private final float mWaveAnimTranslationY;
+ private final float mWaveAnimTranslationYReturnOvershoot;
+
+ // Initialized in init.
+ TaskbarControllers mControllers;
+
+ private TaskbarEduView mTaskbarEduView;
+ private Animator mAnim;
+
+ public TaskbarEduController(TaskbarActivityContext activity) {
+ mActivity = activity;
+
+ final Resources resources = activity.getResources();
+ mWaveAnimTranslationY = resources.getDimension(R.dimen.taskbar_edu_wave_anim_trans_y);
+ mWaveAnimTranslationYReturnOvershoot = resources.getDimension(
+ R.dimen.taskbar_edu_wave_anim_trans_y_return_overshoot);
+ }
+
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ }
+
+ void showEdu() {
+ mActivity.setTaskbarWindowFullscreen(true);
+ mActivity.getDragLayer().post(() -> {
+ mTaskbarEduView = (TaskbarEduView) mActivity.getLayoutInflater().inflate(
+ R.layout.taskbar_edu, mActivity.getDragLayer(), false);
+ mTaskbarEduView.init(new TaskbarEduCallbacks());
+ mTaskbarEduView.addOnCloseListener(() -> mTaskbarEduView = null);
+ mTaskbarEduView.show();
+ startAnim(createWaveAnim());
+ });
+ }
+
+ void hideEdu() {
+ if (mTaskbarEduView != null) {
+ mTaskbarEduView.close(true /* animate */);
+ }
+ }
+
+ /**
+ * Starts the given animation, ending the previous animation first if it's still playing.
+ */
+ private void startAnim(Animator anim) {
+ if (mAnim != null) {
+ mAnim.end();
+ }
+ mAnim = anim;
+ mAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnim = null;
+ }
+ });
+ mAnim.start();
+ }
+
+ /**
+ * Creates a staggered "wave" animation where each icon translates and scales up in succession.
+ */
+ private Animator createWaveAnim() {
+ AnimatorSet waveAnim = new AnimatorSet();
+ View[] icons = mControllers.taskbarViewController.getIconViews();
+ for (int i = 0; i < icons.length; i++) {
+ View icon = icons[i];
+ AnimatorSet iconAnim = new AnimatorSet();
+
+ Keyframe[] scaleKeyframes = new Keyframe[] {
+ Keyframe.ofFloat(0, 1f),
+ Keyframe.ofFloat(WAVE_ANIM_FRACTION_TOP, WAVE_ANIM_ICON_SCALE),
+ Keyframe.ofFloat(WAVE_ANIM_FRACTION_BOTTOM, 1f),
+ Keyframe.ofFloat(1f, 1f)
+ };
+ scaleKeyframes[1].setInterpolator(WAVE_ANIM_TO_TOP_INTERPOLATOR);
+ scaleKeyframes[2].setInterpolator(WAVE_ANIM_TO_BOTTOM_INTERPOLATOR);
+
+ Keyframe[] translationYKeyframes = new Keyframe[] {
+ Keyframe.ofFloat(0, 0f),
+ Keyframe.ofFloat(WAVE_ANIM_FRACTION_TOP, -mWaveAnimTranslationY),
+ Keyframe.ofFloat(WAVE_ANIM_FRACTION_BOTTOM, 0f),
+ // Half of the remaining fraction overshoots, then the other half returns to 0.
+ Keyframe.ofFloat(
+ WAVE_ANIM_FRACTION_BOTTOM + (1 - WAVE_ANIM_FRACTION_BOTTOM) / 2f,
+ mWaveAnimTranslationYReturnOvershoot),
+ Keyframe.ofFloat(1f, 0f)
+ };
+ translationYKeyframes[1].setInterpolator(WAVE_ANIM_TO_TOP_INTERPOLATOR);
+ translationYKeyframes[2].setInterpolator(WAVE_ANIM_TO_BOTTOM_INTERPOLATOR);
+ translationYKeyframes[3].setInterpolator(WAVE_ANIM_OVERSHOOT_INTERPOLATOR);
+ translationYKeyframes[4].setInterpolator(WAVE_ANIM_OVERSHOOT_RETURN_INTERPOLATOR);
+
+ iconAnim.play(ObjectAnimator.ofPropertyValuesHolder(icon,
+ PropertyValuesHolder.ofKeyframe(SCALE_PROPERTY, scaleKeyframes))
+ .setDuration(WAVE_ANIM_EACH_ICON_DURATION));
+ iconAnim.play(ObjectAnimator.ofPropertyValuesHolder(icon,
+ PropertyValuesHolder.ofKeyframe(View.TRANSLATION_Y, translationYKeyframes))
+ .setDuration(WAVE_ANIM_EACH_ICON_DURATION));
+
+ if (icon instanceof PredictedAppIcon) {
+ // Play slot machine animation through random icons from AllAppsList.
+ PredictedAppIcon predictedAppIcon = (PredictedAppIcon) icon;
+ ItemInfo itemInfo = (ItemInfo) icon.getTag();
+ List iconsToAnimate = mControllers.uiController.getAppIconsForEdu()
+ .filter(appInfo -> !TextUtils.equals(appInfo.title, itemInfo.title))
+ .map(appInfo -> appInfo.bitmap)
+ .filter(bitmap -> !bitmap.isNullOrLowRes())
+ .collect(Collectors.toList());
+ // Pick n icons at random.
+ Collections.shuffle(iconsToAnimate);
+ if (iconsToAnimate.size() > WAVE_ANIM_SLOT_MACHINE_NUM_ICONS) {
+ iconsToAnimate = iconsToAnimate.subList(0, WAVE_ANIM_SLOT_MACHINE_NUM_ICONS);
+ }
+ Animator slotMachineAnim = predictedAppIcon.createSlotMachineAnim(iconsToAnimate);
+ if (slotMachineAnim != null) {
+ iconAnim.play(slotMachineAnim.setDuration(WAVE_ANIM_SLOT_MACHINE_DURATION));
+ }
+ }
+
+ iconAnim.setStartDelay(WAVE_ANIM_STAGGER * i);
+ waveAnim.play(iconAnim);
+ }
+ waveAnim.setStartDelay(WAVE_ANIM_DELAY);
+ return waveAnim;
+ }
+
+ /**
+ * Callbacks for {@link TaskbarEduView} to interact with its controller.
+ */
+ class TaskbarEduCallbacks {
+ void onPageChanged(int currentPage, int pageCount) {
+ if (currentPage == 0) {
+ mTaskbarEduView.updateStartButton(R.string.taskbar_edu_close,
+ v -> mTaskbarEduView.close(true /* animate */));
+ } else {
+ mTaskbarEduView.updateStartButton(R.string.taskbar_edu_previous,
+ v -> mTaskbarEduView.snapToPage(currentPage - 1));
+ }
+ if (currentPage == pageCount - 1) {
+ mTaskbarEduView.updateEndButton(R.string.taskbar_edu_done,
+ v -> mTaskbarEduView.close(true /* animate */));
+ } else {
+ mTaskbarEduView.updateEndButton(R.string.taskbar_edu_next,
+ v -> mTaskbarEduView.snapToPage(currentPage + 1));
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java
new file mode 100644
index 0000000000..5efcc4df4c
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduPagedView.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_EDUCATION_DIALOG;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.R;
+import com.android.launcher3.pageindicators.PageIndicatorDots;
+import com.android.launcher3.taskbar.TaskbarEduController.TaskbarEduCallbacks;
+import com.android.launcher3.views.ActivityContext;
+
+/** Horizontal carousel of tutorial screens for Taskbar Edu. */
+public class TaskbarEduPagedView extends PagedView {
+
+ private TaskbarEduView mTaskbarEduView;
+ private TaskbarEduCallbacks mControllerCallbacks;
+
+ public TaskbarEduPagedView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ }
+
+ void setTaskbarEduView(TaskbarEduView taskbarEduView) {
+ mTaskbarEduView = taskbarEduView;
+ mPageIndicator = taskbarEduView.findViewById(R.id.content_page_indicator);
+ initParentViews(taskbarEduView);
+ }
+
+ void setControllerCallbacks(TaskbarEduCallbacks controllerCallbacks) {
+ mControllerCallbacks = controllerCallbacks;
+ mControllerCallbacks.onPageChanged(getCurrentPage(), getPageCount());
+ }
+
+ @Override
+ protected int getChildGap() {
+ return mTaskbarEduView.getPaddingLeft() + mTaskbarEduView.getPaddingRight();
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ if (mMaxScroll > 0) {
+ mPageIndicator.setScroll(l, mMaxScroll);
+ }
+ }
+
+ @Override
+ protected void notifyPageSwitchListener(int prevPage) {
+ super.notifyPageSwitchListener(prevPage);
+ mControllerCallbacks.onPageChanged(getCurrentPage(), getPageCount());
+ }
+
+ @Override
+ protected boolean canScroll(float absVScroll, float absHScroll) {
+ return AbstractFloatingView.getTopOpenViewWithType(
+ ActivityContext.lookupContext(getContext()),
+ TYPE_ALL & ~TYPE_TASKBAR_EDUCATION_DIALOG) == null;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
new file mode 100644
index 0000000000..8525427a64
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
+
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.launcher3.Insettable;
+import com.android.launcher3.R;
+import com.android.launcher3.views.AbstractSlideInView;
+
+/** Education view about the Taskbar. */
+public class TaskbarEduView extends AbstractSlideInView
+ implements Insettable {
+
+ private static final int DEFAULT_OPEN_DURATION = 500;
+ private static final int DEFAULT_CLOSE_DURATION = 200;
+
+ private final Rect mInsets = new Rect();
+
+ private Button mStartButton;
+ private Button mEndButton;
+ private TaskbarEduPagedView mPagedView;
+
+ public TaskbarEduView(Context context, AttributeSet attr) {
+ this(context, attr, 0);
+ }
+
+ public TaskbarEduView(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ protected void init(TaskbarEduController.TaskbarEduCallbacks callbacks) {
+ if (mPagedView != null) {
+ mPagedView.setControllerCallbacks(callbacks);
+ }
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ handleClose(animate, DEFAULT_CLOSE_DURATION);
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_TASKBAR_EDUCATION_DIALOG) != 0;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mContent = findViewById(R.id.edu_view);
+ mStartButton = findViewById(R.id.edu_start_button);
+ mEndButton = findViewById(R.id.edu_end_button);
+ mPagedView = findViewById(R.id.content);
+ mPagedView.setTaskbarEduView(this);
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ mInsets.set(insets);
+ mContent.setPadding(mContent.getPaddingStart(),
+ mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
+ }
+
+ @Override
+ protected void attachToContainer() {
+ if (mColorScrim != null) {
+ getPopupContainer().addView(mColorScrim, 0);
+ }
+ getPopupContainer().addView(this, 1);
+ }
+
+ /** Show the Education flow. */
+ public void show() {
+ attachToContainer();
+ animateOpen();
+ }
+
+ @Override
+ protected Pair getAccessibilityTarget() {
+ return Pair.create(mContent, mIsOpen ? getContext().getString(R.string.taskbar_edu_opened)
+ : getContext().getString(R.string.taskbar_edu_closed));
+ }
+
+ @Override
+ protected int getScrimColor(Context context) {
+ return context.getResources().getColor(R.color.widgets_picker_scrim);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int width = r - l;
+ int height = b - t;
+
+ // Lay out the content as center bottom aligned.
+ int contentWidth = mContent.getMeasuredWidth();
+ int contentLeft = (width - contentWidth - mInsets.left - mInsets.right) / 2 + mInsets.left;
+ mContent.layout(contentLeft, height - mContent.getMeasuredHeight(),
+ contentLeft + contentWidth, height);
+
+ setTranslationShift(mTranslationShift);
+ }
+
+ private void animateOpen() {
+ if (mIsOpen || mOpenCloseAnimator.isRunning()) {
+ return;
+ }
+ mIsOpen = true;
+ mOpenCloseAnimator.setValues(
+ PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+ mOpenCloseAnimator.setInterpolator(AGGRESSIVE_EASE);
+ mOpenCloseAnimator.setDuration(DEFAULT_OPEN_DURATION).start();
+ }
+
+ void snapToPage(int page) {
+ mPagedView.snapToPage(page);
+ }
+
+ void updateStartButton(int textResId, OnClickListener onClickListener) {
+ mStartButton.setText(textResId);
+ mStartButton.setOnClickListener(onClickListener);
+ }
+
+ void updateEndButton(int textResId, OnClickListener onClickListener) {
+ mEndButton.setText(textResId);
+ mEndButton.setOnClickListener(onClickListener);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java
deleted file mode 100644
index 91cf7efab5..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarHotseatController.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import android.view.View;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.CellLayout;
-import com.android.launcher3.DropTarget;
-import com.android.launcher3.Hotseat;
-import com.android.launcher3.ShortcutAndWidgetContainer;
-import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.model.data.ItemInfo;
-
-import java.util.function.Consumer;
-
-/**
- * Works with TaskbarController to update the TaskbarView's Hotseat items.
- */
-public class TaskbarHotseatController {
-
- private final BaseQuickstepLauncher mLauncher;
- private final Hotseat mHotseat;
- private final Consumer mTaskbarCallbacks;
- private final int mNumHotseatIcons;
-
- private final DragController.DragListener mDragListener = new DragController.DragListener() {
- @Override
- public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { }
-
- @Override
- public void onDragEnd() {
- onHotseatUpdated();
- }
- };
-
- public TaskbarHotseatController(
- BaseQuickstepLauncher launcher, Consumer taskbarCallbacks) {
- mLauncher = launcher;
- mHotseat = mLauncher.getHotseat();
- mTaskbarCallbacks = taskbarCallbacks;
- mNumHotseatIcons = mLauncher.getDeviceProfile().numShownHotseatIcons;
- }
-
- protected void init() {
- mLauncher.getDragController().addDragListener(mDragListener);
- onHotseatUpdated();
- }
-
- protected void cleanup() {
- mLauncher.getDragController().removeDragListener(mDragListener);
- }
-
- /**
- * Called when any Hotseat item changes, and reports the new list of items to TaskbarController.
- */
- protected void onHotseatUpdated() {
- ShortcutAndWidgetContainer shortcutsAndWidgets = mHotseat.getShortcutsAndWidgets();
- ItemInfo[] hotseatItemInfos = new ItemInfo[mNumHotseatIcons];
- for (int i = 0; i < shortcutsAndWidgets.getChildCount(); i++) {
- View child = shortcutsAndWidgets.getChildAt(i);
- Object tag = shortcutsAndWidgets.getChildAt(i).getTag();
- if (tag instanceof ItemInfo) {
- ItemInfo itemInfo = (ItemInfo) tag;
- CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
- // Since the hotseat might be laid out vertically or horizontally, use whichever
- // index is higher.
- int index = Math.max(lp.cellX, lp.cellY);
- if (0 <= index && index < hotseatItemInfos.length) {
- hotseatItemInfos[index] = itemInfo;
- }
- }
- }
-
- mTaskbarCallbacks.accept(hotseatItemInfos);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java
deleted file mode 100644
index 683a5b9fc4..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarIconController.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-
-import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
-import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
-
-import android.graphics.Rect;
-import android.inputmethodservice.InputMethodService;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
-
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.R;
-import com.android.launcher3.anim.AlphaUpdateListener;
-import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
-
-/**
- * Controller for taskbar icon UI
- */
-public class TaskbarIconController {
-
- private final Rect mTempRect = new Rect();
-
- private final TaskbarActivityContext mActivity;
- private final TaskbarDragLayer mDragLayer;
-
- private final TaskbarView mTaskbarView;
- private final ImeBarView mImeBarView;
-
- @NonNull
- private TaskbarUIController mUIController = TaskbarUIController.DEFAULT;
-
- TaskbarIconController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer) {
- mActivity = activity;
- mDragLayer = dragLayer;
- mTaskbarView = mDragLayer.findViewById(R.id.taskbar_view);
- mImeBarView = mDragLayer.findViewById(R.id.ime_bar_view);
- }
-
- public void init(OnClickListener clickListener, OnLongClickListener longClickListener) {
- mDragLayer.addOnLayoutChangeListener((v, a, b, c, d, e, f, g, h) ->
- mUIController.alignRealHotseatWithTaskbar());
-
- ButtonProvider buttonProvider = new ButtonProvider(mActivity);
- mImeBarView.init(buttonProvider);
- mTaskbarView.construct(clickListener, longClickListener, buttonProvider);
- mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize;
-
- mDragLayer.init(new Callbacks(), mTaskbarView);
- }
-
- public void onDestroy() {
- mDragLayer.onDestroy();
- }
-
- public void setUIController(@NonNull TaskbarUIController uiController) {
- mUIController = uiController;
- }
-
- /**
- * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
- * instantiating at all, which is what's responsible for sending sysui state flags over.
- *
- * @param vis IME visibility flag
- */
- public void updateImeStatus(int displayId, int vis, boolean showImeSwitcher) {
- if (displayId != mActivity.getDisplayId() || !mActivity.canShowNavButtons()) {
- return;
- }
-
- mImeBarView.setImeSwitcherVisibility(showImeSwitcher);
- setImeIsVisible((vis & InputMethodService.IME_VISIBLE) != 0);
- }
-
- /**
- * Should be called when the IME visibility changes, so we can hide/show Taskbar accordingly.
- */
- public void setImeIsVisible(boolean isImeVisible) {
- mTaskbarView.setTouchesEnabled(!isImeVisible);
- mUIController.onImeVisible(mDragLayer, isImeVisible);
- }
-
- /**
- * Callbacks for {@link TaskbarDragLayer} to interact with the icon controller
- */
- public class Callbacks {
-
- /**
- * Called to update the touchable insets
- */
- public void updateInsetsTouchability(InsetsInfo insetsInfo) {
- insetsInfo.touchableRegion.setEmpty();
- if (mDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
- // Let touches pass through us.
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (mImeBarView.getVisibility() == VISIBLE) {
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
- } else if (!mUIController.isTaskbarTouchable()) {
- // Let touches pass through us.
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- } else if (mTaskbarView.areIconsVisible()) {
- // Buttons are visible, take over the full taskbar area
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
- } else {
- if (mTaskbarView.mSystemButtonContainer.getVisibility() == VISIBLE) {
- mDragLayer.getDescendantRectRelativeToSelf(
- mTaskbarView.mSystemButtonContainer, mTempRect);
- insetsInfo.touchableRegion.set(mTempRect);
- }
- insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
- }
-
- // TaskbarContainerView provides insets to other apps based on contentInsets. These
- // insets should stay consistent even if we expand TaskbarContainerView's bounds, e.g.
- // to show a floating view like Folder. Thus, we set the contentInsets to be where
- // mTaskbarView is, since its position never changes and insets rather than overlays.
- insetsInfo.contentInsets.left = mTaskbarView.getLeft();
- insetsInfo.contentInsets.top = mTaskbarView.getTop();
- insetsInfo.contentInsets.right = mDragLayer.getWidth() - mTaskbarView.getRight();
- insetsInfo.contentInsets.bottom = mDragLayer.getHeight() - mTaskbarView.getBottom();
- }
-
- public void onDragLayerViewRemoved() {
- int count = mDragLayer.getChildCount();
- // Ensure no other children present (like Folders, etc)
- for (int i = 0; i < count; i++) {
- View v = mDragLayer.getChildAt(i);
- if (!((v instanceof TaskbarView) || (v instanceof ImeBarView))) {
- return;
- }
- }
- mActivity.setTaskbarWindowFullscreen(false);
- }
-
- public void updateImeBarVisibilityAlpha(float alpha) {
- if (!mActivity.canShowNavButtons()) {
- // TODO Remove sysui IME bar for gesture nav as well
- return;
- }
- mImeBarView.setAlpha(alpha);
- mImeBarView.setVisibility(alpha == 0 ? GONE : VISIBLE);
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
new file mode 100644
index 0000000000..5fc0695564
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -0,0 +1,98 @@
+package com.android.launcher3.taskbar;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
+
+import android.app.KeyguardManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+/**
+ * Controller for managing keyguard state for taskbar
+ */
+public class TaskbarKeyguardController {
+
+ private static final int KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING |
+ SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING |
+ SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED |
+ SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
+
+ private final TaskbarActivityContext mContext;
+ private int mKeyguardSysuiFlags;
+ private boolean mBouncerShowing;
+ private NavbarButtonsViewController mNavbarButtonsViewController;
+ private final KeyguardManager mKeyguardManager;
+ private boolean mIsScreenOff;
+
+ private final BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mIsScreenOff = true;
+ }
+ };
+
+ public TaskbarKeyguardController(TaskbarActivityContext context) {
+ mContext = context;
+ mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
+ }
+
+ public void init(NavbarButtonsViewController navbarButtonUIController) {
+ mNavbarButtonsViewController = navbarButtonUIController;
+ mContext.registerReceiver(mScreenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
+ }
+
+ public void updateStateForSysuiFlags(int systemUiStateFlags) {
+ boolean bouncerShowing = (systemUiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0;
+ boolean keyguardShowing = (systemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING)
+ != 0;
+ boolean keyguardOccluded =
+ (systemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0;
+ boolean dozing = (systemUiStateFlags & SYSUI_STATE_DEVICE_DOZING) != 0;
+
+ int interestingKeyguardFlags = systemUiStateFlags & KEYGUARD_SYSUI_FLAGS;
+ if (interestingKeyguardFlags == mKeyguardSysuiFlags) {
+ return;
+ }
+ mKeyguardSysuiFlags = interestingKeyguardFlags;
+
+ mBouncerShowing = bouncerShowing;
+
+ mNavbarButtonsViewController.setKeyguardVisible(keyguardShowing || dozing,
+ keyguardOccluded);
+ updateIconsForBouncer();
+ }
+
+ public boolean isScreenOff() {
+ return mIsScreenOff;
+ }
+
+ public void setScreenOn() {
+ mIsScreenOff = false;
+ }
+
+ /**
+ * Hides/shows taskbar when keyguard is up
+ */
+ private void updateIconsForBouncer() {
+ boolean disableBack = (mKeyguardSysuiFlags & SYSUI_STATE_BACK_DISABLED) != 0;
+ boolean disableRecent = (mKeyguardSysuiFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
+ boolean disableHome = (mKeyguardSysuiFlags & SYSUI_STATE_HOME_DISABLED) != 0;
+ boolean onlyBackEnabled = !disableBack && disableRecent && disableHome;
+
+ boolean showBackForBouncer = onlyBackEnabled &&
+ mKeyguardManager.isDeviceSecure() &&
+ mBouncerShowing;
+ mNavbarButtonsViewController.setBackForBouncer(showBackForBouncer);
+ }
+
+ public void onDestroy() {
+ mContext.unregisterReceiver(mScreenOffReceiver);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
new file mode 100644
index 0000000000..7a50d0bf63
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
+import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
+import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.RecentsAnimationController;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.HashMap;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Track LauncherState, RecentsAnimation, resumed state for task bar in one place here and animate
+ * the task bar accordingly.
+ */
+ public class TaskbarLauncherStateController {
+
+ public static final int FLAG_RESUMED = 1 << 0;
+ public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1;
+ public static final int FLAG_TRANSITION_STATE_RUNNING = 1 << 2;
+
+ /** Equivalent to an int with all 1s for binary operation purposes */
+ private static final int FLAGS_ALL = ~0;
+
+ private final AnimatedFloat mIconAlignmentForResumedState =
+ new AnimatedFloat(this::onIconAlignmentRatioChangedForAppAndHomeTransition);
+ private final AnimatedFloat mIconAlignmentForGestureState =
+ new AnimatedFloat(this::onIconAlignmentRatioChangedForAppAndHomeTransition);
+ private final AnimatedFloat mIconAlignmentForLauncherState =
+ new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition);
+
+ private TaskbarControllers mControllers;
+ private AnimatedFloat mTaskbarBackgroundAlpha;
+ private MultiValueAlpha.AlphaProperty mIconAlphaForHome;
+ private BaseQuickstepLauncher mLauncher;
+
+ private Integer mPrevState;
+ private int mState;
+ private LauncherState mLauncherState = LauncherState.NORMAL;
+
+ private boolean mIsAnimatingToLauncherViaGesture;
+ private boolean mIsAnimatingToLauncherViaResume;
+
+ private final StateManager.StateListener mStateListener =
+ new StateManager.StateListener() {
+
+ @Override
+ public void onStateTransitionStart(LauncherState toState) {
+ if (toState != mLauncherState) {
+ // Treat FLAG_TRANSITION_STATE_RUNNING as a changed flag even if a previous
+ // state transition was already running, so we update the new target.
+ mPrevState &= ~FLAG_TRANSITION_STATE_RUNNING;
+ mLauncherState = toState;
+ }
+ updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, true);
+ applyState();
+ }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ mLauncherState = finalState;
+ updateStateForFlag(FLAG_TRANSITION_STATE_RUNNING, false);
+ applyState();
+ }
+ };
+
+ public void init(TaskbarControllers controllers, BaseQuickstepLauncher launcher) {
+ mControllers = controllers;
+ mLauncher = launcher;
+
+ mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
+ .getTaskbarBackgroundAlpha();
+ MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
+ mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
+ mIconAlphaForHome.setConsumer(
+ (Consumer) alpha -> mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1));
+
+ mIconAlignmentForResumedState.finishAnimation();
+ onIconAlignmentRatioChangedForAppAndHomeTransition();
+
+ mLauncher.getStateManager().addStateListener(mStateListener);
+
+ // Initialize to the current launcher state
+ updateStateForFlag(FLAG_RESUMED, launcher.hasBeenResumed());
+ mLauncherState = launcher.getStateManager().getState();
+ applyState(0);
+ }
+
+ public void onDestroy() {
+ mIconAlignmentForResumedState.finishAnimation();
+ mIconAlignmentForGestureState.finishAnimation();
+ mIconAlignmentForLauncherState.finishAnimation();
+
+ mIconAlphaForHome.setConsumer(null);
+ mLauncher.getHotseat().setIconsAlpha(1f);
+ mLauncher.getStateManager().removeStateListener(mStateListener);
+ }
+
+ public Animator createAnimToLauncher(@NonNull LauncherState toState,
+ @NonNull RecentsAnimationCallbacks callbacks, long duration) {
+ // If going to overview, stash the task bar
+ // If going home, align the icons to hotseat
+ AnimatorSet animatorSet = new AnimatorSet();
+
+ // Update stashed flags first to ensure goingToUnstashedLauncherState() returns correctly.
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
+ toState.isTaskbarStashed(mLauncher));
+ stashController.updateStateForFlag(FLAG_IN_APP, false);
+
+ updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
+ animatorSet.play(stashController.applyStateWithoutStart(duration));
+ animatorSet.play(applyState(duration, false));
+
+ TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
+ callbacks.addListener(listener);
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ recentsView.setTaskLaunchListener(() -> {
+ listener.endGestureStateOverride(true);
+ callbacks.removeListener(listener);
+ });
+ return animatorSet;
+ }
+
+ public boolean isAnimatingToLauncher() {
+ return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture;
+ }
+
+ /**
+ * Updates the proper flag to change the state of the task bar.
+ *
+ * Note that this only updates the flag. {@link #applyState()} needs to be called separately.
+ *
+ * @param flag The flag to update.
+ * @param enabled Whether to enable the flag
+ */
+ public void updateStateForFlag(int flag, boolean enabled) {
+ if (enabled) {
+ mState |= flag;
+ } else {
+ mState &= ~flag;
+ }
+ }
+
+ private boolean hasAnyFlag(int flagMask) {
+ return hasAnyFlag(mState, flagMask);
+ }
+
+ private boolean hasAnyFlag(int flags, int flagMask) {
+ return (flags & flagMask) != 0;
+ }
+
+ public void applyState() {
+ applyState(TASKBAR_STASH_DURATION);
+ }
+
+ public void applyState(long duration) {
+ applyState(duration, true);
+ }
+
+ public Animator applyState(boolean start) {
+ return applyState(TASKBAR_STASH_DURATION, start);
+ }
+
+ public Animator applyState(long duration, boolean start) {
+ Animator animator = null;
+ if (mPrevState == null || mPrevState != mState) {
+ // If this is our initial state, treat all flags as changed.
+ int changedFlags = mPrevState == null ? FLAGS_ALL : mPrevState ^ mState;
+ mPrevState = mState;
+ animator = onStateChangeApplied(changedFlags, duration, start);
+ }
+ return animator;
+ }
+
+ private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
+ AnimatorSet animatorSet = new AnimatorSet();
+ if (hasAnyFlag(changedFlags, FLAG_RESUMED)) {
+ boolean isResumed = isResumed();
+ ObjectAnimator anim = mIconAlignmentForResumedState
+ .animateToValue(isResumed && goingToUnstashedLauncherState()
+ ? 1 : 0)
+ .setDuration(duration);
+
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncherViaResume = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsAnimatingToLauncherViaResume = isResumed;
+
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_IN_APP, !isResumed);
+ stashController.applyState(duration);
+ }
+ });
+ animatorSet.play(anim);
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_RECENTS_ANIMATION_RUNNING)) {
+ boolean isRecentsAnimationRunning = isRecentsAnimationRunning();
+ Animator animator = mIconAlignmentForGestureState
+ .animateToValue(isRecentsAnimationRunning && goingToUnstashedLauncherState()
+ ? 1 : 0);
+ if (isRecentsAnimationRunning) {
+ animator.setDuration(duration);
+ }
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncherViaGesture = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsAnimatingToLauncherViaGesture = isRecentsAnimationRunning();
+ }
+ });
+ animatorSet.play(animator);
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING)) {
+ boolean goingToLauncher = hasAnyFlag(FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING);
+ animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(goingToLauncher ? 0 : 1)
+ .setDuration(duration));
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_RUNNING)) {
+ boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING);
+ playStateTransitionAnim(animatorSet, duration, committed);
+
+ if (committed && mLauncherState == LauncherState.QUICK_SWITCH) {
+ // We're about to be paused, set immediately to ensure seamless handoff.
+ updateStateForFlag(FLAG_RESUMED, false);
+ applyState(0 /* duration */);
+ }
+ }
+
+ if (start) {
+ animatorSet.start();
+ }
+ return animatorSet;
+ }
+
+ /** Returns whether we're going to a state where taskbar icons should align with launcher. */
+ private boolean goingToUnstashedLauncherState() {
+ return !mControllers.taskbarStashController.isInStashedLauncherState();
+ }
+
+ private void playStateTransitionAnim(AnimatorSet animatorSet, long duration,
+ boolean committed) {
+ boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher);
+ float toAlignment = mLauncherState.isTaskbarAlignedWithHotseat(mLauncher) ? 1 : 0;
+
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, isInStashedState);
+ Animator stashAnimator = controller.applyStateWithoutStart(duration);
+ if (stashAnimator != null) {
+ stashAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (isInStashedState && committed) {
+ // Reset hotseat alpha to default
+ mLauncher.getHotseat().setIconsAlpha(1);
+ }
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (mLauncher.getHotseat().getIconsAlpha() > 0) {
+ mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
+ }
+ }
+ });
+ animatorSet.play(stashAnimator);
+ }
+
+ animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment)
+ .setDuration(duration));
+ }
+
+ private boolean isResumed() {
+ return (mState & FLAG_RESUMED) != 0;
+ }
+
+ private boolean isRecentsAnimationRunning() {
+ return (mState & FLAG_RECENTS_ANIMATION_RUNNING) != 0;
+ }
+
+ private void onIconAlignmentRatioChangedForStateTransition() {
+ if (!isResumed()) {
+ return;
+ }
+ onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioForLauncherState);
+ }
+
+ private void onIconAlignmentRatioChangedForAppAndHomeTransition() {
+ onIconAlignmentRatioChanged(this::getCurrentIconAlignmentRatioBetweenAppAndHome);
+ }
+
+ private void onIconAlignmentRatioChanged(Supplier alignmentSupplier) {
+ if (mControllers == null) {
+ return;
+ }
+ float alignment = alignmentSupplier.get();
+ mControllers.taskbarViewController.setLauncherIconAlignment(
+ alignment, mLauncher.getDeviceProfile());
+
+ // Switch taskbar and hotseat in last frame
+ setTaskbarViewVisible(alignment < 1);
+ }
+
+ private float getCurrentIconAlignmentRatioBetweenAppAndHome() {
+ return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
+ }
+
+ private float getCurrentIconAlignmentRatioForLauncherState() {
+ return mIconAlignmentForLauncherState.value;
+ }
+
+ private void setTaskbarViewVisible(boolean isVisible) {
+ mIconAlphaForHome.setValue(isVisible ? 1 : 0);
+ }
+
+ private final class TaskBarRecentsAnimationListener implements
+ RecentsAnimationCallbacks.RecentsAnimationListener {
+ private final RecentsAnimationCallbacks mCallbacks;
+
+ TaskBarRecentsAnimationListener(RecentsAnimationCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled(HashMap thumbnailDatas) {
+ endGestureStateOverride(true);
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ endGestureStateOverride(!controller.getFinishTargetIsLauncher());
+ }
+
+ private void endGestureStateOverride(boolean finishedToApp) {
+ mCallbacks.removeListener(this);
+
+ // Update the resumed state immediately to ensure a seamless handoff
+ boolean launcherResumed = !finishedToApp;
+ updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, false);
+ updateStateForFlag(FLAG_RESUMED, launcherResumed);
+ applyState();
+ // Set this last because applyState() might also animate it.
+ mIconAlignmentForResumedState.cancelAnimation();
+ mIconAlignmentForResumedState.updateValue(launcherResumed ? 1 : 0);
+
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
+ controller.applyState();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index d026bfbf37..3cdcdf7f89 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -16,43 +16,71 @@
package com.android.launcher3.taskbar;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
+import android.content.ComponentCallbacks;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
-import android.inputmethodservice.InputMethodService;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
import android.view.Display;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.util.SimpleBroadcastReceiver;
+import com.android.quickstep.RecentsActivity;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
+import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
+import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
/**
- * Class to manager taskbar lifecycle
+ * Class to manage taskbar lifecycle
*/
public class TaskbarManager implements DisplayController.DisplayInfoChangeListener,
SysUINavigationMode.NavigationModeChangeListener {
+ private static final Uri USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(
+ Settings.Secure.USER_SETUP_COMPLETE);
+
private final Context mContext;
private final DisplayController mDisplayController;
private final SysUINavigationMode mSysUINavigationMode;
private final TaskbarNavButtonController mNavButtonController;
+ private final SettingsCache.OnChangeListener mUserSetupCompleteListener;
+ private final ComponentCallbacks mComponentCallbacks;
+ private final SimpleBroadcastReceiver mShutdownReceiver;
+
+ // The source for this provider is set when Launcher is available
+ private final ScopedUnfoldTransitionProgressProvider mUnfoldProgressProvider =
+ new ScopedUnfoldTransitionProgressProvider();
private TaskbarActivityContext mTaskbarActivityContext;
- private BaseQuickstepLauncher mLauncher;
+ private StatefulActivity mActivity;
+ /**
+ * Cache a copy here so we can initialize state whenever taskbar is recreated, since
+ * this class does not get re-initialized w/ new taskbars.
+ */
+ private final TaskbarSharedState mSharedState = new TaskbarSharedState();
private static final int CHANGE_FLAGS =
CHANGE_ACTIVE_SCREEN | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS;
@@ -64,11 +92,42 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service);
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
- mContext = service.createWindowContext(display, TYPE_APPLICATION_OVERLAY, null);
- mNavButtonController = new TaskbarNavButtonController(service);
+ mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
+ mNavButtonController = new TaskbarNavButtonController(service,
+ SystemUiProxy.INSTANCE.get(mContext), new Handler());
+ mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar();
+ mComponentCallbacks = new ComponentCallbacks() {
+ private Configuration mOldConfig = mContext.getResources().getConfiguration();
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ int configDiff = mOldConfig.diff(newConfig);
+ int configsRequiringRecreate = ActivityInfo.CONFIG_ASSETS_PATHS
+ | ActivityInfo.CONFIG_LAYOUT_DIRECTION | ActivityInfo.CONFIG_UI_MODE;
+ if ((configDiff & configsRequiringRecreate) != 0) {
+ // Color has changed, recreate taskbar to reload background color & icons.
+ recreateTaskbar();
+ } else {
+ // Config change might be handled without re-creating the taskbar
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onConfigurationChanged(configDiff);
+ }
+ }
+ mOldConfig = newConfig;
+ }
+
+ @Override
+ public void onLowMemory() { }
+ };
+ mShutdownReceiver = new SimpleBroadcastReceiver(i -> destroyExistingTaskbar());
mDisplayController.addChangeListener(this);
mSysUINavigationMode.addModeChangeListener(this);
+ SettingsCache.INSTANCE.get(mContext).register(USER_SETUP_COMPLETE_URI,
+ mUserSetupCompleteListener);
+ mContext.registerComponentCallbacks(mComponentCallbacks);
+ mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN);
+
recreateTaskbar();
}
@@ -100,61 +159,120 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
}
/**
- * Sets or clears a launcher to act as taskbar callback
+ * Sets a {@link StatefulActivity} to act as taskbar callback
*/
- public void setLauncher(@Nullable BaseQuickstepLauncher launcher) {
- mLauncher = launcher;
+ public void setActivity(@NonNull StatefulActivity activity) {
+ mActivity = activity;
+ mUnfoldProgressProvider.setSourceProvider(getUnfoldTransitionProgressProviderForActivity(
+ activity));
+
if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.setUIController(mLauncher == null
- ? TaskbarUIController.DEFAULT
- : new LauncherTaskbarUIController(launcher, mTaskbarActivityContext));
+ mTaskbarActivityContext.setUIController(
+ createTaskbarUIControllerForActivity(mActivity));
+ }
+ }
+
+ /**
+ * Returns an {@link UnfoldTransitionProgressProvider} to use while the given StatefulActivity
+ * is active.
+ */
+ private UnfoldTransitionProgressProvider getUnfoldTransitionProgressProviderForActivity(
+ StatefulActivity activity) {
+ if (activity instanceof BaseQuickstepLauncher) {
+ return ((BaseQuickstepLauncher) activity).getUnfoldTransitionProgressProvider();
+ }
+ return null;
+ }
+
+ /**
+ * Creates a {@link TaskbarUIController} to use while the given StatefulActivity is active.
+ */
+ private TaskbarUIController createTaskbarUIControllerForActivity(StatefulActivity activity) {
+ if (activity instanceof BaseQuickstepLauncher) {
+ return new LauncherTaskbarUIController((BaseQuickstepLauncher) activity);
+ }
+ if (activity instanceof RecentsActivity) {
+ return new FallbackTaskbarUIController((RecentsActivity) activity);
+ }
+ return TaskbarUIController.DEFAULT;
+ }
+
+ /**
+ * Clears a previously set {@link StatefulActivity}
+ */
+ public void clearActivity(@NonNull StatefulActivity activity) {
+ if (mActivity == activity) {
+ mActivity = null;
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.setUIController(TaskbarUIController.DEFAULT);
+ }
+ mUnfoldProgressProvider.setSourceProvider(null);
}
}
private void recreateTaskbar() {
destroyExistingTaskbar();
- if (!FeatureFlags.ENABLE_TASKBAR.get()) {
+
+ DeviceProfile dp =
+ mUserUnlocked ? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
+
+ boolean isTaskBarEnabled =
+ FeatureFlags.ENABLE_TASKBAR.get() && dp != null && dp.isTaskbarPresent;
+
+ if (!isTaskBarEnabled) {
+ SystemUiProxy.INSTANCE.get(mContext)
+ .notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
return;
}
- if (!mUserUnlocked) {
- return;
- }
- DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
- if (!dp.isTaskbarPresent) {
- return;
- }
- mTaskbarActivityContext = new TaskbarActivityContext(
- mContext, dp.copy(mContext), mNavButtonController);
- mTaskbarActivityContext.init();
- if (mLauncher != null) {
+
+ mTaskbarActivityContext = new TaskbarActivityContext(mContext, dp.copy(mContext),
+ mNavButtonController, mUnfoldProgressProvider);
+
+ mTaskbarActivityContext.init(mSharedState);
+ if (mActivity != null) {
mTaskbarActivityContext.setUIController(
- new LauncherTaskbarUIController(mLauncher, mTaskbarActivityContext));
+ createTaskbarUIControllerForActivity(mActivity));
}
}
- /**
- * See {@link com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags}
- * @param systemUiStateFlags The latest SystemUiStateFlags
- */
public void onSystemUiFlagsChanged(int systemUiStateFlags) {
- boolean isImeVisible = (systemUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0;
+ mSharedState.sysuiStateFlags = systemUiStateFlags;
if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.setImeIsVisible(isImeVisible);
+ mTaskbarActivityContext.updateSysuiStateFlags(systemUiStateFlags, false /* fromInit */);
}
}
/**
- * When in 3 button nav, the above doesn't get called since we prevent sysui nav bar from
- * instantiating at all, which is what's responsible for sending sysui state flags over.
- *
- * @param vis IME visibility flag
- * @param backDisposition Used to determine back button behavior for software keyboard
- * See BACK_DISPOSITION_* constants in {@link InputMethodService}
+ * Sets the flag indicating setup UI is visible
*/
- public void updateImeStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setSetupUIVisible(boolean isVisible) {
+ mSharedState.setupUIVisible = isVisible;
if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.updateImeStatus(displayId, vis, showImeSwitcher);
+ mTaskbarActivityContext.setSetupUIVisible(isVisible);
+ }
+ }
+
+ public void onRotationProposal(int rotation, boolean isValid) {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onRotationProposal(rotation, isValid);
+ }
+ }
+
+ public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.disableNavBarElements(displayId, state1, state2, animate);
+ }
+ }
+
+ public void onSystemBarAttributesChanged(int displayId, int behavior) {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onSystemBarAttributesChanged(displayId, behavior);
+ }
+ }
+
+ public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.onNavButtonsDarkIntensityChanged(darkIntensity);
}
}
@@ -165,5 +283,13 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
destroyExistingTaskbar();
mDisplayController.removeChangeListener(this);
mSysUINavigationMode.removeModeChangeListener(this);
+ SettingsCache.INSTANCE.get(mContext).unregister(USER_SETUP_COMPLETE_URI,
+ mUserSetupCompleteListener);
+ mContext.unregisterComponentCallbacks(mComponentCallbacks);
+ mContext.unregisterReceiver(mShutdownReceiver);
+ }
+
+ public @Nullable TaskbarActivityContext getCurrentActivityContext() {
+ return mTaskbarActivityContext;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
new file mode 100644
index 0000000000..37a9b5e5b2
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.util.SparseArray;
+import android.view.View;
+
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.BgDataModel.FixedContainerItems;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.IntArray;
+import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.LauncherBindableItemsContainer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Launcher model Callbacks for rendering taskbar.
+ */
+public class TaskbarModelCallbacks implements
+ BgDataModel.Callbacks, LauncherBindableItemsContainer {
+
+ private final SparseArray mHotseatItems = new SparseArray<>();
+ private List mPredictedItems = Collections.emptyList();
+
+ private final TaskbarActivityContext mContext;
+ private final TaskbarView mContainer;
+
+ // Initialized in init.
+ private TaskbarControllers mControllers;
+
+ private boolean mBindInProgress = false;
+
+ public TaskbarModelCallbacks(
+ TaskbarActivityContext context, TaskbarView container) {
+ mContext = context;
+ mContainer = container;
+ }
+
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ }
+
+ @Override
+ public void startBinding() {
+ mBindInProgress = true;
+ mHotseatItems.clear();
+ mPredictedItems = Collections.emptyList();
+ }
+
+ @Override
+ public void finishBindingItems(IntSet pagesBoundFirst) {
+ mBindInProgress = false;
+ commitItemsToUI();
+ }
+
+ @Override
+ public void bindAppsAdded(IntArray newScreens, ArrayList addNotAnimated,
+ ArrayList addAnimated) {
+ boolean add1 = handleItemsAdded(addNotAnimated);
+ boolean add2 = handleItemsAdded(addAnimated);
+ if (add1 || add2) {
+ commitItemsToUI();
+ }
+ }
+
+ @Override
+ public void bindItems(List shortcuts, boolean forceAnimateIcons) {
+ if (handleItemsAdded(shortcuts)) {
+ commitItemsToUI();
+ }
+ }
+
+ private boolean handleItemsAdded(List items) {
+ boolean modified = false;
+ for (ItemInfo item : items) {
+ if (item.container == Favorites.CONTAINER_HOTSEAT) {
+ mHotseatItems.put(item.screenId, item);
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+
+ @Override
+ public void bindWorkspaceItemsChanged(List updated) {
+ updateWorkspaceItems(updated, mContext);
+ }
+
+ @Override
+ public void bindRestoreItemsChange(HashSet updates) {
+ updateRestoreItems(updates, mContext);
+ }
+
+ @Override
+ public void mapOverItems(ItemOperator op) {
+ final int itemCount = mContainer.getChildCount();
+ for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
+ View item = mContainer.getChildAt(itemIdx);
+ if (op.evaluate((ItemInfo) item.getTag(), item)) {
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
+ if (handleItemsRemoved(matcher)) {
+ commitItemsToUI();
+ }
+ }
+
+ private boolean handleItemsRemoved(ItemInfoMatcher matcher) {
+ boolean modified = false;
+ for (int i = mHotseatItems.size() - 1; i >= 0; i--) {
+ if (matcher.matchesInfo(mHotseatItems.valueAt(i))) {
+ modified = true;
+ mHotseatItems.removeAt(i);
+ }
+ }
+ return modified;
+ }
+
+ @Override
+ public void bindItemsModified(List items) {
+ boolean removed = handleItemsRemoved(ItemInfoMatcher.ofItems(items));
+ boolean added = handleItemsAdded(items);
+ if (removed || added) {
+ commitItemsToUI();
+ }
+ }
+
+ @Override
+ public void bindExtraContainerItems(FixedContainerItems item) {
+ if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) {
+ mPredictedItems = item.items;
+ commitItemsToUI();
+ }
+ }
+
+ private void commitItemsToUI() {
+ if (mBindInProgress) {
+ return;
+ }
+
+ ItemInfo[] hotseatItemInfos =
+ new ItemInfo[mContext.getDeviceProfile().numShownHotseatIcons];
+ int predictionSize = mPredictedItems.size();
+ int predictionNextIndex = 0;
+
+ boolean isHotseatEmpty = true;
+ for (int i = 0; i < hotseatItemInfos.length; i++) {
+ hotseatItemInfos[i] = mHotseatItems.get(i);
+ if (hotseatItemInfos[i] == null && predictionNextIndex < predictionSize) {
+ hotseatItemInfos[i] = mPredictedItems.get(predictionNextIndex);
+ hotseatItemInfos[i].screenId = i;
+ predictionNextIndex++;
+ }
+ if (hotseatItemInfos[i] != null) {
+ isHotseatEmpty = false;
+ }
+ }
+ mContainer.updateHotseatItems(hotseatItemInfos);
+
+ final boolean finalIsHotseatEmpty = isHotseatEmpty;
+ mControllers.runAfterInit(() -> {
+ mControllers.taskbarStashController.updateStateForFlag(
+ TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, finalIsHotseatEmpty);
+ mControllers.taskbarStashController.applyState();
+ });
+ }
+
+ @Override
+ public void bindDeepShortcutMap(HashMap deepShortcutMapCopy) {
+ mControllers.taskbarPopupController.setDeepShortcutMap(deepShortcutMapCopy);
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 3b5afad691..d23336505a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -16,13 +16,18 @@
package com.android.launcher3.taskbar;
-import static android.view.Display.DEFAULT_DISPLAY;
-import android.content.Intent;
-import android.view.inputmethod.InputMethodManager;
+import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS;
+import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+
+import android.os.Bundle;
+import android.os.Handler;
import androidx.annotation.IntDef;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
@@ -34,17 +39,23 @@ import java.lang.annotation.RetentionPolicy;
* Controller for 3 button mode in the taskbar.
* Handles all the functionality of the various buttons, making/routing the right calls into
* launcher or sysui/system.
- *
- * TODO: Create callbacks to hook into UI layer since state will change for more context buttons/
- * assistant invocation.
*/
public class TaskbarNavButtonController {
+
+ /** Allow some time in between the long press for back and recents. */
+ static final int SCREEN_PIN_LONG_PRESS_THRESHOLD = 200;
+ static final int SCREEN_PIN_LONG_PRESS_RESET = SCREEN_PIN_LONG_PRESS_THRESHOLD + 100;
+
+ private long mLastScreenPinLongPress;
+ private boolean mScreenPinned;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
BUTTON_BACK,
BUTTON_HOME,
BUTTON_RECENTS,
- BUTTON_IME_SWITCH
+ BUTTON_IME_SWITCH,
+ BUTTON_A11Y,
})
public @interface TaskbarButton {}
@@ -53,11 +64,22 @@ public class TaskbarNavButtonController {
static final int BUTTON_HOME = BUTTON_BACK << 1;
static final int BUTTON_RECENTS = BUTTON_HOME << 1;
static final int BUTTON_IME_SWITCH = BUTTON_RECENTS << 1;
+ static final int BUTTON_A11Y = BUTTON_IME_SWITCH << 1;
+
+ private static final int SCREEN_UNPIN_COMBO = BUTTON_BACK | BUTTON_RECENTS;
+ private int mLongPressedButtons = 0;
private final TouchInteractionService mService;
+ private final SystemUiProxy mSystemUiProxy;
+ private final Handler mHandler;
- public TaskbarNavButtonController(TouchInteractionService service) {
+ private final Runnable mResetLongPress = this::resetScreenUnpin;
+
+ public TaskbarNavButtonController(TouchInteractionService service,
+ SystemUiProxy systemUiProxy, Handler handler) {
mService = service;
+ mSystemUiProxy = systemUiProxy;
+ mHandler = handler;
}
public void onButtonClick(@TaskbarButton int buttonType) {
@@ -69,32 +91,115 @@ public class TaskbarNavButtonController {
navigateHome();
break;
case BUTTON_RECENTS:
- navigateToOverview();;
+ navigateToOverview();
break;
case BUTTON_IME_SWITCH:
showIMESwitcher();
break;
+ case BUTTON_A11Y:
+ notifyA11yClick(false /* longClick */);
+ break;
}
}
+ public boolean onButtonLongClick(@TaskbarButton int buttonType) {
+ switch (buttonType) {
+ case BUTTON_HOME:
+ startAssistant();
+ return true;
+ case BUTTON_A11Y:
+ notifyA11yClick(true /* longClick */);
+ return true;
+ case BUTTON_BACK:
+ case BUTTON_RECENTS:
+ mLongPressedButtons |= buttonType;
+ return determineScreenUnpin();
+ case BUTTON_IME_SWITCH:
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the user has long pressed back and recents buttons
+ * "together" (within {@link #SCREEN_PIN_LONG_PRESS_THRESHOLD})ms
+ * If so, then requests the system to turn off screen pinning.
+ *
+ * @return true if the long press is a valid user action in attempting to unpin an app
+ * Will always return {@code false} when screen pinning is not active.
+ * NOTE: Returning true does not mean that screen pinning has stopped
+ */
+ private boolean determineScreenUnpin() {
+ long timeNow = System.currentTimeMillis();
+ if (!mScreenPinned) {
+ return false;
+ }
+
+ if (mLastScreenPinLongPress == 0) {
+ // First button long press registered, just mark time and wait for second button press
+ mLastScreenPinLongPress = System.currentTimeMillis();
+ mHandler.postDelayed(mResetLongPress, SCREEN_PIN_LONG_PRESS_RESET);
+ return true;
+ }
+
+ if ((timeNow - mLastScreenPinLongPress) > SCREEN_PIN_LONG_PRESS_THRESHOLD) {
+ // Too long in-between presses, reset the clock
+ resetScreenUnpin();
+ return false;
+ }
+
+ if ((mLongPressedButtons & SCREEN_UNPIN_COMBO) == SCREEN_UNPIN_COMBO) {
+ // Hooray! They did it (finally...)
+ mSystemUiProxy.stopScreenPinning();
+ mHandler.removeCallbacks(mResetLongPress);
+ resetScreenUnpin();
+ }
+ return true;
+ }
+
+ private void resetScreenUnpin() {
+ mLongPressedButtons = 0;
+ mLastScreenPinLongPress = 0;
+ }
+
+ public void updateSysuiFlags(int sysuiFlags) {
+ mScreenPinned = (sysuiFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
+ }
+
private void navigateHome() {
- mService.startActivity(new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
}
private void navigateToOverview() {
- mService.getOverviewCommandHelper()
- .addCommand(OverviewCommandHelper.TYPE_SHOW);
+ if (mScreenPinned) {
+ return;
+ }
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle");
+ mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_TOGGLE);
}
private void executeBack() {
- SystemUiProxy.INSTANCE.getNoCreate().onBackPressed();
+ mSystemUiProxy.onBackPressed();
}
private void showIMESwitcher() {
- mService.getSystemService(InputMethodManager.class)
- .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */,
- DEFAULT_DISPLAY);
+ mSystemUiProxy.onImeSwitcherPressed();
+ }
+
+ private void notifyA11yClick(boolean longClick) {
+ if (longClick) {
+ mSystemUiProxy.notifyAccessibilityButtonLongClicked();
+ } else {
+ mSystemUiProxy.notifyAccessibilityButtonClicked(mService.getDisplayId());
+ }
+ }
+
+ private void startAssistant() {
+ if (mScreenPinned) {
+ return;
+ }
+ Bundle args = new Bundle();
+ args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
+ mSystemUiProxy.startAssistant(args);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
new file mode 100644
index 0000000000..952f597f72
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.views.ActivityContext;
+
+import java.util.HashMap;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Implements interfaces required to show and allow interacting with a PopupContainerWithArrow.
+ */
+public class TaskbarPopupController {
+
+ private static final SystemShortcut.Factory
+ APP_INFO = SystemShortcut.AppInfo::new;
+
+ private final PopupDataProvider mPopupDataProvider;
+
+ public TaskbarPopupController() {
+ // TODO (b/198438631): add notifications dots change listener
+ mPopupDataProvider = new PopupDataProvider(packageUserKey -> {});
+ }
+
+ @NonNull
+ public PopupDataProvider getPopupDataProvider() {
+ return mPopupDataProvider;
+ }
+
+ public void setDeepShortcutMap(HashMap deepShortcutMapCopy) {
+ mPopupDataProvider.setDeepShortcutMap(deepShortcutMapCopy);
+ }
+
+ /**
+ * Shows the notifications and deep shortcuts associated with a Taskbar {@param icon}.
+ * @return the container if shown or null.
+ */
+ public PopupContainerWithArrow showForIcon(BubbleTextView icon) {
+ TaskbarActivityContext context = ActivityContext.lookupContext(icon.getContext());
+ if (PopupContainerWithArrow.getOpen(context) != null) {
+ // There is already an items container open, so don't open this one.
+ icon.clearFocus();
+ return null;
+ }
+ ItemInfo item = (ItemInfo) icon.getTag();
+ if (!PopupContainerWithArrow.canShow(icon, item)) {
+ return null;
+ }
+
+ final PopupContainerWithArrow container =
+ (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+ R.layout.popup_container, context.getDragLayer(), false);
+ // TODO (b/198438631): configure for taskbar/context
+
+ container.populateAndShow(icon,
+ mPopupDataProvider.getShortcutCountForItem(item),
+ mPopupDataProvider.getNotificationKeysForItem(item),
+ // TODO (b/198438631): add support for INSTALL shortcut factory
+ Stream.of(APP_INFO)
+ .map(s -> s.getShortcut(context, item))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList()));
+ container.requestFocus();
+ return container;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java
new file mode 100644
index 0000000000..94a3307bc3
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimView.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * View that handles scrimming the taskbar and the inverted corners it draws. The scrim is used
+ * when bubbles is expanded.
+ */
+public class TaskbarScrimView extends View {
+ private final Paint mTaskbarScrimPaint;
+ private final Path mInvertedLeftCornerPath, mInvertedRightCornerPath;
+
+ private boolean mShowScrim;
+ private float mLeftCornerRadius, mRightCornerRadius;
+ private float mBackgroundHeight;
+
+ public TaskbarScrimView(Context context) {
+ this(context, null);
+ }
+
+ public TaskbarScrimView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TaskbarScrimView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public TaskbarScrimView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ mTaskbarScrimPaint = new Paint();
+ mTaskbarScrimPaint.setColor(getResources().getColor(android.R.color.system_neutral1_1000));
+ mTaskbarScrimPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+ mTaskbarScrimPaint.setStyle(Paint.Style.FILL);
+
+ mInvertedLeftCornerPath = new Path();
+ mInvertedRightCornerPath = new Path();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mShowScrim) {
+ canvas.save();
+ canvas.translate(0, canvas.getHeight() - mBackgroundHeight);
+
+ // Scrim the taskbar itself.
+ canvas.drawRect(0, 0, canvas.getWidth(), mBackgroundHeight, mTaskbarScrimPaint);
+
+ // Scrim the inverted rounded corners above the taskbar.
+ canvas.translate(0, -mLeftCornerRadius);
+ canvas.drawPath(mInvertedLeftCornerPath, mTaskbarScrimPaint);
+ canvas.translate(0, mLeftCornerRadius);
+ canvas.translate(canvas.getWidth() - mRightCornerRadius, -mRightCornerRadius);
+ canvas.drawPath(mInvertedRightCornerPath, mTaskbarScrimPaint);
+
+ canvas.restore();
+ }
+ }
+
+ /**
+ * Sets the height of the taskbar background.
+ * @param height the height of the background.
+ */
+ protected void setBackgroundHeight(float height) {
+ mBackgroundHeight = height;
+ if (mShowScrim) {
+ invalidate();
+ }
+ }
+
+ /**
+ * Sets the alpha of the taskbar scrim.
+ * @param alpha the alpha of the scrim.
+ */
+ protected void setScrimAlpha(float alpha) {
+ mShowScrim = alpha > 0f;
+ mTaskbarScrimPaint.setAlpha((int) (alpha * 255));
+ invalidate();
+ }
+
+ /**
+ * Sets the radius of the left and right corners above the taskbar.
+ * @param leftCornerRadius the radius of the left corner.
+ * @param rightCornerRadius the radius of the right corner.
+ */
+ protected void setCornerSizes(float leftCornerRadius, float rightCornerRadius) {
+ mLeftCornerRadius = leftCornerRadius;
+ mRightCornerRadius = rightCornerRadius;
+
+ Path square = new Path();
+ square.addRect(0, 0, mLeftCornerRadius, mLeftCornerRadius, Path.Direction.CW);
+ Path circle = new Path();
+ circle.addCircle(mLeftCornerRadius, 0, mLeftCornerRadius, Path.Direction.CW);
+ mInvertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE);
+ square.reset();
+ square.addRect(0, 0, mRightCornerRadius, mRightCornerRadius, Path.Direction.CW);
+ circle.reset();
+ circle.addCircle(0, 0, mRightCornerRadius, Path.Direction.CW);
+ mInvertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE);
+
+ if (mShowScrim) {
+ invalidate();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
new file mode 100644
index 0000000000..4b4ee4423c
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
+
+import android.animation.ObjectAnimator;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.SystemUiProxy;
+
+/**
+ * Handles properties/data collection, and passes the results to {@link TaskbarScrimView} to render.
+ */
+public class TaskbarScrimViewController {
+
+ private static final float SCRIM_ALPHA = 0.6f;
+
+ private static final Interpolator SCRIM_ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ private static final Interpolator SCRIM_ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+
+ private final TaskbarActivityContext mActivity;
+ private final TaskbarScrimView mScrimView;
+
+ // Alpha property for the scrim.
+ private final AnimatedFloat mScrimAlpha = new AnimatedFloat(this::updateScrimAlpha);
+
+ // Initialized in init.
+ private TaskbarControllers mControllers;
+
+ public TaskbarScrimViewController(TaskbarActivityContext activity, TaskbarScrimView scrimView) {
+ mActivity = activity;
+ mScrimView = scrimView;
+ mScrimView.setCornerSizes(mActivity.getLeftCornerRadius(),
+ mActivity.getRightCornerRadius());
+ mScrimView.setBackgroundHeight(mActivity.getDeviceProfile().taskbarSize);
+ }
+
+ /**
+ * Initializes the controller
+ */
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ }
+
+ /**
+ * Updates the scrim state based on the flags.
+ */
+ public void updateStateForSysuiFlags(int stateFlags, boolean skipAnim) {
+ final boolean bubblesExpanded = (stateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0;
+ final boolean manageMenuExpanded =
+ (stateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0;
+ final boolean showScrim = !mControllers.navbarButtonsViewController.isImeVisible()
+ && bubblesExpanded && mControllers.taskbarStashController.isInAppAndNotStashed();
+ final float scrimAlpha = manageMenuExpanded
+ // When manage menu shows there's the first scrim and second scrim so figure out
+ // what the total transparency would be.
+ ? (SCRIM_ALPHA + (SCRIM_ALPHA * (1 - SCRIM_ALPHA)))
+ : showScrim ? SCRIM_ALPHA : 0;
+ showScrim(showScrim, scrimAlpha, skipAnim);
+ }
+
+ private void showScrim(boolean showScrim, float alpha, boolean skipAnim) {
+ mScrimView.setOnClickListener(showScrim ? (view) -> onClick() : null);
+ mScrimView.setClickable(showScrim);
+ ObjectAnimator anim = mScrimAlpha.animateToValue(showScrim ? alpha : 0);
+ anim.setInterpolator(showScrim ? SCRIM_ALPHA_IN : SCRIM_ALPHA_OUT);
+ anim.start();
+ if (skipAnim) {
+ anim.end();
+ }
+ }
+
+ private void updateScrimAlpha() {
+ mScrimView.setScrimAlpha(mScrimAlpha.value);
+ }
+
+ private void onClick() {
+ SystemUiProxy.INSTANCE.get(mActivity).onBackPressed();
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
new file mode 100644
index 0000000000..23beef0a8a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+/**
+ * State shared across different taskbar instance
+ */
+public class TaskbarSharedState {
+
+ public int sysuiStateFlags;
+
+ public boolean setupUIVisible = false;
+
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
new file mode 100644
index 0000000000..7f7585000c
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static android.view.HapticFeedbackConstants.LONG_PRESS;
+
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.annotation.Nullable;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.SystemUiProxy;
+
+import java.util.function.IntPredicate;
+
+/**
+ * Coordinates between controllers such as TaskbarViewController and StashedHandleViewController to
+ * create a cohesive animation between stashed/unstashed states.
+ */
+public class TaskbarStashController {
+
+ public static final int FLAG_IN_APP = 1 << 0;
+ public static final int FLAG_STASHED_IN_APP_MANUAL = 1 << 1; // long press, persisted
+ public static final int FLAG_STASHED_IN_APP_PINNED = 1 << 2; // app pinning
+ public static final int FLAG_STASHED_IN_APP_EMPTY = 1 << 3; // no hotseat icons
+ public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 4; // setup wizard and AllSetActivity
+ public static final int FLAG_STASHED_IN_APP_IME = 1 << 5; // IME is visible
+ public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 6;
+
+ // If we're in an app and any of these flags are enabled, taskbar should be stashed.
+ private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
+ | FLAG_STASHED_IN_APP_PINNED | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP
+ | FLAG_STASHED_IN_APP_IME;
+
+ // If any of these flags are enabled, inset apps by our stashed height instead of our unstashed
+ // height. This way the reported insets are consistent even during transitions out of the app.
+ // Currently any flag that causes us to stash in an app is included, except for IME since that
+ // covers the underlying app anyway and thus the app shouldn't change insets.
+ private static final int FLAGS_REPORT_STASHED_INSETS_TO_APP = FLAGS_STASHED_IN_APP
+ & ~FLAG_STASHED_IN_APP_IME;
+
+ /**
+ * How long to stash/unstash when manually invoked via long press.
+ */
+ public static final long TASKBAR_STASH_DURATION = 300;
+
+ /**
+ * How long to stash/unstash when keyboard is appearing/disappearing.
+ */
+ private static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
+
+ /**
+ * The scale TaskbarView animates to when being stashed.
+ */
+ private static final float STASHED_TASKBAR_SCALE = 0.5f;
+
+ /**
+ * How long the hint animation plays, starting on motion down.
+ */
+ private static final long TASKBAR_HINT_STASH_DURATION =
+ ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT;
+
+ /**
+ * The scale that TaskbarView animates to when hinting towards the stashed state.
+ */
+ private static final float STASHED_TASKBAR_HINT_SCALE = 0.9f;
+
+ /**
+ * The scale that the stashed handle animates to when hinting towards the unstashed state.
+ */
+ private static final float UNSTASHED_TASKBAR_HANDLE_HINT_SCALE = 1.1f;
+
+ /**
+ * The SharedPreferences key for whether user has manually stashed the taskbar.
+ */
+ private static final String SHARED_PREFS_STASHED_KEY = "taskbar_is_stashed";
+
+ /**
+ * Whether taskbar should be stashed out of the box.
+ */
+ private static final boolean DEFAULT_STASHED_PREF = false;
+
+ private final TaskbarActivityContext mActivity;
+ private final SharedPreferences mPrefs;
+ private final int mStashedHeight;
+ private final int mUnstashedHeight;
+ private final SystemUiProxy mSystemUiProxy;
+
+ // Initialized in init.
+ private TaskbarControllers mControllers;
+ // Taskbar background properties.
+ private AnimatedFloat mTaskbarBackgroundOffset;
+ private AnimatedFloat mTaskbarImeBgAlpha;
+ // TaskbarView icon properties.
+ private AlphaProperty mIconAlphaForStash;
+ private AnimatedFloat mIconScaleForStash;
+ private AnimatedFloat mIconTranslationYForStash;
+ // Stashed handle properties.
+ private AlphaProperty mTaskbarStashedHandleAlpha;
+ private AnimatedFloat mTaskbarStashedHandleHintScale;
+
+ /** Whether we are currently visually stashed (might change based on launcher state). */
+ private boolean mIsStashed = false;
+ private int mState;
+
+ private @Nullable AnimatorSet mAnimator;
+ private boolean mIsSystemGestureInProgress;
+ private boolean mIsImeShowing;
+
+ // Evaluate whether the handle should be stashed
+ private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
+ flags -> {
+ boolean inApp = hasAnyFlag(flags, FLAG_IN_APP);
+ boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP);
+ boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE);
+ return (inApp && stashedInApp) || (!inApp && stashedLauncherState);
+ });
+
+ public TaskbarStashController(TaskbarActivityContext activity) {
+ mActivity = activity;
+ mPrefs = Utilities.getPrefs(mActivity);
+ final Resources resources = mActivity.getResources();
+ mStashedHeight = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
+ mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
+ mUnstashedHeight = mActivity.getDeviceProfile().taskbarSize;
+ }
+
+ public void init(TaskbarControllers controllers, TaskbarSharedState sharedState) {
+ mControllers = controllers;
+
+ TaskbarDragLayerController dragLayerController = controllers.taskbarDragLayerController;
+ mTaskbarBackgroundOffset = dragLayerController.getTaskbarBackgroundOffset();
+ mTaskbarImeBgAlpha = dragLayerController.getImeBgTaskbar();
+
+ TaskbarViewController taskbarViewController = controllers.taskbarViewController;
+ mIconAlphaForStash = taskbarViewController.getTaskbarIconAlpha().getProperty(
+ TaskbarViewController.ALPHA_INDEX_STASH);
+ mIconScaleForStash = taskbarViewController.getTaskbarIconScaleForStash();
+ mIconTranslationYForStash = taskbarViewController.getTaskbarIconTranslationYForStash();
+
+ StashedHandleViewController stashedHandleController =
+ controllers.stashedHandleViewController;
+ mTaskbarStashedHandleAlpha = stashedHandleController.getStashedHandleAlpha().getProperty(
+ StashedHandleViewController.ALPHA_INDEX_STASHED);
+ mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale();
+
+ boolean isManuallyStashedInApp = supportsManualStashing()
+ && mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
+ boolean isInSetup = !mActivity.isUserSetupComplete() || sharedState.setupUIVisible;
+ updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
+ // TODO(b/204384193): Temporarily disable SUW specific logic
+ // updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
+ if (isInSetup) {
+ // Update the in-app state to ensure isStashed() reflects right state during SUW
+ updateStateForFlag(FLAG_IN_APP, true);
+ }
+ applyState();
+
+ notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
+ }
+
+ /**
+ * Returns whether the taskbar can visually stash into a handle based on the current device
+ * state.
+ */
+ private boolean supportsVisualStashing() {
+ return !mActivity.isThreeButtonNav();
+ }
+
+ /**
+ * Returns whether the user can manually stash the taskbar based on the current device state.
+ */
+ private boolean supportsManualStashing() {
+ return supportsVisualStashing()
+ && (!Utilities.IS_RUNNING_IN_TEST_HARNESS || supportsStashingForTests());
+ }
+
+ private boolean supportsStashingForTests() {
+ // TODO: enable this for tests that specifically check stash/unstash behavior.
+ return false;
+ }
+
+ /**
+ * Sets the flag indicating setup UI is visible
+ */
+ protected void setSetupUIVisible(boolean isVisible) {
+ updateStateForFlag(FLAG_STASHED_IN_APP_SETUP,
+ isVisible || !mActivity.isUserSetupComplete());
+ applyState();
+ }
+
+ /**
+ * Returns whether the taskbar is currently visually stashed.
+ */
+ public boolean isStashed() {
+ return mIsStashed;
+ }
+
+ /**
+ * Returns whether the taskbar should be stashed in apps (e.g. user long pressed to stash).
+ */
+ public boolean isStashedInApp() {
+ return hasAnyFlag(FLAGS_STASHED_IN_APP);
+ }
+
+ /**
+ * Returns whether the taskbar should be stashed in the current LauncherState.
+ */
+ public boolean isInStashedLauncherState() {
+ return hasAnyFlag(FLAG_IN_STASHED_LAUNCHER_STATE) && supportsVisualStashing();
+ }
+
+ private boolean hasAnyFlag(int flagMask) {
+ return hasAnyFlag(mState, flagMask);
+ }
+
+ private boolean hasAnyFlag(int flags, int flagMask) {
+ return (flags & flagMask) != 0;
+ }
+
+
+ /**
+ * Returns whether the taskbar is currently visible and in an app.
+ */
+ public boolean isInAppAndNotStashed() {
+ return !mIsStashed && (mState & FLAG_IN_APP) != 0;
+ }
+
+ /**
+ * Returns the height that taskbar will inset when inside apps.
+ */
+ public int getContentHeightToReportToApps() {
+ if (hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) {
+ boolean isAnimating = mAnimator != null && mAnimator.isStarted();
+ return mControllers.stashedHandleViewController.isStashedHandleVisible() || isAnimating
+ ? mStashedHeight : 0;
+ }
+ return mUnstashedHeight;
+ }
+
+ public int getStashedHeight() {
+ return mStashedHeight;
+ }
+
+ /**
+ * Should be called when long pressing the nav region when taskbar is present.
+ * @return Whether taskbar was stashed and now is unstashed.
+ */
+ public boolean onLongPressToUnstashTaskbar() {
+ if (!isStashed()) {
+ // We only listen for long press on the nav region to unstash the taskbar. To stash the
+ // taskbar, we use an OnLongClickListener on TaskbarView instead.
+ return false;
+ }
+ if (updateAndAnimateIsManuallyStashedInApp(false)) {
+ mControllers.taskbarActivityContext.getDragLayer().performHapticFeedback(LONG_PRESS);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Updates whether we should stash the taskbar when in apps, and animates to the changed state.
+ * @return Whether we started an animation to either be newly stashed or unstashed.
+ */
+ public boolean updateAndAnimateIsManuallyStashedInApp(boolean isManuallyStashedInApp) {
+ if (!supportsManualStashing()) {
+ return false;
+ }
+ if (hasAnyFlag(FLAG_STASHED_IN_APP_MANUAL) != isManuallyStashedInApp) {
+ mPrefs.edit().putBoolean(SHARED_PREFS_STASHED_KEY, isManuallyStashedInApp).apply();
+ updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
+ applyState();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Create a stash animation and save to {@link #mAnimator}.
+ * @param isStashed whether it's a stash animation or an unstash animation
+ * @param duration duration of the animation
+ * @param startDelay how many milliseconds to delay the animation after starting it.
+ */
+ private void createAnimToIsStashed(boolean isStashed, long duration, long startDelay) {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ mAnimator = new AnimatorSet();
+
+ if (!supportsVisualStashing()) {
+ // Just hide/show the icons and background instead of stashing into a handle.
+ mAnimator.play(mIconAlphaForStash.animateToValue(isStashed ? 0 : 1)
+ .setDuration(duration));
+ mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
+ hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration));
+ mAnimator.setStartDelay(startDelay);
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimator = null;
+ }
+ });
+ return;
+ }
+
+ AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
+ // Not exactly half and may overlap. See [first|second]HalfDurationScale below.
+ AnimatorSet firstHalfAnimatorSet = new AnimatorSet();
+ AnimatorSet secondHalfAnimatorSet = new AnimatorSet();
+
+ final float firstHalfDurationScale;
+ final float secondHalfDurationScale;
+
+ if (isStashed) {
+ firstHalfDurationScale = 0.75f;
+ secondHalfDurationScale = 0.5f;
+ final float stashTranslation = (mUnstashedHeight - mStashedHeight) / 2f;
+
+ fullLengthAnimatorSet.playTogether(
+ mTaskbarBackgroundOffset.animateToValue(1),
+ mIconTranslationYForStash.animateToValue(stashTranslation)
+ );
+ firstHalfAnimatorSet.playTogether(
+ mIconAlphaForStash.animateToValue(0),
+ mIconScaleForStash.animateToValue(STASHED_TASKBAR_SCALE)
+ );
+ secondHalfAnimatorSet.playTogether(
+ mTaskbarStashedHandleAlpha.animateToValue(1)
+ );
+ } else {
+ firstHalfDurationScale = 0.5f;
+ secondHalfDurationScale = 0.75f;
+
+ fullLengthAnimatorSet.playTogether(
+ mTaskbarBackgroundOffset.animateToValue(0),
+ mIconScaleForStash.animateToValue(1),
+ mIconTranslationYForStash.animateToValue(0)
+ );
+ firstHalfAnimatorSet.playTogether(
+ mTaskbarStashedHandleAlpha.animateToValue(0)
+ );
+ secondHalfAnimatorSet.playTogether(
+ mIconAlphaForStash.animateToValue(1)
+ );
+ }
+
+ fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
+ .createRevealAnimToIsStashed(isStashed));
+ // Return the stashed handle to its default scale in case it was changed as part of the
+ // feedforward hint. Note that the reveal animation above also visually scales it.
+ fullLengthAnimatorSet.play(mTaskbarStashedHandleHintScale.animateToValue(1f));
+
+ fullLengthAnimatorSet.setDuration(duration);
+ firstHalfAnimatorSet.setDuration((long) (duration * firstHalfDurationScale));
+ secondHalfAnimatorSet.setDuration((long) (duration * secondHalfDurationScale));
+ secondHalfAnimatorSet.setStartDelay((long) (duration * (1 - secondHalfDurationScale)));
+
+ mAnimator.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
+ secondHalfAnimatorSet);
+ mAnimator.setStartDelay(startDelay);
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsStashed = isStashed;
+ onIsStashed(mIsStashed);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimator = null;
+ }
+ });
+ }
+
+ /**
+ * Creates and starts a partial stash animation, hinting at the new state that will trigger when
+ * long press is detected.
+ * @param animateForward Whether we are going towards the new stashed state or returning to the
+ * unstashed state.
+ */
+ public void startStashHint(boolean animateForward) {
+ if (isStashed() || !supportsManualStashing()) {
+ // Already stashed, no need to hint in that direction.
+ return;
+ }
+ mIconScaleForStash.animateToValue(
+ animateForward ? STASHED_TASKBAR_HINT_SCALE : 1)
+ .setDuration(TASKBAR_HINT_STASH_DURATION).start();
+ }
+
+ /**
+ * Creates and starts a partial unstash animation, hinting at the new state that will trigger
+ * when long press is detected.
+ * @param animateForward Whether we are going towards the new unstashed state or returning to
+ * the stashed state.
+ */
+ public void startUnstashHint(boolean animateForward) {
+ if (!isStashed()) {
+ // Already unstashed, no need to hint in that direction.
+ return;
+ }
+ mTaskbarStashedHandleHintScale.animateToValue(
+ animateForward ? UNSTASHED_TASKBAR_HANDLE_HINT_SCALE : 1)
+ .setDuration(TASKBAR_HINT_STASH_DURATION).start();
+ }
+
+ private void onIsStashed(boolean isStashed) {
+ mControllers.stashedHandleViewController.onIsStashed(isStashed);
+ }
+
+ public void applyState() {
+ applyState(TASKBAR_STASH_DURATION);
+ }
+
+ public void applyState(long duration) {
+ mStatePropertyHolder.setState(mState, duration, true);
+ }
+
+ public void applyState(long duration, long startDelay) {
+ mStatePropertyHolder.setState(mState, duration, startDelay, true);
+ }
+
+ public Animator applyStateWithoutStart() {
+ return applyStateWithoutStart(TASKBAR_STASH_DURATION);
+ }
+
+ public Animator applyStateWithoutStart(long duration) {
+ return mStatePropertyHolder.setState(mState, duration, false);
+ }
+
+ /**
+ * Should be called when a system gesture starts and settles, so we can defer updating
+ * FLAG_STASHED_IN_APP_IME until after the gesture transition completes.
+ */
+ public void setSystemGestureInProgress(boolean inProgress) {
+ mIsSystemGestureInProgress = inProgress;
+ // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
+ if (!mIsSystemGestureInProgress) {
+ updateStateForFlag(FLAG_STASHED_IN_APP_IME, mIsImeShowing);
+ applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
+ }
+ }
+
+ /**
+ * When hiding the IME, delay the unstash animation to align with the end of the transition.
+ */
+ private long getTaskbarStashStartDelayForIme() {
+ if (mIsImeShowing) {
+ // Only delay when IME is exiting, not entering.
+ return 0;
+ }
+ // This duration is based on input_method_extract_exit.xml.
+ long imeExitDuration = mControllers.taskbarActivityContext.getResources()
+ .getInteger(android.R.integer.config_shortAnimTime);
+ return imeExitDuration - TASKBAR_STASH_DURATION_FOR_IME;
+ }
+
+ /** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */
+ public void updateStateForSysuiFlags(int systemUiStateFlags, boolean skipAnim) {
+ long animDuration = TASKBAR_STASH_DURATION;
+ long startDelay = 0;
+
+ updateStateForFlag(FLAG_STASHED_IN_APP_PINNED,
+ hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING));
+
+ // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
+ mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
+ if (!mIsSystemGestureInProgress) {
+ updateStateForFlag(FLAG_STASHED_IN_APP_IME, mIsImeShowing);
+ animDuration = TASKBAR_STASH_DURATION_FOR_IME;
+ startDelay = getTaskbarStashStartDelayForIme();
+ }
+
+ applyState(skipAnim ? 0 : animDuration, skipAnim ? 0 : startDelay);
+ }
+
+ /**
+ * Updates the proper flag to indicate whether the task bar should be stashed.
+ *
+ * Note that this only updates the flag. {@link #applyState()} needs to be called separately.
+ *
+ * @param flag The flag to update.
+ * @param enabled Whether to enable the flag: True will cause the task bar to be stashed /
+ * unstashed.
+ */
+ public void updateStateForFlag(int flag, boolean enabled) {
+ if (enabled) {
+ mState |= flag;
+ } else {
+ mState &= ~flag;
+ }
+ }
+
+ /**
+ * Called after updateStateForFlag() and applyState() have been called.
+ * @param changedFlags The flags that have changed.
+ */
+ private void onStateChangeApplied(int changedFlags) {
+ if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP)) {
+ mControllers.uiController.onStashedInAppChanged();
+ }
+ if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAG_IN_APP)) {
+ notifyStashChange(/* visible */ hasAnyFlag(FLAG_IN_APP),
+ /* stashed */ isStashedInApp());
+ }
+ if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_MANUAL)) {
+ if (hasAnyFlag(FLAG_STASHED_IN_APP_MANUAL)) {
+ mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_LONGPRESS_HIDE);
+ } else {
+ mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_LONGPRESS_SHOW);
+ }
+ }
+ }
+
+ private void notifyStashChange(boolean visible, boolean stashed) {
+ mSystemUiProxy.notifyTaskbarStatus(visible, stashed);
+ mControllers.rotationButtonController.onTaskbarStateChange(visible, stashed);
+ }
+
+ private class StatePropertyHolder {
+ private final IntPredicate mStashCondition;
+
+ private boolean mIsStashed;
+ private int mPrevFlags;
+
+ StatePropertyHolder(IntPredicate stashCondition) {
+ mStashCondition = stashCondition;
+ }
+
+ /**
+ * @see #setState(int, long, long, boolean) with a default startDelay = 0.
+ */
+ public Animator setState(int flags, long duration, boolean start) {
+ return setState(flags, duration, 0 /* startDelay */, start);
+ }
+
+ /**
+ * Applies the latest state, potentially calling onStateChangeApplied() and creating a new
+ * animation (stored in mAnimator) which is started if {@param start} is true.
+ * @param flags The latest flags to apply (see the top of this file).
+ * @param duration The length of the animation.
+ * @param startDelay How long to delay the animation after calling start().
+ * @param start Whether to start mAnimator immediately.
+ * @return mAnimator if mIsStashed changed, else null.
+ */
+ public Animator setState(int flags, long duration, long startDelay, boolean start) {
+ int changedFlags = mPrevFlags ^ flags;
+ if (mPrevFlags != flags) {
+ onStateChangeApplied(changedFlags);
+ mPrevFlags = flags;
+ }
+ boolean isStashed = mStashCondition.test(flags);
+ if (mIsStashed != isStashed) {
+ mIsStashed = isStashed;
+
+ // This sets mAnimator.
+ createAnimToIsStashed(mIsStashed, duration, startDelay);
+ if (start) {
+ mAnimator.start();
+ }
+ return mAnimator;
+ }
+ return null;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
deleted file mode 100644
index a701aae088..0000000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import static com.android.launcher3.LauncherState.TASKBAR;
-import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.states.StateAnimationConfig;
-import com.android.quickstep.AnimatedFloat;
-
-/**
- * StateHandler to animate Taskbar according to Launcher's state machine. Does nothing if Taskbar
- * isn't present (i.e. {@link #setAnimationController} is never called).
- */
-public class TaskbarStateHandler implements StateManager.StateHandler {
-
- private final BaseQuickstepLauncher mLauncher;
-
- // Contains Taskbar-related methods and fields we should aniamte. If null, don't do anything.
- private @Nullable TaskbarAnimationController mAnimationController = null;
-
- public TaskbarStateHandler(BaseQuickstepLauncher launcher) {
- mLauncher = launcher;
- }
-
- public void setAnimationController(TaskbarAnimationController callbacks) {
- mAnimationController = callbacks;
- }
-
- @Override
- public void setState(LauncherState state) {
- setState(state, PropertySetter.NO_ANIM_PROPERTY_SETTER);
- }
-
- @Override
- public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
- PendingAnimation animation) {
- setState(toState, animation);
- }
-
- private void setState(LauncherState toState, PropertySetter setter) {
- if (mAnimationController == null) {
- return;
- }
-
- boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
- setter.setFloat(mAnimationController.getTaskbarVisibilityForLauncherState(),
- AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR);
- setter.setFloat(mAnimationController.getTaskbarScaleForLauncherState(),
- AnimatedFloat.VALUE, toState.getTaskbarScale(mLauncher), LINEAR);
- setter.setFloat(mAnimationController.getTaskbarTranslationYForLauncherState(),
- AnimatedFloat.VALUE, toState.getTaskbarTranslationY(mLauncher), ACCEL_DEACCEL);
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 50adeadbfc..abad9060ab 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -15,6 +15,15 @@
*/
package com.android.launcher3.taskbar;
+import android.view.View;
+
+import androidx.annotation.CallSuper;
+
+import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+
+import java.util.stream.Stream;
+
/**
* Base class for providing different taskbar UI
*/
@@ -22,20 +31,40 @@ public class TaskbarUIController {
public static final TaskbarUIController DEFAULT = new TaskbarUIController();
- /**
- * Pads the Hotseat to line up exactly with Taskbar's copy of the Hotseat.
- */
- public void alignRealHotseatWithTaskbar() { }
+ // Initialized in init.
+ protected TaskbarControllers mControllers;
- protected void onCreate() { }
+ @CallSuper
+ protected void init(TaskbarControllers taskbarControllers) {
+ mControllers = taskbarControllers;
+ }
- protected void onDestroy() { }
+ @CallSuper
+ protected void onDestroy() {
+ mControllers = null;
+ }
protected boolean isTaskbarTouchable() {
return true;
}
- protected void onImeVisible(TaskbarDragLayer container, boolean isVisible) {
- container.updateImeBarVisibilityAlpha(isVisible ? 1 : 0);
+ protected void onStashedInAppChanged() { }
+
+ public Stream getAppIconsForEdu() {
+ return Stream.empty();
+ }
+
+ public void onTaskbarIconLaunched(WorkspaceItemInfo item) { }
+
+ public View getRootView() {
+ return mControllers.taskbarActivityContext.getDragLayer();
+ }
+
+ /**
+ * Called when swiping from the bottom nav region in fully gestural mode.
+ * @param inProgress True if the animation started, false if we just settled on an end target.
+ */
+ public void setSystemGestureInProgress(boolean inProgress) {
+ mControllers.taskbarStashController.setSystemGestureInProgress(inProgress);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java
new file mode 100644
index 0000000000..c785186446
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.view.View;
+import android.view.WindowManager;
+
+import com.android.quickstep.util.LauncherViewsMoveFromCenterTranslationApplier;
+import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
+
+/**
+ * Controls animation of taskbar icons when unfolding foldable devices
+ */
+public class TaskbarUnfoldAnimationController {
+
+ private final ScopedUnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
+ private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimator;
+ private final TransitionListener mTransitionListener = new TransitionListener();
+ private TaskbarViewController mTaskbarViewController;
+
+ public TaskbarUnfoldAnimationController(ScopedUnfoldTransitionProgressProvider
+ unfoldTransitionProgressProvider, WindowManager windowManager) {
+ mUnfoldTransitionProgressProvider = unfoldTransitionProgressProvider;
+ mMoveFromCenterAnimator = new UnfoldMoveFromCenterAnimator(windowManager,
+ new LauncherViewsMoveFromCenterTranslationApplier());
+ }
+
+ /**
+ * Initializes the controller
+ * @param taskbarControllers references to all other taskbar controllers
+ */
+ public void init(TaskbarControllers taskbarControllers) {
+ mTaskbarViewController = taskbarControllers.taskbarViewController;
+ mTaskbarViewController.addOneTimePreDrawListener(() ->
+ mUnfoldTransitionProgressProvider.setReadyToHandleTransition(true));
+ mUnfoldTransitionProgressProvider.addCallback(mTransitionListener);
+ }
+
+ /**
+ * Destroys the controller
+ */
+ public void onDestroy() {
+ mUnfoldTransitionProgressProvider.setReadyToHandleTransition(false);
+ mUnfoldTransitionProgressProvider.removeCallback(mTransitionListener);
+ }
+
+ private class TransitionListener implements TransitionProgressListener {
+
+ @Override
+ public void onTransitionStarted() {
+ mMoveFromCenterAnimator.updateDisplayProperties();
+ View[] icons = mTaskbarViewController.getIconViews();
+ for (View icon : icons) {
+ // TODO(b/193794563) we should re-register views if they are re-bound/re-inflated
+ // during the animation
+ mMoveFromCenterAnimator.registerViewForAnimation(icon);
+ }
+
+ mMoveFromCenterAnimator.onTransitionStarted();
+ }
+
+ @Override
+ public void onTransitionFinished() {
+ mMoveFromCenterAnimator.onTransitionFinished();
+ mMoveFromCenterAnimator.clearRegisteredViews();
+ }
+
+ @Override
+ public void onTransitionProgress(float progress) {
+ mMoveFromCenterAnimator.onTransitionProgress(progress);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index c6573a639c..59393d7b5b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -15,76 +15,54 @@
*/
package com.android.launcher3.taskbar;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.makeMeasureSpec;
-
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.util.AttributeSet;
-import android.view.DragEvent;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
-import android.widget.LinearLayout;
+import android.widget.FrameLayout;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.views.ActivityContext;
/**
* Hosts the Taskbar content such as Hotseat and Recent Apps. Drawn on top of other apps.
*/
-public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconParent, Insettable {
+public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable {
- private final int mIconTouchSize;
- private final boolean mIsRtl;
- private final int mTouchSlop;
- private final RectF mTempDelegateBounds = new RectF();
- private final RectF mDelegateSlopBounds = new RectF();
private final int[] mTempOutLocation = new int[2];
+ private final Rect mIconLayoutBounds = new Rect();
+ private final int mIconTouchSize;
private final int mItemMarginLeftRight;
+ private final int mItemPadding;
private final TaskbarActivityContext mActivityContext;
- // Initialized in TaskbarController constructor.
+ // Initialized in init.
+ private TaskbarViewController.TaskbarViewCallbacks mControllerCallbacks;
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
- LinearLayout mSystemButtonContainer;
- LinearLayout mHotseatIconsContainer;
-
- // Delegate touches to the closest view if within mIconTouchSize.
- private boolean mDelegateTargeted;
- private View mDelegateView;
// Prevents dispatching touches to children if true
private boolean mTouchEnabled = true;
- private boolean mIsDraggingItem;
// Only non-null when the corresponding Folder is open.
private @Nullable FolderIcon mLeaveBehindFolderIcon;
- /** Provider of buttons added to taskbar in 3 button nav */
- private ButtonProvider mButtonProvider;
-
- private boolean mDisableRelayout;
- private boolean mAreHolesAllowed;
-
public TaskbarView(@NonNull Context context) {
this(context, null);
}
@@ -105,85 +83,80 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
Resources resources = getResources();
mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
- mItemMarginLeftRight = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
- mIsRtl = Utilities.isRtl(resources);
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
+ int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx;
+
+ // We layout the icons to be of mIconTouchSize in width and height
+ mItemMarginLeftRight = actualMargin - (mIconTouchSize - actualIconSize) / 2;
+ mItemPadding = (mIconTouchSize - actualIconSize) / 2;
+
+ // Needed to draw folder leave-behind when opening one.
+ setWillNotDraw(false);
}
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mSystemButtonContainer = findViewById(R.id.system_button_layout);
- mHotseatIconsContainer = findViewById(R.id.hotseat_icons_layout);
+ protected void init(TaskbarViewController.TaskbarViewCallbacks callbacks) {
+ mControllerCallbacks = callbacks;
+ mIconClickListener = mControllerCallbacks.getIconOnClickListener();
+ mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener();
+
+ setOnLongClickListener(mControllerCallbacks.getBackgroundOnLongClickListener());
}
- protected void construct(OnClickListener clickListener, OnLongClickListener longClickListener,
- ButtonProvider buttonProvider) {
- mIconClickListener = clickListener;
- mIconLongClickListener = longClickListener;
- mButtonProvider = buttonProvider;
-
- if (mActivityContext.canShowNavButtons()) {
- createNavButtons();
- } else {
- mSystemButtonContainer.setVisibility(GONE);
- }
-
- int numHotseatIcons = mActivityContext.getDeviceProfile().numShownHotseatIcons;
- updateHotseatItems(new ItemInfo[numHotseatIcons]);
- }
-
- /**
- * Enables/disables empty icons in taskbar so that the layout matches with Launcher
- */
- public void setHolesAllowedInLayout(boolean areHolesAllowed) {
- if (mAreHolesAllowed != areHolesAllowed) {
- mAreHolesAllowed = areHolesAllowed;
- updateHotseatItemsVisibility();
- // TODO: Add animation
- }
- }
-
- private void setHolesAllowedInLayoutNoAnimation(boolean areHolesAllowed) {
- if (mAreHolesAllowed != areHolesAllowed) {
- mAreHolesAllowed = areHolesAllowed;
- updateHotseatItemsVisibility();
- onMeasure(makeMeasureSpec(getMeasuredWidth(), EXACTLY),
- makeMeasureSpec(getMeasuredHeight(), EXACTLY));
- onLayout(false, getLeft(), getTop(), getRight(), getBottom());
+ private void removeAndRecycle(View view) {
+ removeView(view);
+ view.setOnClickListener(null);
+ view.setOnLongClickListener(null);
+ if (!(view.getTag() instanceof FolderInfo)) {
+ mActivityContext.getViewCache().recycleView(view.getSourceLayoutResId(), view);
}
+ view.setTag(null);
}
/**
* Inflates/binds the Hotseat views to show in the Taskbar given their ItemInfos.
*/
protected void updateHotseatItems(ItemInfo[] hotseatItemInfos) {
+ int nextViewIndex = 0;
+ int numViewsAnimated = 0;
+
for (int i = 0; i < hotseatItemInfos.length; i++) {
- ItemInfo hotseatItemInfo = hotseatItemInfos[
- !mIsRtl ? i : hotseatItemInfos.length - i - 1];
- View hotseatView = mHotseatIconsContainer.getChildAt(i);
+ ItemInfo hotseatItemInfo = hotseatItemInfos[i];
+ if (hotseatItemInfo == null) {
+ continue;
+ }
// Replace any Hotseat views with the appropriate type if it's not already that type.
final int expectedLayoutResId;
boolean isFolder = false;
- boolean needsReinflate = false;
- if (hotseatItemInfo != null && hotseatItemInfo.isPredictedItem()) {
+ if (hotseatItemInfo.isPredictedItem()) {
expectedLayoutResId = R.layout.taskbar_predicted_app_icon;
} else if (hotseatItemInfo instanceof FolderInfo) {
expectedLayoutResId = R.layout.folder_icon;
isFolder = true;
- // Unlike for BubbleTextView, we can't reapply a new FolderInfo after inflation, so
- // if the info changes we need to reinflate. This should only happen if a new folder
- // is dragged to the position that another folder previously existed.
- needsReinflate = hotseatView != null && hotseatView.getTag() != hotseatItemInfo;
} else {
expectedLayoutResId = R.layout.taskbar_app_icon;
}
- if (hotseatView == null
- || hotseatView.getSourceLayoutResId() != expectedLayoutResId
- || needsReinflate) {
- mHotseatIconsContainer.removeView(hotseatView);
+
+ View hotseatView = null;
+ while (nextViewIndex < getChildCount()) {
+ hotseatView = getChildAt(nextViewIndex);
+
+ // see if the view can be reused
+ if ((hotseatView.getSourceLayoutResId() != expectedLayoutResId)
+ || (isFolder && (hotseatView.getTag() != hotseatItemInfo))) {
+ // Unlike for BubbleTextView, we can't reapply a new FolderInfo after inflation,
+ // so if the info changes we need to reinflate. This should only happen if a new
+ // folder is dragged to the position that another folder previously existed.
+ removeAndRecycle(hotseatView);
+ hotseatView = null;
+ } else {
+ // View found
+ break;
+ }
+ }
+
+ if (hotseatView == null) {
if (isFolder) {
FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId,
@@ -193,40 +166,68 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
} else {
hotseatView = inflate(expectedLayoutResId);
}
- int iconSize = mActivityContext.getDeviceProfile().iconSizePx;
- LayoutParams lp = new LayoutParams(iconSize, iconSize);
- lp.setMargins(mItemMarginLeftRight, 0, mItemMarginLeftRight, 0);
- mHotseatIconsContainer.addView(hotseatView, i, lp);
+ LayoutParams lp = new LayoutParams(mIconTouchSize, mIconTouchSize);
+ hotseatView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ addView(hotseatView, nextViewIndex, lp);
}
// Apply the Hotseat ItemInfos, or hide the view if there is none for a given index.
if (hotseatView instanceof BubbleTextView
&& hotseatItemInfo instanceof WorkspaceItemInfo) {
- ((BubbleTextView) hotseatView).applyFromWorkspaceItem(
- (WorkspaceItemInfo) hotseatItemInfo);
- hotseatView.setOnClickListener(mIconClickListener);
- hotseatView.setOnLongClickListener(mIconLongClickListener);
- } else if (isFolder) {
- hotseatView.setOnClickListener(mIconClickListener);
- hotseatView.setOnLongClickListener(mIconLongClickListener);
- } else {
- hotseatView.setOnClickListener(null);
- hotseatView.setOnLongClickListener(null);
- hotseatView.setTag(null);
+ BubbleTextView btv = (BubbleTextView) hotseatView;
+ WorkspaceItemInfo workspaceInfo = (WorkspaceItemInfo) hotseatItemInfo;
+
+ boolean animate = btv.shouldAnimateIconChange((WorkspaceItemInfo) hotseatItemInfo);
+ btv.applyFromWorkspaceItem(workspaceInfo, animate, numViewsAnimated);
+ if (animate) {
+ numViewsAnimated++;
+ }
}
- updateHotseatItemVisibility(hotseatView);
+ setClickAndLongClickListenersForIcon(hotseatView);
+ nextViewIndex++;
+ }
+ // Remove remaining views
+ while (nextViewIndex < getChildCount()) {
+ removeAndRecycle(getChildAt(nextViewIndex));
}
}
- protected void updateHotseatItemsVisibility() {
- for (int i = mHotseatIconsContainer.getChildCount() - 1; i >= 0; i--) {
- updateHotseatItemVisibility(mHotseatIconsContainer.getChildAt(i));
- }
+ /**
+ * Sets OnClickListener and OnLongClickListener for the given view.
+ */
+ public void setClickAndLongClickListenersForIcon(View icon) {
+ icon.setOnClickListener(mIconClickListener);
+ icon.setOnLongClickListener(mIconLongClickListener);
}
- private void updateHotseatItemVisibility(View hotseatView) {
- hotseatView.setVisibility(
- hotseatView.getTag() != null ? VISIBLE : (mAreHolesAllowed ? INVISIBLE : GONE));
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ int count = getChildCount();
+ int spaceNeeded = count * (mItemMarginLeftRight * 2 + mIconTouchSize);
+ 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.right = iconEnd;
+ mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2;
+ mIconLayoutBounds.bottom = mIconLayoutBounds.top + 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);
+ iconEnd = iconStart - mItemMarginLeftRight;
+ }
+ mIconLayoutBounds.left = iconEnd;
}
@Override
@@ -239,158 +240,54 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
@Override
public boolean onTouchEvent(MotionEvent event) {
- boolean handled = delegateTouchIfNecessary(event);
- return super.onTouchEvent(event) || handled;
+ if (!mTouchEnabled) {
+ return true;
+ }
+ if (mIconLayoutBounds.contains((int) event.getX(), (int) event.getY())) {
+ // Don't allow long pressing between icons.
+ return true;
+ }
+ if (mControllerCallbacks.onTouchEvent(event)) {
+ int oldAction = event.getAction();
+ try {
+ event.setAction(MotionEvent.ACTION_CANCEL);
+ return super.onTouchEvent(event);
+ } finally {
+ event.setAction(oldAction);
+ }
+ }
+ return super.onTouchEvent(event);
}
public void setTouchesEnabled(boolean touchEnabled) {
this.mTouchEnabled = touchEnabled;
}
- /**
- * User touched the Taskbar background. Determine whether the touch is close enough to a view
- * that we should forward the touches to it.
- * @return Whether a delegate view was chosen and it handled the touch event.
- */
- private boolean delegateTouchIfNecessary(MotionEvent event) {
- final float x = event.getX();
- final float y = event.getY();
- if (mDelegateView == null && event.getAction() == MotionEvent.ACTION_DOWN) {
- View delegateView = findDelegateView(x, y);
- if (delegateView != null) {
- mDelegateTargeted = true;
- mDelegateView = delegateView;
- mDelegateSlopBounds.set(mTempDelegateBounds);
- mDelegateSlopBounds.inset(-mTouchSlop, -mTouchSlop);
- }
- }
-
- boolean sendToDelegate = mDelegateTargeted;
- boolean inBounds = true;
- switch (event.getAction()) {
- case MotionEvent.ACTION_MOVE:
- inBounds = mDelegateSlopBounds.contains(x, y);
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mDelegateTargeted = false;
- break;
- }
-
- boolean handled = false;
- if (sendToDelegate) {
- if (inBounds) {
- // Offset event coordinates to be inside the target view
- event.setLocation(mDelegateView.getWidth() / 2f, mDelegateView.getHeight() / 2f);
- } else {
- // Offset event coordinates to be outside the target view (in case it does
- // something like tracking pressed state)
- event.setLocation(-mTouchSlop * 2, -mTouchSlop * 2);
- }
- handled = mDelegateView.dispatchTouchEvent(event);
- // Cleanup if this was the last event to send to the delegate.
- if (!mDelegateTargeted) {
- mDelegateView = null;
- }
- }
- return handled;
- }
-
- /**
- * Return an item whose touch bounds contain the given coordinates,
- * or null if no such item exists.
- *
- * Also sets {@link #mTempDelegateBounds} to be the touch bounds of the chosen delegate view.
- */
- private @Nullable View findDelegateView(float x, float y) {
- for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (!child.isShown() || !child.isClickable()) {
- continue;
- }
- int childCenterX = child.getLeft() + child.getWidth() / 2;
- int childCenterY = child.getTop() + child.getHeight() / 2;
- mTempDelegateBounds.set(
- childCenterX - mIconTouchSize / 2f,
- childCenterY - mIconTouchSize / 2f,
- childCenterX + mIconTouchSize / 2f,
- childCenterY + mIconTouchSize / 2f);
- if (mTempDelegateBounds.contains(x, y)) {
- return child;
- }
- }
- return null;
- }
-
/**
* Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
* touch bounds.
*/
public boolean isEventOverAnyItem(MotionEvent ev) {
getLocationOnScreen(mTempOutLocation);
- float xInOurCoordinates = ev.getX() - mTempOutLocation[0];
- float yInOurCoorindates = ev.getY() - mTempOutLocation[1];
- return findDelegateView(xInOurCoordinates, yInOurCoorindates) != null;
+ int xInOurCoordinates = (int) ev.getX() - mTempOutLocation[0];
+ int yInOurCoorindates = (int) ev.getY() - mTempOutLocation[1];
+ return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates);
+ }
+
+ public Rect getIconLayoutBounds() {
+ return mIconLayoutBounds;
}
/**
- * Add back/home/recents buttons into a single ViewGroup that will be inserted at
- * {@param navButtonStartIndex}
+ * Returns the app icons currently shown in the taskbar.
*/
- private void createNavButtons() {
- LinearLayout.LayoutParams buttonParams = new LinearLayout.LayoutParams(
- mActivityContext.getDeviceProfile().iconSizePx,
- mActivityContext.getDeviceProfile().iconSizePx
- );
- buttonParams.gravity = Gravity.CENTER;
-
- mSystemButtonContainer.addView(mButtonProvider.getBack(), buttonParams);
- mSystemButtonContainer.addView(mButtonProvider.getHome(), buttonParams);
- mSystemButtonContainer.addView(mButtonProvider.getRecents(), buttonParams);
- }
-
- @Override
- public boolean onDragEvent(DragEvent event) {
- switch (event.getAction()) {
- case DragEvent.ACTION_DRAG_STARTED:
- mIsDraggingItem = true;
- AbstractFloatingView.closeAllOpenViews(mActivityContext);
- return true;
- case DragEvent.ACTION_DRAG_ENDED:
- mIsDraggingItem = false;
- break;
- }
- return super.onDragEvent(event);
- }
-
- public boolean isDraggingItem() {
- return mIsDraggingItem;
- }
-
- /**
- * @return The bounding box of where the hotseat elements are relative to this TaskbarView.
- */
- protected RectF getHotseatBounds() {
- RectF result;
- mDisableRelayout = true;
- boolean wereHolesAllowed = mAreHolesAllowed;
- setHolesAllowedInLayoutNoAnimation(true);
- result = new RectF(
- mHotseatIconsContainer.getLeft(),
- mHotseatIconsContainer.getTop(),
- mHotseatIconsContainer.getRight(),
- mHotseatIconsContainer.getBottom());
- setHolesAllowedInLayoutNoAnimation(wereHolesAllowed);
- mDisableRelayout = false;
-
- return result;
- }
-
- @Override
- public void requestLayout() {
- if (!mDisableRelayout) {
- super.requestLayout();
+ public View[] getIconViews() {
+ final int count = getChildCount();
+ View[] icons = new View[count];
+ for (int i = 0; i < count; i++) {
+ icons[i] = getChildAt(i);
}
+ return icons;
}
// FolderIconParent implemented methods.
@@ -421,7 +318,7 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
}
private View inflate(@LayoutRes int layoutResId) {
- return mActivityContext.getLayoutInflater().inflate(layoutResId, this, false);
+ return mActivityContext.getViewCache().getView(layoutResId, mActivityContext, this);
}
@Override
@@ -429,11 +326,8 @@ public class TaskbarView extends LinearLayout implements FolderIcon.FolderIconPa
// Ignore, we just implement Insettable to draw behind system insets.
}
- public void setIconsVisibility(boolean isVisible) {
- mHotseatIconsContainer.setVisibility(isVisible ? VISIBLE : INVISIBLE);
- }
-
public boolean areIconsVisible() {
- return mHotseatIconsContainer.getVisibility() == VISIBLE;
+ // Consider the overall visibility
+ return getVisibility() == VISIBLE;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
new file mode 100644
index 0000000000..445a23bf3f
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.quickstep.AnimatedFloat.VALUE;
+
+import android.graphics.Rect;
+import android.util.FloatProperty;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.AnimatedFloat;
+
+/**
+ * Handles properties/data collection, then passes the results to TaskbarView to render.
+ */
+public class TaskbarViewController {
+ private static final Runnable NO_OP = () -> { };
+
+ public static final int ALPHA_INDEX_HOME = 0;
+ public static final int ALPHA_INDEX_KEYGUARD = 1;
+ public static final int ALPHA_INDEX_STASH = 2;
+ public static final int ALPHA_INDEX_RECENTS_DISABLED = 3;
+ public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4;
+ private static final int NUM_ALPHA_CHANNELS = 5;
+
+ private final TaskbarActivityContext mActivity;
+ private final TaskbarView mTaskbarView;
+ private final MultiValueAlpha mTaskbarIconAlpha;
+ private final AnimatedFloat mTaskbarIconScaleForStash = new AnimatedFloat(this::updateScale);
+ private final AnimatedFloat mTaskbarIconTranslationYForHome = new AnimatedFloat(
+ this::updateTranslationY);
+ private final AnimatedFloat mTaskbarIconTranslationYForStash = new AnimatedFloat(
+ this::updateTranslationY);
+ private AnimatedFloat mTaskbarNavButtonTranslationY;
+
+ private final TaskbarModelCallbacks mModelCallbacks;
+
+ // Initialized in init.
+ private TaskbarControllers mControllers;
+
+ // Animation to align icons with Launcher, created lazily. This allows the controller to be
+ // active only during the animation and does not need to worry about layout changes.
+ private AnimatorPlaybackController mIconAlignControllerLazy = null;
+ private Runnable mOnControllerPreCreateCallback = NO_OP;
+
+ public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) {
+ mActivity = activity;
+ mTaskbarView = taskbarView;
+ mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, NUM_ALPHA_CHANNELS);
+ mTaskbarIconAlpha.setUpdateVisibility(true);
+ mModelCallbacks = new TaskbarModelCallbacks(activity, mTaskbarView);
+ }
+
+ public void init(TaskbarControllers controllers) {
+ mControllers = controllers;
+ mTaskbarView.init(new TaskbarViewCallbacks());
+ mTaskbarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarSize;
+
+ mTaskbarIconScaleForStash.updateValue(1f);
+
+ mModelCallbacks.init(controllers);
+ if (mActivity.isUserSetupComplete()) {
+ // Only load the callbacks if user setup is completed
+ LauncherAppState.getInstance(mActivity).getModel().addCallbacksAndLoad(mModelCallbacks);
+ }
+ mTaskbarNavButtonTranslationY =
+ controllers.navbarButtonsViewController.getTaskbarNavButtonTranslationY();
+ }
+
+ public void onDestroy() {
+ LauncherAppState.getInstance(mActivity).getModel().removeCallbacks(mModelCallbacks);
+ }
+
+ public boolean areIconsVisible() {
+ return mTaskbarView.areIconsVisible();
+ }
+
+ public MultiValueAlpha getTaskbarIconAlpha() {
+ return mTaskbarIconAlpha;
+ }
+
+ /**
+ * Should be called when the IME visibility changes, so we can make Taskbar not steal touches.
+ */
+ public void setImeIsVisible(boolean isImeVisible) {
+ mTaskbarView.setTouchesEnabled(!isImeVisible);
+ }
+
+ /**
+ * Should be called when the recents button is disabled, so we can hide taskbar icons as well.
+ */
+ public void setRecentsButtonDisabled(boolean isDisabled) {
+ // TODO: check TaskbarStashController#supportsStashing(), to stash instead of setting alpha.
+ mTaskbarIconAlpha.getProperty(ALPHA_INDEX_RECENTS_DISABLED).setValue(isDisabled ? 0 : 1);
+ }
+
+ /**
+ * Sets OnClickListener and OnLongClickListener for the given view.
+ */
+ public void setClickAndLongClickListenersForIcon(View icon) {
+ mTaskbarView.setClickAndLongClickListenersForIcon(icon);
+ }
+
+ /**
+ * Adds one time pre draw listener to the taskbar view, it is called before
+ * drawing a frame and invoked only once
+ * @param listener callback that will be invoked before drawing the next frame
+ */
+ public void addOneTimePreDrawListener(Runnable listener) {
+ mTaskbarView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ final ViewTreeObserver viewTreeObserver = mTaskbarView.getViewTreeObserver();
+ if (viewTreeObserver.isAlive()) {
+ listener.run();
+ viewTreeObserver.removeOnPreDrawListener(this);
+ }
+ return true;
+ }
+ });
+ }
+
+ public Rect getIconLayoutBounds() {
+ return mTaskbarView.getIconLayoutBounds();
+ }
+
+ public View[] getIconViews() {
+ return mTaskbarView.getIconViews();
+ }
+
+ public AnimatedFloat getTaskbarIconScaleForStash() {
+ return mTaskbarIconScaleForStash;
+ }
+
+ public AnimatedFloat getTaskbarIconTranslationYForStash() {
+ return mTaskbarIconTranslationYForStash;
+ }
+
+ /**
+ * Applies scale properties for the entire TaskbarView (rather than individual icons).
+ */
+ private void updateScale() {
+ float scale = mTaskbarIconScaleForStash.value;
+ mTaskbarView.setScaleX(scale);
+ mTaskbarView.setScaleY(scale);
+ }
+
+ private void updateTranslationY() {
+ mTaskbarView.setTranslationY(mTaskbarIconTranslationYForHome.value
+ + mTaskbarIconTranslationYForStash.value);
+ }
+
+ /**
+ * Sets the taskbar icon alignment relative to Launcher hotseat icons
+ * @param alignmentRatio [0, 1]
+ * 0 => not aligned
+ * 1 => fully aligned
+ */
+ public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
+ if (mIconAlignControllerLazy == null) {
+ mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
+ }
+ mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
+ if (alignmentRatio <= 0 || alignmentRatio >= 1) {
+ // Cleanup lazy controller so that it is created again in next animation
+ mIconAlignControllerLazy = null;
+ }
+ }
+
+ /**
+ * Creates an animation for aligning the taskbar icons with the provided Launcher device profile
+ */
+ private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
+ mOnControllerPreCreateCallback.run();
+ PendingAnimation setter = new PendingAnimation(100);
+ Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
+ float scaleUp = ((float) launcherDp.iconSizePx) / mActivity.getDeviceProfile().iconSizePx;
+ int hotseatCellSize =
+ (launcherDp.availableWidthPx - hotseatPadding.left - hotseatPadding.right)
+ / launcherDp.numShownHotseatIcons;
+
+ int offsetY = launcherDp.getTaskbarOffsetY();
+ setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, LINEAR);
+ setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, LINEAR);
+
+ int collapsedHeight = mActivity.getDefaultTaskbarWindowHeight();
+ int expandedHeight = Math.max(collapsedHeight,
+ mActivity.getDeviceProfile().taskbarSize + offsetY);
+ setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
+ anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
+
+ int count = mTaskbarView.getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = mTaskbarView.getChildAt(i);
+ ItemInfo info = (ItemInfo) child.getTag();
+ setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
+
+ float childCenter = (child.getLeft() + child.getRight()) / 2;
+ float hotseatIconCenter = hotseatPadding.left + hotseatCellSize * info.screenId
+ + hotseatCellSize / 2;
+ setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR);
+ }
+
+ AnimatorPlaybackController controller = setter.createPlaybackController();
+ mOnControllerPreCreateCallback = () -> controller.setPlayFraction(0);
+ return controller;
+ }
+
+ public void onRotationChanged(DeviceProfile deviceProfile) {
+ if (areIconsVisible()) {
+ // We only translate on rotation when on home
+ return;
+ }
+ mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY());
+ }
+
+ /**
+ * Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
+ * touch bounds.
+ */
+ public boolean isEventOverAnyItem(MotionEvent ev) {
+ return mTaskbarView.isEventOverAnyItem(ev);
+ }
+
+ /**
+ * Callbacks for {@link TaskbarView} to interact with its controller.
+ */
+ public class TaskbarViewCallbacks {
+ private final float mSquaredTouchSlop = Utilities.squaredTouchSlop(mActivity);
+
+ private float mDownX, mDownY;
+ private boolean mCanceledStashHint;
+
+ public View.OnClickListener getIconOnClickListener() {
+ return mActivity.getItemOnClickListener();
+ }
+
+ public View.OnLongClickListener getIconOnLongClickListener() {
+ return mControllers.taskbarDragController::startDragOnLongClick;
+ }
+
+ public View.OnLongClickListener getBackgroundOnLongClickListener() {
+ return view -> mControllers.taskbarStashController
+ .updateAndAnimateIsManuallyStashedInApp(true);
+ }
+
+ /**
+ * Get the first chance to handle TaskbarView#onTouchEvent, and return whether we want to
+ * consume the touch so TaskbarView treats it as an ACTION_CANCEL.
+ */
+ public boolean onTouchEvent(MotionEvent motionEvent) {
+ final float x = motionEvent.getRawX();
+ final float y = motionEvent.getRawY();
+ switch (motionEvent.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDownX = x;
+ mDownY = y;
+ mControllers.taskbarStashController.startStashHint(/* animateForward = */ true);
+ mCanceledStashHint = false;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (!mCanceledStashHint
+ && squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop) {
+ mControllers.taskbarStashController.startStashHint(
+ /* animateForward= */ false);
+ mCanceledStashHint = true;
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ if (!mCanceledStashHint) {
+ mControllers.taskbarStashController.startStashHint(
+ /* animateForward= */ false);
+ }
+ break;
+ }
+ return false;
+ }
+ }
+
+ public static final FloatProperty ICON_TRANSLATE_X =
+ new FloatProperty("taskbarAligmentTranslateX") {
+
+ @Override
+ public void setValue(View view, float v) {
+ if (view instanceof BubbleTextView) {
+ ((BubbleTextView) view).setTranslationXForTaskbarAlignmentAnimation(v);
+ } else if (view instanceof FolderIcon) {
+ ((FolderIcon) view).setTranslationForTaskbarAlignmentAnimation(v);
+ } else {
+ view.setTranslationX(v);
+ }
+ }
+
+ @Override
+ public Float get(View view) {
+ if (view instanceof BubbleTextView) {
+ return ((BubbleTextView) view)
+ .getTranslationXForTaskbarAlignmentAnimation();
+ } else if (view instanceof FolderIcon) {
+ return ((FolderIcon) view).getTranslationXForTaskbarAlignmentAnimation();
+ }
+ return view.getTranslationX();
+ }
+ };
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 76a5782d11..aa26645eb9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -17,10 +17,15 @@
package com.android.launcher3.uioverrides;
import android.app.Person;
+import android.content.Context;
import android.content.pm.ShortcutInfo;
+import android.content.res.Resources;
import android.view.Display;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.Mode;
public class ApiWrapper {
@@ -37,4 +42,31 @@ public class ApiWrapper {
public static boolean isInternalDisplay(Display display) {
return display.getType() == Display.TYPE_INTERNAL;
}
+
+ /**
+ * Returns a unique ID representing the display
+ */
+ public static String getUniqueId(Display display) {
+ return display.getUniqueId();
+ }
+
+ /**
+ * Returns the minimum space that should be left empty at the end of hotseat
+ */
+ public static int getHotseatEndOffset(Context context) {
+ if (SysUINavigationMode.INSTANCE.get(context).getMode() == Mode.THREE_BUTTONS) {
+ Resources res = context.getResources();
+ /*
+ * 3 nav buttons +
+ * Little space at the end for contextual buttons +
+ * Little space between icons and nav buttons
+ */
+ return 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
+ + res.getDimensionPixelSize(R.dimen.taskbar_contextual_button_margin)
+ + res.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing);
+ } else {
+ return 0;
+ }
+
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 1d523151db..0eaea83801 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -17,6 +17,8 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
+import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
+import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
@@ -27,8 +29,6 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
-import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
-import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.util.FloatProperty;
@@ -40,7 +40,6 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.views.RecentsView;
/**
@@ -97,13 +96,6 @@ public abstract class BaseRecentsViewStateController
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
- PagedOrientationHandler orientationHandler =
- ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
- FloatProperty taskViewsFloat = orientationHandler.getSplitSelectTaskOffset(
- TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
- mLauncher.getDeviceProfile());
- setter.setFloat(mRecentsView, taskViewsFloat,
- toState.getSplitSelectTranslation(mLauncher), LINEAR);
setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
@@ -112,8 +104,9 @@ public abstract class BaseRecentsViewStateController
mRecentsView, getTaskModalnessProperty(),
toState.getOverviewModalness(),
config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR));
- setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS,
- toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f, LINEAR);
+ boolean showAsGrid = toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile());
+ setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
+ showAsGrid ? INSTANT : FINAL_FRAME);
}
abstract FloatProperty getTaskModalnessProperty();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java
index c115bbb9fb..c46809afc6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/DeviceFlag.java
@@ -17,21 +17,17 @@
package com.android.launcher3.uioverrides;
import android.annotation.TargetApi;
-import android.content.Context;
import android.os.Build;
import android.provider.DeviceConfig;
import com.android.launcher3.config.FeatureFlags.DebugFlag;
-import java.util.ArrayList;
-
@TargetApi(Build.VERSION_CODES.P)
public class DeviceFlag extends DebugFlag {
public static final String NAMESPACE_LAUNCHER = "launcher";
private final boolean mDefaultValueInCode;
- ArrayList mListeners;
public DeviceFlag(String key, boolean defaultValue, String description) {
super(key, getDeviceValue(key, defaultValue), description);
@@ -43,54 +39,12 @@ public class DeviceFlag extends DebugFlag {
return super.appendProps(src).append(", mDefaultValueInCode=").append(mDefaultValueInCode);
}
- @Override
- public void initialize(Context context) {
- super.initialize(context);
- if (mListeners == null) {
- mListeners = new ArrayList<>();
- registerDeviceConfigChangedListener(context);
- }
- }
-
- @Override
- public void addChangeListener(Context context, Runnable r) {
- if (mListeners == null) {
- initialize(context);
- }
- mListeners.add(r);
- }
-
- @Override
- public void removeChangeListener(Runnable r) {
- if (mListeners == null) {
- return;
- }
- mListeners.remove(r);
- }
-
@Override
public boolean get() {
// Override this method in order to let Robolectric ShadowDeviceFlag to stub it.
return super.get();
}
- private void registerDeviceConfigChangedListener(Context context) {
- DeviceConfig.addOnPropertiesChangedListener(
- NAMESPACE_LAUNCHER,
- context.getMainExecutor(),
- properties -> {
- if (!NAMESPACE_LAUNCHER.equals(properties.getNamespace())
- || !properties.getKeyset().contains(key)) {
- return;
- }
- defaultValue = getDeviceValue(key, mDefaultValueInCode);
- initialize(context);
- for (Runnable r: mListeners) {
- r.run();
- }
- });
- }
-
protected static boolean getDeviceValue(String key, boolean defaultValue) {
return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, defaultValue);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index d839a36213..ee6e8cee9b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -15,6 +15,16 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
+import android.animation.Keyframe;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
@@ -23,8 +33,10 @@ import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Process;
import android.util.AttributeSet;
+import android.util.FloatProperty;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -35,6 +47,8 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.icons.LauncherIcons;
@@ -45,6 +59,10 @@ import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
* A BubbleTextView with a ring around it's drawable
*/
@@ -53,6 +71,9 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView {
private static final int RING_SHADOW_COLOR = 0x99000000;
private static final float RING_EFFECT_RATIO = 0.095f;
+ private static final long ICON_CHANGE_ANIM_DURATION = 360;
+ private static final long ICON_CHANGE_ANIM_STAGGER = 50;
+
boolean mIsDrawingDot = false;
private final DeviceProfile mDeviceProfile;
private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -67,6 +88,25 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView {
private int mPlateColor;
boolean mDrawForDrag = false;
+ // Used for the "slot-machine" education animation.
+ private List mSlotMachineIcons;
+ private Animator mSlotMachineAnim;
+ private float mSlotMachineIconTranslationY;
+
+ private static final FloatProperty SLOT_MACHINE_TRANSLATION_Y =
+ new FloatProperty("slotMachineTranslationY") {
+ @Override
+ public void setValue(PredictedAppIcon predictedAppIcon, float transY) {
+ predictedAppIcon.mSlotMachineIconTranslationY = transY;
+ predictedAppIcon.invalidate();
+ }
+
+ @Override
+ public Float get(PredictedAppIcon predictedAppIcon) {
+ return predictedAppIcon.mSlotMachineIconTranslationY;
+ }
+ };
+
public PredictedAppIcon(Context context) {
this(context, null, 0);
}
@@ -88,15 +128,38 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView {
@Override
public void onDraw(Canvas canvas) {
int count = canvas.save();
+ boolean isSlotMachineAnimRunning = mSlotMachineAnim != null;
if (!mIsPinned) {
drawEffect(canvas);
+ if (isSlotMachineAnimRunning) {
+ // Clip to to outside of the ring during the slot machine animation.
+ canvas.clipPath(mRingPath);
+ }
canvas.translate(getWidth() * RING_EFFECT_RATIO, getHeight() * RING_EFFECT_RATIO);
canvas.scale(1 - 2 * RING_EFFECT_RATIO, 1 - 2 * RING_EFFECT_RATIO);
}
- super.onDraw(canvas);
+ if (isSlotMachineAnimRunning) {
+ drawSlotMachineIcons(canvas);
+ } else {
+ super.onDraw(canvas);
+ }
canvas.restoreToCount(count);
}
+ private void drawSlotMachineIcons(Canvas canvas) {
+ canvas.translate((getWidth() - getIconSize()) / 2f,
+ (getHeight() - getIconSize()) / 2f + mSlotMachineIconTranslationY);
+ for (Drawable icon : mSlotMachineIcons) {
+ icon.setBounds(0, 0, getIconSize(), getIconSize());
+ icon.draw(canvas);
+ canvas.translate(0, getSlotMachineIconPlusSpacingSize());
+ }
+ }
+
+ private float getSlotMachineIconPlusSpacingSize() {
+ return getIconSize() + getOutlineOffsetY();
+ }
+
@Override
protected void drawDotIfNecessary(Canvas canvas) {
mIsDrawingDot = true;
@@ -109,9 +172,17 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView {
}
@Override
- public void applyFromWorkspaceItem(WorkspaceItemInfo info) {
- super.applyFromWorkspaceItem(info);
- mPlateColor = ColorUtils.setAlphaComponent(mDotParams.color, 200);
+ public void applyFromWorkspaceItem(WorkspaceItemInfo info, boolean animate, int staggerIndex) {
+ // Create the slot machine animation first, since it uses the current icon to start.
+ Animator slotMachineAnim = animate
+ ? createSlotMachineAnim(Collections.singletonList(info.bitmap), false)
+ : null;
+ super.applyFromWorkspaceItem(info, animate, staggerIndex);
+ int oldPlateColor = mPlateColor;
+ int newPlateColor = ColorUtils.setAlphaComponent(mDotParams.color, 200);
+ if (!animate) {
+ mPlateColor = newPlateColor;
+ }
if (mIsPinned) {
setContentDescription(info.contentDescription);
} else {
@@ -119,6 +190,76 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView {
getContext().getString(R.string.hotseat_prediction_content_description,
info.contentDescription));
}
+
+ if (animate) {
+ ValueAnimator plateColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(),
+ oldPlateColor, newPlateColor);
+ plateColorAnim.addUpdateListener(valueAnimator -> {
+ mPlateColor = (int) valueAnimator.getAnimatedValue();
+ invalidate();
+ });
+ AnimatorSet changeIconAnim = new AnimatorSet();
+ if (slotMachineAnim != null) {
+ changeIconAnim.play(slotMachineAnim);
+ }
+ changeIconAnim.play(plateColorAnim);
+ changeIconAnim.setStartDelay(staggerIndex * ICON_CHANGE_ANIM_STAGGER);
+ changeIconAnim.setDuration(ICON_CHANGE_ANIM_DURATION).start();
+ }
+ }
+
+ /**
+ * Returns an Animator that translates the given icons in a "slot-machine" fashion, beginning
+ * and ending with the original icon.
+ */
+ public @Nullable Animator createSlotMachineAnim(List iconsToAnimate) {
+ return createSlotMachineAnim(iconsToAnimate, true);
+ }
+
+ /**
+ * Returns an Animator that translates the given icons in a "slot-machine" fashion, beginning
+ * with the original icon, then cycling through the given icons, optionally ending back with
+ * the original icon.
+ * @param endWithOriginalIcon Whether we should land back on the icon we started with, rather
+ * than the last item in iconsToAnimate.
+ */
+ public @Nullable Animator createSlotMachineAnim(List iconsToAnimate,
+ boolean endWithOriginalIcon) {
+ if (mIsPinned || iconsToAnimate == null || iconsToAnimate.isEmpty()) {
+ return null;
+ }
+ if (mSlotMachineAnim != null) {
+ mSlotMachineAnim.end();
+ }
+
+ // Bookend the other animating icons with the original icon on both ends.
+ mSlotMachineIcons = new ArrayList<>(iconsToAnimate.size() + 2);
+ mSlotMachineIcons.add(getIcon());
+ iconsToAnimate.stream()
+ .map(iconInfo -> iconInfo.newThemedIcon(mContext))
+ .forEach(mSlotMachineIcons::add);
+ if (endWithOriginalIcon) {
+ mSlotMachineIcons.add(getIcon());
+ }
+
+ float finalTrans = -getSlotMachineIconPlusSpacingSize() * (mSlotMachineIcons.size() - 1);
+ Keyframe[] keyframes = new Keyframe[] {
+ Keyframe.ofFloat(0f, 0f),
+ Keyframe.ofFloat(0.82f, finalTrans - getOutlineOffsetY() / 2f), // Overshoot
+ Keyframe.ofFloat(1f, finalTrans) // Ease back into the final position
+ };
+ keyframes[1].setInterpolator(ACCEL_DEACCEL);
+ keyframes[2].setInterpolator(ACCEL_DEACCEL);
+
+ mSlotMachineAnim = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofKeyframe(SLOT_MACHINE_TRANSLATION_Y, keyframes));
+ mSlotMachineAnim.addListener(AnimatorListeners.forEndCallback(() -> {
+ mSlotMachineIcons = null;
+ mSlotMachineAnim = null;
+ mSlotMachineIconTranslationY = 0;
+ invalidate();
+ }));
+ return mSlotMachineAnim;
}
/**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index ec9893c84f..9050ddc511 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -52,10 +52,10 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.appprediction.PredictionRowView;
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
@@ -68,7 +68,9 @@ import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchControll
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.OnboardingPrefs;
+import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
@@ -84,7 +86,6 @@ import com.android.quickstep.views.TaskView;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
@@ -107,7 +108,8 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
}
@Override
- protected void logAppLaunch(ItemInfo info, InstanceId instanceId) {
+ public void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info,
+ InstanceId instanceId) {
// If the app launch is from any of the surfaces in AllApps then add the InstanceId from
// LiveSearchManager to recreate the AllApps session on the server side.
if (mAllAppsSessionLogId != null && ALL_APPS.equals(
@@ -115,8 +117,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
instanceId = mAllAppsSessionLogId;
}
- StatsLogger logger = getStatsLogManager()
- .logger().withItemInfo(info).withInstanceId(instanceId);
+ StatsLogger logger = statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId);
if (mAllAppsPredictions != null
&& (info.itemType == ITEM_TYPE_APPLICATION
@@ -139,6 +140,15 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
mHotseatPredictionController.logLaunchedAppRankingInfo(info, instanceId);
}
+ @Override
+ protected void completeAddShortcut(Intent data, int container, int screenId, int cellX,
+ int cellY, PendingRequestArgs args) {
+ if (container == CONTAINER_HOTSEAT) {
+ mHotseatPredictionController.onDeferredDrop(cellX, cellY);
+ }
+ super.completeAddShortcut(data, container, screenId, cellX, cellY, args);
+ }
+
@Override
protected LauncherAccessibilityDelegate createAccessibilityDelegate() {
return new QuickstepAccessibilityDelegate(this);
@@ -166,7 +176,11 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
// Only pause is taskbar controller is not present
mHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null);
- return super.startActivitySafely(v, intent, item);
+ boolean started = super.startActivitySafely(v, intent, item);
+ if (getTaskbarUIController() == null && !started) {
+ mHotseatPredictionController.setPauseUIUpdate(false);
+ }
+ return started;
}
@Override
@@ -231,12 +245,9 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
}
@Override
- public void bindWorkspaceItemsChanged(List updated) {
- super.bindWorkspaceItemsChanged(updated);
- if (getTaskbarUIController() != null && updated.stream()
- .filter(w -> w.container == CONTAINER_HOTSEAT).findFirst().isPresent()) {
- getTaskbarUIController().onHotseatUpdated();
- }
+ public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher) {
+ super.bindWorkspaceComponentsRemoved(matcher);
+ mHotseatPredictionController.onModelItemsRemoved(matcher);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 996d36aadc..32ce1c40d7 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -18,20 +18,22 @@ package com.android.launcher3.uioverrides;
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.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;
import android.annotation.TargetApi;
import android.os.Build;
import android.util.FloatProperty;
+import android.util.Pair;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
@@ -39,6 +41,7 @@ import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.views.ClearAllButton;
import com.android.quickstep.views.LauncherRecentsView;
@@ -65,6 +68,11 @@ public final class RecentsViewStateController extends
}
setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig(), state);
mRecentsView.setFullscreenProgress(state.getOverviewFullscreenProgress());
+ // In Overview, we may be layering app surfaces behind Launcher, so we need to notify
+ // DepthController to prevent optimizations which might occlude the layers behind
+ mLauncher.getDepthController().setHasContentBehindLauncher(state.overviewUi);
+
+ handleSplitSelectionState(state, null);
}
@Override
@@ -80,14 +88,12 @@ public final class RecentsViewStateController extends
builder.addListener(
AnimatorListeners.forSuccessCallback(mRecentsView::resetTaskVisuals));
}
+ // In Overview, we may be layering app surfaces behind Launcher, so we need to notify
+ // DepthController to prevent optimizations which might occlude the layers behind
+ builder.addListener(AnimatorListeners.forSuccessCallback(() ->
+ mLauncher.getDepthController().setHasContentBehindLauncher(toState.overviewUi)));
- // Create or dismiss split screen select animations
- LauncherState currentState = mLauncher.getStateManager().getState();
- if (isSplitSelectionState(toState) && !isSplitSelectionState(currentState)) {
- builder.add(mRecentsView.createSplitSelectInitAnimation().buildAnim());
- } else if (!isSplitSelectionState(toState) && isSplitSelectionState(currentState)) {
- builder.add(mRecentsView.cancelSplitSelect(true).buildAnim());
- }
+ handleSplitSelectionState(toState, builder);
setAlphas(builder, config, toState);
builder.setFloat(mRecentsView, FULLSCREEN_PROGRESS,
@@ -95,10 +101,52 @@ public final class RecentsViewStateController extends
}
/**
- * @return true if {@param toState} is {@link LauncherState#OVERVIEW_SPLIT_SELECT}
+ * Create or dismiss split screen select animations.
+ * @param builder if null then this will run the split select animations right away, otherwise
+ * will add animations to builder.
*/
- private boolean isSplitSelectionState(@NonNull LauncherState toState) {
- return toState == OVERVIEW_SPLIT_SELECT;
+ private void handleSplitSelectionState(@NonNull LauncherState toState,
+ @Nullable PendingAnimation builder) {
+ LauncherState currentState = mLauncher.getStateManager().getState();
+ boolean animate = builder != null;
+ PagedOrientationHandler orientationHandler =
+ ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
+ Pair taskViewsFloat =
+ orientationHandler.getSplitSelectTaskOffset(
+ TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
+ mLauncher.getDeviceProfile());
+
+ if (isSplitSelectionState(currentState, toState)) {
+ // Animation to "dismiss" selected taskView
+ PendingAnimation splitSelectInitAnimation =
+ mRecentsView.createSplitSelectInitAnimation();
+ // Add properties to shift remaining taskViews to get out of placeholder view
+ splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.first,
+ toState.getSplitSelectTranslation(mLauncher), LINEAR);
+ splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
+
+ if (!animate && isSplitSelectionState(currentState, toState)) {
+ splitSelectInitAnimation.buildAnim().start();
+ } else if (animate &&
+ isSplitSelectionState(currentState, toState)) {
+ builder.add(splitSelectInitAnimation.buildAnim());
+ }
+ }
+
+ if (isSplitSelectionState(currentState, toState)) {
+ mRecentsView.applySplitPrimaryScrollOffset();
+ } else {
+ mRecentsView.resetSplitPrimaryScrollOffset();
+ }
+ }
+
+ /**
+ * @return true if {@param toState} is {@link LauncherState#OVERVIEW_SPLIT_SELECT}
+ * and {@param fromState} is not {@link LauncherState#OVERVIEW_SPLIT_SELECT}
+ */
+ private boolean isSplitSelectionState(@NonNull LauncherState fromState,
+ @NonNull LauncherState toState) {
+ return fromState != OVERVIEW_SPLIT_SELECT && toState == OVERVIEW_SPLIT_SELECT;
}
private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
@@ -106,16 +154,10 @@ public final class RecentsViewStateController extends
float clearAllButtonAlpha = state.areElementsVisible(mLauncher, CLEAR_ALL_BUTTON) ? 1 : 0;
propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
clearAllButtonAlpha, LINEAR);
- float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS)
- && mRecentsView.shouldShowOverviewActionsForState(state) ? 1 : 0;
+ float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
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/plugins/PluginInitializerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
deleted file mode 100644
index d14e8efdd6..0000000000
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginInitializerImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.launcher3.uioverrides.plugins;
-
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-
-import android.content.Context;
-import android.os.Looper;
-
-import com.android.launcher3.Utilities;
-import com.android.systemui.shared.plugins.PluginInitializer;
-
-public class PluginInitializerImpl implements PluginInitializer {
- @Override
- public Looper getBgLooper() {
- return MODEL_EXECUTOR.getLooper();
- }
-
- @Override
- public void onPluginManagerInit() {
- }
-
- @Override
- public String[] getWhitelistedPlugins(Context context) {
- return new String[0];
- }
-
- @Override
- public PluginEnablerImpl getPluginEnabler(Context context) {
- return new PluginEnablerImpl(context);
- }
-
- @Override
- public void handleWtfs() {
- }
-
- public boolean isDebuggable() {
- return Utilities.IS_DEBUG_DEVICE;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
index 2e422b77f6..df0ac7ce22 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
@@ -16,21 +16,29 @@ package com.android.launcher3.uioverrides.plugins;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
+import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import com.android.launcher3.Utilities;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.shared.plugins.PluginActionManager;
+import com.android.systemui.shared.plugins.PluginInstance;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.plugins.PluginPrefs;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
public class PluginManagerWrapper {
@@ -46,21 +54,36 @@ public class PluginManagerWrapper {
private PluginManagerWrapper(Context c) {
mContext = c;
- PluginInitializerImpl pluginInitializer = new PluginInitializerImpl();
- mPluginManager = new PluginManagerImpl(c, pluginInitializer);
- mPluginEnabler = pluginInitializer.getPluginEnabler(c);
+ mPluginEnabler = new PluginEnablerImpl(c);
+ List privilegedPlugins = Collections.emptyList();
+ PluginInstance.Factory instanceFactory = new PluginInstance.Factory(
+ getClass().getClassLoader(), new PluginInstance.InstanceFactory<>(),
+ new PluginInstance.VersionChecker(), privilegedPlugins,
+ Utilities.IS_DEBUG_DEVICE);
+ PluginActionManager.Factory instanceManagerFactory = new PluginActionManager.Factory(
+ c, c.getPackageManager(), c.getMainExecutor(), MODEL_EXECUTOR,
+ c.getSystemService(NotificationManager.class), mPluginEnabler,
+ privilegedPlugins, instanceFactory);
+
+ mPluginManager = new PluginManagerImpl(c, instanceManagerFactory,
+ Utilities.IS_DEBUG_DEVICE,
+ Optional.ofNullable(Thread.getDefaultUncaughtExceptionHandler()), mPluginEnabler,
+ new PluginPrefs(c), privilegedPlugins);
}
public PluginEnablerImpl getPluginEnabler() {
return mPluginEnabler;
}
- public void addPluginListener(PluginListener extends Plugin> listener, Class> pluginClass) {
+ /** */
+ public void addPluginListener(
+ PluginListener listener, Class pluginClass) {
addPluginListener(listener, pluginClass, false);
}
- public void addPluginListener(PluginListener extends Plugin> listener, Class> pluginClass,
- boolean allowMultiple) {
+ /** */
+ public void addPluginListener(
+ PluginListener listener, Class pluginClass, boolean allowMultiple) {
mPluginManager.addPluginListener(listener, pluginClass, allowMultiple);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index f8c9fd128f..8f89d30564 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -68,6 +68,11 @@ public class AllAppsState extends LauncherState {
return scaleAndTranslation;
}
+ @Override
+ public boolean isTaskbarStashed(Launcher launcher) {
+ return true;
+ }
+
@Override
protected float getDepthUnchecked(Context context) {
// The scrim fades in at approximately 50% of the swipe gesture.
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index fe5a3475ff..b7330072d4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -23,6 +23,7 @@ import android.graphics.Color;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@@ -73,8 +74,7 @@ public class BackgroundAppState extends OverviewState {
return super.getVisibleElements(launcher)
& ~OVERVIEW_ACTIONS
& ~CLEAR_ALL_BUTTON
- & ~VERTICAL_SWIPE_INDICATOR
- | TASKBAR;
+ & ~VERTICAL_SWIPE_INDICATOR;
}
@Override
@@ -89,6 +89,10 @@ public class BackgroundAppState extends OverviewState {
@Override
public int getWorkspaceScrimColor(Launcher launcher) {
+ DeviceProfile dp = launcher.getDeviceProfile();
+ if (dp.isTaskbarPresentInApps) {
+ return launcher.getColor(R.color.taskbar_background);
+ }
return Color.TRANSPARENT;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 8c128c8e08..08d0a80f03 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -21,14 +21,11 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERV
import android.content.Context;
import android.graphics.Rect;
import android.os.SystemProperties;
-import android.view.View;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Themes;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.util.LayoutUtils;
@@ -67,10 +64,7 @@ public class OverviewState extends LauncherState {
@Override
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
- Workspace workspace = launcher.getWorkspace();
- View workspacePage = workspace.getPageAt(workspace.getCurrentPage());
- float workspacePageWidth = workspacePage != null && workspacePage.getWidth() != 0
- ? workspacePage.getWidth() : launcher.getDeviceProfile().availableWidthPx;
+ float workspacePageWidth = launcher.getDeviceProfile().getWorkspaceWidth();
recentsView.getTaskSize(sTempRect);
float scale = (float) sTempRect.width() / workspacePageWidth;
float parallaxFactor = 0.5f;
@@ -82,16 +76,6 @@ public class OverviewState extends LauncherState {
return new float[] {NO_SCALE, NO_OFFSET};
}
- @Override
- public float getTaskbarScale(Launcher launcher) {
- return 1f;
- }
-
- @Override
- public float getTaskbarTranslationY(Launcher launcher) {
- return 0f;
- }
-
@Override
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
return new PageAlphaProvider(DEACCEL_2) {
@@ -107,6 +91,11 @@ public class OverviewState extends LauncherState {
return CLEAR_ALL_BUTTON | OVERVIEW_ACTIONS;
}
+ @Override
+ public boolean isTaskbarStashed(Launcher launcher) {
+ return true;
+ }
+
@Override
public int getWorkspaceScrimColor(Launcher launcher) {
return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
@@ -114,7 +103,7 @@ public class OverviewState extends LauncherState {
@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/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index d36e76b89b..969abc2804 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
@@ -42,6 +43,10 @@ public class QuickSwitchState extends BackgroundAppState {
@Override
public int getWorkspaceScrimColor(Launcher launcher) {
+ DeviceProfile dp = launcher.getDeviceProfile();
+ if (dp.isTaskbarPresentInApps) {
+ return launcher.getColor(R.color.taskbar_background);
+ }
return Themes.getAttrColor(launcher, R.attr.overviewScrimColor);
}
@@ -53,6 +58,16 @@ public class QuickSwitchState extends BackgroundAppState {
@Override
public int getVisibleElements(Launcher launcher) {
- return TASKBAR;
+ return NONE;
+ }
+
+ @Override
+ public boolean isTaskbarStashed(Launcher launcher) {
+ return !launcher.getDeviceProfile().isTaskbarPresentInApps;
+ }
+
+ @Override
+ public boolean isTaskbarAlignedWithHotseat(Launcher launcher) {
+ return false;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 0e2fbbc2bf..75cf5cb3a5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides.states;
import static android.view.View.VISIBLE;
+import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.HINT_STATE_TWO_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -44,6 +45,10 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_SCRIM_OPAQUE_THRESHOLD;
+import static com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController.ALL_APPS_SCRIM_VISIBLE_THRESHOLD;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import android.animation.ValueAnimator;
@@ -52,6 +57,7 @@ import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.SysUINavigationMode;
@@ -171,6 +177,13 @@ public class QuickstepAtomicAnimationFactory extends
mHintToNormalDuration = (int) va.getDuration();
}
config.duration = Math.max(config.duration, mHintToNormalDuration);
+ } else if (fromState == ALL_APPS && toState == NORMAL) {
+ config.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
+ 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD,
+ 1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD));
+ config.setInterpolator(ANIM_SCRIM_FADE, Interpolators.clampToProgress(DEACCEL,
+ 1 - ALL_APPS_SCRIM_OPAQUE_THRESHOLD,
+ 1 - ALL_APPS_SCRIM_VISIBLE_THRESHOLD));
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
index 6968494b0f..e79d56b631 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java
@@ -17,8 +17,6 @@
package com.android.launcher3.uioverrides.states;
import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.views.RecentsView;
/**
@@ -30,11 +28,6 @@ public class SplitScreenSelectState extends OverviewState {
super(id);
}
- @Override
- public void onBackPressed(Launcher launcher) {
- launcher.getStateManager().goToState(OVERVIEW);
- }
-
@Override
public int getVisibleElements(Launcher launcher) {
return SPLIT_PLACHOLDER_VIEW;
@@ -43,13 +36,6 @@ public class SplitScreenSelectState extends OverviewState {
@Override
public float getSplitSelectTranslation(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
- int splitPosition = recentsView.getSplitPlaceholder().getSplitController()
- .getActiveSplitPositionOption().mStagePosition;
- if (!recentsView.shouldShiftThumbnailsForSplitSelect(splitPosition)) {
- return 0f;
- }
- PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
- int direction = orientationHandler.getSplitTranslationDirectionFactor(splitPosition);
- return launcher.getResources().getDimension(R.dimen.split_placeholder_size) * direction;
+ return recentsView.getSplitSelectTranslation();
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 283743dc64..ef6f53e8f5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -24,7 +24,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
-import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
+import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.ObjectAnimator;
@@ -38,11 +38,11 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.OverviewToHomeAnim;
+import com.android.quickstep.util.VibratorWrapper;
import com.android.quickstep.views.RecentsView;
/**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 40c3e02238..f6148a7c8f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -41,7 +41,7 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
-import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
+import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
@@ -67,14 +67,15 @@ import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.BaseSwipeDetector;
import com.android.launcher3.touch.BothAxesSwipeDetector;
import com.android.launcher3.util.TouchController;
-import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.MotionPauseDetector;
+import com.android.quickstep.util.VibratorWrapper;
import com.android.quickstep.util.WorkspaceRevealAnim;
import com.android.quickstep.views.LauncherRecentsView;
+import com.android.quickstep.views.RecentsView;
/**
* Handles quick switching to a recent task from the home screen. To give as much flexibility to
@@ -235,8 +236,10 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
// - RecentsView fade (if it's empty)
PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2));
xAnim.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1], LINEAR);
+ // Use QuickSwitchState instead of OverviewState to determine scrim color,
+ // since we need to take potential taskbar into account.
xAnim.setViewBackgroundColor(mLauncher.getScrimView(),
- toState.getWorkspaceScrimColor(mLauncher), LINEAR);
+ QUICK_SWITCH.getWorkspaceScrimColor(mLauncher), LINEAR);
if (mRecentsView.getTaskViewCount() == 0) {
xAnim.addFloat(mRecentsView, CONTENT_ALPHA, 0f, 1f, LINEAR);
}
@@ -309,6 +312,11 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
}
});
overviewAnim.start();
+
+ // Create an empty state transition so StateListeners get onStateTransitionStart().
+ mLauncher.getStateManager().createAnimationToNewWorkspace(
+ OVERVIEW, config.duration, StateAnimationConfig.SKIP_ALL_ANIMATIONS)
+ .dispatchOnStart();
return;
}
@@ -383,6 +391,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
config.animFlags = SKIP_ALL_ANIMATIONS;
updateNonOverviewAnim(targetState, config);
nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
+ mNonOverviewAnim.dispatchOnStart();
new WorkspaceRevealAnim(mLauncher, false /* animateOverviewScrim */).start();
} else {
@@ -398,6 +407,14 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
nonOverviewAnim.setFloatValues(startProgress, endProgress);
mNonOverviewAnim.dispatchOnStart();
}
+ if (targetState == QUICK_SWITCH) {
+ // Navigating to quick switch, add scroll feedback since the first time is not
+ // considered a scroll by the RecentsView.
+ VibratorWrapper.INSTANCE.get(mLauncher).vibrate(
+ RecentsView.SCROLL_VIBRATION_PRIMITIVE,
+ RecentsView.SCROLL_VIBRATION_PRIMITIVE_SCALE,
+ RecentsView.SCROLL_VIBRATION_FALLBACK);
+ }
nonOverviewAnim.setDuration(Math.max(xDuration, yDuration));
mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 3c83d25b71..59ade49761 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -52,22 +52,22 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
/**
* The progress at which all apps content will be fully visible.
*/
- protected static final float ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD = 0.8f;
+ public static final float ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD = 0.8f;
/**
* Minimum clamping progress for fading in all apps content
*/
- protected static final float ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD = 0.5f;
+ public static final float ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD = 0.5f;
/**
* Minimum clamping progress for fading in all apps scrim
*/
- protected static final float ALL_APPS_SCRIM_VISIBLE_THRESHOLD = .1f;
+ public static final float ALL_APPS_SCRIM_VISIBLE_THRESHOLD = .1f;
/**
* Maximum clamping progress for opaque all apps scrim
*/
- protected static final float ALL_APPS_SCRIM_OPAQUE_THRESHOLD = .5f;
+ public static final float ALL_APPS_SCRIM_OPAQUE_THRESHOLD = .5f;
private final PortraitOverviewStateTouchHelper mOverviewPortraitStateTouchHelper;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
index fe69c9b87d..1bc789bd6e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
@@ -19,6 +19,7 @@ import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN;
@@ -47,17 +48,6 @@ public class StatusBarTouchController implements TouchController {
private static final String TAG = "StatusBarController";
- /**
- * Window flag: Enable touches to slide out of a window into neighboring
- * windows in mid-gesture instead of being captured for the duration of
- * the gesture.
- *
- * This flag changes the behavior of touch focus for this window only.
- * Touches can slide out of the window but they cannot necessarily slide
- * back in (unless the other window with touch focus permits it).
- */
- private static final int FLAG_SLIPPERY = 0x20000000;
-
private final Launcher mLauncher;
private final SystemUiProxy mSystemUiProxy;
private final float mTouchSlop;
@@ -140,6 +130,15 @@ public class StatusBarTouchController implements TouchController {
return true;
}
+ /**
+ * FLAG_SLIPPERY enables touches to slide out of a window into neighboring
+ * windows in mid-gesture instead of being captured for the duration of
+ * the gesture.
+ *
+ * This flag changes the behavior of touch focus for this window only.
+ * Touches can slide out of the window but they cannot necessarily slide
+ * back in (unless the other window with touch focus permits it).
+ */
private void setWindowSlippery(boolean enable) {
Window w = mLauncher.getWindow();
WindowManager.LayoutParams wlp = w.getAttributes();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 180af0bd9f..308bca62e4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -22,6 +22,7 @@ import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_BOTH
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.os.SystemClock;
+import android.os.VibrationEffect;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
@@ -34,7 +35,6 @@ import com.android.launcher3.Utilities;
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.touch.BaseSwipeDetector;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
@@ -42,6 +42,7 @@ import com.android.launcher3.util.FlingBlockCheck;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.util.VibratorWrapper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -56,6 +57,12 @@ public abstract class TaskViewTouchController
private static final long MIN_TASK_DISMISS_ANIMATION_DURATION = 300;
private static final long MAX_TASK_DISMISS_ANIMATION_DURATION = 600;
+ public static final int TASK_DISMISS_VIBRATION_PRIMITIVE =
+ Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1;
+ public static final float TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE = 1f;
+ public static final VibrationEffect TASK_DISMISS_VIBRATION_FALLBACK =
+ VibratorWrapper.EFFECT_TEXTURE_TICK;
+
protected final T mActivity;
private final SingleAxisSwipeDetector mDetector;
private final RecentsView mRecentsView;
@@ -77,6 +84,8 @@ public abstract class TaskViewTouchController
private TaskView mTaskBeingDragged;
+ private boolean mIsDismissHapticRunning = false;
+
public TaskViewTouchController(T activity) {
mActivity = activity;
mRecentsView = activity.getOverviewPanel();
@@ -158,26 +167,21 @@ public abstract class TaskViewTouchController
mTaskBeingDragged = view;
int upDirection = mRecentsView.getPagedOrientationHandler()
.getUpDirection(mIsRtl);
- if (!SysUINavigationMode.getMode(mActivity).hasGestures || (
- mActivity.getDeviceProfile().isTablet
- && FeatureFlags.ENABLE_OVERVIEW_GRID.get())) {
- // Don't allow swipe down to open if we don't support swipe up
- // to enter overview, or when grid layout is enabled.
- directionsToDetectScroll = upDirection;
- mAllowGoingUp = true;
- mAllowGoingDown = false;
- } else {
- // The task can be dragged up to dismiss it,
- // and down to open if it's the current page.
- mAllowGoingUp = true;
- if (i == mRecentsView.getCurrentPage()) {
- mAllowGoingDown = true;
- directionsToDetectScroll = DIRECTION_BOTH;
- } else {
- mAllowGoingDown = false;
- directionsToDetectScroll = upDirection;
- }
- }
+
+ // The task can be dragged up to dismiss it
+ mAllowGoingUp = true;
+
+ // The task can be dragged down to open it if:
+ // - It's the current page
+ // - We support gestures to enter overview
+ // - It's the focused task if in grid view
+ // - The task is snapped
+ mAllowGoingDown = i == mRecentsView.getCurrentPage()
+ && SysUINavigationMode.getMode(mActivity).hasGestures
+ && (!mRecentsView.showAsGrid() || mTaskBeingDragged.isFocusedTask())
+ && mRecentsView.isTaskInExpectedScrollPosition(i);
+
+ directionsToDetectScroll = mAllowGoingDown ? DIRECTION_BOTH : upDirection;
break;
}
}
@@ -233,7 +237,8 @@ public abstract class TaskViewTouchController
if (goingUp) {
currentInterpolator = Interpolators.LINEAR;
pa = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
- true /* animateTaskView */, true /* removeTask */, maxDuration);
+ true /* animateTaskView */, true /* removeTask */, maxDuration,
+ false /* dismissingForSplitSelection*/);
mEndDisplacement = -secondaryTaskDimension;
} else {
@@ -339,10 +344,10 @@ public abstract class TaskViewTouchController
fling = false;
}
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+ boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl);
float progress = mCurrentAnimation.getProgressFraction();
float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
if (fling) {
- boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl);
goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
} else {
goingToEnd = interpolatedProgress > SUCCESS_TRANSITION_PROGRESS;
@@ -362,6 +367,11 @@ public abstract class TaskViewTouchController
mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
velocity * orientationHandler.getSecondaryTranslationDirectionFactor(),
mEndDisplacement, animationDuration);
+ if (goingUp && goingToEnd && !mIsDismissHapticRunning) {
+ VibratorWrapper.INSTANCE.get(mActivity).vibrate(TASK_DISMISS_VIBRATION_PRIMITIVE,
+ TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE, TASK_DISMISS_VIBRATION_FALLBACK);
+ mIsDismissHapticRunning = true;
+ }
}
private void clearState() {
@@ -369,5 +379,6 @@ public abstract class TaskViewTouchController
mDetector.setDetectableScrollConditions(0, false);
mTaskBeingDragged = null;
mCurrentAnimation = null;
+ mIsDismissHapticRunning = false;
}
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index ac1772c300..9f1e47f15a 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -36,7 +36,6 @@ import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
-import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
@@ -46,6 +45,7 @@ import static com.android.quickstep.GestureState.STATE_END_TARGET_SET;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_CANCELED;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -55,6 +55,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
+import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -73,6 +74,7 @@ import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.view.WindowInsets;
import android.view.animation.Interpolator;
import android.widget.Toast;
+import android.window.PictureInPictureSurfaceTransaction;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -89,16 +91,18 @@ import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.tracing.InputConsumerProto;
import com.android.launcher3.tracing.SwipeHandlerProto;
+import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
+import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.InputConsumerProxy;
import com.android.quickstep.util.InputProxyHandlerFactory;
+import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.ProtoTracer;
import com.android.quickstep.util.RecentsOrientedState;
@@ -106,7 +110,8 @@ import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.SwipePipToHomeAnimator;
-import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.util.TaskViewSimulator;
+import com.android.quickstep.util.VibratorWrapper;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -119,6 +124,8 @@ import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.function.Consumer;
/**
@@ -149,6 +156,17 @@ public abstract class AbsSwipeUpHandler,
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
private boolean mRecentsViewScrollLinked = false;
+ private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks =
+ new ActivityLifecycleCallbacksAdapter() {
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ if (mActivity != activity) {
+ return;
+ }
+ mRecentsView = null;
+ mActivity = null;
+ }
+ };
private static int getFlagForIndex(int index, String name) {
if (DEBUG_STATES) {
@@ -162,45 +180,51 @@ public abstract class AbsSwipeUpHandler,
getFlagForIndex(0, "STATE_LAUNCHER_PRESENT");
protected static final int STATE_LAUNCHER_STARTED =
getFlagForIndex(1, "STATE_LAUNCHER_STARTED");
- protected static final int STATE_LAUNCHER_DRAWN = getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
+ protected static final int STATE_LAUNCHER_DRAWN =
+ getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
+ // Called when the Launcher has connected to the touch interaction service (and the taskbar
+ // ui controller is initialized)
+ protected static final int STATE_LAUNCHER_BIND_TO_SERVICE =
+ getFlagForIndex(3, "STATE_LAUNCHER_BIND_TO_SERVICE");
// Internal initialization states
private static final int STATE_APP_CONTROLLER_RECEIVED =
- getFlagForIndex(3, "STATE_APP_CONTROLLER_RECEIVED");
+ getFlagForIndex(4, "STATE_APP_CONTROLLER_RECEIVED");
// Interaction finish states
private static final int STATE_SCALED_CONTROLLER_HOME =
- getFlagForIndex(4, "STATE_SCALED_CONTROLLER_HOME");
+ getFlagForIndex(5, "STATE_SCALED_CONTROLLER_HOME");
private static final int STATE_SCALED_CONTROLLER_RECENTS =
- getFlagForIndex(5, "STATE_SCALED_CONTROLLER_RECENTS");
+ getFlagForIndex(6, "STATE_SCALED_CONTROLLER_RECENTS");
protected static final int STATE_HANDLER_INVALIDATED =
- getFlagForIndex(6, "STATE_HANDLER_INVALIDATED");
+ getFlagForIndex(7, "STATE_HANDLER_INVALIDATED");
private static final int STATE_GESTURE_STARTED =
- getFlagForIndex(7, "STATE_GESTURE_STARTED");
+ getFlagForIndex(8, "STATE_GESTURE_STARTED");
private static final int STATE_GESTURE_CANCELLED =
- getFlagForIndex(8, "STATE_GESTURE_CANCELLED");
+ getFlagForIndex(9, "STATE_GESTURE_CANCELLED");
private static final int STATE_GESTURE_COMPLETED =
- getFlagForIndex(9, "STATE_GESTURE_COMPLETED");
+ getFlagForIndex(10, "STATE_GESTURE_COMPLETED");
private static final int STATE_CAPTURE_SCREENSHOT =
- getFlagForIndex(10, "STATE_CAPTURE_SCREENSHOT");
+ getFlagForIndex(11, "STATE_CAPTURE_SCREENSHOT");
protected static final int STATE_SCREENSHOT_CAPTURED =
- getFlagForIndex(11, "STATE_SCREENSHOT_CAPTURED");
+ getFlagForIndex(12, "STATE_SCREENSHOT_CAPTURED");
private static final int STATE_SCREENSHOT_VIEW_SHOWN =
- getFlagForIndex(12, "STATE_SCREENSHOT_VIEW_SHOWN");
+ getFlagForIndex(13, "STATE_SCREENSHOT_VIEW_SHOWN");
private static final int STATE_RESUME_LAST_TASK =
- getFlagForIndex(13, "STATE_RESUME_LAST_TASK");
+ getFlagForIndex(14, "STATE_RESUME_LAST_TASK");
private static final int STATE_START_NEW_TASK =
- getFlagForIndex(14, "STATE_START_NEW_TASK");
+ getFlagForIndex(15, "STATE_START_NEW_TASK");
private static final int STATE_CURRENT_TASK_FINISHED =
- getFlagForIndex(15, "STATE_CURRENT_TASK_FINISHED");
+ getFlagForIndex(16, "STATE_CURRENT_TASK_FINISHED");
private static final int STATE_FINISH_WITH_NO_END =
- getFlagForIndex(16, "STATE_FINISH_WITH_NO_END");
+ getFlagForIndex(17, "STATE_FINISH_WITH_NO_END");
private static final int LAUNCHER_UI_STATES =
- STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
+ STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED |
+ STATE_LAUNCHER_BIND_TO_SERVICE;
public static final long MAX_SWIPE_DURATION = 350;
public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS;
@@ -212,6 +236,8 @@ public abstract class AbsSwipeUpHandler,
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.
*/
@@ -220,7 +246,7 @@ public abstract class AbsSwipeUpHandler,
protected final TaskAnimationManager mTaskAnimationManager;
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
- private RunningWindowAnim mRunningWindowAnim;
+ private RunningWindowAnim[] mRunningWindowAnim;
// Possible second animation running at the same time as mRunningWindowAnim
private Animator mParallelRunningAnim;
private boolean mIsMotionPaused;
@@ -251,22 +277,33 @@ public abstract class AbsSwipeUpHandler,
private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
protected boolean mIsSwipingPipToHome;
+ // TODO(b/195473090) no split PIP for now, remove once we have more clarity
+ // can try to have RectFSpringAnim evaluate multiple rects at once
+ private final SwipePipToHomeAnimator[] mSwipePipToHomeAnimators =
+ new SwipePipToHomeAnimator[2];
+
+ // 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,
InputConsumerController inputConsumer) {
- super(context, deviceState, gestureState, new TransformParams());
+ super(context, deviceState, gestureState);
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumerProxy =
- new InputConsumerProxy(inputConsumer, () -> {
+ new InputConsumerProxy(context,
+ () -> mRecentsView.getPagedViewOrientedState().getRecentsActivityRotation(),
+ inputConsumer, () -> {
endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
endLauncherTransitionController();
}, new InputProxyHandlerFactory(mActivityInterface, mGestureState));
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
+ mQuickSwitchScaleScrollThreshold = context.getResources().getDimension(
+ R.dimen.quick_switch_scaling_scroll_threshold);
initAfterSubclassConstructor();
initStateCallbacks();
@@ -384,9 +421,10 @@ public abstract class AbsSwipeUpHandler,
// Set up a entire animation lifecycle callback to notify the current recents view when
// the animation is canceled
mGestureState.runOnceAtState(STATE_RECENTS_ANIMATION_CANCELED, () -> {
- ThumbnailData snapshot = mGestureState.consumeRecentsAnimationCanceledSnapshot();
- if (snapshot != null) {
- mRecentsView.switchToScreenshot(snapshot, () -> {
+ HashMap snapshots =
+ mGestureState.consumeRecentsAnimationCanceledSnapshot();
+ if (snapshots != null) {
+ mRecentsView.switchToScreenshot(snapshots, () -> {
if (mRecentsAnimationController != null) {
mRecentsAnimationController.cleanupScreenshot();
}
@@ -397,7 +435,9 @@ public abstract class AbsSwipeUpHandler,
setupRecentsViewUi();
linkRecentsViewScroll();
+ activity.runOnBindToTouchInteractionService(this::onLauncherBindToService);
+ mActivity.registerActivityLifecycleCallbacks(mLifecycleCallbacks);
return true;
}
@@ -419,7 +459,8 @@ public abstract class AbsSwipeUpHandler,
// RecentsView never updates the display rotation until swipe-up, force update
// RecentsOrientedState before passing to TaskViewSimulator.
mRecentsView.updateRecentsRotation();
- mTaskViewSimulator.setOrientationState(mRecentsView.getPagedViewOrientedState());
+ runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
+ .setOrientationState(mRecentsView.getPagedViewOrientedState()));
// If we've already ended the gesture and are going home, don't prepare recents UI,
// as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL.
@@ -428,6 +469,10 @@ public abstract class AbsSwipeUpHandler,
mAnimationFactory = mActivityInterface.prepareRecentsUI(mDeviceState,
mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
maybeUpdateRecentsAttachedState(false /* animate */);
+ if (mGestureState.getEndTarget() != null) {
+ // Update the end target in case the gesture ended before we init.
+ mAnimationFactory.setEndTarget(mGestureState.getEndTarget());
+ }
};
if (mWasLauncherAlreadyVisible) {
// Launcher is visible, but might be about to stop. Thus, if we prepare recents
@@ -472,6 +517,11 @@ public abstract class AbsSwipeUpHandler,
mStateCallback.setState(STATE_LAUNCHER_STARTED);
}
+ private void onLauncherBindToService() {
+ mStateCallback.setState(STATE_LAUNCHER_BIND_TO_SERVICE);
+ flushOnRecentsAnimationAndLauncherBound();
+ }
+
private void onLauncherPresentAndGestureStarted() {
// Re-setup the recents UI when gesture starts, as the state could have been changed during
// that time by a previous window transition.
@@ -512,7 +562,26 @@ public abstract class AbsSwipeUpHandler,
}
protected void notifyGestureAnimationStartToRecents() {
- mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
+ ActivityManager.RunningTaskInfo[] runningTasks;
+ if (mIsSwipeForStagedSplit) {
+ int[] splitTaskIds =
+ LauncherSplitScreenListener.INSTANCE.getNoCreate().getRunningSplitTaskIds();
+ runningTasks = new ActivityManager.RunningTaskInfo[splitTaskIds.length];
+ for (int i = 0; i < splitTaskIds.length; i++) {
+ int taskId = splitTaskIds[i];
+ // Order matters here, we want first indexed RunningTaskInfo to be leftTop task
+ for (ActivityManager.RunningTaskInfo rti : mGestureState.getRunningTasks()) {
+ if (taskId == rti.taskId) {
+ runningTasks[i] = rti;
+ break;
+ }
+
+ }
+ }
+ } else {
+ runningTasks = new ActivityManager.RunningTaskInfo[]{mGestureState.getRunningTask()};
+ }
+ mRecentsView.onGestureAnimationStart(runningTasks);
}
private void launcherFrameDrawn() {
@@ -539,7 +608,7 @@ public abstract class AbsSwipeUpHandler,
@Override
public void onMotionPauseDetected() {
mHasMotionEverBeenPaused = true;
- maybeUpdateRecentsAttachedState();
+ maybeUpdateRecentsAttachedState(true/* animate */, true/* moveFocusedTask */);
performHapticFeedback();
}
@@ -550,18 +619,24 @@ public abstract class AbsSwipeUpHandler,
};
}
- 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 +655,12 @@ public abstract class AbsSwipeUpHandler,
} 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
@@ -587,15 +668,15 @@ public abstract class AbsSwipeUpHandler,
if (animate) {
ValueAnimator reapplyWindowTransformAnim = ValueAnimator.ofFloat(0, 1);
reapplyWindowTransformAnim.addUpdateListener(anim -> {
- if (mRunningWindowAnim == null) {
- applyWindowTransform();
+ if (mRunningWindowAnim == null || mRunningWindowAnim.length == 0) {
+ applyScrollAndTransform();
}
});
reapplyWindowTransformAnim.setDuration(RECENTS_ATTACH_DURATION).start();
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED,
reapplyWindowTransformAnim::cancel);
} else {
- applyWindowTransform();
+ applyScrollAndTransform();
}
}
@@ -631,13 +712,24 @@ public abstract class AbsSwipeUpHandler,
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
WindowInsets result = view.onApplyWindowInsets(windowInsets);
buildAnimationController();
+ // Reapply the current shift to ensure it takes new insets into account, e.g. when long
+ // pressing to stash taskbar without moving the finger.
+ updateFinalShift();
return result;
}
private void onAnimatorPlaybackControllerCreated(AnimatorControllerWithResistance anim) {
+ boolean isFirstCreation = mLauncherTransitionController == null;
mLauncherTransitionController = anim;
- mLauncherTransitionController.getNormalController().dispatchOnStart();
- updateLauncherTransitionProgress();
+ if (isFirstCreation) {
+ mStateCallback.runOnceAtState(STATE_GESTURE_STARTED, () -> {
+ // Wait until the gesture is started (touch slop was passed) to start in sync with
+ // mWindowTransitionController. This ensures we don't hide the taskbar background
+ // when long pressing to stash it, for instance.
+ mLauncherTransitionController.getNormalController().dispatchOnStart();
+ updateLauncherTransitionProgress();
+ });
+ }
}
public Intent getLaunchIntent() {
@@ -659,7 +751,7 @@ public abstract class AbsSwipeUpHandler,
}
updateSysUiFlags(mCurrentShift.value);
- applyWindowTransform();
+ applyScrollAndTransform();
updateLauncherTransitionProgress();
}
@@ -669,7 +761,8 @@ public abstract class AbsSwipeUpHandler,
|| !canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
}
- mLauncherTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
+ mLauncherTransitionController.setProgress(
+ Math.max(mCurrentShift.value, getScaleProgressDueToScroll()), mDragLengthFactor);
}
/**
@@ -704,24 +797,25 @@ public abstract class AbsSwipeUpHandler,
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
+ super.onRecentsAnimationStart(controller, targets);
ActiveGestureLog.INSTANCE.addLog("startRecentsAnimationCallback", targets.apps.length);
+ mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(targets);
mRecentsAnimationController = controller;
mRecentsAnimationTargets = targets;
- mTransformParams.setTargetSet(mRecentsAnimationTargets);
- RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
- mGestureState.getRunningTaskId());
-
- if (runningTaskTarget != null) {
- mTaskViewSimulator.setPreview(runningTaskTarget);
- }
// Only initialize the device profile, if it has not been initialized before, as in some
// configurations targets.homeContentInsets may not be correct.
if (mActivity == null) {
- DeviceProfile dp = mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile();
- if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
+ RemoteAnimationTargetCompat primaryTaskTarget = targets.apps[0];
+ // orientation state is independent of which remote target handle we use since both
+ // should be pointing to the same one. Just choose index 0 for now since that works for
+ // both split and non-split
+ RecentsOrientedState orientationState = mRemoteTargetHandles[0].getTaskViewSimulator()
+ .getOrientationState();
+ DeviceProfile dp = orientationState.getLauncherDeviceProfile();
+ if (targets.minimizedHomeBounds != null && primaryTaskTarget != null) {
Rect overviewStackBounds = mActivityInterface
- .getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
+ .getOverviewWindowBounds(targets.minimizedHomeBounds, primaryTaskTarget);
dp = dp.getMultiWindowProfile(mContext,
new WindowBounds(overviewStackBounds, targets.homeContentInsets));
} else {
@@ -731,16 +825,14 @@ public abstract class AbsSwipeUpHandler,
dp.updateInsets(targets.homeContentInsets);
dp.updateIsSeascape(mContext);
initTransitionEndpoints(dp);
- mTaskViewSimulator.getOrientationState().setMultiWindowMode(dp.isMultiWindowMode);
+ orientationState.setMultiWindowMode(dp.isMultiWindowMode);
}
// Notify when the animation starts
- if (!mRecentsAnimationStartCallbacks.isEmpty()) {
- for (Runnable action : new ArrayList<>(mRecentsAnimationStartCallbacks)) {
- action.run();
- }
- mRecentsAnimationStartCallbacks.clear();
- }
+ flushOnRecentsAnimationAndLauncherBound();
+
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ false /*shown*/, true /*animate*/);
// Only add the callback to enable the input consumer after we actually have the controller
mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
@@ -751,11 +843,16 @@ public abstract class AbsSwipeUpHandler,
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap thumbnailDatas) {
ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation");
mActivityInitListener.unregister();
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
+ if (mRecentsAnimationTargets != null) {
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ true /*shown*/, true /*animate*/);
+ }
+
// Defer clearing the controller and the targets until after we've updated the state
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
@@ -845,9 +942,17 @@ public abstract class AbsSwipeUpHandler,
private void endRunningWindowAnim(boolean cancel) {
if (mRunningWindowAnim != null) {
if (cancel) {
- mRunningWindowAnim.cancel();
+ for (RunningWindowAnim r : mRunningWindowAnim) {
+ if (r != null) {
+ r.cancel();
+ }
+ }
} else {
- mRunningWindowAnim.end();
+ for (RunningWindowAnim r : mRunningWindowAnim) {
+ if (r != null) {
+ r.end();
+ }
+ }
}
}
if (mParallelRunningAnim != null) {
@@ -861,6 +966,9 @@ public abstract class AbsSwipeUpHandler,
// Fast-finish the attaching animation if it's still running.
maybeUpdateRecentsAttachedState(false);
final GestureEndTarget endTarget = mGestureState.getEndTarget();
+ // Wait until the given View (if supplied) draws before resuming the last task.
+ View postResumeLastTask = mActivityInterface.onSettledOnEndTarget(endTarget);
+
if (endTarget != NEW_TASK) {
InteractionJankMonitorWrapper.cancel(
InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
@@ -869,11 +977,13 @@ public abstract class AbsSwipeUpHandler,
InteractionJankMonitorWrapper.cancel(
InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
}
+
switch (endTarget) {
case HOME:
mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT);
// Notify swipe-to-home (recents animation) is finished
SystemUiProxy.INSTANCE.get(mContext).notifySwipeToHomeFinished();
+ LauncherSplitScreenListener.INSTANCE.getNoCreate().notifySwipingToHome();
break;
case RECENTS:
mStateCallback.setState(STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
@@ -883,19 +993,29 @@ public abstract class AbsSwipeUpHandler,
mStateCallback.setState(STATE_START_NEW_TASK | STATE_CAPTURE_SCREENSHOT);
break;
case LAST_TASK:
- mStateCallback.setState(STATE_RESUME_LAST_TASK);
+ if (postResumeLastTask != null) {
+ ViewUtils.postFrameDrawn(postResumeLastTask,
+ () -> mStateCallback.setState(STATE_RESUME_LAST_TASK));
+ } else {
+ mStateCallback.setState(STATE_RESUME_LAST_TASK);
+ }
+ if (mRecentsAnimationTargets != null) {
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ true /*shown*/, false /*animate*/);
+ }
break;
}
ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + endTarget);
}
/** @return Whether this was the task we were waiting to appear, and thus handled it. */
- protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ protected boolean handleTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {
if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
return false;
}
- if (mStateCallback.hasStates(STATE_START_NEW_TASK)
- && appearedTaskTarget.taskId == mGestureState.getLastStartedTaskId()) {
+ boolean hasStartedTaskBefore = Arrays.stream(appearedTaskTarget).anyMatch(
+ targetCompat -> targetCompat.taskId == mGestureState.getLastStartedTaskId());
+ if (mStateCallback.hasStates(STATE_START_NEW_TASK) && hasStartedTaskBefore) {
reset();
return true;
}
@@ -976,6 +1096,7 @@ public abstract class AbsSwipeUpHandler,
isFling, isCancel);
// Set the state, but don't notify until the animation completes
mGestureState.setEndTarget(endTarget, false /* isAtomic */);
+ mAnimationFactory.setEndTarget(endTarget);
float endShift = endTarget.isLauncher ? 1 : 0;
final float startShift;
@@ -1020,9 +1141,6 @@ public abstract class AbsSwipeUpHandler,
if (mRecentsView != null) {
int nearestPage = mRecentsView.getDestinationPage();
boolean isScrolling = false;
- // Update page scroll before snapping to page to make sure we snapped to the
- // position calculated with target gesture in mind.
- mRecentsView.updateScrollSynchronously();
if (mRecentsView.getNextPage() != nearestPage) {
// We shouldn't really scroll to the next page when swiping up to recents.
// Only allow settling on the next page if it's nearest to the center.
@@ -1091,7 +1209,7 @@ public abstract class AbsSwipeUpHandler,
@UiThread
private void animateToProgress(float start, float end, long duration, Interpolator interpolator,
GestureEndTarget target, PointF velocityPxPerMs) {
- runOnRecentsAnimationStart(() -> animateToProgressInternal(start, end, duration,
+ runOnRecentsAnimationAndLauncherBound(() -> animateToProgressInternal(start, end, duration,
interpolator, target, velocityPxPerMs));
}
@@ -1128,8 +1246,15 @@ public abstract class AbsSwipeUpHandler,
mActivityRestartListener);
mParallelRunningAnim = mActivityInterface.getParallelAnimationToLauncher(
- mGestureState.getEndTarget(), duration);
+ mGestureState.getEndTarget(), duration,
+ mTaskAnimationManager.getCurrentCallbacks());
if (mParallelRunningAnim != null) {
+ mParallelRunningAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mParallelRunningAnim = null;
+ }
+ });
mParallelRunningAnim.start();
}
}
@@ -1145,21 +1270,25 @@ public abstract class AbsSwipeUpHandler,
boolean isTranslucent = runningTaskTarget != null && runningTaskTarget.isTranslucent;
boolean appCanEnterPip = !mDeviceState.isPipActive()
&& runningTaskTarget != null
+ && runningTaskTarget.allowEnterPip
&& runningTaskTarget.taskInfo.pictureInPictureParams != null
&& runningTaskTarget.taskInfo.pictureInPictureParams.isAutoEnterEnabled();
HomeAnimationFactory homeAnimFactory =
createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
runningTaskTarget);
- mIsSwipingPipToHome = homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
- final RectFSpringAnim windowAnim;
+ mIsSwipingPipToHome = !mIsSwipeForStagedSplit
+ && homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
+ final RectFSpringAnim[] windowAnim;
if (mIsSwipingPipToHome) {
mSwipePipToHomeAnimator = createWindowAnimationToPip(
homeAnimFactory, runningTaskTarget, start);
- windowAnim = mSwipePipToHomeAnimator;
+ mSwipePipToHomeAnimators[0] = mSwipePipToHomeAnimator;
+ windowAnim = mSwipePipToHomeAnimators;
} else {
mSwipePipToHomeAnimator = null;
windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
- windowAnim.addAnimatorListener(new AnimationSuccessListener() {
+
+ windowAnim[0].addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
if (mRecentsAnimationController == null) {
@@ -1173,14 +1302,22 @@ public abstract class AbsSwipeUpHandler,
}
});
}
- windowAnim.start(mContext, velocityPxPerMs);
- mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
+ mRunningWindowAnim = new RunningWindowAnim[windowAnim.length];
+ for (int i = 0, windowAnimLength = windowAnim.length; i < windowAnimLength; i++) {
+ RectFSpringAnim windowAnimation = windowAnim[i];
+ if (windowAnimation == null) {
+ continue;
+ }
+ windowAnimation.start(mContext, velocityPxPerMs);
+ mRunningWindowAnim[i] = RunningWindowAnim.wrap(windowAnimation);
+ }
homeAnimFactory.setSwipeVelocity(velocityPxPerMs.y);
homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
mLauncherTransitionController = null;
if (mRecentsView != null) {
- mRecentsView.onPrepareGestureEndAnimation(null, mGestureState.getEndTarget());
+ mRecentsView.onPrepareGestureEndAnimation(null, mGestureState.getEndTarget(),
+ getRemoteTaskViewSimulators());
}
} else {
AnimatorSet animatorSet = new AnimatorSet();
@@ -1222,24 +1359,42 @@ public abstract class AbsSwipeUpHandler,
animatorSet.play(windowAnim);
if (mRecentsView != null) {
mRecentsView.onPrepareGestureEndAnimation(
- animatorSet, mGestureState.getEndTarget());
+ animatorSet, mGestureState.getEndTarget(),
+ getRemoteTaskViewSimulators());
}
animatorSet.setDuration(duration).setInterpolator(interpolator);
animatorSet.start();
- mRunningWindowAnim = RunningWindowAnim.wrap(animatorSet);
+ mRunningWindowAnim = new RunningWindowAnim[]{RunningWindowAnim.wrap(animatorSet)};
}
}
+ 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();
+ }
+ }
+
+ /**
+ * TODO(b/195473090) handle multiple task simulators (if needed) for PIP
+ */
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 RecentsOrientedState orientationState = mRemoteTargetHandles[0].getTaskViewSimulator()
+ .getOrientationState();
+ final int windowRotation = calculateWindowRotation(runningTaskTarget, orientationState);
final int homeRotation = orientationState.getRecentsActivityRotation();
- final Matrix homeToWindowPositionMap = new Matrix();
- final RectF startRect = updateProgressForStartRect(homeToWindowPositionMap, startProgress);
+ final Matrix[] homeToWindowPositionMaps = new Matrix[mRemoteTargetHandles.length];
+ final RectF startRect = updateProgressForStartRect(homeToWindowPositionMaps,
+ startProgress)[0];
+ final Matrix homeToWindowPositionMap = homeToWindowPositionMaps[0];
// Move the startRect to Launcher space as floatingIconView runs in Launcher
final Matrix windowToHomePositionMap = new Matrix();
homeToWindowPositionMap.invert(windowToHomePositionMap);
@@ -1268,7 +1423,7 @@ public abstract class AbsSwipeUpHandler,
// is not ROTATION_0 (which implies the rotation is turned on in launcher settings).
if (homeRotation == ROTATION_0
&& (windowRotation == ROTATION_90 || windowRotation == ROTATION_270)) {
- builder.setFromRotation(mTaskViewSimulator, windowRotation,
+ builder.setFromRotation(mRemoteTargetHandles[0].getTaskViewSimulator(), windowRotation,
taskInfo.displayCutoutInsets);
}
final SwipePipToHomeAnimator swipePipToHomeAnimator = builder.build();
@@ -1298,7 +1453,7 @@ public abstract class AbsSwipeUpHandler,
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
}
});
- setupWindowAnimation(swipePipToHomeAnimator);
+ setupWindowAnimation(new RectFSpringAnim[]{swipePipToHomeAnimator});
return swipePipToHomeAnimator;
}
@@ -1325,19 +1480,19 @@ public abstract class AbsSwipeUpHandler,
* @param homeAnimationFactory The home animation factory.
*/
@Override
- protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
+ protected RectFSpringAnim[] createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
- RectFSpringAnim anim =
+ RectFSpringAnim[] anim =
super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
setupWindowAnimation(anim);
return anim;
}
- private void setupWindowAnimation(RectFSpringAnim anim) {
- anim.addOnUpdateListener((v, r, p) -> {
+ private void setupWindowAnimation(RectFSpringAnim[] anims) {
+ anims[0].addOnUpdateListener((r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
- anim.addAnimatorListener(new AnimationSuccessListener() {
+ anims[0].addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
if (mRecentsView != null) {
@@ -1349,7 +1504,7 @@ public abstract class AbsSwipeUpHandler,
}
});
if (mRecentsAnimationTargets != null) {
- mRecentsAnimationTargets.addReleaseCheck(anim);
+ mRecentsAnimationTargets.addReleaseCheck(anims[0]);
}
}
@@ -1360,7 +1515,9 @@ public abstract class AbsSwipeUpHandler,
mActivity.clearRunOnceOnStartCallback();
resetLauncherListeners();
}
- if (mGestureState.getEndTarget() != null && !mGestureState.isRunningAnimationToLauncher()) {
+ if (mGestureState.isRecentsAnimationRunning() && mGestureState.getEndTarget() != null
+ && !mGestureState.getEndTarget().isLauncher) {
+ // Continued quick switch.
cancelCurrentAnimation();
} else {
mStateCallback.setStateOnUiThread(STATE_FINISH_WITH_NO_END);
@@ -1415,6 +1572,9 @@ public abstract class AbsSwipeUpHandler,
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
+ if (mActivity != null) {
+ mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
+ }
}
/**
@@ -1492,6 +1652,11 @@ public abstract class AbsSwipeUpHandler,
boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
+ if (mRecentsAnimationTargets != null) {
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ true /*shown*/, false /*animate*/);
+ }
+
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
if (mActivity != null) {
mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
@@ -1580,7 +1745,7 @@ public abstract class AbsSwipeUpHandler,
// If there are no targets or the animation not started, then there is nothing to finish
mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else {
- maybeFinishSwipePipToHome();
+ maybeFinishSwipeToHome();
finishRecentsControllerToHome(
() -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
}
@@ -1589,11 +1754,12 @@ public abstract class AbsSwipeUpHandler,
}
/**
- * Resets the {@link #mIsSwipingPipToHome} and notifies SysUI that transition is finished
- * if applicable. This should happen before {@link #finishRecentsControllerToHome(Runnable)}.
+ * Notifies SysUI that transition is finished if applicable and also pass leash transactions
+ * from Launcher to WM.
+ * This should happen before {@link #finishRecentsControllerToHome(Runnable)}.
*/
- private void maybeFinishSwipePipToHome() {
- if (mIsSwipingPipToHome && mSwipePipToHomeAnimator != null) {
+ private void maybeFinishSwipeToHome() {
+ if (mIsSwipingPipToHome && mSwipePipToHomeAnimators[0] != null) {
SystemUiProxy.INSTANCE.get(mContext).stopSwipePipToHome(
mSwipePipToHomeAnimator.getComponentName(),
mSwipePipToHomeAnimator.getDestinationBounds(),
@@ -1603,6 +1769,18 @@ public abstract class AbsSwipeUpHandler,
mSwipePipToHomeAnimator.getFinishTransaction(),
mSwipePipToHomeAnimator.getContentOverlay());
mIsSwipingPipToHome = false;
+ } else if (mIsSwipeForStagedSplit) {
+ // Transaction to hide the task to avoid flicker for entering PiP from split-screen.
+ PictureInPictureSurfaceTransaction tx =
+ new PictureInPictureSurfaceTransaction.Builder()
+ .setAlpha(0f)
+ .build();
+ int[] taskIds =
+ LauncherSplitScreenListener.INSTANCE.getNoCreate().getRunningSplitTaskIds();
+ for (int taskId : taskIds) {
+ mRecentsAnimationController.setFinishTaskTransaction(taskId,
+ tx, null /* overlay */);
+ }
}
}
@@ -1615,7 +1793,10 @@ public abstract class AbsSwipeUpHandler,
endLauncherTransitionController();
mRecentsView.onSwipeUpAnimationSuccess();
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy);
+ mTaskAnimationManager.setLiveTileCleanUpHandler(() -> {
+ mRecentsView.cleanupRemoteTargets();
+ mInputConsumerProxy.destroy();
+ });
mTaskAnimationManager.enableLiveTileRestartListener();
}
@@ -1634,8 +1815,8 @@ public abstract class AbsSwipeUpHandler,
* depend on proper class initialization.
*/
protected void initAfterSubclassConstructor() {
- initTransitionEndpoints(
- mTaskViewSimulator.getOrientationState().getLauncherDeviceProfile());
+ initTransitionEndpoints(mRemoteTargetHandles[0].getTaskViewSimulator()
+ .getOrientationState().getLauncherDeviceProfile());
}
protected void performHapticFeedback() {
@@ -1652,13 +1833,14 @@ public abstract class AbsSwipeUpHandler,
protected void linkRecentsViewScroll() {
SurfaceTransactionApplier.create(mRecentsView, applier -> {
- mTransformParams.setSyncTransactionApplier(applier);
- runOnRecentsAnimationStart(() ->
+ runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
+ .setSyncTransactionApplier(applier));
+ runOnRecentsAnimationAndLauncherBound(() ->
mRecentsAnimationTargets.addReleaseCheck(applier));
});
mRecentsView.addOnScrollChangedListener(mOnRecentsScrollListener);
- runOnRecentsAnimationStart(() ->
+ runOnRecentsAnimationAndLauncherBound(() ->
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
mRecentsAnimationTargets));
mRecentsViewScrollLinked = true;
@@ -1704,14 +1886,26 @@ public abstract class AbsSwipeUpHandler,
}
/**
- * Runs the given {@param action} if the recents animation has already started, or queues it to
- * be run when it is next started.
+ * Runs the given {@param action} if the recents animation has already started and Launcher has
+ * been created and bound to the TouchInteractionService, or queues it to be run when it this
+ * next happens.
*/
- protected void runOnRecentsAnimationStart(Runnable action) {
- if (mRecentsAnimationTargets == null) {
- mRecentsAnimationStartCallbacks.add(action);
- } else {
- action.run();
+ private void runOnRecentsAnimationAndLauncherBound(Runnable action) {
+ mRecentsAnimationStartCallbacks.add(action);
+ flushOnRecentsAnimationAndLauncherBound();
+ }
+
+ private void flushOnRecentsAnimationAndLauncherBound() {
+ if (mRecentsAnimationTargets == null ||
+ !mStateCallback.hasStates(STATE_LAUNCHER_BIND_TO_SERVICE)) {
+ return;
+ }
+
+ if (!mRecentsAnimationStartCallbacks.isEmpty()) {
+ for (Runnable action : new ArrayList<>(mRecentsAnimationStartCallbacks)) {
+ action.run();
+ }
+ mRecentsAnimationStartCallbacks.clear();
}
}
@@ -1725,6 +1919,10 @@ public abstract class AbsSwipeUpHandler,
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ if (!controller.getFinishTargetIsLauncher()) {
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
+ true /*shown*/, true /*animate*/);
+ }
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
if (mRecentsView != null) {
@@ -1733,9 +1931,9 @@ public abstract class AbsSwipeUpHandler,
}
@Override
- public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
if (mRecentsAnimationController != null) {
- if (handleTaskAppeared(appearedTaskTarget)) {
+ if (handleTaskAppeared(appearedTaskTargets)) {
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
mActivityInterface.onLaunchTaskSuccess();
@@ -1775,21 +1973,59 @@ public abstract class AbsSwipeUpHandler,
/**
* Applies the transform on the recents animation
*/
- protected void applyWindowTransform() {
- if (mWindowTransitionController != null) {
- mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
- }
+ protected void applyScrollAndTransform() {
// No need to apply any transform if there is ongoing swipe-pip-to-home animator since
// that animator handles the leash solely.
- if (mRecentsAnimationTargets != null && !mIsSwipingPipToHome) {
- if (mRecentsViewScrollLinked && mRecentsView != null) {
- mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
+ boolean notSwipingPipToHome = mRecentsAnimationTargets != null && !mIsSwipingPipToHome;
+ boolean setRecentsScroll = mRecentsViewScrollLinked && mRecentsView != null;
+ for (RemoteTargetHandle remoteHandle : mRemoteTargetHandles) {
+ AnimatorControllerWithResistance playbackController =
+ remoteHandle.getPlaybackController();
+ if (playbackController != null) {
+ playbackController.setProgress(Math.max(mCurrentShift.value,
+ getScaleProgressDueToScroll()), mDragLengthFactor);
+ }
+
+ if (notSwipingPipToHome) {
+ TaskViewSimulator taskViewSimulator = remoteHandle.getTaskViewSimulator();
+ if (setRecentsScroll) {
+ taskViewSimulator.setScroll(mRecentsView.getScrollOffset());
+ }
+ taskViewSimulator.apply(remoteHandle.getTransformParams());
}
- mTaskViewSimulator.apply(mTransformParams);
}
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
@@ -1811,7 +2047,6 @@ public abstract class AbsSwipeUpHandler,
}
public interface Factory {
-
AbsSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs);
}
}
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index f7e8781573..95c871099b 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -53,6 +53,16 @@ public class AnimatedFloat {
mUpdateCallback = updateCallback;
}
+ /**
+ * Returns an animation from the current value to the given value.
+ */
+ public ObjectAnimator animateToValue(float end) {
+ return animateToValue(value, end);
+ }
+
+ /**
+ * Returns an animation from the given start value to the given end value.
+ */
public ObjectAnimator animateToValue(float start, float end) {
cancelAnimation();
mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, start, end);
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index fac4d52826..1d4ed4c487 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -30,6 +30,7 @@ import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
@@ -40,6 +41,7 @@ import android.graphics.Rect;
import android.os.Build;
import android.view.Gravity;
import android.view.MotionEvent;
+import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -48,10 +50,10 @@ import com.android.launcher3.DeviceProfile;
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;
+import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.views.ScrimView;
@@ -65,6 +67,7 @@ import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import java.util.HashMap;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -77,12 +80,14 @@ public abstract class BaseActivityInterface thumbnailDatas,
+ Runnable runnable) {
ACTIVITY_TYPE activity = getCreatedActivity();
if (activity == null) {
return;
@@ -198,46 +207,31 @@ public abstract class BaseActivityInterface mCallback;
private boolean mIsAttachedToWindow;
+ private boolean mHasEverAttachedToWindow;
DefaultAnimationFactory(Consumer callback) {
mCallback = callback;
@@ -435,7 +466,7 @@ public abstract class BaseActivityInterface mActivity.getStateManager().goToState(
- controller.getInterpolatedProgress() > 0.5 ? mOverviewState : mBackgroundState,
+ controller.getInterpolatedProgress() > 0.5 ? mTargetState : mBackgroundState,
false));
RecentsView recentsView = mActivity.getOverviewPanel();
@@ -461,6 +492,9 @@ public abstract class BaseActivityInterface
+ remoteTargetHandle.getTransformParams().setHomeBuilderProxy(
+ FallbackSwipeHandler.this::updateHomeActivityTransformDuringSwipeUp));
}
}
@@ -109,7 +110,9 @@ public class FallbackSwipeHandler extends
protected void initTransitionEndpoints(DeviceProfile dp) {
super.initTransitionEndpoints(dp);
if (mRunningOverHome) {
- mMaxLauncherScale = 1 / mTaskViewSimulator.getFullScreenScale();
+ // Full screen scale should be independent of remote target handle
+ mMaxLauncherScale = 1 / mRemoteTargetHandles[0].getTaskViewSimulator()
+ .getFullScreenScale();
}
}
@@ -144,7 +147,7 @@ public class FallbackSwipeHandler extends
}
@Override
- protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ protected boolean handleTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {
if (mActiveAnimationFactory != null
&& mActiveAnimationFactory.handleHomeTaskAppeared(appearedTaskTarget)) {
mActiveAnimationFactory = null;
@@ -174,7 +177,8 @@ public class FallbackSwipeHandler extends
protected void notifyGestureAnimationStartToRecents() {
if (mRunningOverHome) {
if (SysUINavigationMode.getMode(mContext).hasGestures) {
- mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
+ mRecentsView.onGestureAnimationStartOnHome(
+ new ActivityManager.RunningTaskInfo[]{mGestureState.getRunningTask()});
}
} else {
super.notifyGestureAnimationStartToRecents();
@@ -202,19 +206,24 @@ public class FallbackSwipeHandler extends
mHomeAlpha = new AnimatedFloat();
mHomeAlpha.value = Utilities.boundToRange(1 - mCurrentShift.value, 0, 1);
mVerticalShiftForScale.value = mCurrentShift.value;
- mTransformParams.setHomeBuilderProxy(
- this::updateHomeActivityTransformDuringHomeAnim);
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTransformParams().setHomeBuilderProxy(
+ FallbackHomeAnimationFactory.this
+ ::updateHomeActivityTransformDuringHomeAnim));
} else {
mHomeAlpha = new AnimatedFloat(this::updateHomeAlpha);
mHomeAlpha.value = 0;
-
- mHomeAlphaParams.setHomeBuilderProxy(
- this::updateHomeActivityTransformDuringHomeAnim);
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTransformParams().setHomeBuilderProxy(
+ FallbackHomeAnimationFactory.this
+ ::updateHomeActivityTransformDuringHomeAnim));
}
mRecentsAlpha.value = 1;
- mTransformParams.setBaseBuilderProxy(
- this::updateRecentsActivityTransformDuringHomeAnim);
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTransformParams().setHomeBuilderProxy(
+ FallbackHomeAnimationFactory.this
+ ::updateRecentsActivityTransformDuringHomeAnim));
}
@NonNull
@@ -251,7 +260,8 @@ public class FallbackSwipeHandler extends
}
}
- public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
+ RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
if (appearedTaskTarget.activityType == ACTIVITY_TYPE_HOME) {
RemoteAnimationTargets targets = new RemoteAnimationTargets(
new RemoteAnimationTargetCompat[] {appearedTaskTarget},
@@ -306,8 +316,7 @@ public class FallbackSwipeHandler extends
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
+ public void update(RectF currentRect, float progress, float radius) {
if (mSurfaceControl != null) {
currentRect.roundOut(mTempRect);
Transaction t = new Transaction();
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index e3ae36182e..ed0623da24 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -20,6 +20,7 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import android.annotation.Nullable;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.Intent;
@@ -35,6 +36,7 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
@@ -122,10 +124,6 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
public static final int STATE_RECENTS_ANIMATION_ENDED =
getFlagForIndex("STATE_RECENTS_ANIMATION_ENDED");
- // Called when we create an overscroll window when swiping right to left on the most recent app
- public static final int STATE_OVERSCROLL_WINDOW_CREATED =
- getFlagForIndex("STATE_OVERSCROLL_WINDOW_CREATED");
-
// Called when RecentsView stops scrolling and settles on a TaskView.
public static final int STATE_RECENTS_SCROLLING_FINISHED =
getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
@@ -138,12 +136,13 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
private final int mGestureId;
private ActivityManager.RunningTaskInfo mRunningTask;
+ private ActivityManager.RunningTaskInfo[] mRunningTasks;
private GestureEndTarget mEndTarget;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
private Set mPreviouslyAppearedTaskIds = new HashSet<>();
private int mLastStartedTaskId = -1;
private RecentsAnimationController mRecentsAnimationController;
- private ThumbnailData mRecentsAnimationCanceledSnapshot;
+ private HashMap mRecentsAnimationCanceledSnapshots;
/** The time when the swipe up gesture is triggered. */
private long mSwipeUpStartTimeMs;
@@ -237,6 +236,14 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
return mRunningTask;
}
+ /**
+ * This will array will contain the task returned by {@link #getRunningTask()}
+ * @return the running tasks for this gesture.
+ */
+ public ActivityManager.RunningTaskInfo[] getRunningTasks() {
+ return mRunningTasks;
+ }
+
/**
* @return the running task id for this gesture.
*/
@@ -251,6 +258,15 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
mRunningTask = runningTask;
}
+ /**
+ * TODO(b/210903248) refactor to consolidate w/ method above
+ * Updates the running task for the gesture to be the given {@param runningTask}.
+ */
+ public void updateRunningTasks(ActivityManager.RunningTaskInfo[] runningTasks) {
+ mRunningTasks = runningTasks;
+ updateRunningTask(runningTasks[0]);
+ }
+
/**
* Updates the last task that appeared during this gesture.
*/
@@ -346,8 +362,8 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
* @return whether the recents animation is started but not yet ended
*/
public boolean isRecentsAnimationRunning() {
- return mStateCallback.hasStates(STATE_RECENTS_ANIMATION_INITIALIZED) &&
- !mStateCallback.hasStates(STATE_RECENTS_ANIMATION_ENDED);
+ return mStateCallback.hasStates(STATE_RECENTS_ANIMATION_STARTED)
+ && !mStateCallback.hasStates(STATE_RECENTS_ANIMATION_ENDED);
}
@Override
@@ -358,16 +374,16 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- mRecentsAnimationCanceledSnapshot = thumbnailData;
+ public void onRecentsAnimationCanceled(HashMap thumbnailDatas) {
+ mRecentsAnimationCanceledSnapshots = thumbnailDatas;
mStateCallback.setState(STATE_RECENTS_ANIMATION_CANCELED);
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
- if (mRecentsAnimationCanceledSnapshot != null) {
+ if (mRecentsAnimationCanceledSnapshots != null) {
// Clean up the screenshot to finalize the recents animation cancel
if (mRecentsAnimationController != null) {
mRecentsAnimationController.cleanupScreenshot();
}
- mRecentsAnimationCanceledSnapshot = null;
+ mRecentsAnimationCanceledSnapshots = null;
}
}
@@ -382,10 +398,15 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
* while STATE_RECENTS_ANIMATION_CANCELED state is being set, and the caller is responsible for
* calling {@link RecentsAnimationController#cleanupScreenshot()}.
*/
- ThumbnailData consumeRecentsAnimationCanceledSnapshot() {
- ThumbnailData data = mRecentsAnimationCanceledSnapshot;
- mRecentsAnimationCanceledSnapshot = null;
- return data;
+ @Nullable
+ HashMap consumeRecentsAnimationCanceledSnapshot() {
+ if (mRecentsAnimationCanceledSnapshots != null) {
+ HashMap data =
+ new HashMap(mRecentsAnimationCanceledSnapshots);
+ mRecentsAnimationCanceledSnapshots = null;
+ return data;
+ }
+ return null;
}
void setSwipeUpStartTimeMs(long uptimeMs) {
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index 0b2a057eb8..0b093234f3 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -36,9 +36,10 @@ public interface InputConsumer {
int TYPE_SCREEN_PINNED = 1 << 6;
int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
int TYPE_RESET_GESTURE = 1 << 8;
- int TYPE_OVERSCROLL = 1 << 9;
+ int TYPE_PROGRESS_DELEGATE = 1 << 9;
int TYPE_SYSUI_OVERLAY = 1 << 10;
int TYPE_ONE_HANDED = 1 << 11;
+ int TYPE_TASKBAR_STASH = 1 << 12;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@@ -50,9 +51,10 @@ public interface InputConsumer {
"TYPE_SCREEN_PINNED", // 6
"TYPE_OVERVIEW_WITHOUT_FOCUS", // 7
"TYPE_RESET_GESTURE", // 8
- "TYPE_OVERSCROLL", // 9
+ "TYPE_PROGRESS_DELEGATE", // 9
"TYPE_SYSUI_OVERLAY", // 10
"TYPE_ONE_HANDED", // 11
+ "TYPE_TASKBAR_STASH", // 12
};
InputConsumer NO_OP = () -> TYPE_NO_OP;
diff --git a/quickstep/src/com/android/quickstep/KtR.java b/quickstep/src/com/android/quickstep/KtR.java
new file mode 100644
index 0000000000..a768ef5253
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/KtR.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import com.android.launcher3.R;
+
+/**
+ * Bridge class to allow using resources in Kotlin.
+ *
+ * TODO(b/204069723) Can't use resources directly in Kotlin
+ */
+public class KtR {
+ public static final class id {
+ public static int menu_option_layout = R.id.menu_option_layout;
+ }
+
+ public static final class dimen {
+ public static int task_menu_spacing = R.dimen.task_menu_spacing;
+ public static int task_menu_horizontal_padding = R.dimen.task_menu_horizontal_padding;
+ }
+
+ public static final class layout {
+ public static int task_menu_with_arrow = R.layout.task_menu_with_arrow;
+ public static int task_view_menu_option = R.layout.task_view_menu_option;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index fb1391a309..719c2ae78c 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -71,7 +71,7 @@ public final class LauncherActivityInterface extends
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
PagedOrientationHandler orientationHandler) {
- calculateTaskSize(context, dp, outRect, orientationHandler);
+ calculateTaskSize(context, dp, outRect);
if (dp.isVerticalBarLayout() && SysUINavigationMode.getMode(context) != Mode.NO_BUTTON) {
return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
} else {
@@ -130,7 +130,6 @@ public final class LauncherActivityInterface extends
pa.addFloat(getDepthController(),
new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
fromDepthRatio, toDepthRatio, LINEAR);
-
}
};
@@ -173,7 +172,8 @@ public final class LauncherActivityInterface extends
}
@Nullable
- private LauncherTaskbarUIController getTaskbarController() {
+ @Override
+ public LauncherTaskbarUIController getTaskbarController() {
BaseQuickstepLauncher launcher = getCreatedActivity();
if (launcher == null) {
return null;
@@ -189,7 +189,7 @@ public final class LauncherActivityInterface extends
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;
}
@@ -288,25 +288,23 @@ public final class LauncherActivityInterface extends
} else {
om.hideOverlay(150);
}
- }
-
- @Override
- void onOverviewServiceBound() {
- final BaseQuickstepLauncher activity = getCreatedActivity();
- if (activity == null) return;
- activity.getAppTransitionManager().registerRemoteTransitions();
+ LauncherTaskbarUIController taskbarController = getTaskbarController();
+ if (taskbarController != null) {
+ taskbarController.hideEdu();
+ }
}
@Override
public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget,
- long duration) {
+ long duration, RecentsAnimationCallbacks callbacks) {
LauncherTaskbarUIController uiController = getTaskbarController();
- Animator superAnimator = super.getParallelAnimationToLauncher(endTarget, duration);
- if (uiController == null) {
+ Animator superAnimator = super.getParallelAnimationToLauncher(
+ endTarget, duration, callbacks);
+ if (uiController == null || callbacks == null) {
return superAnimator;
}
LauncherState toState = stateFromGestureEndTarget(endTarget);
- Animator taskbarAnimator = uiController.createAnimToLauncher(toState, duration);
+ Animator taskbarAnimator = uiController.createAnimToLauncher(toState, callbacks, duration);
if (superAnimator == null) {
return taskbarAnimator;
} else {
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 19cad53bb1..a72935b250 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -18,18 +18,14 @@ package com.android.quickstep;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.Utilities.boundToRange;
import static com.android.launcher3.Utilities.dpToPx;
import static com.android.launcher3.Utilities.mapBoundToRange;
import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
-import static java.lang.Math.round;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -59,10 +55,8 @@ import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
-import com.android.quickstep.util.WorkspaceRevealAnim;
import com.android.quickstep.views.FloatingWidgetView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -106,9 +100,11 @@ public class LauncherSwipeHandlerV2 extends
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
mActivity.getRootView().setForceHideBackArrow(true);
- mActivity.setHintUserWillBeActive();
+ if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+ mActivity.setHintUserWillBeActive();
+ }
- if (!canUseWorkspaceView || appCanEnterPip) {
+ if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForStagedSplit) {
return new LauncherHomeAnimationFactory();
}
if (workspaceView instanceof LauncherAppWidgetHostView) {
@@ -119,8 +115,6 @@ public class LauncherSwipeHandlerV2 extends
}
private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) {
- final ResourceProvider rp = DynamicResource.provider(mActivity);
- final float transY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
RectF iconLocation = new RectF();
FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView,
true /* hideOriginal */, iconLocation, false /* isOpening */);
@@ -131,13 +125,15 @@ public class LauncherSwipeHandlerV2 extends
return new FloatingViewHomeAnimationFactory(floatingIconView) {
- // There is a delay in loading the icon, so we need to keep the window
- // opaque until it is ready.
- private boolean mIsFloatingIconReady = false;
+ @Nullable
+ @Override
+ protected View getViewIgnoredInWorkspaceRevealAnimation() {
+ return workspaceView;
+ }
+ @NonNull
@Override
public RectF getWindowTargetRect() {
- super.getWindowTargetRect();
return iconLocation;
}
@@ -150,24 +146,9 @@ public class LauncherSwipeHandlerV2 extends
}
@Override
- public boolean keepWindowOpaque() {
- if (mIsFloatingIconReady || floatingIconView.isVisibleToUser()) {
- mIsFloatingIconReady = true;
- return false;
- }
- return true;
- }
-
- @Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect,
- float progress, float radius) {
- super.update(config, currentRect, progress, radius);
- int fgAlpha = 255;
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- progress = config.getInterpolatedProgress();
- fgAlpha = config.getFgAlpha();
- }
- floatingIconView.update(1f, fgAlpha, currentRect, progress,
+ public void update(RectF currentRect, float progress, float radius) {
+ super.update(currentRect, progress, radius);
+ floatingIconView.update(1f /* alpha */, 255 /* fgAlpha */, currentRect, progress,
windowAlphaThreshold, radius, false);
}
};
@@ -179,14 +160,16 @@ public class LauncherSwipeHandlerV2 extends
final float floatingWidgetAlpha = isTargetTranslucent ? 0 : 1;
RectF backgroundLocation = new RectF();
Rect crop = new Rect();
- mTaskViewSimulator.getCurrentCropRect().roundOut(crop);
+ // We can assume there is only one remote target here because staged split never animates
+ // into the app icon, only into the homescreen
+ mRemoteTargetHandles[0].getTaskViewSimulator().getCurrentCropRect().roundOut(crop);
Size windowSize = new Size(crop.width(), crop.height());
int fallbackBackgroundColor =
FloatingWidgetView.getDefaultBackgroundColor(mContext, runningTaskTarget);
FloatingWidgetView floatingWidgetView = FloatingWidgetView.getFloatingWidgetView(mActivity,
hostView, backgroundLocation, windowSize,
- mTaskViewSimulator.getCurrentCornerRadius(), isTargetTranslucent,
- fallbackBackgroundColor);
+ mRemoteTargetHandles[0].getTaskViewSimulator().getCurrentCornerRadius(),
+ isTargetTranslucent, fallbackBackgroundColor);
return new FloatingViewHomeAnimationFactory(floatingWidgetView) {
@@ -217,14 +200,8 @@ public class LauncherSwipeHandlerV2 extends
}
@Override
- public boolean keepWindowOpaque() {
- return false;
- }
-
- @Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
- super.update(config, currentRect, progress, radius);
+ public void update(RectF currentRect, float progress, float radius) {
+ super.update(currentRect, progress, radius);
final float fallbackBackgroundAlpha =
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
final float foregroundAlpha =
@@ -267,7 +244,7 @@ public class LauncherSwipeHandlerV2 extends
}
}
- return mActivity.getWorkspace().getFirstMatchForAppClose(launchCookieItemId,
+ return mActivity.getFirstMatchForAppClose(launchCookieItemId,
runningTaskView.getTask().key.getComponent().getPackageName(),
UserHandle.of(runningTaskView.getTask().key.userId));
}
@@ -283,27 +260,12 @@ public class LauncherSwipeHandlerV2 extends
private final float mTransY;
private final FloatingView mFloatingView;
private ValueAnimator mBounceBackAnimator;
- private final AnimatorSet mWorkspaceReveal;
FloatingViewHomeAnimationFactory(FloatingView floatingView) {
mFloatingView = floatingView;
ResourceProvider rp = DynamicResource.provider(mActivity);
mTransY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
-
- mWorkspaceReveal = PROTOTYPE_APP_CLOSE.get()
- ? new WorkspaceRevealAnim(mActivity, true /* animateScrim */).getAnimators()
- : null;
- }
-
- @Override
- public @NonNull RectF getWindowTargetRect() {
- if (PROTOTYPE_APP_CLOSE.get()) {
- // We want the target rect to be at this offset position, so that all
- // launcher content can spring back upwards.
- mFloatingView.setPositionOffsetY(mTransY);
- }
- return super.getWindowTargetRect();
}
@Override
@@ -311,20 +273,6 @@ public class LauncherSwipeHandlerV2 extends
return false;
}
- @Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- DragLayer dl = mActivity.getDragLayer();
- float translationY = config.getWorkspaceTransY();
- dl.setTranslationY(translationY);
-
- long duration = mWorkspaceReveal.getDuration();
- long playTime = boundToRange(round(duration * progress), 0, duration);
- mWorkspaceReveal.setCurrentPlayTime(playTime);
- }
- }
-
protected void bounceBackToRestingPosition() {
final float startValue = mTransY;
final float endValue = 0;
@@ -358,31 +306,6 @@ public class LauncherSwipeHandlerV2 extends
mBounceBackAnimator.start();
}
- @Override
- public void setAnimation(RectFSpringAnim anim) {
- if (PROTOTYPE_APP_CLOSE.get()) {
- // Use a spring to put drag layer translation back to 0.
- anim.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mFloatingView.setPositionOffsetY(0);
- bounceBackToRestingPosition();
- }
- });
-
- // Will be updated manually below so that the two animations are in sync.
- mWorkspaceReveal.start();
- mWorkspaceReveal.pause();
-
- anim.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mWorkspaceReveal.end();
- }
- });
- }
- }
-
@Override
public void onCancel() {
mFloatingView.fastFinish();
@@ -415,13 +338,9 @@ public class LauncherSwipeHandlerV2 extends
@Override
public void playAtomicAnimation(float velocity) {
- if (!PROTOTYPE_APP_CLOSE.get()) {
- new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
- getViewIgnoredInWorkspaceRevealAnimation())
- .start();
- } else if (shouldPlayAtomicWorkspaceReveal()) {
- new WorkspaceRevealAnim(mActivity, true).start();
- }
+ new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
+ getViewIgnoredInWorkspaceRevealAnimation())
+ .start();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/OrientationRectF.java b/quickstep/src/com/android/quickstep/OrientationRectF.java
new file mode 100644
index 0000000000..59a202cf76
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OrientationRectF.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.states.RotationHelper.deltaRotation;
+import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.util.Log;
+import android.view.MotionEvent;
+
+public class OrientationRectF extends RectF {
+
+ private static final String TAG = "OrientationRectF";
+ private static final boolean DEBUG = false;
+
+ private final int mRotation;
+ private final float mHeight;
+ private final float mWidth;
+
+ private final Matrix mTmpMatrix = new Matrix();
+ private final float[] mTmpPoint = new float[2];
+
+ public OrientationRectF(float left, float top, float right, float bottom, int rotation) {
+ super(left, top, right, bottom);
+ mRotation = rotation;
+ mHeight = bottom;
+ mWidth = right;
+ }
+
+ @Override
+ public String toString() {
+ String s = super.toString();
+ s += " rotation: " + mRotation;
+ return s;
+ }
+
+ @Override
+ public boolean contains(float x, float y) {
+ // Mark bottom right as included in the Rect (copied from Rect src, added "=" in "<=")
+ return left < right && top < bottom // check for empty first
+ && x >= left && x <= right && y >= top && y <= bottom;
+ }
+
+ public boolean applyTransformFromRotation(MotionEvent event, int currentRotation,
+ boolean forceTransform) {
+ return applyTransform(event, deltaRotation(currentRotation, mRotation), forceTransform);
+ }
+
+ public boolean applyTransformToRotation(MotionEvent event, int currentRotation,
+ boolean forceTransform) {
+ return applyTransform(event, deltaRotation(mRotation, currentRotation), forceTransform);
+ }
+
+ private boolean applyTransform(MotionEvent event, int deltaRotation, boolean forceTransform) {
+ mTmpMatrix.reset();
+ postDisplayRotation(deltaRotation, mHeight, mWidth, mTmpMatrix);
+ if (forceTransform) {
+ if (DEBUG) {
+ Log.d(TAG, "Transforming rotation due to forceTransform, "
+ + "deltaRotation: " + deltaRotation
+ + "mRotation: " + mRotation
+ + " this: " + this);
+ }
+ event.applyTransform(mTmpMatrix);
+ return true;
+ }
+ mTmpPoint[0] = event.getX();
+ mTmpPoint[1] = event.getY();
+ mTmpMatrix.mapPoints(mTmpPoint);
+
+ if (DEBUG) {
+ Log.d(TAG, "original: " + event.getX() + ", " + event.getY()
+ + " new: " + mTmpPoint[0] + ", " + mTmpPoint[1]
+ + " rect: " + this + " forceTransform: " + forceTransform
+ + " contains: " + contains(mTmpPoint[0], mTmpPoint[1])
+ + " this: " + this);
+ }
+
+ if (contains(mTmpPoint[0], mTmpPoint[1])) {
+ event.applyTransform(mTmpMatrix);
+ return true;
+ }
+ return false;
+ }
+
+ int getRotation() {
+ return mRotation;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 35a851ab65..ecff4f1a45 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -22,11 +22,7 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_UP;
-import static com.android.launcher3.states.RotationHelper.deltaRotation;
-import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
-
import android.content.res.Resources;
-import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.Log;
@@ -44,8 +40,8 @@ import java.util.Objects;
/**
* Maintains state for supporting nav bars and tracking their gestures in multiple orientations.
- * See {@link OrientationRectF#applyTransform(MotionEvent, boolean)} for transformation of
- * MotionEvents from one orientation's coordinate space to another's.
+ * See {@link OrientationRectF#applyTransformToRotation(MotionEvent, int, boolean)} for
+ * transformation of MotionEvents from one orientation's coordinate space to another's.
*
* This class only supports single touch/pointer gesture tracking for touches started in a supported
* nav bar region.
@@ -95,9 +91,6 @@ class OrientationTouchTransformer {
private static final int QUICKSTEP_ROTATION_UNINITIALIZED = -1;
- private final Matrix mTmpMatrix = new Matrix();
- private final float[] mTmpPoint = new float[2];
-
private final Map mSwipeTouchRegions =
new HashMap();
private final RectF mAssistantLeftRegion = new RectF();
@@ -365,7 +358,7 @@ class OrientationTouchTransformer {
if (mLastRectTouched == null) {
return;
}
- mLastRectTouched.applyTransform(event, true);
+ mLastRectTouched.applyTransformFromRotation(event, mCurrentDisplay.rotation, true);
break;
}
case ACTION_CANCEL:
@@ -373,7 +366,7 @@ class OrientationTouchTransformer {
if (mLastRectTouched == null) {
return;
}
- mLastRectTouched.applyTransform(event, true);
+ mLastRectTouched.applyTransformFromRotation(event, mCurrentDisplay.rotation, true);
mLastRectTouched = null;
break;
}
@@ -387,14 +380,14 @@ class OrientationTouchTransformer {
if (rect == null) {
continue;
}
- if (rect.applyTransform(event, false)) {
+ if (rect.applyTransformFromRotation(event, mCurrentDisplay.rotation, false)) {
mLastRectTouched = rect;
- mActiveTouchRotation = rect.mRotation;
+ mActiveTouchRotation = rect.getRotation();
if (mEnableMultipleRegions
&& mCurrentDisplay.rotation == mActiveTouchRotation) {
// TODO(b/154580671) might make this block unnecessary
// Start a touch session for the default nav region for the display
- mQuickStepStartingRotation = mLastRectTouched.mRotation;
+ mQuickStepStartingRotation = mLastRectTouched.getRotation();
resetSwipeRegions();
}
if (DEBUG) {
@@ -423,65 +416,4 @@ class OrientationTouchTransformer {
pw.println(" mNavBarLargerGesturalHeight=" + mNavBarLargerGesturalHeight);
pw.println(" mOneHandedModeRegion=" + mOneHandedModeRegion);
}
-
- private class OrientationRectF extends RectF {
-
- private int mRotation;
- private float mHeight;
- private float mWidth;
-
- OrientationRectF(float left, float top, float right, float bottom, int rotation) {
- super(left, top, right, bottom);
- this.mRotation = rotation;
- mHeight = bottom;
- mWidth = right;
- }
-
- @Override
- public String toString() {
- String s = super.toString();
- s += " rotation: " + mRotation;
- return s;
- }
-
- @Override
- public boolean contains(float x, float y) {
- // Mark bottom right as included in the Rect (copied from Rect src, added "=" in "<=")
- return left < right && top < bottom // check for empty first
- && x >= left && x <= right && y >= top && y <= bottom;
- }
-
- boolean applyTransform(MotionEvent event, boolean forceTransform) {
- mTmpMatrix.reset();
- postDisplayRotation(deltaRotation(mCurrentDisplay.rotation, mRotation),
- mHeight, mWidth, mTmpMatrix);
- if (forceTransform) {
- if (DEBUG) {
- Log.d(TAG, "Transforming rotation due to forceTransform, "
- + "mCurrentRotation: " + mCurrentDisplay.rotation
- + "mRotation: " + mRotation
- + " this: " + this);
- }
- event.transform(mTmpMatrix);
- return true;
- }
- mTmpPoint[0] = event.getX();
- mTmpPoint[1] = event.getY();
- mTmpMatrix.mapPoints(mTmpPoint);
-
- if (DEBUG) {
- Log.d(TAG, "original: " + event.getX() + ", " + event.getY()
- + " new: " + mTmpPoint[0] + ", " + mTmpPoint[1]
- + " rect: " + this + " forceTransform: " + forceTransform
- + " contains: " + contains(mTmpPoint[0], mTmpPoint[1])
- + " this: " + this);
- }
-
- if (contains(mTmpPoint[0], mTmpPoint[1])) {
- event.transform(mTmpMatrix);
- return true;
- }
- return false;
- }
- }
}
diff --git a/quickstep/src/com/android/quickstep/OverscrollPluginFactory.java b/quickstep/src/com/android/quickstep/OverscrollPluginFactory.java
deleted file mode 100644
index 4c261abc7a..0000000000
--- a/quickstep/src/com/android/quickstep/OverscrollPluginFactory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
-
-import com.android.launcher3.R;
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.launcher3.util.ResourceBasedOverride;
-import com.android.systemui.plugins.OverscrollPlugin;
-
-/**
- * Resource overrideable factory for forcing a local overscroll plugin.
- * Override {@link R.string#overscroll_plugin_factory_class} to set a different class.
- */
-public class OverscrollPluginFactory implements ResourceBasedOverride {
- public static final MainThreadInitializedObject INSTANCE = forOverride(
- OverscrollPluginFactory.class,
- R.string.overscroll_plugin_factory_class);
-
- /**
- * Get the plugin that is defined locally in launcher, as opposed to a dynamic side loaded one.
- */
- public OverscrollPlugin getLocalOverscrollPlugin() {
- return null;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 5d1f90885a..75e8dd1f7a 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -32,12 +32,14 @@ import androidx.annotation.UiThread;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.util.RunnableList;
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
+import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.ArrayList;
+import java.util.HashMap;
/**
* Helper class to handle various atomic commands for switching between Overview.
@@ -49,6 +51,7 @@ public class OverviewCommandHelper {
public static final int TYPE_SHOW_NEXT_FOCUS = 2;
public static final int TYPE_HIDE = 3;
public static final int TYPE_TOGGLE = 4;
+ public static final int TYPE_HOME = 5;
private static final String TRANSITION_NAME = "Transition:toOverview";
@@ -114,11 +117,12 @@ public class OverviewCommandHelper {
mPendingCommands.clear();
}
+ @Nullable
private TaskView getNextTask(RecentsView view) {
final TaskView runningTaskView = view.getRunningTaskView();
if (runningTaskView == null) {
- return view.getTaskViewCount() > 0 ? view.getTaskViewAt(0) : null;
+ return view.getTaskViewAt(0);
} else {
final TaskView nextTask = view.getNextTaskView();
return nextTask != null ? nextTask : runningTaskView;
@@ -154,6 +158,11 @@ public class OverviewCommandHelper {
// already hidden
return true;
}
+ if (cmd.type == TYPE_HOME) {
+ mService.startActivity(mOverviewComponentObserver.getHomeIntent());
+ LauncherSplitScreenListener.INSTANCE.getNoCreate().notifySwipingToHome();
+ return true;
+ }
} else {
switch (cmd.type) {
case TYPE_SHOW:
@@ -168,6 +177,10 @@ public class OverviewCommandHelper {
}
case TYPE_TOGGLE:
return launchTask(recents, getNextTask(recents), cmd);
+ case TYPE_HOME:
+ recents.startHome();
+ LauncherSplitScreenListener.INSTANCE.getNoCreate().notifySwipingToHome();
+ return true;
}
}
@@ -200,7 +213,7 @@ public class OverviewCommandHelper {
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap thumbnailDatas) {
interactionHandler.onGestureCancelled();
cmd.removeListener(this);
@@ -244,8 +257,8 @@ public class OverviewCommandHelper {
// Ensure that recents view has focus so that it receives the followup key inputs
TaskView taskView = rv.getNextTaskView();
if (taskView == null) {
- if (rv.getTaskViewCount() > 0) {
- taskView = rv.getTaskViewAt(0);
+ taskView = rv.getTaskViewAt(0);
+ if (taskView != null) {
taskView.requestFocus();
} else {
rv.requestFocus();
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index 65847f11bb..a551f55de5 100644
--- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -24,8 +24,6 @@ import android.util.Log;
import com.android.launcher3.BuildConfig;
import com.android.launcher3.MainProcessInitializer;
-import com.android.launcher3.util.Executors;
-import com.android.quickstep.logging.SettingsChangeLogger;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.ThreadedRendererCompat;
@@ -62,9 +60,5 @@ public class QuickstepProcessInitializer extends MainProcessInitializer {
// Elevate GPU priority for Quickstep and Remote animations.
ThreadedRendererCompat.setContextPriority(
ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
-
- // Initialize settings logger after a default timeout
- Executors.MAIN_EXECUTOR.getHandler()
- .postDelayed(() -> new SettingsChangeLogger(context), SETUP_DELAY_MILLIS);
}
}
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 39af0db8ff..95ab62f1f6 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -2,10 +2,10 @@ package com.android.quickstep;
import android.app.Activity;
import android.content.Context;
+import android.graphics.Rect;
import android.os.Bundle;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
@@ -21,7 +21,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
}
@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: {
@@ -53,20 +53,30 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
Bundle::putInt, PortraitStatesTouchController::getHotseatTop);
}
- case TestProtocol.REQUEST_OVERVIEW_SHARE_ENABLED: {
- response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- FeatureFlags.ENABLE_OVERVIEW_SHARE.get());
+ case TestProtocol.REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET: {
+ if (!mDeviceProfile.isTablet) {
+ return null;
+ }
+ Rect focusedTaskRect = new Rect();
+ LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile,
+ focusedTaskRect);
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height());
return response;
}
- case TestProtocol.REQUEST_OVERVIEW_CONTENT_PUSH_ENABLED: {
- response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
- FeatureFlags.ENABLE_OVERVIEW_CONTENT_PUSH.get());
+ case TestProtocol.REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET: {
+ if (!mDeviceProfile.isTablet) {
+ return null;
+ }
+ Rect gridTaskRect = new Rect();
+ LauncherActivityInterface.INSTANCE.calculateGridTaskSize(mContext, mDeviceProfile,
+ gridTaskRect, PagedOrientationHandler.PORTRAIT);
+ response.putParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, gridTaskRect);
return response;
}
}
- return super.call(method);
+ return super.call(method, arg);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 3080f040ac..097850fd6f 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -22,35 +22,36 @@ import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.os.Build;
import android.os.Process;
-import android.util.Log;
+import android.os.RemoteException;
import android.util.SparseBooleanArray;
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.testing.TestProtocol;
+import com.android.quickstep.util.GroupTask;
import com.android.launcher3.util.LooperExecutor;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.KeyguardManagerCompat;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
+import com.android.wm.shell.util.StagedSplitBounds;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
import java.util.function.Consumer;
/**
* Manages the recent task list from the system, caching it as necessary.
*/
@TargetApi(Build.VERSION_CODES.R)
-public class RecentTasksList extends TaskStackChangeListener {
+public class RecentTasksList {
private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);
private final KeyguardManagerCompat mKeyguardManager;
private final LooperExecutor mMainThreadExecutor;
- private final ActivityManagerWrapper mActivityManagerWrapper;
+ private final SystemUiProxy mSysUiProxy;
// The list change id, increments as the task list changes in the system
private int mChangeId;
@@ -62,12 +63,17 @@ public class RecentTasksList extends TaskStackChangeListener {
private TaskLoadResult mResultsUi = INVALID_RESULT;
public RecentTasksList(LooperExecutor mainThreadExecutor,
- KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) {
+ KeyguardManagerCompat keyguardManager, SystemUiProxy sysUiProxy) {
mMainThreadExecutor = mainThreadExecutor;
mKeyguardManager = keyguardManager;
mChangeId = 1;
- mActivityManagerWrapper = activityManagerWrapper;
- TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
+ mSysUiProxy = sysUiProxy;
+ sysUiProxy.registerRecentTasksListener(new IRecentTasksListener.Stub() {
+ @Override
+ public void onRecentTasksChanged() throws RemoteException {
+ mMainThreadExecutor.execute(RecentTasksList.this::onRecentTasksChanged);
+ }
+ });
}
@VisibleForTesting
@@ -78,10 +84,11 @@ public class RecentTasksList extends TaskStackChangeListener {
/**
* Fetches the task keys skipping any local cache.
*/
- public void getTaskKeys(int numTasks, Consumer> callback) {
+ public void getTaskKeys(int numTasks, Consumer> callback) {
// Kick off task loading in the background
UI_HELPER_EXECUTOR.execute(() -> {
- ArrayList tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */);
+ ArrayList tasks = loadTasksInBackground(numTasks, -1,
+ true /* loadKeysOnly */);
mMainThreadExecutor.execute(() -> callback.accept(tasks));
});
}
@@ -93,14 +100,15 @@ public class RecentTasksList extends TaskStackChangeListener {
* @param callback The callback to receive the list of recent tasks
* @return The change id of the current task list
*/
- public synchronized int getTasks(boolean loadKeysOnly, Consumer> callback) {
+ public synchronized int getTasks(boolean loadKeysOnly,
+ Consumer> callback) {
final int requestLoadId = mChangeId;
if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
// The list is up to date, send the callback on the next frame,
// so that requestID can be returned first.
if (callback != null) {
// Copy synchronously as the changeId might change by next frame
- ArrayList result = copyOf(mResultsUi);
+ ArrayList result = copyOf(mResultsUi);
mMainThreadExecutor.post(() -> {
callback.accept(result);
});
@@ -120,7 +128,7 @@ public class RecentTasksList extends TaskStackChangeListener {
mLoadingTasksInBackground = false;
mResultsUi = loadResult;
if (callback != null) {
- ArrayList result = copyOf(mResultsUi);
+ ArrayList result = copyOf(mResultsUi);
callback.accept(result);
}
});
@@ -136,35 +144,7 @@ public class RecentTasksList extends TaskStackChangeListener {
return mChangeId == changeId;
}
- @Override
- public void onTaskStackChanged() {
- invalidateLoadedTasks();
- }
-
- @Override
- public void onRecentTaskListUpdated() {
- // In some cases immediately after booting, the tasks in the system recent task list may be
- // loaded, but not in the active task hierarchy in the system. These tasks are displayed in
- // overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved()
- // callback (those are for changes to the active tasks), but the task list is still updated,
- // so we should also invalidate the change id to ensure we load a new list instead of
- // reusing a stale list.
- invalidateLoadedTasks();
- }
-
- @Override
- public void onTaskRemoved(int taskId) {
- invalidateLoadedTasks();
- }
-
-
- @Override
- public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
- invalidateLoadedTasks();
- }
-
- @Override
- public synchronized void onActivityUnpinned() {
+ public void onRecentTasksChanged() {
invalidateLoadedTasks();
}
@@ -180,8 +160,8 @@ public class RecentTasksList extends TaskStackChangeListener {
@VisibleForTesting
TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) {
int currentUserId = Process.myUserHandle().getIdentifier();
- List rawTasks =
- mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
+ ArrayList rawTasks =
+ mSysUiProxy.getRecentTasks(numTasks, currentUserId);
// The raw tasks are given in most-recent to least-recent order, we need to reverse it
Collections.reverse(rawTasks);
@@ -197,45 +177,84 @@ public class RecentTasksList extends TaskStackChangeListener {
};
TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
- for (ActivityManager.RecentTaskInfo rawTask : rawTasks) {
- Task.TaskKey taskKey = new Task.TaskKey(rawTask);
- Task task;
- if (!loadKeysOnly) {
- boolean isLocked = tmpLockedUsers.get(taskKey.userId);
- task = Task.from(taskKey, rawTask, isLocked);
- } else {
- task = new Task(taskKey);
+ for (GroupedRecentTaskInfo rawTask : rawTasks) {
+ ActivityManager.RecentTaskInfo taskInfo1 = rawTask.mTaskInfo1;
+ ActivityManager.RecentTaskInfo taskInfo2 = rawTask.mTaskInfo2;
+ Task.TaskKey task1Key = new Task.TaskKey(taskInfo1);
+ Task task1 = loadKeysOnly
+ ? new Task(task1Key)
+ : Task.from(task1Key, taskInfo1,
+ tmpLockedUsers.get(task1Key.userId) /* isLocked */);
+ task1.setLastSnapshotData(taskInfo1);
+ Task task2 = null;
+ if (taskInfo2 != null) {
+ Task.TaskKey task2Key = new Task.TaskKey(taskInfo2);
+ task2 = loadKeysOnly
+ ? new Task(task2Key)
+ : Task.from(task2Key, taskInfo2,
+ tmpLockedUsers.get(task2Key.userId) /* isLocked */);
+ task2.setLastSnapshotData(taskInfo2);
}
- task.setLastSnapshotData(rawTask);
- allTasks.add(task);
+ final SplitConfigurationOptions.StagedSplitBounds launcherSplitBounds =
+ convertSplitBounds(rawTask.mStagedSplitBounds);
+ allTasks.add(new GroupTask(task1, task2, launcherSplitBounds));
}
return allTasks;
}
- private ArrayList copyOf(ArrayList tasks) {
- ArrayList newTasks = new ArrayList<>();
+ private SplitConfigurationOptions.StagedSplitBounds convertSplitBounds(
+ StagedSplitBounds shellSplitBounds) {
+ return shellSplitBounds == null ?
+ null :
+ new SplitConfigurationOptions.StagedSplitBounds(
+ shellSplitBounds.leftTopBounds, shellSplitBounds.rightBottomBounds,
+ shellSplitBounds.leftTopTaskId, shellSplitBounds.rightBottomTaskId);
+ }
+
+ private ArrayList copyOf(ArrayList tasks) {
+ ArrayList newTasks = new ArrayList<>();
for (int i = 0; i < tasks.size(); i++) {
- newTasks.add(new Task(tasks.get(i)));
+ newTasks.add(new GroupTask(tasks.get(i)));
}
return newTasks;
}
- private static class TaskLoadResult extends ArrayList {
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "RecentTasksList:");
+ writer.println(prefix + " mChangeId=" + mChangeId);
+ writer.println(prefix + " mResultsUi=[id=" + mResultsUi.mRequestId + ", tasks=");
+ for (GroupTask task : mResultsUi) {
+ writer.println(prefix + " t1=" + task.task1.key.id
+ + " t2=" + (task.hasMultipleTasks() ? task.task2.key.id : "-1"));
+ }
+ writer.println(prefix + " ]");
+ int currentUserId = Process.myUserHandle().getIdentifier();
+ ArrayList rawTasks =
+ mSysUiProxy.getRecentTasks(Integer.MAX_VALUE, currentUserId);
+ writer.println(prefix + " rawTasks=[");
+ for (GroupedRecentTaskInfo task : rawTasks) {
+ writer.println(prefix + " t1=" + task.mTaskInfo1.taskId
+ + " t2=" + (task.mTaskInfo2 != null ? task.mTaskInfo2.taskId : "-1"));
+ }
+ writer.println(prefix + " ]");
+ }
- final int mId;
+ private static class TaskLoadResult extends ArrayList {
+
+ final int mRequestId;
// If the result was loaded with keysOnly = true
final boolean mKeysOnly;
- TaskLoadResult(int id, boolean keysOnly, int size) {
+ TaskLoadResult(int requestId, boolean keysOnly, int size) {
super(size);
- mId = id;
+ mRequestId = requestId;
mKeysOnly = keysOnly;
}
boolean isValidForRequest(int requestId, boolean loadKeysOnly) {
- return mId == requestId && (!mKeysOnly || loadKeysOnly);
+ return mRequestId == requestId && (!mKeysOnly || loadKeysOnly);
}
}
}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 9dfcd12dde..103f350c0f 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.RECENTS_LAUNCH_DU
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;
@@ -60,6 +60,8 @@ import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.taskbar.FallbackTaskbarUIController;
+import com.android.launcher3.taskbar.TaskbarManager;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.RunnableList;
@@ -73,9 +75,9 @@ import com.android.quickstep.fallback.RecentsDragLayer;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.util.SplitSelectStateController;
+import com.android.quickstep.util.TISBindHelper;
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;
@@ -102,6 +104,9 @@ public final class RecentsActivity extends StatefulActivity {
private ScrimView mScrimView;
private FallbackRecentsView mFallbackRecentsView;
private OverviewActionsView mActionsView;
+ private TISBindHelper mTISBindHelper;
+ private @Nullable TaskbarManager mTaskbarManager;
+ private @Nullable FallbackTaskbarUIController mTaskbarUIController;
private Configuration mOldConfig;
@@ -122,13 +127,31 @@ public final class RecentsActivity extends StatefulActivity {
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),
+ getStateManager(), null /*depthController*/);
mDragLayer.recreateControllers();
- mFallbackRecentsView.init(mActionsView, splitPlaceholderView);
+ mFallbackRecentsView.init(mActionsView, controller);
+
+ mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
+ }
+
+ private void onTISConnected(TouchInteractionService.TISBinder binder) {
+ mTaskbarManager = binder.getTaskbarManager();
+ mTaskbarManager.setActivity(this);
+ }
+
+ @Override
+ public void runOnBindToTouchInteractionService(Runnable r) {
+ mTISBindHelper.runOnBindToTouchInteractionService(r);
+ }
+
+ public void setTaskbarUIController(FallbackTaskbarUIController taskbarUIController) {
+ mTaskbarUIController = taskbarUIController;
+ }
+
+ public FallbackTaskbarUIController getTaskbarUIController() {
+ return mTaskbarUIController;
}
@Override
@@ -228,7 +251,7 @@ public final class RecentsActivity extends StatefulActivity {
RemoteAnimationAdapterCompat adapterCompat = new RemoteAnimationAdapterCompat(
wrapper, RECENTS_LAUNCH_DURATION,
RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
- - STATUS_BAR_TRANSITION_PRE_DELAY);
+ - STATUS_BAR_TRANSITION_PRE_DELAY, getIApplicationThread());
final ActivityOptionsWrapper activityOptions = new ActivityOptionsWrapper(
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat),
onEndCallback);
@@ -290,7 +313,7 @@ public final class RecentsActivity extends StatefulActivity {
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();
@@ -350,6 +373,11 @@ public final class RecentsActivity extends StatefulActivity {
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
mActivityLaunchAnimationRunner = null;
+
+ mTISBindHelper.onDestroy();
+ if (mTaskbarManager != null) {
+ mTaskbarManager.clearActivity(this);
+ }
}
@Override
@@ -372,7 +400,8 @@ public final class RecentsActivity extends StatefulActivity {
LauncherAnimationRunner runner = new LauncherAnimationRunner(
getMainThreadHandler(), mAnimationToHomeFactory, true);
RemoteAnimationAdapterCompat adapterCompat =
- new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0);
+ new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0,
+ getIApplicationThread());
startActivity(createHomeIntent(),
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat).toBundle());
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index a21c7140de..b50267633b 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -16,11 +16,14 @@
package com.android.quickstep;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import android.graphics.Rect;
import android.util.ArraySet;
+import android.view.RemoteAnimationTarget;
import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
@@ -29,6 +32,8 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.Set;
/**
@@ -39,6 +44,7 @@ public class RecentsAnimationCallbacks implements
com.android.systemui.shared.system.RecentsAnimationListener {
private final Set mListeners = new ArraySet<>();
+ private final SystemUiProxy mSystemUiProxy;
private final boolean mAllowMinimizeSplitScreen;
// TODO(141886704): Remove these references when they are no longer needed
@@ -46,7 +52,9 @@ public class RecentsAnimationCallbacks implements
private boolean mCancelled;
- public RecentsAnimationCallbacks(boolean allowMinimizeSplitScreen) {
+ public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy,
+ boolean allowMinimizeSplitScreen) {
+ mSystemUiProxy = systemUiProxy;
mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
}
@@ -70,7 +78,7 @@ public class RecentsAnimationCallbacks implements
public void notifyAnimationCanceled() {
mCancelled = true;
- onAnimationCanceled(null);
+ onAnimationCanceled(new HashMap<>());
}
// Called only in Q platform
@@ -89,8 +97,19 @@ public class RecentsAnimationCallbacks implements
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
Rect homeContentInsets, Rect minimizedHomeBounds) {
+ // Convert appTargets to type RemoteAnimationTarget for all apps except Home app
+ RemoteAnimationTarget[] nonHomeApps = Arrays.stream(appTargets)
+ .filter(remoteAnimationTarget ->
+ remoteAnimationTarget.activityType != ACTIVITY_TYPE_HOME)
+ .map(RemoteAnimationTargetCompat::unwrap)
+ .toArray(RemoteAnimationTarget[]::new);
+
+ RemoteAnimationTarget[] nonAppTargets =
+ mSystemUiProxy.onGoingToRecentsLegacy(mCancelled, nonHomeApps);
+
RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
- wallpaperTargets, homeContentInsets, minimizedHomeBounds);
+ wallpaperTargets, RemoteAnimationTargetCompat.wrap(nonAppTargets),
+ homeContentInsets, minimizedHomeBounds);
mController = new RecentsAnimationController(animationController,
mAllowMinimizeSplitScreen, this::onAnimationFinished);
@@ -108,20 +127,20 @@ public class RecentsAnimationCallbacks implements
@BinderThread
@Override
- public final void onAnimationCanceled(ThumbnailData thumbnailData) {
+ public final void onAnimationCanceled(HashMap thumbnailDatas) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
- listener.onRecentsAnimationCanceled(thumbnailData);
+ listener.onRecentsAnimationCanceled(thumbnailDatas);
}
});
}
@BinderThread
@Override
- public void onTaskAppeared(RemoteAnimationTargetCompat app) {
+ public void onTasksAppeared(RemoteAnimationTargetCompat[] apps) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
- listener.onTaskAppeared(app);
+ listener.onTasksAppeared(apps);
}
});
}
@@ -149,16 +168,17 @@ public class RecentsAnimationCallbacks implements
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
* is passed back for rendering screenshot to replace live tile.
*/
- default void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {}
+ default void onRecentsAnimationCanceled(
+ @NonNull HashMap thumbnailDatas) {}
/**
* Callback made whenever the recents animation is finished.
*/
- default void onRecentsAnimationFinished(RecentsAnimationController controller) {}
+ default void onRecentsAnimationFinished(@NonNull RecentsAnimationController controller) {}
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
- default void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {}
+ default void onTasksAppeared(@NonNull RemoteAnimationTargetCompat[] appearedTaskTarget) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 53b66752e2..f343485e7d 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -46,6 +46,8 @@ public class RecentsAnimationController {
private boolean mUseLauncherSysBarFlags = false;
private boolean mSplitScreenMinimized = false;
private boolean mFinishRequested = false;
+ // Only valid when mFinishRequested == true.
+ private boolean mFinishTargetIsLauncher;
private RunnableList mPendingFinishCallbacks = new RunnableList();
public RecentsAnimationController(RecentsAnimationControllerCompat controller,
@@ -145,6 +147,7 @@ public class RecentsAnimationController {
// Finish not yet requested
mFinishRequested = true;
+ mFinishTargetIsLauncher = toRecents;
mOnFinishedListener.accept(this);
mPendingFinishCallbacks.add(callback);
UI_HELPER_EXECUTOR.execute(() -> {
@@ -217,4 +220,12 @@ public class RecentsAnimationController {
public RecentsAnimationControllerCompat getController() {
return mController;
}
+
+ /**
+ * RecentsAnimationListeners can check this in onRecentsAnimationFinished() to determine whether
+ * the animation was finished to launcher vs an app.
+ */
+ public boolean getFinishTargetIsLauncher() {
+ return mFinishTargetIsLauncher;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 444d77a612..73d14246a0 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -18,6 +18,7 @@ package com.android.quickstep;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
@@ -58,8 +59,6 @@ import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.Surface;
@@ -67,7 +66,6 @@ import androidx.annotation.BinderThread;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
@@ -85,7 +83,6 @@ import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
/**
* Manages the state of the system during a swipe up gesture.
@@ -147,7 +144,7 @@ public class RecentsAnimationDeviceState implements
mContext = context;
mDisplayController = DisplayController.INSTANCE.get(context);
mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
- mDisplayId = mDisplayController.getInfo().id;
+ mDisplayId = DEFAULT_DISPLAY;
mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
runOnDestroy(() -> mDisplayController.removeChangeListener(this));
mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context);
@@ -398,14 +395,6 @@ public class RecentsAnimationDeviceState implements
&& mGestureBlockedActivities.contains(runningTaskInfo.topActivity);
}
- /**
- * @return the packages of gesture-blocked activities.
- */
- public List getGestureBlockedActivityPackages() {
- return mGestureBlockedActivities.stream().map(ComponentName::getPackageName)
- .collect(Collectors.toList());
- }
-
/**
* Updates the system ui state flags from SystemUI.
*/
@@ -591,8 +580,7 @@ public class RecentsAnimationDeviceState implements
final Info displayInfo = mDisplayController.getInfo();
return (mRotationTouchHelper.touchInOneHandedModeRegion(ev)
&& displayInfo.rotation != Surface.ROTATION_90
- && displayInfo.rotation != Surface.ROTATION_270
- && displayInfo.densityDpi < DisplayMetrics.DENSITY_600);
+ && displayInfo.rotation != Surface.ROTATION_270);
}
return false;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 3861bab04b..b6d9016727 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -31,9 +31,9 @@ public class RecentsAnimationTargets extends RemoteAnimationTargets {
public final Rect minimizedHomeBounds;
public RecentsAnimationTargets(RemoteAnimationTargetCompat[] apps,
- RemoteAnimationTargetCompat[] wallpapers, Rect homeContentInsets,
- Rect minimizedHomeBounds) {
- super(apps, wallpapers, new RemoteAnimationTargetCompat[0], MODE_CLOSING);
+ RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
+ Rect homeContentInsets, Rect minimizedHomeBounds) {
+ super(apps, wallpapers, nonApps, MODE_CLOSING);
this.homeContentInsets = homeContentInsets;
this.minimizedHomeBounds = minimizedHomeBounds;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 1e82c8cbfa..5d77a6e916 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -24,6 +24,7 @@ import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
+import android.content.Intent;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
@@ -34,6 +35,7 @@ import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.IconProvider.IconChangeListener;
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -41,6 +43,7 @@ import com.android.systemui.shared.system.KeyguardManagerCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
@@ -70,7 +73,7 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL
private RecentsModel(Context context) {
mContext = context;
mTaskList = new RecentTasksList(MAIN_EXECUTOR,
- new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
+ new KeyguardManagerCompat(context), SystemUiProxy.INSTANCE.get(context));
IconProvider iconProvider = new IconProvider(context);
mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider);
@@ -95,7 +98,7 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL
* always called on the UI thread.
* @return the request id associated with this call.
*/
- public int getTasks(Consumer> callback) {
+ public int getTasks(Consumer> callback) {
return mTaskList.getTasks(false /* loadKeysOnly */, callback);
}
@@ -120,9 +123,9 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL
* @param callback Receives true if task is removed, false otherwise
*/
public void isTaskRemoved(int taskId, Consumer callback) {
- mTaskList.getTasks(true /* loadKeysOnly */, (tasks) -> {
- for (Task task : tasks) {
- if (task.key.id == taskId) {
+ mTaskList.getTasks(true /* loadKeysOnly */, (taskGroups) -> {
+ for (GroupTask group : taskGroups) {
+ if (group.containsTask(taskId)) {
callback.accept(false);
return;
}
@@ -148,14 +151,15 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL
ActivityManager.RunningTaskInfo runningTask =
ActivityManagerWrapper.getInstance().getRunningTask();
int runningTaskId = runningTask != null ? runningTask.id : -1;
- mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> {
- for (Task task : tasks) {
- if (task.key.id == runningTaskId) {
+ mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), taskGroups -> {
+ for (GroupTask group : taskGroups) {
+ if (group.containsTask(runningTaskId)) {
// Skip the running task, it's not going to have an up-to-date snapshot by the
// time the user next enters overview
continue;
}
- mThumbnailCache.updateThumbnailInCache(task);
+ mThumbnailCache.updateThumbnailInCache(group.task1);
+ mThumbnailCache.updateThumbnailInCache(group.task2);
}
});
}
@@ -174,7 +178,7 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL
@Override
public void onTaskRemoved(int taskId) {
- Task.TaskKey stubKey = new Task.TaskKey(taskId, 0, null, null, 0, 0);
+ Task.TaskKey stubKey = new Task.TaskKey(taskId, 0, new Intent(), null, 0, 0);
mThumbnailCache.remove(stubKey);
mIconCache.onTaskRemoved(stubKey);
}
@@ -217,6 +221,11 @@ public class RecentsModel extends TaskStackChangeListener implements IconChangeL
mThumbnailChangeListeners.remove(listener);
}
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "RecentsModel:");
+ mTaskList.dump(" ", writer);
+ }
+
/**
* Listener for receiving various task properties changes
*/
diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
index c032889db5..b20d48806a 100644
--- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
@@ -77,8 +77,12 @@ public class RemoteAnimationTargets {
* Gets the navigation bar remote animation target if exists.
*/
public RemoteAnimationTargetCompat getNavBarRemoteAnimationTarget() {
+ return getNonAppTargetOfType(TYPE_NAVIGATION_BAR);
+ }
+
+ public RemoteAnimationTargetCompat getNonAppTargetOfType(int type) {
for (RemoteAnimationTargetCompat target : nonApps) {
- if (target.windowType == TYPE_NAVIGATION_BAR) {
+ if (target.windowType == type) {
return target;
}
}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
new file mode 100644
index 0000000000..ed1a06d05d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
+import com.android.quickstep.util.AnimatorControllerWithResistance;
+import com.android.quickstep.util.LauncherSplitScreenListener;
+import com.android.quickstep.util.TaskViewSimulator;
+import com.android.quickstep.util.TransformParams;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+/**
+ * Glues together the necessary components to animate a remote target using a
+ * {@link TaskViewSimulator}
+ */
+public class RemoteTargetGluer {
+ private RemoteTargetHandle[] mRemoteTargetHandles;
+ private StagedSplitBounds mStagedSplitBounds;
+
+ /**
+ * Use this constructor if remote targets are split-screen independent
+ */
+ public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy,
+ RemoteAnimationTargets targets) {
+ mRemoteTargetHandles = createHandles(context, sizingStrategy, targets.apps.length);
+ }
+
+ /**
+ * Use this constructor if you want the number of handles created to match the number of active
+ * running tasks
+ */
+ public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy) {
+ int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
+ .getRunningSplitTaskIds();
+ mRemoteTargetHandles = createHandles(context, sizingStrategy, splitIds.length == 2 ? 2 : 1);
+ }
+
+ private RemoteTargetHandle[] createHandles(Context context,
+ BaseActivityInterface sizingStrategy, int numHandles) {
+ RemoteTargetHandle[] handles = new RemoteTargetHandle[numHandles];
+ for (int i = 0; i < numHandles; i++) {
+ TaskViewSimulator tvs = new TaskViewSimulator(context, sizingStrategy);
+ TransformParams transformParams = new TransformParams();
+ handles[i] = new RemoteTargetHandle(tvs, transformParams);
+ }
+ return handles;
+ }
+
+ /**
+ * Pairs together {@link TaskViewSimulator}s and {@link TransformParams} into a
+ * {@link RemoteTargetHandle}
+ * Assigns only the apps associated with {@param targets} into their own TaskViewSimulators.
+ * Length of targets.apps should match that of {@link #mRemoteTargetHandles}.
+ *
+ * If split screen may be active when this is called, you might want to use
+ * {@link #assignTargetsForSplitScreen(RemoteAnimationTargets)}
+ */
+ public RemoteTargetHandle[] assignTargets(RemoteAnimationTargets targets) {
+ for (int i = 0; i < mRemoteTargetHandles.length; i++) {
+ RemoteAnimationTargetCompat primaryTaskTarget = targets.apps[i];
+ mRemoteTargetHandles[i].mTransformParams.setTargetSet(
+ createRemoteAnimationTargetsForTarget(targets, null));
+ mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
+ }
+ return mRemoteTargetHandles;
+ }
+
+ /**
+ * Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this matches the
+ * apps in targets.apps to that of the _active_ split screened tasks.
+ * See {@link #assignTargetsForSplitScreen(RemoteAnimationTargets, int[])}
+ */
+ public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) {
+ int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
+ .getRunningSplitTaskIds();
+ return assignTargetsForSplitScreen(targets, splitIds);
+ }
+
+ /**
+ * Assigns the provided splitIDs to the {@link #mRemoteTargetHandles}, with index 0 will being
+ * the left/top task, index 1 right/bottom
+ */
+ public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets,
+ int[] splitIds) {
+ RemoteAnimationTargetCompat topLeftTarget; // only one set if single/fullscreen task
+ RemoteAnimationTargetCompat bottomRightTarget;
+ if (mRemoteTargetHandles.length == 1) {
+ // If we're not in split screen, the splitIds count doesn't really matter since we
+ // should always hit this case.
+ mRemoteTargetHandles[0].mTransformParams.setTargetSet(targets);
+ if (targets.apps.length > 0) {
+ // Unclear why/when target.apps length == 0, but it sure does happen :(
+ topLeftTarget = targets.apps[0];
+ mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget, null);
+ }
+ } else {
+ // split screen
+ topLeftTarget = targets.findTask(splitIds[0]);
+ bottomRightTarget = targets.findTask(splitIds[1]);
+
+ // remoteTargetHandle[0] denotes topLeft task, so we pass in the bottomRight to exclude,
+ // vice versa
+ mStagedSplitBounds = new StagedSplitBounds(
+ topLeftTarget.screenSpaceBounds,
+ bottomRightTarget.screenSpaceBounds, splitIds[0], splitIds[1]);
+ mRemoteTargetHandles[0].mTransformParams.setTargetSet(
+ createRemoteAnimationTargetsForTarget(targets, bottomRightTarget));
+ mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget,
+ mStagedSplitBounds);
+
+ mRemoteTargetHandles[1].mTransformParams.setTargetSet(
+ createRemoteAnimationTargetsForTarget(targets, topLeftTarget));
+ mRemoteTargetHandles[1].mTaskViewSimulator.setPreview(bottomRightTarget,
+ mStagedSplitBounds);
+ }
+ return mRemoteTargetHandles;
+ }
+
+ /**
+ * Ensures that we aren't excluding ancillary targets such as home/recents
+ *
+ * @param targetToExclude Will be excluded from the resulting return value.
+ * Pass in {@code null} to not exclude anything
+ * @return RemoteAnimationTargets where all the app targets from the passed in
+ * {@param targets} are included except {@param targetToExclude}
+ */
+ private RemoteAnimationTargets createRemoteAnimationTargetsForTarget(
+ RemoteAnimationTargets targets,
+ @Nullable RemoteAnimationTargetCompat targetToExclude) {
+ int finalLength = targets.unfilteredApps.length - (targetToExclude == null ? 0 : 1);
+ RemoteAnimationTargetCompat[] targetsWithoutExcluded =
+ new RemoteAnimationTargetCompat[finalLength];
+ int i = 0;
+ for (RemoteAnimationTargetCompat targetCompat : targets.unfilteredApps) {
+ if (targetCompat == targetToExclude) {
+ continue;
+ }
+ targetsWithoutExcluded[i] = targetCompat;
+ i++;
+ }
+ return new RemoteAnimationTargets(targetsWithoutExcluded,
+ targets.wallpapers, targets.nonApps, targets.targetMode);
+ }
+
+ public RemoteTargetHandle[] getRemoteTargetHandles() {
+ return mRemoteTargetHandles;
+ }
+
+ public StagedSplitBounds getStagedSplitBounds() {
+ return mStagedSplitBounds;
+ }
+
+ /**
+ * Container to keep together all the associated objects whose properties need to be updated to
+ * animate a single remote app target
+ */
+ public static class RemoteTargetHandle {
+ private final TaskViewSimulator mTaskViewSimulator;
+ private final TransformParams mTransformParams;
+ @Nullable
+ private AnimatorControllerWithResistance mPlaybackController;
+
+ public RemoteTargetHandle(TaskViewSimulator taskViewSimulator,
+ TransformParams transformParams) {
+ mTransformParams = transformParams;
+ mTaskViewSimulator = taskViewSimulator;
+ }
+
+ public TaskViewSimulator getTaskViewSimulator() {
+ return mTaskViewSimulator;
+ }
+
+ public TransformParams getTransformParams() {
+ return mTransformParams;
+ }
+
+ @Nullable
+ public AnimatorControllerWithResistance getPlaybackController() {
+ return mPlaybackController;
+ }
+
+ public void setPlaybackController(
+ @Nullable AnimatorControllerWithResistance playbackController) {
+ mPlaybackController = playbackController;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 678b176151..35efddf123 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Surface.ROTATION_0;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
@@ -25,7 +26,6 @@ import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
import android.content.Context;
import android.content.res.Resources;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
@@ -35,7 +35,6 @@ import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.quickstep.util.RecentsOrientedState;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -146,10 +145,10 @@ public class RotationTouchHelper implements
mDisplayController = DisplayController.INSTANCE.get(mContext);
Resources resources = mContext.getResources();
mSysUiNavMode = SysUINavigationMode.INSTANCE.get(mContext);
- mDisplayId = mDisplayController.getInfo().id;
+ mDisplayId = DEFAULT_DISPLAY;
mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
- () -> QuickStepContract.getWindowCornerRadius(resources));
+ () -> QuickStepContract.getWindowCornerRadius(mContext));
// Register for navigation mode changes
SysUINavigationMode.Mode newMode = mSysUiNavMode.addModeChangeListener(this);
diff --git a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
new file mode 100644
index 0000000000..f474796962
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
+import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
+import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.MainThreadInitializedObject;
+
+public class SimpleOrientationTouchTransformer implements
+ DisplayController.DisplayInfoChangeListener {
+
+ public static final MainThreadInitializedObject INSTANCE =
+ new MainThreadInitializedObject<>(SimpleOrientationTouchTransformer::new);
+
+ private OrientationRectF mOrientationRectF;
+
+ public SimpleOrientationTouchTransformer(Context context) {
+ DisplayController.INSTANCE.get(context).addChangeListener(this);
+ onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
+ CHANGE_ALL);
+ }
+
+ @Override
+ public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
+ if ((flags & (CHANGE_ROTATION | CHANGE_ACTIVE_SCREEN)) == 0) {
+ return;
+ }
+ mOrientationRectF = new OrientationRectF(0, 0, info.currentSize.y, info.currentSize.x,
+ info.rotation);
+ }
+
+ public void transform(MotionEvent ev, int rotation) {
+ mOrientationRectF.applyTransformToRotation(ev, rotation, true /* forceTransform */);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 44954555b0..8e9b668c15 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -17,7 +17,7 @@ package com.android.quickstep;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_SELECT;
import android.animation.Animator;
import android.content.Context;
@@ -27,7 +27,6 @@ import android.graphics.Rect;
import android.graphics.RectF;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
@@ -36,28 +35,32 @@ import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.util.AppCloseConfig;
+import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.RectFSpringAnim2;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
-public abstract class SwipeUpAnimationLogic {
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+public abstract class SwipeUpAnimationLogic implements
+ RecentsAnimationCallbacks.RecentsAnimationListener{
protected static final Rect TEMP_RECT = new Rect();
+ protected final RemoteTargetGluer mTargetGluer;
protected DeviceProfile mDp;
protected final Context mContext;
protected final RecentsAnimationDeviceState mDeviceState;
protected final GestureState mGestureState;
- protected final TaskViewSimulator mTaskViewSimulator;
- protected final TransformParams mTransformParams;
+ protected RemoteTargetHandle[] mRemoteTargetHandles;
// Shift in the range of [0, 1].
// 0 => preview snapShot is completely visible, and hotseat is completely translated down
@@ -70,37 +73,48 @@ public abstract class SwipeUpAnimationLogic {
// How much further we can drag past recents, as a factor of mTransitionDragLength.
protected float mDragLengthFactor = 1;
- protected AnimatorControllerWithResistance mWindowTransitionController;
+ protected boolean mIsSwipeForStagedSplit;
public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState,
- GestureState gestureState, TransformParams transformParams) {
+ GestureState gestureState) {
mContext = context;
mDeviceState = deviceState;
mGestureState = gestureState;
- mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface());
- mTransformParams = transformParams;
- mTaskViewSimulator.getOrientationState().update(
- mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
- mDeviceState.getRotationTouchHelper().getDisplayRotation());
+ mIsSwipeForStagedSplit = ENABLE_SPLIT_SELECT.get() &&
+ LauncherSplitScreenListener.INSTANCE.getNoCreate()
+ .getRunningSplitTaskIds().length > 1;
+
+ mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getActivityInterface());
+ mRemoteTargetHandles = mTargetGluer.getRemoteTargetHandles();
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().getOrientationState().update(
+ mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
+ mDeviceState.getRotationTouchHelper().getDisplayRotation()
+ ));
}
protected void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
-
- mTaskViewSimulator.setDp(dp);
mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength(
- dp, mContext, TEMP_RECT,
- mTaskViewSimulator.getOrientationState().getOrientationHandler());
+ dp, mContext, TEMP_RECT, mRemoteTargetHandles[0].getTaskViewSimulator()
+ .getOrientationState().getOrientationHandler());
mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
- PendingAnimation pa = new PendingAnimation(mTransitionDragLength * 2);
- mTaskViewSimulator.addAppToOverviewAnim(pa, LINEAR);
- AnimatorPlaybackController normalController = pa.createPlaybackController();
- mWindowTransitionController = AnimatorControllerWithResistance.createForRecents(
- normalController, mContext, mTaskViewSimulator.getOrientationState(),
- mDp, mTaskViewSimulator.recentsViewScale, AnimatedFloat.VALUE,
- mTaskViewSimulator.recentsViewSecondaryTranslation, AnimatedFloat.VALUE);
+ for (RemoteTargetHandle remoteHandle : mRemoteTargetHandles) {
+ PendingAnimation pendingAnimation = new PendingAnimation(mTransitionDragLength * 2);
+ TaskViewSimulator taskViewSimulator = remoteHandle.getTaskViewSimulator();
+ taskViewSimulator.setDp(dp);
+ taskViewSimulator.addAppToOverviewAnim(pendingAnimation, LINEAR);
+ AnimatorPlaybackController playbackController =
+ pendingAnimation.createPlaybackController();
+
+ remoteHandle.setPlaybackController(AnimatorControllerWithResistance.createForRecents(
+ playbackController, mContext, taskViewSimulator.getOrientationState(),
+ mDp, taskViewSimulator.recentsViewScale, AnimatedFloat.VALUE,
+ taskViewSimulator.recentsViewSecondaryTranslation, AnimatedFloat.VALUE
+ ));
+ }
}
@UiThread
@@ -125,7 +139,9 @@ public abstract class SwipeUpAnimationLogic {
public abstract void updateFinalShift();
protected PagedOrientationHandler getOrientationHandler() {
- return mTaskViewSimulator.getOrientationState().getOrientationHandler();
+ // OrientationHandler should be independent of remote target, can directly take one
+ return mRemoteTargetHandles[0].getTaskViewSimulator()
+ .getOrientationState().getOrientationHandler();
}
protected abstract class HomeAnimationFactory {
@@ -167,10 +183,7 @@ public abstract class SwipeUpAnimationLogic {
public void setAnimation(RectFSpringAnim anim) { }
- public boolean keepWindowOpaque() { return false; }
-
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) { }
+ public void update(RectF currentRect, float progress, float radius) { }
public void onCancel() { }
@@ -207,16 +220,35 @@ public abstract class SwipeUpAnimationLogic {
* @param startProgress The progress of {@link #mCurrentShift} to start thw window from.
* @return {@link RectF} represents the bounds as starting point in window space.
*/
- protected RectF updateProgressForStartRect(Matrix outMatrix, float startProgress) {
+ protected RectF[] updateProgressForStartRect(Matrix[] outMatrix, float startProgress) {
mCurrentShift.updateValue(startProgress);
- mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
- RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());
+ RectF[] startRects = new RectF[mRemoteTargetHandles.length];
+ for (int i = 0, mRemoteTargetHandlesLength = mRemoteTargetHandles.length;
+ i < mRemoteTargetHandlesLength; i++) {
+ RemoteTargetHandle remoteHandle = mRemoteTargetHandles[i];
+ TaskViewSimulator tvs = remoteHandle.getTaskViewSimulator();
+ tvs.apply(remoteHandle.getTransformParams().setProgress(startProgress));
- mTaskViewSimulator.applyWindowToHomeRotation(outMatrix);
+ startRects[i] = new RectF(tvs.getCurrentCropRect());
+ outMatrix[i] = new Matrix();
+ tvs.applyWindowToHomeRotation(outMatrix[i]);
+ tvs.getCurrentMatrix().mapRect(startRects[i]);
+ }
+ return startRects;
+ }
- final RectF startRect = new RectF(cropRectF);
- mTaskViewSimulator.getCurrentMatrix().mapRect(startRect);
- return startRect;
+ /** Helper to avoid writing some for-loops to iterate over {@link #mRemoteTargetHandles} */
+ protected void runActionOnRemoteHandles(Consumer consumer) {
+ for (RemoteTargetHandle handle : mRemoteTargetHandles) {
+ consumer.accept(handle);
+ }
+ }
+
+ /** @return only the TaskViewSimulators from {@link #mRemoteTargetHandles} */
+ protected TaskViewSimulator[] getRemoteTaskViewSimulators() {
+ return Arrays.stream(mRemoteTargetHandles)
+ .map(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator())
+ .toArray(TaskViewSimulator[]::new);
}
/**
@@ -224,33 +256,41 @@ public abstract class SwipeUpAnimationLogic {
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
* @param homeAnimationFactory The home animation factory.
*/
- protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
+ protected RectFSpringAnim[] createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
+ // TODO(b/195473584) compute separate end targets for different staged split
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
+ RectFSpringAnim[] out = new RectFSpringAnim[mRemoteTargetHandles.length];
+ Matrix[] homeToWindowPositionMap = new Matrix[mRemoteTargetHandles.length];
+ RectF[] startRects = updateProgressForStartRect(homeToWindowPositionMap, startProgress);
+ for (int i = 0, mRemoteTargetHandlesLength = mRemoteTargetHandles.length;
+ i < mRemoteTargetHandlesLength; i++) {
+ RemoteTargetHandle remoteHandle = mRemoteTargetHandles[i];
+ out[i] = getWindowAnimationToHomeInternal(homeAnimationFactory,
+ targetRect, remoteHandle.getTransformParams(),
+ remoteHandle.getTaskViewSimulator(), startRects[i], homeToWindowPositionMap[i]);
+ }
+ return out;
+ }
- Matrix homeToWindowPositionMap = new Matrix();
- final RectF startRect = updateProgressForStartRect(homeToWindowPositionMap, startProgress);
- RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());
-
+ private RectFSpringAnim getWindowAnimationToHomeInternal(
+ HomeAnimationFactory homeAnimationFactory, RectF targetRect,
+ TransformParams transformParams, TaskViewSimulator taskViewSimulator,
+ RectF startRect, Matrix homeToWindowPositionMap) {
+ RectF cropRectF = new RectF(taskViewSimulator.getCurrentCropRect());
// Move the startRect to Launcher space as floatingIconView runs in Launcher
Matrix windowToHomePositionMap = new Matrix();
homeToWindowPositionMap.invert(windowToHomePositionMap);
windowToHomePositionMap.mapRect(startRect);
- RectFSpringAnim anim;
- if (PROTOTYPE_APP_CLOSE.get()) {
- anim = new RectFSpringAnim2(startRect, targetRect, mContext,
- mTaskViewSimulator.getCurrentCornerRadius(),
- homeAnimationFactory.getEndRadius(cropRectF));
- } else {
- anim = new RectFSpringAnim(startRect, targetRect, mContext);
- }
+ RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
homeAnimationFactory.setAnimation(anim);
SpringAnimationRunner runner = new SpringAnimationRunner(
- homeAnimationFactory, cropRectF, homeToWindowPositionMap);
- anim.addOnUpdateListener(runner);
+ homeAnimationFactory, cropRectF, homeToWindowPositionMap,
+ transformParams, taskViewSimulator);
anim.addAnimatorListener(runner);
+ anim.addOnUpdateListener(runner);
return anim;
}
@@ -262,6 +302,7 @@ public abstract class SwipeUpAnimationLogic {
final RectF mWindowCurrentRect = new RectF();
final Matrix mHomeToWindowPositionMap;
+ private final TransformParams mLocalTransformParams;
final HomeAnimationFactory mAnimationFactory;
final AnimatorPlaybackController mHomeAnim;
@@ -271,41 +312,36 @@ public abstract class SwipeUpAnimationLogic {
final float mEndRadius;
SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
- Matrix homeToWindowPositionMap) {
+ Matrix homeToWindowPositionMap, TransformParams transformParams,
+ TaskViewSimulator taskViewSimulator) {
mAnimationFactory = factory;
mHomeAnim = factory.createActivityAnimationToHome();
mCropRectF = cropRectF;
mHomeToWindowPositionMap = homeToWindowPositionMap;
+ mLocalTransformParams = transformParams;
cropRectF.roundOut(mCropRect);
// End on a "round-enough" radius so that the shape reveal doesn't have to do too much
// rounding at the end of the animation.
- mStartRadius = mTaskViewSimulator.getCurrentCornerRadius();
+ mStartRadius = taskViewSimulator.getCurrentCornerRadius();
mEndRadius = factory.getEndRadius(cropRectF);
}
@Override
- public void onUpdate(@Nullable AppCloseConfig config, RectF currentRect, float progress) {
+ public void onUpdate(RectF currentRect, float progress) {
mHomeAnim.setPlayFraction(progress);
mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
float alpha = mAnimationFactory.getWindowAlpha(progress);
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- alpha = config.getWindowAlpha();
- cornerRadius = config.getCornerRadius();
- }
- if (mAnimationFactory.keepWindowOpaque()) {
- alpha = 1f;
- }
- mTransformParams
+ mLocalTransformParams
.setTargetAlpha(alpha)
.setCornerRadius(cornerRadius);
- mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
- mAnimationFactory.update(config, currentRect, progress,
- mMatrix.mapRadius(cornerRadius));
+ mLocalTransformParams.applySurfaceParams(mLocalTransformParams
+ .createSurfaceParams(this));
+ mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index d040904f98..67e7f88c33 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
+import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.app.PendingIntent;
@@ -33,6 +35,8 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import com.android.launcher3.util.MainThreadInitializedObject;
@@ -45,11 +49,17 @@ import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionContro
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.pip.IPip;
import com.android.wm.shell.pip.IPipAnimationListener;
+import com.android.wm.shell.recents.IRecentTasks;
+import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
import com.android.wm.shell.transition.IShellTransitions;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
+
+import java.util.ArrayList;
+import java.util.Arrays;
/**
* Holds the reference to SystemUI.
@@ -68,16 +78,21 @@ public class SystemUiProxy implements ISystemUiProxy,
private IOneHanded mOneHanded;
private IShellTransitions mShellTransitions;
private IStartingWindow mStartingWindow;
+ private IRecentTasks mRecentTasks;
private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
MAIN_EXECUTOR.execute(() -> clearProxy());
};
- // Save the listeners passed into the proxy since when set/register these listeners,
- // setProxy may not have been called, eg. OverviewProxyService is not connected yet.
- private IPipAnimationListener mPendingPipAnimationListener;
- private ISplitScreenListener mPendingSplitScreenListener;
- private IStartingWindowListener mPendingStartingWindowListener;
- private ISmartspaceCallback mPendingSmartspaceCallback;
+ // Save the listeners passed into the proxy since OverviewProxyService may not have been bound
+ // yet, and we'll need to set/register these listeners with SysUI when they do. Note that it is
+ // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
+ // in case SysUI needs to rebind.
+ private IPipAnimationListener mPipAnimationListener;
+ private ISplitScreenListener mSplitScreenListener;
+ private IStartingWindowListener mStartingWindowListener;
+ private ISmartspaceCallback mSmartspaceCallback;
+ private IRecentTasksListener mRecentTasksListener;
+ private final ArrayList mRemoteTransitions = new ArrayList<>();
// Used to dedupe calls to SystemUI
private int mLastShelfHeight;
@@ -85,6 +100,7 @@ public class SystemUiProxy implements ISystemUiProxy,
private float mLastNavButtonAlpha;
private boolean mLastNavButtonAnimate;
private boolean mHasNavButtonAlphaBeenSet = false;
+ private Runnable mPendingSetNavButtonAlpha = null;
// TODO(141886704): Find a way to remove this
private int mLastSystemUiStateFlags;
@@ -110,6 +126,17 @@ public class SystemUiProxy implements ISystemUiProxy,
}
}
+ @Override
+ public void onImeSwitcherPressed() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.onImeSwitcherPressed();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call onImeSwitcherPressed", e);
+ }
+ }
+ }
+
@Override
public void setHomeRotationEnabled(boolean enabled) {
if (mSystemUiProxy != null) {
@@ -129,7 +156,7 @@ public class SystemUiProxy implements ISystemUiProxy,
public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
IOneHanded oneHanded, IShellTransitions shellTransitions,
- IStartingWindow startingWindow,
+ IStartingWindow startingWindow, IRecentTasks recentTasks,
ISmartspaceTransitionController smartSpaceTransitionController) {
unlinkToDeath();
mSystemUiProxy = proxy;
@@ -139,28 +166,36 @@ public class SystemUiProxy implements ISystemUiProxy,
mShellTransitions = shellTransitions;
mStartingWindow = startingWindow;
mSmartspaceTransitionController = smartSpaceTransitionController;
+ mRecentTasks = recentTasks;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
- if (mPendingPipAnimationListener != null && mPip != null) {
- setPinnedStackAnimationListener(mPendingPipAnimationListener);
- mPendingPipAnimationListener = null;
+ if (mPipAnimationListener != null && mPip != null) {
+ setPinnedStackAnimationListener(mPipAnimationListener);
}
- if (mPendingSplitScreenListener != null && mSplitScreen != null) {
- registerSplitScreenListener(mPendingSplitScreenListener);
- mPendingSplitScreenListener = null;
+ if (mSplitScreenListener != null && mSplitScreen != null) {
+ registerSplitScreenListener(mSplitScreenListener);
}
- if (mPendingStartingWindowListener != null && mStartingWindow != null) {
- setStartingWindowListener(mPendingStartingWindowListener);
- mPendingStartingWindowListener = null;
+ if (mStartingWindowListener != null && mStartingWindow != null) {
+ setStartingWindowListener(mStartingWindowListener);
}
- if (mPendingSmartspaceCallback != null && mSmartspaceTransitionController != null) {
- setSmartspaceCallback(mPendingSmartspaceCallback);
- mPendingSmartspaceCallback = null;
+ if (mSmartspaceCallback != null && mSmartspaceTransitionController != null) {
+ setSmartspaceCallback(mSmartspaceCallback);
+ }
+ for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
+ registerRemoteTransition(mRemoteTransitions.get(i));
+ }
+ if (mRecentTasksListener != null && mRecentTasks != null) {
+ registerRecentTasksListener(mRecentTasksListener);
+ }
+
+ if (mPendingSetNavButtonAlpha != null) {
+ mPendingSetNavButtonAlpha.run();
+ mPendingSetNavButtonAlpha = null;
}
}
public void clearProxy() {
- setProxy(null, null, null, null, null, null, null);
+ setProxy(null, null, null, null, null, null, null, null);
}
// TODO(141886704): Find a way to remove this
@@ -240,14 +275,18 @@ public class SystemUiProxy implements ISystemUiProxy,
boolean changed = Float.compare(alpha, mLastNavButtonAlpha) != 0
|| animate != mLastNavButtonAnimate
|| !mHasNavButtonAlphaBeenSet;
- if (mSystemUiProxy != null && changed) {
- mLastNavButtonAlpha = alpha;
- mLastNavButtonAnimate = animate;
- mHasNavButtonAlphaBeenSet = true;
- try {
- mSystemUiProxy.setNavBarButtonAlpha(alpha, animate);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setNavBarButtonAlpha", e);
+ if (changed) {
+ if (mSystemUiProxy == null) {
+ mPendingSetNavButtonAlpha = () -> setNavBarButtonAlpha(alpha, animate);
+ } else {
+ mLastNavButtonAlpha = alpha;
+ mLastNavButtonAnimate = animate;
+ mHasNavButtonAlphaBeenSet = true;
+ try {
+ mSystemUiProxy.setNavBarButtonAlpha(alpha, animate);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call setNavBarButtonAlpha", e);
+ }
}
}
}
@@ -346,7 +385,7 @@ public class SystemUiProxy implements ISystemUiProxy,
try {
mSystemUiProxy.setSplitScreenMinimized(minimized);
} catch (RemoteException e) {
- Log.w(TAG, "Failed call stopScreenPinning", e);
+ Log.w(TAG, "Failed call setSplitScreenMinimized", e);
}
}
}
@@ -387,6 +426,34 @@ public class SystemUiProxy implements ISystemUiProxy,
}
}
+ @Override
+ public void notifyTaskbarStatus(boolean visible, boolean stashed) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.notifyTaskbarStatus(visible, stashed);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call notifyTaskbarStatus with arg: " +
+ visible + ", " + stashed, e);
+ }
+ }
+ }
+
+ /**
+ * NOTE: If called to suspend, caller MUST call this method to also un-suspend
+ * @param suspend should be true to stop auto-hide, false to resume normal behavior
+ */
+ @Override
+ public void notifyTaskbarAutohideSuspend(boolean suspend) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.notifyTaskbarAutohideSuspend(suspend);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call notifyTaskbarAutohideSuspend with arg: " +
+ suspend, e);
+ }
+ }
+ }
+
@Override
public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
Insets visibleInsets, Task.TaskKey task) {
@@ -442,9 +509,8 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
}
- } else {
- mPendingPipAnimationListener = listener;
}
+ mPipAnimationListener = listener;
}
public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
@@ -482,9 +548,8 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call registerSplitScreenListener");
}
- } else {
- mPendingSplitScreenListener = listener;
}
+ mSplitScreenListener = listener;
}
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
@@ -495,68 +560,44 @@ public class SystemUiProxy implements ISystemUiProxy,
Log.w(TAG, "Failed call unregisterSplitScreenListener");
}
}
- mPendingSplitScreenListener = null;
- }
-
- public void setSideStageVisibility(boolean visible) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.setSideStageVisibility(visible);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setSideStageVisibility");
- }
- }
- }
-
- public void exitSplitScreen() {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.exitSplitScreen();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call exitSplitScreen");
- }
- }
- }
-
- public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.exitSplitScreenOnHide(exitSplitScreenOnHide);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call exitSplitScreen");
- }
- }
- }
-
- public void startTask(int taskId, int stage, int position, Bundle options) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.startTask(taskId, stage, position, options);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call startTask");
- }
- }
+ mSplitScreenListener = null;
}
/** Start multiple tasks in split-screen simultaneously. */
public void startTasks(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions,
- @SplitConfigurationOptions.StagePosition int sidePosition,
+ @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio,
RemoteTransitionCompat remoteTransition) {
if (mSystemUiProxy != null) {
try {
mSplitScreen.startTasks(mainTaskId, mainOptions, sideTaskId, sideOptions,
- sidePosition, remoteTransition.getTransition());
+ sidePosition, splitRatio, remoteTransition.getTransition());
} catch (RemoteException e) {
Log.w(TAG, "Failed call startTask");
}
}
}
- public void startShortcut(String packageName, String shortcutId, int stage, int position,
+ /**
+ * Start multiple tasks in split-screen simultaneously.
+ */
+ public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId,
+ Bundle sideOptions, @SplitConfigurationOptions.StagePosition int sidePosition,
+ float splitRatio, RemoteAnimationAdapter adapter) {
+ if (mSystemUiProxy != null) {
+ try {
+ mSplitScreen.startTasksWithLegacyTransition(mainTaskId, mainOptions, sideTaskId,
+ sideOptions, sidePosition, splitRatio, adapter);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call startTasksWithLegacyTransition");
+ }
+ }
+ }
+
+ public void startShortcut(String packageName, String shortcutId, int position,
Bundle options, UserHandle user) {
if (mSplitScreen != null) {
try {
- mSplitScreen.startShortcut(packageName, shortcutId, stage, position, options,
+ mSplitScreen.startShortcut(packageName, shortcutId, position, options,
user);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startShortcut");
@@ -564,11 +605,11 @@ public class SystemUiProxy implements ISystemUiProxy,
}
}
- public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
+ public void startIntent(PendingIntent intent, Intent fillInIntent, int position,
Bundle options) {
if (mSplitScreen != null) {
try {
- mSplitScreen.startIntent(intent, fillInIntent, stage, position, options);
+ mSplitScreen.startIntent(intent, fillInIntent, position, options);
} catch (RemoteException e) {
Log.w(TAG, "Failed call startIntent");
}
@@ -585,6 +626,25 @@ public class SystemUiProxy implements ISystemUiProxy,
}
}
+ /**
+ * Call this when going to recents so that shell can set-up and provide appropriate leashes
+ * for animation (eg. DividerBar).
+ *
+ * @param cancel true if recents starting is being cancelled.
+ * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
+ */
+ public RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
+ RemoteAnimationTarget[] apps) {
+ if (mSplitScreen != null) {
+ try {
+ return mSplitScreen.onGoingToRecentsLegacy(cancel, apps);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call onGoingToRecentsLegacy");
+ }
+ }
+ return null;
+ }
+
//
// One handed
//
@@ -622,6 +682,9 @@ public class SystemUiProxy implements ISystemUiProxy,
Log.w(TAG, "Failed call registerRemoteTransition");
}
}
+ if (!mRemoteTransitions.contains(remoteTransition)) {
+ mRemoteTransitions.add(remoteTransition);
+ }
}
public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
@@ -632,6 +695,7 @@ public class SystemUiProxy implements ISystemUiProxy,
Log.w(TAG, "Failed call registerRemoteTransition");
}
}
+ mRemoteTransitions.remove(remoteTransition);
}
//
@@ -648,12 +712,10 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
- } else {
- mPendingStartingWindowListener = listener;
}
+ mStartingWindowListener = listener;
}
-
//
// SmartSpace transitions
//
@@ -665,8 +727,45 @@ public class SystemUiProxy implements ISystemUiProxy,
} catch (RemoteException e) {
Log.w(TAG, "Failed call setStartingWindowListener", e);
}
- } else {
- mPendingSmartspaceCallback = callback;
}
+ mSmartspaceCallback = callback;
+ }
+
+ //
+ // Recents
+ //
+
+ public void registerRecentTasksListener(IRecentTasksListener listener) {
+ if (mRecentTasks != null) {
+ try {
+ mRecentTasks.registerRecentTasksListener(listener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call registerRecentTasksListener", e);
+ }
+ }
+ mRecentTasksListener = listener;
+ }
+
+ public void unregisterRecentTasksListener(IRecentTasksListener listener) {
+ if (mRecentTasks != null) {
+ try {
+ mRecentTasks.unregisterRecentTasksListener(listener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call unregisterRecentTasksListener");
+ }
+ }
+ mRecentTasksListener = null;
+ }
+
+ public ArrayList getRecentTasks(int numTasks, int userId) {
+ if (mRecentTasks != null) {
+ try {
+ return new ArrayList<>(Arrays.asList(mRecentTasks.getRecentTasks(numTasks,
+ RECENT_IGNORE_UNAVAILABLE, userId)));
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call getRecentTasks", e);
+ }
+ }
+ return new ArrayList<>();
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 67bd85fffe..82c7c08153 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -20,6 +20,7 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import android.app.ActivityManager;
import android.content.Context;
@@ -27,7 +28,9 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.SystemProperties;
import android.util.Log;
+import android.view.RemoteAnimationTarget;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.Utilities;
@@ -41,6 +44,9 @@ import com.android.systemui.shared.system.RemoteTransitionCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import java.util.Arrays;
+import java.util.HashMap;
+
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
public static final boolean ENABLE_SHELL_TRANSITIONS =
SystemProperties.getBoolean("persist.debug.shell_transit", false);
@@ -106,9 +112,17 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
// But force-finish it anyways
finishRunningRecentsAnimation(false /* toHome */);
+ if (mCallbacks != null) {
+ // If mCallbacks still != null, that means we are getting this startRecentsAnimation()
+ // before the previous one got onRecentsAnimationStart(). In that case, cleanup the
+ // previous animation so it doesn't mess up/listen to state changes in this animation.
+ cleanUpRecentsAnimation();
+ }
+
final BaseActivityInterface activityInterface = gestureState.getActivityInterface();
mLastGestureState = gestureState;
- mCallbacks = new RecentsAnimationCallbacks(activityInterface.allowMinimizeSplitScreen());
+ mCallbacks = new RecentsAnimationCallbacks(SystemUiProxy.INSTANCE.get(mCtx),
+ activityInterface.allowMinimizeSplitScreen());
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
@@ -126,7 +140,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap thumbnailDatas) {
cleanUpRecentsAnimation();
}
@@ -136,18 +150,29 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
}
@Override
- public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
+ RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
+ // Convert appTargets to type RemoteAnimationTarget for all apps except Home app
+ RemoteAnimationTarget[] nonHomeApps = Arrays.stream(appearedTaskTargets)
+ .filter(remoteAnimationTarget ->
+ remoteAnimationTarget.activityType != ACTIVITY_TYPE_HOME)
+ .map(RemoteAnimationTargetCompat::unwrap)
+ .toArray(RemoteAnimationTarget[]::new);
+
+ RemoteAnimationTarget[] nonAppTargets =
+ SystemUiProxy.INSTANCE.getNoCreate()
+ .onGoingToRecentsLegacy(false, nonHomeApps);
+
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode()
&& activityInterface.getCreatedActivity() != null) {
RecentsView recentsView =
activityInterface.getCreatedActivity().getOverviewPanel();
if (recentsView != null) {
- RemoteAnimationTargetCompat[] apps = new RemoteAnimationTargetCompat[1];
- apps[0] = appearedTaskTarget;
- recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, apps,
+ recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId,
+ appearedTaskTargets,
new RemoteAnimationTargetCompat[0] /* wallpaper */,
- new RemoteAnimationTargetCompat[0] /* nonApps */);
+ RemoteAnimationTargetCompat.wrap(nonAppTargets) /* nonApps */);
return;
}
}
@@ -169,7 +194,8 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
if (ENABLE_SHELL_TRANSITIONS) {
RemoteTransitionCompat transition = new RemoteTransitionCompat(mCallbacks,
- mController != null ? mController.getController() : null);
+ mController != null ? mController.getController() : null,
+ mCtx.getIApplicationThread());
Bundle options = ActivityOptionsCompat.makeRemoteTransition(transition)
.setTransientLaunch().toBundle();
mCtx.startActivity(intent, options);
@@ -194,6 +220,22 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
return mCallbacks;
}
+ public void endLiveTile() {
+ if (mLastGestureState == null) {
+ return;
+ }
+ BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode()
+ && activityInterface.getCreatedActivity() != null) {
+ RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel();
+ if (recentsView != null) {
+ recentsView.switchToScreenshot(null,
+ () -> recentsView.finishRecentsAnimation(true /* toRecents */,
+ false /* shouldPip */, null));
+ }
+ }
+ }
+
public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) {
mLiveTileCleanUpHandler = cleanUpHandler;
}
@@ -262,6 +304,11 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
mLastAppearedTaskTarget = null;
}
+ @Nullable
+ public RecentsAnimationCallbacks getCurrentCallbacks() {
+ return mCallbacks;
+ }
+
public void dump() {
// TODO
}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index e75d751582..276e1c2a6f 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -23,6 +23,7 @@ import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBN
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
import android.annotation.SuppressLint;
+import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Matrix;
@@ -51,8 +52,10 @@ import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskView;
+import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.util.ArrayList;
import java.util.List;
@@ -63,41 +66,45 @@ import java.util.List;
public class TaskOverlayFactory implements ResourceBasedOverride {
public static List getEnabledShortcuts(TaskView taskView,
- DeviceProfile deviceProfile) {
+ DeviceProfile deviceProfile, TaskIdAttributeContainer taskContainer) {
final ArrayList shortcuts = new ArrayList<>();
final BaseDraggingActivity activity = BaseActivity.fromContext(taskView.getContext());
+ boolean hasMultipleTasks = taskView.getTaskIds()[1] != -1;
for (TaskShortcutFactory menuOption : MENU_OPTIONS) {
- SystemShortcut shortcut = menuOption.getShortcut(activity, taskView);
- if (menuOption == TaskShortcutFactory.SPLIT_SCREEN &&
- FeatureFlags.ENABLE_SPLIT_SELECT.get()) {
- addSplitOptions(shortcuts, activity, taskView, deviceProfile);
+ if (hasMultipleTasks && !menuOption.showForSplitscreen()) {
continue;
}
- if (shortcut != null) {
+ SystemShortcut shortcut = menuOption.getShortcut(activity, taskContainer);
+ if (shortcut == null) {
+ continue;
+ }
+
+ if (menuOption == TaskShortcutFactory.SPLIT_SCREEN &&
+ FeatureFlags.ENABLE_SPLIT_SELECT.get()) {
+ addSplitOptions(shortcuts, activity, taskView, deviceProfile);
+ } else {
shortcuts.add(shortcut);
}
}
RecentsOrientedState orientedState = taskView.getRecentsView().getPagedViewOrientedState();
- boolean canLauncherRotate = orientedState.canRecentsActivityRotate();
+ boolean canLauncherRotate = orientedState.isRecentsActivityRotationAllowed();
boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0;
// Add overview actions to the menu when in in-place rotate landscape mode.
if (!canLauncherRotate && isInLandscape) {
// Add screenshot action to task menu.
SystemShortcut screenshotShortcut = TaskShortcutFactory.SCREENSHOT
- .getShortcut(activity, taskView);
+ .getShortcut(activity, taskContainer);
if (screenshotShortcut != null) {
- screenshotShortcut.setHasFinishRecentsInAction(true);
shortcuts.add(screenshotShortcut);
}
// Add modal action only if display orientation is the same as the device orientation.
if (orientedState.getDisplayRotation() == ROTATION_0) {
SystemShortcut modalShortcut = TaskShortcutFactory.MODAL
- .getShortcut(activity, taskView);
+ .getShortcut(activity, taskContainer);
if (modalShortcut != null) {
- modalShortcut.setHasFinishRecentsInAction(true);
shortcuts.add(modalShortcut);
}
}
@@ -106,10 +113,35 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
}
- public static void addSplitOptions(List outShortcuts,
+ /**
+ * Does NOT add split options in the following scenarios:
+ * * The taskView to add split options is already showing split screen tasks
+ * * There aren't at least 2 tasks in overview to show split options for
+ * * Device is in "Lock task mode"
+ * * The taskView to show split options for is the focused task AND we haven't started
+ * scrolling in overview (if we haven't scrolled, there's a split overview action button so
+ * we don't need this menu option)
+ */
+ private static void addSplitOptions(List outShortcuts,
BaseDraggingActivity activity, TaskView taskView, DeviceProfile deviceProfile) {
- PagedOrientationHandler orientationHandler =
- taskView.getRecentsView().getPagedOrientationHandler();
+ RecentsView recentsView = taskView.getRecentsView();
+ PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+ int[] taskViewTaskIds = taskView.getTaskIds();
+ boolean taskViewHasMultipleTasks = taskViewTaskIds[0] != -1 &&
+ taskViewTaskIds[1] != -1;
+ boolean notEnoughTasksToSplit = recentsView.getTaskViewCount() < 2;
+ boolean isFocusedTask = deviceProfile.overviewShowAsGrid && taskView.isFocusedTask();
+ boolean isTaskInExpectedScrollPosition =
+ recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
+ ActivityManager activityManager =
+ (ActivityManager) taskView.getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ boolean isLockTaskMode = activityManager.isInLockTaskMode();
+
+ if (taskViewHasMultipleTasks || notEnoughTasksToSplit || isLockTaskMode ||
+ (isFocusedTask && isTaskInExpectedScrollPosition)) {
+ return;
+ }
+
List positions =
orientationHandler.getSplitPositionOptions(deviceProfile);
for (SplitPositionOption option : positions) {
@@ -212,6 +244,11 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
}
}
+ private void enterSplitSelect() {
+ RecentsView overviewPanel = mThumbnailView.getTaskView().getRecentsView();
+ overviewPanel.initiateSplitSelect(mThumbnailView.getTaskView());
+ }
+
/**
* Called when the overlay is no longer used.
*/
@@ -305,18 +342,14 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
mTask = task;
}
- public void onShare() {
- if (mIsAllowedByPolicy) {
- endLiveTileMode(() -> mImageApi.startShareActivity(null));
- } else {
- showBlockedByPolicyMessage();
- }
- }
-
@SuppressLint("NewApi")
public void onScreenshot() {
endLiveTileMode(() -> saveScreenshot(mTask));
}
+
+ public void onSplit() {
+ endLiveTileMode(TaskOverlay.this::enterSplitSelect);
+ }
}
}
@@ -325,10 +358,10 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
* controller.
*/
public interface OverlayUICallbacks {
- /** User has indicated they want to share the current task. */
- void onShare();
-
/** User has indicated they want to screenshot the current task. */
void onScreenshot();
+
+ /** User wants to start split screen with current app. */
+ void onSplit();
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index a078bf331e..f507ea3dfc 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -35,7 +35,6 @@ import android.window.SplashScreen;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
@@ -45,6 +44,7 @@ import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskView;
+import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
@@ -61,9 +61,31 @@ import java.util.List;
* Represents a system shortcut that can be shown for a recent task.
*/
public interface TaskShortcutFactory {
- SystemShortcut getShortcut(BaseDraggingActivity activity, TaskView view);
+ SystemShortcut getShortcut(BaseDraggingActivity activity,
+ TaskIdAttributeContainer taskContainer);
- TaskShortcutFactory APP_INFO = (activity, view) -> new AppInfo(activity, view.getItemInfo());
+ default boolean showForSplitscreen() {
+ return false;
+ }
+
+ TaskShortcutFactory APP_INFO = new TaskShortcutFactory() {
+ @Override
+ public SystemShortcut getShortcut(BaseDraggingActivity activity,
+ TaskIdAttributeContainer taskContainer) {
+ TaskView taskView = taskContainer.getTaskView();
+ AppInfo.SplitAccessibilityInfo accessibilityInfo =
+ new AppInfo.SplitAccessibilityInfo(taskView.containsMultipleTasks(),
+ TaskUtils.getTitle(taskView.getContext(), taskContainer.getTask()),
+ taskContainer.getA11yNodeId()
+ );
+ return new AppInfo(activity, taskContainer.getItemInfo(), accessibilityInfo);
+ }
+
+ @Override
+ public boolean showForSplitscreen() {
+ return true;
+ }
+ };
abstract class MultiWindowFactory implements TaskShortcutFactory {
@@ -82,28 +104,28 @@ public interface TaskShortcutFactory {
protected abstract boolean onActivityStarted(BaseDraggingActivity activity);
@Override
- public SystemShortcut getShortcut(BaseDraggingActivity activity, TaskView taskView) {
- final Task task = taskView.getTask();
+ public SystemShortcut getShortcut(BaseDraggingActivity activity,
+ TaskIdAttributeContainer taskContainer) {
+ final Task task = taskContainer.getTask();
if (!task.isDockable) {
return null;
}
if (!isAvailable(activity, task.key.displayId)) {
return null;
}
- return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskView, this,
+ return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskContainer, this,
mLauncherEvent);
}
}
class SplitSelectSystemShortcut extends SystemShortcut {
private final TaskView mTaskView;
- private SplitPositionOption mSplitPositionOption;
+ private final SplitPositionOption mSplitPositionOption;
public SplitSelectSystemShortcut(BaseDraggingActivity target, TaskView taskView,
SplitPositionOption option) {
- super(option.mIconResId, option.mTextResId, target, taskView.getItemInfo());
+ super(option.iconResId, option.textResId, target, taskView.getItemInfo());
mTaskView = taskView;
mSplitPositionOption = option;
- setEnabled(taskView.getRecentsView().getTaskViewCount() > 1);
}
@Override
@@ -112,7 +134,7 @@ public interface TaskShortcutFactory {
}
}
- class MultiWindowSystemShortcut extends SystemShortcut {
+ class MultiWindowSystemShortcut extends SystemShortcut {
private Handler mHandler;
@@ -123,13 +145,14 @@ public interface TaskShortcutFactory {
private final LauncherEvent mLauncherEvent;
public MultiWindowSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity,
- TaskView taskView, MultiWindowFactory factory, LauncherEvent launcherEvent) {
- super(iconRes, textRes, activity, taskView.getItemInfo());
+ TaskIdAttributeContainer taskContainer, MultiWindowFactory factory,
+ LauncherEvent launcherEvent) {
+ super(iconRes, textRes, activity, taskContainer.getItemInfo());
mLauncherEvent = launcherEvent;
mHandler = new Handler(Looper.getMainLooper());
- mTaskView = taskView;
+ mTaskView = taskContainer.getTaskView();
mRecentsView = activity.getOverviewPanel();
- mThumbnailView = taskView.getThumbnail();
+ mThumbnailView = taskContainer.getThumbnailView();
mFactory = factory;
}
@@ -219,6 +242,7 @@ public interface TaskShortcutFactory {
}
}
+ /** @Deprecated */
TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory(R.drawable.ic_split_screen,
R.string.recent_task_option_split_screen, LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP) {
@@ -232,16 +256,6 @@ public interface TaskShortcutFactory {
&& (displayId == -1 || displayId == DEFAULT_DISPLAY);
}
- @Override
- public SystemShortcut getShortcut(BaseDraggingActivity activity, TaskView taskView) {
- SystemShortcut shortcut = super.getShortcut(activity, taskView);
- if (shortcut != null && FeatureFlags.ENABLE_SPLIT_SELECT.get()) {
- // Disable if there's only one recent app for split screen
- shortcut.setEnabled(taskView.getRecentsView().getTaskViewCount() > 1);
- }
- return shortcut;
- }
-
@Override
protected ActivityOptions makeLaunchOptions(Activity activity) {
final ActivityCompat act = new ActivityCompat(activity);
@@ -284,7 +298,7 @@ public interface TaskShortcutFactory {
}
};
- TaskShortcutFactory PIN = (activity, tv) -> {
+ TaskShortcutFactory PIN = (activity, taskContainer) -> {
if (!SystemUiProxy.INSTANCE.get(activity).isActive()) {
return null;
}
@@ -295,18 +309,20 @@ public interface TaskShortcutFactory {
// We shouldn't be able to pin while an app is locked.
return null;
}
- return new PinSystemShortcut(activity, tv);
+ return new PinSystemShortcut(activity, taskContainer);
};
- class PinSystemShortcut extends SystemShortcut {
+ class PinSystemShortcut extends SystemShortcut {
private static final String TAG = "PinSystemShortcut";
private final TaskView mTaskView;
- public PinSystemShortcut(BaseDraggingActivity target, TaskView tv) {
- super(R.drawable.ic_pin, R.string.recent_task_option_pin, target, tv.getItemInfo());
- mTaskView = tv;
+ public PinSystemShortcut(BaseDraggingActivity target,
+ TaskIdAttributeContainer taskContainer) {
+ super(R.drawable.ic_pin, R.string.recent_task_option_pin, target,
+ taskContainer.getItemInfo());
+ mTaskView = taskContainer.getTaskView();
}
@Override
@@ -320,20 +336,22 @@ public interface TaskShortcutFactory {
}
}
- TaskShortcutFactory INSTALL = (activity, view) ->
+ TaskShortcutFactory INSTALL = (activity, taskContainer) ->
InstantAppResolver.newInstance(activity).isInstantApp(activity,
- view.getTask().getTopComponent().getPackageName())
- ? new SystemShortcut.Install(activity, view.getItemInfo()) : null;
+ taskContainer.getTask().getTopComponent().getPackageName())
+ ? new SystemShortcut.Install(activity, taskContainer.getItemInfo()) : null;
- TaskShortcutFactory WELLBEING = (activity, view) ->
- WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, view.getItemInfo());
+ TaskShortcutFactory WELLBEING = (activity, taskContainer) ->
+ WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity, taskContainer.getItemInfo());
- TaskShortcutFactory SCREENSHOT = (activity, tv) -> tv.getThumbnail().getTaskOverlay()
- .getScreenshotShortcut(activity, tv.getItemInfo());
+ TaskShortcutFactory SCREENSHOT = (activity, taskContainer) ->
+ taskContainer.getThumbnailView().getTaskOverlay()
+ .getScreenshotShortcut(activity, taskContainer.getItemInfo());
- TaskShortcutFactory MODAL = (activity, tv) -> {
+ TaskShortcutFactory MODAL = (activity, taskContainer) -> {
if (ENABLE_OVERVIEW_SELECTIONS.get()) {
- return tv.getThumbnail().getTaskOverlay().getModalStateSystemShortcut(tv.getItemInfo());
+ return taskContainer.getThumbnailView()
+ .getTaskOverlay().getModalStateSystemShortcut(taskContainer.getItemInfo());
}
return null;
};
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index a8a0219594..3175ba8463 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -104,6 +104,9 @@ public class TaskThumbnailCache {
* Synchronously fetches the thumbnail for the given {@param task} and puts it in the cache.
*/
public void updateThumbnailInCache(Task task) {
+ if (task == null) {
+ return;
+ }
Preconditions.assertUIThread();
// Fetch the thumbnail for this task and put it in the cache
if (task.thumbnail == null) {
@@ -131,7 +134,8 @@ public class TaskThumbnailCache {
Preconditions.assertUIThread();
boolean lowResolution = !mHighResLoadingState.isEnabled();
- if (task.thumbnail != null && (!task.thumbnail.reducedResolution || lowResolution)) {
+ if (task.thumbnail != null && task.thumbnail.thumbnail != null
+ && (!task.thumbnail.reducedResolution || lowResolution)) {
// Nothing to load, the thumbnail is already high-resolution or matches what the
// request, so just callback
callback.accept(task.thumbnail);
@@ -149,7 +153,8 @@ public class TaskThumbnailCache {
Preconditions.assertUIThread();
ThumbnailData cachedThumbnail = mCache.getAndInvalidateIfModified(key);
- if (cachedThumbnail != null && (!cachedThumbnail.reducedResolution || lowResolution)) {
+ if (cachedThumbnail != null && cachedThumbnail.thumbnail != null
+ && (!cachedThumbnail.reducedResolution || lowResolution)) {
// Already cached, lets use that thumbnail
callback.accept(cachedThumbnail);
return null;
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 37fda73d44..5d9a537165 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -27,10 +28,11 @@ import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FAD
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_IN_INTERPOLATOR;
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.QuickstepTransitionManager.SPLIT_DIVIDER_ANIM_DURATION;
+import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
@@ -41,6 +43,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
@@ -62,15 +65,16 @@ import com.android.launcher3.anim.AnimationSuccessListener;
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;
import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskView;
@@ -79,6 +83,9 @@ import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
*/
@@ -139,39 +146,21 @@ public final class TaskViewUtils {
// 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;
}
return taskView;
}
- public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
- RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets,
- RemoteAnimationTargetCompat[] nonAppTargets, DepthController depthController,
+ public static void createRecentsWindowAnimator(
+ @NonNull TaskView v, boolean skipViewChanges,
+ @NonNull RemoteAnimationTargetCompat[] appTargets,
+ @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
+ @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
+ @Nullable DepthController depthController,
PendingAnimation out) {
- boolean isRunningTask = v.isRunningTask();
- TransformParams params = null;
- TaskViewSimulator tsv = null;
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask) {
- params = v.getRecentsView().getLiveTileParams();
- tsv = v.getRecentsView().getLiveTileTaskViewSimulator();
- }
- createRecentsWindowAnimator(v, skipViewChanges, appTargets, wallpaperTargets, nonAppTargets,
- depthController, out, params, tsv);
- }
-
- /**
- * Creates an animation that controls the window of the opening targets for the recents launch
- * animation.
- */
- public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
- RemoteAnimationTargetCompat[] appTargets,
- RemoteAnimationTargetCompat[] wallpaperTargets,
- RemoteAnimationTargetCompat[] nonAppTargets, DepthController depthController,
- PendingAnimation out, @Nullable TransformParams params,
- @Nullable TaskViewSimulator tsv) {
+ RecentsView recentsView = v.getRecentsView();
boolean isQuickSwitch = v.isEndQuickswitchCuj();
v.setEndQuickswitchCuj(false);
@@ -182,64 +171,77 @@ public final class TaskViewUtils {
inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
final RemoteAnimationTargetCompat navBarTarget = targets.getNavBarRemoteAnimationTarget();
- if (params == null) {
- SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
- targets.addReleaseCheck(applier);
+ SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
+ targets.addReleaseCheck(applier);
- params = new TransformParams()
- .setSyncTransactionApplier(applier)
- .setTargetSet(targets);
+ RemoteTargetHandle[] remoteTargetHandles;
+ RemoteTargetHandle[] recentsViewHandles = recentsView.getRemoteTargetHandles();
+ if (v.isRunningTask() && recentsViewHandles != null) {
+ // Re-use existing handles
+ remoteTargetHandles = recentsViewHandles;
+ } else {
+ RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
+ recentsView.getSizeStrategy(), targets);
+ if (v.containsMultipleTasks()) {
+ remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets, v.getTaskIds());
+ } else {
+ remoteTargetHandles = gluer.assignTargets(targets);
+ }
+ }
+ for (RemoteTargetHandle remoteTargetGluer : remoteTargetHandles) {
+ remoteTargetGluer.getTransformParams().setSyncTransactionApplier(applier);
}
- final RecentsView recentsView = v.getRecentsView();
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);
- int startScroll = recentsView.getScrollOffset(taskIndex);
+ int taskRectTranslationPrimary = recentsView.getScrollOffset(taskIndex);
+ int taskRectTranslationSecondary = showAsGrid ? (int) v.getGridTranslationY() : 0;
- TaskViewSimulator topMostSimulator = null;
+ RemoteTargetHandle[] topMostSimulators = null;
- if (tsv == null && targets.apps.length > 0) {
- tsv = new TaskViewSimulator(context, recentsView.getSizeStrategy());
- tsv.setDp(dp);
+ if (!v.isRunningTask()) {
+ // TVSs already initialized from the running task, no need to re-init
+ for (RemoteTargetHandle targetHandle : remoteTargetHandles) {
+ TaskViewSimulator tvsLocal = targetHandle.getTaskViewSimulator();
+ tvsLocal.setDp(dp);
- // RecentsView never updates the display rotation until swipe-up so the value may
- // be stale. Use the display value instead.
- int displayRotation = DisplayController.INSTANCE.get(context).getInfo().rotation;
- tsv.getOrientationState().update(displayRotation, displayRotation);
+ // RecentsView never updates the display rotation until swipe-up so the value may
+ // be stale. Use the display value instead.
+ int displayRotation = DisplayController.INSTANCE.get(context).getInfo().rotation;
+ tvsLocal.getOrientationState().update(displayRotation, displayRotation);
- tsv.setPreview(targets.apps[targets.apps.length - 1]);
- tsv.fullScreenProgress.value = 0;
- tsv.recentsViewScale.value = 1;
- if (showAsGrid) {
- tsv.taskSecondaryTranslation.value = gridTranslationSecondary;
+ tvsLocal.fullScreenProgress.value = 0;
+ tvsLocal.recentsViewScale.value = 1;
+ tvsLocal.setIsGridTask(v.isGridTask());
+ tvsLocal.getOrientationState().getOrientationHandler().set(tvsLocal,
+ TaskViewSimulator::setTaskRectTranslation, taskRectTranslationPrimary,
+ taskRectTranslationSecondary);
+
+ // Fade in the task during the initial 20% of the animation
+ out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0, 1,
+ clampToProgress(LINEAR, 0, 0.2f));
}
- tsv.setScroll(startScroll);
-
- // Fade in the task during the initial 20% of the animation
- out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1,
- clampToProgress(LINEAR, 0, 0.2f));
}
- if (tsv != null) {
- out.setFloat(tsv.fullScreenProgress,
+ for (RemoteTargetHandle targetHandle : remoteTargetHandles) {
+ TaskViewSimulator tvsLocal = targetHandle.getTaskViewSimulator();
+ out.setFloat(tvsLocal.fullScreenProgress,
AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
- out.setFloat(tsv.recentsViewScale,
- AnimatedFloat.VALUE, tsv.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
- if (showAsGrid) {
- out.setFloat(tsv.taskSecondaryTranslation, AnimatedFloat.VALUE, 0,
- TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL);
- }
- out.setFloat(tsv.recentsViewScroll, AnimatedFloat.VALUE, 0,
+ out.setFloat(tvsLocal.recentsViewScale,
+ AnimatedFloat.VALUE, tvsLocal.getFullScreenScale(),
+ TOUCH_RESPONSE_INTERPOLATOR);
+ out.setFloat(tvsLocal.recentsViewScroll, AnimatedFloat.VALUE, 0,
TOUCH_RESPONSE_INTERPOLATOR);
- TaskViewSimulator finalTsv = tsv;
- TransformParams finalParams = params;
- out.addOnFrameCallback(() -> finalTsv.apply(finalParams));
+ out.addOnFrameCallback(() -> {
+ for (RemoteTargetHandle handle : remoteTargetHandles) {
+ handle.getTaskViewSimulator().apply(handle.getTransformParams());
+ }
+ });
if (navBarTarget != null) {
final Rect cropRect = new Rect();
out.addOnFrameListener(new MultiValueUpdateListener() {
@@ -252,15 +254,20 @@ public final class TaskViewUtils {
public void onUpdate(float percent, boolean initOnly) {
final SurfaceParams.Builder navBuilder =
new SurfaceParams.Builder(navBarTarget.leash);
- if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
- finalTsv.getCurrentCropRect().round(cropRect);
- navBuilder.withMatrix(finalTsv.getCurrentMatrix())
- .withWindowCrop(cropRect)
- .withAlpha(mNavFadeIn.value);
- } else {
- navBuilder.withAlpha(mNavFadeOut.value);
+
+ // TODO Do we need to operate over multiple TVSs for the navbar leash?
+ for (RemoteTargetHandle handle : remoteTargetHandles) {
+ if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
+ TaskViewSimulator taskViewSimulator = handle.getTaskViewSimulator();
+ taskViewSimulator.getCurrentCropRect().round(cropRect);
+ navBuilder.withMatrix(taskViewSimulator.getCurrentMatrix())
+ .withWindowCrop(cropRect)
+ .withAlpha(mNavFadeIn.value);
+ } else {
+ navBuilder.withAlpha(mNavFadeOut.value);
+ }
+ handle.getTransformParams().applySurfaceParams(navBuilder.build());
}
- finalParams.applySurfaceParams(navBuilder.build());
}
});
} else if (inLiveTileMode) {
@@ -272,14 +279,16 @@ public final class TaskViewUtils {
controller.animateNavigationBarToApp(RECENTS_LAUNCH_DURATION);
}
}
- topMostSimulator = tsv;
+ topMostSimulators = remoteTargetHandles;
}
- if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulator != null) {
+ if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulators.length > 0) {
out.addFloat(v, VIEW_ALPHA, 1, 0, clampToProgress(LINEAR, 0.2f, 0.4f));
- TaskViewSimulator simulatorToCopy = topMostSimulator;
- simulatorToCopy.apply(params);
+ RemoteTargetHandle[] simulatorCopies = topMostSimulators;
+ for (RemoteTargetHandle handle : simulatorCopies) {
+ handle.getTaskViewSimulator().apply(handle.getTransformParams());
+ }
// Mt represents the overall transformation on the thumbnailView relative to the
// Launcher's rootView
@@ -293,36 +302,49 @@ public final class TaskViewUtils {
// During animation we apply transformation on the thumbnailView (and not the rootView)
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
// Mt K(0)` K(t) Mt`
- TaskThumbnailView ttv = v.getThumbnail();
- RectF tvBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
- float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()};
- getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
- RectF tvBoundsInRoot = new RectF(
- tvBoundsMapped[0], tvBoundsMapped[1],
- tvBoundsMapped[2], tvBoundsMapped[3]);
+ TaskThumbnailView[] thumbnails = v.getThumbnails();
+ Matrix[] mt = new Matrix[simulatorCopies.length];
+ Matrix[] mti = new Matrix[simulatorCopies.length];
+ for (int i = 0; i < thumbnails.length; i++) {
+ TaskThumbnailView ttv = thumbnails[i];
+ RectF localBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
+ float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()};
+ getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
+ RectF localBoundsInRoot = new RectF(
+ tvBoundsMapped[0], tvBoundsMapped[1],
+ tvBoundsMapped[2], tvBoundsMapped[3]);
+ Matrix localMt = new Matrix();
+ localMt.setRectToRect(localBounds, localBoundsInRoot, ScaleToFit.FILL);
+ mt[i] = localMt;
- Matrix mt = new Matrix();
- mt.setRectToRect(tvBounds, tvBoundsInRoot, ScaleToFit.FILL);
-
- Matrix mti = new Matrix();
- mt.invert(mti);
-
- Matrix k0i = new Matrix();
- simulatorToCopy.getCurrentMatrix().invert(k0i);
+ Matrix localMti = new Matrix();
+ localMt.invert(localMti);
+ mti[i] = localMti;
+ }
+ Matrix[] k0i = new Matrix[simulatorCopies.length];
+ for (int i = 0; i < simulatorCopies.length; i++) {
+ k0i[i] = new Matrix();
+ simulatorCopies[i].getTaskViewSimulator().getCurrentMatrix().invert(k0i[i]);
+ }
Matrix animationMatrix = new Matrix();
out.addOnFrameCallback(() -> {
- animationMatrix.set(mt);
- animationMatrix.postConcat(k0i);
- animationMatrix.postConcat(simulatorToCopy.getCurrentMatrix());
- animationMatrix.postConcat(mti);
- ttv.setAnimationMatrix(animationMatrix);
+ for (int i = 0; i < simulatorCopies.length; i++) {
+ animationMatrix.set(mt[i]);
+ animationMatrix.postConcat(k0i[i]);
+ animationMatrix.postConcat(simulatorCopies[i]
+ .getTaskViewSimulator().getCurrentMatrix());
+ animationMatrix.postConcat(mti[i]);
+ thumbnails[i].setAnimationMatrix(animationMatrix);
+ }
});
out.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- ttv.setAnimationMatrix(null);
+ for (TaskThumbnailView ttv : thumbnails) {
+ ttv.setAnimationMatrix(null);
+ }
}
});
}
@@ -365,8 +387,8 @@ public final class TaskViewUtils {
* device is considered in multiWindowMode and things like insets and stuff change
* and calculations have to be adjusted in the animations for that
*/
- public static void composeRecentsSplitLaunchAnimator(@NonNull TaskView initialView,
- @NonNull TaskView v, @NonNull TransitionInfo transitionInfo,
+ public static void composeRecentsSplitLaunchAnimator(@NonNull Task initalTask,
+ @NonNull Task secondTask, @NonNull TransitionInfo transitionInfo,
SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2];
@@ -376,7 +398,7 @@ public final class TaskViewUtils {
final int mode = change.getMode();
// Find the target tasks' root tasks since those are the split stages that need to
// be animated (the tasks themselves are children and thus inherit animation).
- if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
+ if (taskId == initalTask.key.id || taskId == secondTask.key.id) {
if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
throw new IllegalStateException(
"Expected task to be showing, but it is " + mode);
@@ -385,7 +407,7 @@ public final class TaskViewUtils {
throw new IllegalStateException("Initiating multi-split launch but the split"
+ "root of " + taskId + " is already visible or has broken hierarchy.");
}
- splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] =
+ splitRoots[taskId == initalTask.key.id ? 0 : 1] =
transitionInfo.getChange(change.getParent());
}
}
@@ -404,78 +426,102 @@ public final class TaskViewUtils {
finishCallback.run();
}
- /** Legacy version (until shell transitions are enabled) */
- public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull AnimatorSet anim,
- @NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
+ /**
+ * Legacy version (until shell transitions are enabled)
+ *
+ * If {@param launchingTaskView} is not null, then this will play the tasks launch animation
+ * from the position of the GroupedTaskView (when user taps on the TaskView to start it).
+ * Technically this case should be taken care of by
+ * {@link #composeRecentsSplitLaunchAnimatorLegacy()} below, but the way we launch tasks whether
+ * it's a single task or multiple tasks results in different entry-points.
+ *
+ * If it is null, then it will simply fade in the starting apps and fade out launcher (for the
+ * case where launcher handles animating starting split tasks from app icon) */
+ public static void composeRecentsSplitLaunchAnimatorLegacy(
+ @Nullable GroupedTaskView launchingTaskView,
+ @NonNull Task initialTask,
+ @NonNull Task secondTask, @NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
- @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
- @NonNull StateManager stateManager, @NonNull DepthController depthController,
- int targetStage) {
- PendingAnimation out = new PendingAnimation(RECENTS_LAUNCH_DURATION);
- boolean isRunningTask = v.isRunningTask();
- TransformParams params = null;
- TaskViewSimulator tvs = null;
- RecentsView recentsView = v.getRecentsView();
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask) {
- params = recentsView.getLiveTileParams();
- tvs = recentsView.getLiveTileTaskViewSimulator();
+ @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
+ @NonNull StateManager stateManager,
+ @Nullable DepthController depthController,
+ @NonNull Runnable finishCallback) {
+ if (launchingTaskView != null) {
+ AnimatorSet animatorSet = new AnimatorSet();
+ RecentsView recentsView = launchingTaskView.getRecentsView();
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ finishCallback.run();
+ }
+ });
+ composeRecentsLaunchAnimator(animatorSet, launchingTaskView,
+ appTargets, wallpaperTargets, nonAppTargets,
+ true, stateManager,
+ recentsView, depthController);
+ animatorSet.start();
+ return;
}
- boolean inLiveTileMode =
- ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1;
- final RemoteAnimationTargets targets =
- new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
- inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
+ final ArrayList openingTargets = new ArrayList<>();
+ final ArrayList closingTargets = new ArrayList<>();
+ for (RemoteAnimationTargetCompat appTarget : appTargets) {
+ final int taskId = appTarget.taskInfo != null ? appTarget.taskInfo.taskId : -1;
+ final int mode = appTarget.mode;
+ final SurfaceControl leash = appTarget.leash.getSurfaceControl();
+ if (leash == null) {
+ continue;
+ }
- if (params == null) {
- SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
- targets.addReleaseCheck(applier);
-
- params = new TransformParams()
- .setSyncTransactionApplier(applier)
- .setTargetSet(targets);
+ if (mode == MODE_OPENING) {
+ openingTargets.add(leash);
+ } else if (taskId == initialTask.key.id || taskId == secondTask.key.id) {
+ throw new IllegalStateException("Expected task to be opening, but it is " + mode);
+ } else if (mode == MODE_CLOSING) {
+ closingTargets.add(leash);
+ }
}
- Rect crop = new Rect();
- Context context = v.getContext();
- DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
- if (tvs == null && targets.apps.length > 0) {
- tvs = new TaskViewSimulator(recentsView.getContext(), recentsView.getSizeStrategy());
- tvs.setDp(dp);
-
- // RecentsView never updates the display rotation until swipe-up so the value may
- // be stale. Use the display value instead.
- int displayRotation = DisplayController.INSTANCE.get(recentsView.getContext())
- .getInfo().rotation;
- tvs.getOrientationState().update(displayRotation, displayRotation);
-
- tvs.setPreview(targets.apps[targets.apps.length - 1]);
- tvs.fullScreenProgress.value = 0;
- tvs.recentsViewScale.value = 1;
-// tvs.setScroll(startScroll);
-
- // Fade in the task during the initial 20% of the animation
- out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1,
- clampToProgress(LINEAR, 0, 0.2f));
+ for (int i = 0; i < nonAppTargets.length; ++i) {
+ final SurfaceControl leash = appTargets[i].leash.getSurfaceControl();
+ if (nonAppTargets[i].windowType == TYPE_DOCK_DIVIDER && leash != null) {
+ openingTargets.add(leash);
+ }
}
- TaskViewSimulator topMostSimulator = null;
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.setDuration(SPLIT_LAUNCH_DURATION);
+ animator.addUpdateListener(valueAnimator -> {
+ float progress = valueAnimator.getAnimatedFraction();
+ for (SurfaceControl leash: openingTargets) {
+ t.setAlpha(leash, progress);
+ }
+ for (SurfaceControl leash: closingTargets) {
+ t.setAlpha(leash, 1 - progress);
+ }
+ t.apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ for (SurfaceControl leash: openingTargets) {
+ t.show(leash).setAlpha(leash, 0.0f);
+ }
+ t.apply();
+ }
- if (tvs != null) {
- out.setFloat(tvs.fullScreenProgress,
- AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
- out.setFloat(tvs.recentsViewScale,
- AnimatedFloat.VALUE, tvs.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
- out.setFloat(tvs.recentsViewScroll,
- AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
-
- TaskViewSimulator finalTsv = tvs;
- TransformParams finalParams = params;
- out.addOnFrameCallback(() -> finalTsv.apply(finalParams));
- topMostSimulator = tvs;
- }
-
- anim.play(out.buildAnim());
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ for (SurfaceControl leash: closingTargets) {
+ t.hide(leash);
+ }
+ super.onAnimationEnd(animation);
+ finishCallback.run();
+ }
+ });
+ animator.start();
}
public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
@@ -483,13 +529,18 @@ public final class TaskViewUtils {
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
@NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
@NonNull StateManager stateManager, @NonNull RecentsView recentsView,
- @NonNull DepthController depthController) {
+ @Nullable DepthController depthController) {
boolean skipLauncherChanges = !launcherClosing;
TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
nonAppTargets, depthController, pa);
+ if (launcherClosing) {
+ // TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets,
+ true /*shown*/, true /*animate*/, pa);
+ }
Animator childStateAnimation = null;
// Found a visible recents task that matches the opening app, lets launch the app from there
@@ -498,7 +549,7 @@ public final class TaskViewUtils {
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);
@@ -542,4 +593,90 @@ public final class TaskViewUtils {
stateManager.setCurrentAnimation(anim, childStateAnimation);
anim.addListener(windowAnimEndListener);
}
+
+ public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
+ boolean shown, boolean animate) {
+ setSplitAuxiliarySurfacesShown(nonApps, shown, animate,null);
+ }
+
+ private static void setSplitAuxiliarySurfacesShown(
+ @NonNull RemoteAnimationTargetCompat[] nonApps, boolean shown, boolean animate,
+ @Nullable PendingAnimation splitLaunchAnimation) {
+ if (nonApps == null || nonApps.length == 0) {
+ return;
+ }
+
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ List auxiliarySurfaces = new ArrayList<>(nonApps.length);
+ boolean hasSurfaceToAnimate = false;
+ for (int i = 0; i < nonApps.length; ++i) {
+ final RemoteAnimationTargetCompat targ = nonApps[i];
+ final SurfaceControl leash = targ.leash.getSurfaceControl();
+ if (targ.windowType == TYPE_DOCK_DIVIDER && leash != null) {
+ auxiliarySurfaces.add(leash);
+ hasSurfaceToAnimate = true;
+ }
+ }
+ if (!hasSurfaceToAnimate) {
+ return;
+ }
+
+ if (!animate) {
+ for (SurfaceControl leash : auxiliarySurfaces) {
+ t.setAlpha(leash, shown ? 1 : 0);
+ if (shown) {
+ t.show(leash);
+ } else {
+ t.hide(leash);
+ }
+ }
+ t.apply();
+ return;
+ }
+
+ ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
+ dockFadeAnimator.addUpdateListener(valueAnimator -> {
+ float progress = valueAnimator.getAnimatedFraction();
+ for (SurfaceControl leash : auxiliarySurfaces) {
+ t.setAlpha(leash, shown ? progress : 1 - progress);
+ }
+ t.apply();
+ });
+ dockFadeAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ if (shown) {
+ for (SurfaceControl leash : auxiliarySurfaces) {
+ t.setAlpha(leash, 0);
+ t.show(leash);
+ }
+ t.apply();
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (!shown) {
+ for (SurfaceControl leash : auxiliarySurfaces) {
+ t.hide(leash);
+ }
+ t.apply();
+ }
+ t.close();
+ }
+ });
+ dockFadeAnimator.setDuration(SPLIT_DIVIDER_ANIM_DURATION);
+ if (splitLaunchAnimation != null) {
+ // If split apps are launching, we want to delay showing the divider bar until the very
+ // end once the apps are mostly in place. This is because we aren't moving the divider
+ // leash in the relative position with the launching apps.
+ dockFadeAnimator.setStartDelay(
+ splitLaunchAnimation.getDuration() - SPLIT_DIVIDER_ANIM_DURATION);
+ splitLaunchAnimation.add(dockFadeAnimator);
+ } else {
+ dockFadeAnimator.start();
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 0f5671c543..539239d36a 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -25,6 +25,7 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TI
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
@@ -32,6 +33,7 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHE
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
import android.annotation.TargetApi;
@@ -40,7 +42,6 @@ import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.Service;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
@@ -67,7 +68,6 @@ import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
@@ -90,18 +90,19 @@ import com.android.quickstep.inputconsumers.AssistantInputConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
-import com.android.quickstep.inputconsumers.OverscrollInputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.inputconsumers.OverviewWithoutFocusInputConsumer;
+import com.android.quickstep.inputconsumers.ProgressDelegateInputConsumer;
import com.android.quickstep.inputconsumers.ResetGestureInputConsumer;
import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
import com.android.quickstep.inputconsumers.SysUiOverlayInputConsumer;
+import com.android.quickstep.inputconsumers.TaskbarStashInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AssistantUtilities;
+import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.ProtoTracer;
+import com.android.quickstep.util.ProxyScreenStatusProvider;
import com.android.quickstep.util.SplitScreenBounds;
-import com.android.systemui.plugins.OverscrollPlugin;
-import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -113,6 +114,7 @@ import com.android.systemui.shared.system.smartspace.ISmartspaceTransitionContro
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.pip.IPip;
+import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.transition.IShellTransitions;
@@ -121,13 +123,14 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.LinkedList;
+import java.util.function.Function;
/**
* Service connected by system-UI for handling touch interaction.
*/
@TargetApi(Build.VERSION_CODES.R)
-public class TouchInteractionService extends Service implements PluginListener,
- ProtoTraceable {
+public class TouchInteractionService extends Service
+ implements ProtoTraceable {
private static final String TAG = "TouchInteractionService";
@@ -146,8 +149,8 @@ public class TouchInteractionService extends Service implements PluginListener {
SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
- splitscreen, onehanded, shellTransitions, startingWindow,
+ splitscreen, onehanded, shellTransitions, startingWindow, recentTasks,
smartspaceTransitionController);
TouchInteractionService.this.initInputMonitor();
preloadOverview(true /* fromInit */);
- mDeviceState.runOnUserUnlocked(() -> {
- final BaseActivityInterface ai =
- mOverviewComponentObserver.getActivityInterface();
- if (ai == null) return;
- ai.onOverviewServiceBound();
- });
});
sIsInitialized = true;
}
@@ -262,16 +261,47 @@ public class TouchInteractionService extends Service implements PluginListener SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb));
}
+ @BinderThread
@Override
- public void onImeWindowStatusChanged(int displayId, IBinder token, int vis,
- int backDisposition, boolean showImeSwitcher) {
- MAIN_EXECUTOR.execute(() -> mTaskbarManager.updateImeStatus(
- displayId, vis, backDisposition, showImeSwitcher));
+ public void onScreenTurnedOn() {
+ MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurnedOn);
+ }
+
+ @Override
+ public void onRotationProposal(int rotation, boolean isValid) {
+ executeForTaskbarManager(() -> mTaskbarManager.onRotationProposal(rotation, isValid));
+ }
+
+ @Override
+ public void disable(int displayId, int state1, int state2, boolean animate) {
+ executeForTaskbarManager(() -> mTaskbarManager
+ .disableNavBarElements(displayId, state1, state2, animate));
+ }
+
+ @Override
+ public void onSystemBarAttributesChanged(int displayId, int behavior) {
+ executeForTaskbarManager(() -> mTaskbarManager
+ .onSystemBarAttributesChanged(displayId, behavior));
+ }
+
+ @Override
+ public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+ executeForTaskbarManager(() -> mTaskbarManager
+ .onNavButtonsDarkIntensityChanged(darkIntensity));
+ }
+
+ private void executeForTaskbarManager(final Runnable r) {
+ MAIN_EXECUTOR.execute(() -> {
+ if (mTaskbarManager == null) {
+ return;
+ }
+ r.run();
+ });
}
public TaskbarManager getTaskbarManager() {
@@ -281,6 +311,13 @@ public class TouchInteractionService extends Service implements PluginListener proxy) {
+ mSwipeUpProxyProvider = proxy != null ? proxy : (i -> null);
+ }
}
private static boolean sConnected = false;
@@ -291,7 +328,6 @@ public class TouchInteractionService extends Service implements PluginListener mSwipeUpProxyProvider = i -> null;
@Override
public void onCreate() {
@@ -340,6 +377,7 @@ public class TouchInteractionService extends Service implements PluginListener mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
+ gestureState.updateRunningTasks(TraceHelper.allowIpcs("getRunningTask.0",
+ () -> mAM.getRunningTasks(false /* filterOnlyVisibleRecents */)));
}
return gestureState;
}
private InputConsumer newConsumer(GestureState previousGestureState,
GestureState newGestureState, MotionEvent event) {
+ AnimatedFloat progressProxy = mSwipeUpProxyProvider.apply(mGestureState);
+ if (progressProxy != null) {
+ return new ProgressDelegateInputConsumer(this, mTaskAnimationManager,
+ mGestureState, mInputMonitorCompat, progressProxy);
+ }
+
boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
if (!mDeviceState.isUserUnlocked()) {
@@ -660,24 +716,12 @@ public class TouchInteractionService extends Service implements PluginListener newList = new ArrayList<>(tasks.size() + 1);
- newList.addAll(tasks);
- newList.add(Task.from(new TaskKey(mHomeTaskInfo), mHomeTaskInfo, false));
- tasks = newList;
+ ArrayList newList = new ArrayList<>(taskGroups.size() + 1);
+ newList.addAll(taskGroups);
+ newList.add(new GroupTask(
+ Task.from(new TaskKey(mHomeTaskInfo), mHomeTaskInfo, false),
+ null, null));
+ taskGroups = newList;
}
}
- super.applyLoadPlan(tasks);
+ super.applyLoadPlan(taskGroups);
}
@Override
@@ -175,10 +202,18 @@ public class FallbackRecentsView extends RecentsView
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
+ }
}
@Override
@@ -205,4 +246,11 @@ public class FallbackRecentsView extends RecentsView {
private static final int FLAG_SHOW_AS_GRID = BaseState.getFlag(4);
private static final int FLAG_SCRIM = BaseState.getFlag(5);
private static final int FLAG_LIVE_TILE = BaseState.getFlag(6);
+ 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_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_SHOW_AS_GRID | FLAG_SCRIM | FLAG_LIVE_TILE | FLAG_OVERVIEW_UI);
public static final RecentsState BACKGROUND_APP = new BackgroundAppState(2,
- FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN);
+ FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN | FLAG_OVERVIEW_UI);
public static final RecentsState HOME = new RecentsState(3, 0);
public static final RecentsState BG_LAUNCHER = new LauncherState(4, 0);
+ public static final RecentsState OVERVIEW_SPLIT_SELECT = new RecentsState(5,
+ FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_OVERVIEW_UI);
public final int ordinal;
private final int mFlags;
@@ -133,11 +135,14 @@ public class RecentsState implements BaseState {
* 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);
+ return hasFlag(FLAG_SHOW_AS_GRID) && deviceProfile.overviewShowAsGrid;
}
- private boolean showAsGrid(DeviceProfile deviceProfile) {
- return deviceProfile.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get();
+ /**
+ * True if the state has overview panel visible.
+ */
+ public boolean overviewUi() {
+ return hasFlag(FLAG_OVERVIEW_UI);
}
private static class ModalState extends RecentsState {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
index 510820a1e5..162ace4965 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
@@ -24,6 +24,8 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
+import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_GESTURE;
+import static com.android.internal.app.AssistUtils.INVOCATION_TYPE_KEY;
import static com.android.launcher3.Utilities.squaredHypot;
import android.animation.Animator;
@@ -64,8 +66,6 @@ public class AssistantInputConsumer extends DelegateInputConsumer {
private static final String OPA_BUNDLE_TRIGGER = "triggered_by";
// From //java/com/google/android/apps/gsa/assistant/shared/proto/opa_trigger.proto.
private static final int OPA_BUNDLE_TRIGGER_DIAG_SWIPE_GESTURE = 83;
- private static final String INVOCATION_TYPE_KEY = "invocation_type";
- private static final int INVOCATION_TYPE_GESTURE = 1;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index fcc0217499..3d737ca0e4 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -60,6 +60,8 @@ import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
+import java.util.HashMap;
+
/**
* A placeholder input consumer used when the device is still locked, e.g. from secure camera.
*/
@@ -239,7 +241,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap thumbnailDatas) {
mRecentsAnimationController = null;
mTransformParams.setTargetSet(null);
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 725c7c45a5..0bd8832fa2 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -29,7 +29,6 @@ import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS;
import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
-import static com.android.quickstep.GestureState.STATE_OVERSCROLL_WINDOW_CREATED;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
import android.annotation.TargetApi;
@@ -490,7 +489,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
@Override
public boolean allowInterceptByParent() {
- return !mPassedPilferInputSlop || mGestureState.hasState(STATE_OVERSCROLL_WINDOW_CREATED);
+ return !mPassedPilferInputSlop;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
deleted file mode 100644
index fb420a272a..0000000000
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.inputconsumers;
-
-import static android.view.MotionEvent.ACTION_CANCEL;
-import static android.view.MotionEvent.ACTION_DOWN;
-import static android.view.MotionEvent.ACTION_MOVE;
-import static android.view.MotionEvent.ACTION_POINTER_DOWN;
-import static android.view.MotionEvent.ACTION_POINTER_UP;
-import static android.view.MotionEvent.ACTION_UP;
-
-import static com.android.launcher3.Utilities.squaredHypot;
-
-import static java.lang.Math.abs;
-
-import android.content.Context;
-import android.graphics.PointF;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.R;
-import com.android.quickstep.GestureState;
-import com.android.quickstep.InputConsumer;
-import com.android.quickstep.views.RecentsView;
-import com.android.systemui.plugins.OverscrollPlugin;
-import com.android.systemui.shared.system.InputMonitorCompat;
-
-/**
- * Input consumer for handling events to pass to an {@code OverscrollPlugin}.
- */
-public class OverscrollInputConsumer extends DelegateInputConsumer {
- private static final String TAG = "OverscrollInputConsumer";
- private static final boolean DEBUG_LOGS_ENABLED = false;
- private static void debugPrint(String log) {
- if (DEBUG_LOGS_ENABLED) {
- Log.v(TAG, log);
- }
- }
-
- private final PointF mDownPos = new PointF();
- private final PointF mLastPos = new PointF();
- private final PointF mStartDragPos = new PointF();
- private final int mAngleThreshold;
-
- private final int mFlingDistanceThresholdPx;
- private final int mFlingVelocityThresholdPx;
- private int mActivePointerId = -1;
- private boolean mPassedSlop = false;
- // True if we set ourselves as active, meaning we no longer pass events to the delegate.
- private boolean mPassedActiveThreshold = false;
- // When a gesture crosses this length, this recognizer will attempt to interpret touch events.
- private final float mSquaredSlop;
- // When a gesture crosses this length, this recognizer will become the sole active recognizer.
- private final float mSquaredActiveThreshold;
- // When a gesture crosses this length, the overscroll view should be shown.
- private final float mSquaredFinishThreshold;
- private boolean mThisDownIsIgnored = false;
-
- private final GestureState mGestureState;
- @Nullable
- private final OverscrollPlugin mPlugin;
-
- @Nullable
- private RecentsView mRecentsView;
-
- public OverscrollInputConsumer(Context context, GestureState gestureState,
- InputConsumer delegate, InputMonitorCompat inputMonitor, OverscrollPlugin plugin) {
- super(delegate, inputMonitor);
-
- mAngleThreshold = context.getResources()
- .getInteger(R.integer.assistant_gesture_corner_deg_threshold);
- mFlingDistanceThresholdPx = (int) context.getResources()
- .getDimension(R.dimen.gestures_overscroll_fling_threshold);
- mFlingVelocityThresholdPx = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
- mGestureState = gestureState;
- mPlugin = plugin;
-
- float slop = ViewConfiguration.get(context).getScaledTouchSlop();
-
- mSquaredSlop = slop * slop;
-
-
- float finishGestureThreshold = (int) context.getResources()
- .getDimension(R.dimen.gestures_overscroll_finish_threshold);
- mSquaredFinishThreshold = finishGestureThreshold * finishGestureThreshold;
-
- float activeThreshold = (int) context.getResources()
- .getDimension(R.dimen.gestures_overscroll_active_threshold);
- mSquaredActiveThreshold = activeThreshold * activeThreshold;
- }
-
- @Override
- public int getType() {
- return TYPE_OVERSCROLL | mDelegate.getType();
- }
-
- @Override
- public void onMotionEvent(MotionEvent ev) {
- if (mPlugin == null) {
- return;
- }
-
- debugPrint("got event, underlying activity is " + getUnderlyingActivity());
- switch (ev.getActionMasked()) {
- case ACTION_DOWN: {
- debugPrint("ACTION_DOWN");
- mActivePointerId = ev.getPointerId(0);
- mDownPos.set(ev.getX(), ev.getY());
- mLastPos.set(mDownPos);
- if (mPlugin.blockOtherGestures()) {
- debugPrint("mPlugin.blockOtherGestures(), becoming active on ACTION_DOWN");
- // Otherwise, if an appear gesture is performed when the Activity is visible,
- // the Activity will dismiss its keyboard.
- mPassedActiveThreshold = true;
- mPassedSlop = true;
- mStartDragPos.set(mLastPos.x, mLastPos.y);
- setActive(ev);
- }
- break;
- }
- case ACTION_POINTER_DOWN: {
- if (mState != STATE_ACTIVE) {
- mState = STATE_DELEGATE_ACTIVE;
- }
- break;
- }
- case ACTION_POINTER_UP: {
- int ptrIdx = ev.getActionIndex();
- int ptrId = ev.getPointerId(ptrIdx);
- if (ptrId == mActivePointerId) {
- final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
- mDownPos.set(
- ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
- ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
- mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
- mActivePointerId = ev.getPointerId(newPointerIdx);
- }
- break;
- }
- case ACTION_MOVE: {
- if (mState == STATE_DELEGATE_ACTIVE) {
- break;
- }
-
- if (!mDelegate.allowInterceptByParent()) {
- mState = STATE_DELEGATE_ACTIVE;
- break;
- }
-
- // Update last touch position.
- int pointerIndex = ev.findPointerIndex(mActivePointerId);
- if (pointerIndex == -1) {
- break;
- }
- mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
-
- float squaredDist = squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y);
- if ((!mPassedSlop) && (squaredDist > mSquaredSlop)) {
- mPassedSlop = true;
- mStartDragPos.set(mLastPos.x, mLastPos.y);
- mGestureState.setState(GestureState.STATE_OVERSCROLL_WINDOW_CREATED);
- }
-
- boolean becomeActive = mPassedSlop && !mPassedActiveThreshold && isOverscrolled()
- && (squaredDist > mSquaredActiveThreshold);
- if (becomeActive) {
- debugPrint("Past slop and past threshold, set active");
- mPassedActiveThreshold = true;
- setActive(ev);
- }
-
- if (mPassedActiveThreshold) {
- debugPrint("ACTION_MOVE Relaying touch event");
- mPlugin.onTouchEvent(ev, getHorizontalDistancePx(), getVerticalDistancePx(),
- (int) Math.sqrt(mSquaredFinishThreshold), mFlingDistanceThresholdPx,
- mFlingVelocityThresholdPx, getDeviceState(), getUnderlyingActivity());
- }
-
- break;
- }
- case ACTION_CANCEL:
- case ACTION_UP:
- debugPrint("ACTION_UP");
- if (mPassedActiveThreshold) {
- debugPrint("ACTION_UP Relaying touch event");
-
- mPlugin.onTouchEvent(ev, getHorizontalDistancePx(), getVerticalDistancePx(),
- (int) Math.sqrt(mSquaredFinishThreshold), mFlingDistanceThresholdPx,
- mFlingVelocityThresholdPx, getDeviceState(), getUnderlyingActivity());
- }
-
-
- mPassedSlop = false;
- mPassedActiveThreshold = false;
- mState = STATE_INACTIVE;
- break;
- }
-
- if (mState != STATE_ACTIVE) {
- mDelegate.onMotionEvent(ev);
- }
- }
-
- private boolean isOverscrolled() {
- if (mRecentsView == null) {
- BaseDraggingActivity activity = mGestureState.getActivityInterface()
- .getCreatedActivity();
- if (activity != null) {
- mRecentsView = activity.getOverviewPanel();
- }
- }
-
- // Make sure there isn't an app to quick switch to on our right
- int maxIndex = 0;
- if (mRecentsView != null && mRecentsView.hasRecentsExtraCard()) {
- maxIndex = 1;
- }
-
- boolean atRightMostApp = mRecentsView == null
- || (mRecentsView.getRunningTaskIndex() <= maxIndex);
-
- // Check if the gesture is within our angle threshold of horizontal
- float deltaY = abs(mLastPos.y - mDownPos.y);
- float deltaX = mLastPos.x - mDownPos.x;
-
- boolean angleInBounds = (Math.toDegrees(Math.atan2(deltaY, abs(deltaX))) < mAngleThreshold);
-
- boolean overscrollVisible = mPlugin.blockOtherGestures();
- boolean overscrollInvisibleAndLeftSwipe = !overscrollVisible && deltaX < 0;
- boolean gestureDirectionMatchesVisibility = overscrollVisible
- || overscrollInvisibleAndLeftSwipe;
- return atRightMostApp && angleInBounds && gestureDirectionMatchesVisibility;
- }
-
- private String getDeviceState() {
- String deviceState = OverscrollPlugin.DEVICE_STATE_UNKNOWN;
- int consumerType = mDelegate.getType();
- if (((consumerType & InputConsumer.TYPE_OVERVIEW) > 0)
- || ((consumerType & InputConsumer.TYPE_OVERVIEW_WITHOUT_FOCUS)) > 0) {
- deviceState = OverscrollPlugin.DEVICE_STATE_LAUNCHER;
- } else if ((consumerType & InputConsumer.TYPE_OTHER_ACTIVITY) > 0) {
- deviceState = OverscrollPlugin.DEVICE_STATE_APP;
- } else if (((consumerType & InputConsumer.TYPE_RESET_GESTURE) > 0)
- || ((consumerType & InputConsumer.TYPE_DEVICE_LOCKED) > 0)) {
- deviceState = OverscrollPlugin.DEVICE_STATE_LOCKED;
- }
-
- return deviceState;
- }
-
- private int getHorizontalDistancePx() {
- return (int) (mLastPos.x - mDownPos.x);
- }
-
- private int getVerticalDistancePx() {
- return (int) (mLastPos.y - mDownPos.y);
- }
-
- private @NonNull String getUnderlyingActivity() {
- // Overly defensive, got guidance on code review that something in the chain of
- // `mGestureState.getRunningTask().topActivity` can be null and thus cause a null pointer
- // exception to be thrown, but we aren't sure which part can be null.
- if ((mGestureState == null) || (mGestureState.getRunningTask() == null)
- || (mGestureState.getRunningTask().topActivity == null)) {
- return "";
- }
- return mGestureState.getRunningTask().topActivity.flattenToString();
- }
-}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
new file mode 100644
index 0000000000..71dca663f0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.inputconsumers;
+
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+import static com.android.launcher3.touch.BaseSwipeDetector.calculateDuration;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_POSITIVE;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
+import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
+import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Point;
+import android.view.MotionEvent;
+
+import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.MultiStateCallback;
+import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.RecentsAnimationController;
+import com.android.quickstep.RecentsAnimationTargets;
+import com.android.quickstep.TaskAnimationManager;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+import java.util.HashMap;
+
+/**
+ * Input consumer which delegates the swipe-progress handling
+ */
+public class ProgressDelegateInputConsumer implements InputConsumer,
+ RecentsAnimationCallbacks.RecentsAnimationListener,
+ SingleAxisSwipeDetector.Listener {
+
+ private static final float SWIPE_DISTANCE_THRESHOLD = 0.2f;
+
+ private static final String[] STATE_NAMES = DEBUG_STATES ? new String[3] : null;
+ private static int getFlagForIndex(int index, String name) {
+ if (DEBUG_STATES) {
+ STATE_NAMES[index] = name;
+ }
+ return 1 << index;
+ }
+
+ private static final int STATE_TARGET_RECEIVED =
+ getFlagForIndex(0, "STATE_TARGET_RECEIVED");
+ private static final int STATE_HANDLER_INVALIDATED =
+ getFlagForIndex(1, "STATE_HANDLER_INVALIDATED");
+ private static final int STATE_FLING_FINISHED =
+ getFlagForIndex(2, "STATE_FLING_FINISHED");
+
+ private final Context mContext;
+ private final TaskAnimationManager mTaskAnimationManager;
+ private final GestureState mGestureState;
+ private final InputMonitorCompat mInputMonitorCompat;
+ private final MultiStateCallback mStateCallback;
+
+ private final Point mDisplaySize;
+ private final SingleAxisSwipeDetector mSwipeDetector;
+
+ private final AnimatedFloat mProgress;
+
+ private boolean mDragStarted = false;
+
+ private RecentsAnimationController mRecentsAnimationController;
+ private Boolean mFlingEndsOnHome;
+
+ public ProgressDelegateInputConsumer(Context context,
+ TaskAnimationManager taskAnimationManager, GestureState gestureState,
+ InputMonitorCompat inputMonitorCompat, AnimatedFloat progress) {
+ mContext = context;
+ mTaskAnimationManager = taskAnimationManager;
+ mGestureState = gestureState;
+ mInputMonitorCompat = inputMonitorCompat;
+ mProgress = progress;
+
+ // Do not use DeviceProfile as the user data might be locked
+ mDisplaySize = DisplayController.INSTANCE.get(context).getInfo().currentSize;
+
+ // Init states
+ mStateCallback = new MultiStateCallback(STATE_NAMES);
+ mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
+ this::endRemoteAnimation);
+ mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_FLING_FINISHED,
+ this::onFlingFinished);
+
+ mSwipeDetector = new SingleAxisSwipeDetector(mContext, this, VERTICAL);
+ mSwipeDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_PROGRESS_DELEGATE;
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ if (mFlingEndsOnHome == null) {
+ mSwipeDetector.onTouchEvent(ev);
+ }
+ }
+
+ @Override
+ public void onDragStart(boolean start, float startDisplacement) {
+ mDragStarted = true;
+ TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
+ mInputMonitorCompat.pilferPointers();
+ Intent intent = mGestureState.getHomeIntent()
+ .putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
+ mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, this);
+ }
+
+ @Override
+ public boolean onDrag(float displacement) {
+ if (mDisplaySize.y > 0) {
+ mProgress.updateValue(displacement / -mDisplaySize.y);
+ }
+ return true;
+ }
+
+ @Override
+ public void onDragEnd(float velocity) {
+ final boolean willExit;
+ if (mSwipeDetector.isFling(velocity)) {
+ willExit = velocity < 0;
+ } else {
+ willExit = mProgress.value > SWIPE_DISTANCE_THRESHOLD;
+ }
+ float endValue = willExit ? 1 : 0;
+ long duration = calculateDuration(velocity, endValue - mProgress.value);
+ mFlingEndsOnHome = willExit;
+
+ ObjectAnimator anim = mProgress.animateToValue(endValue);
+ anim.setDuration(duration).setInterpolator(scrollInterpolatorForVelocity(velocity));
+ anim.addListener(AnimatorListeners.forSuccessCallback(
+ () -> mStateCallback.setState(STATE_FLING_FINISHED)));
+ anim.start();
+ }
+
+ private void onFlingFinished() {
+ if (mRecentsAnimationController != null) {
+ boolean endToRecents = mFlingEndsOnHome == null ? true : mFlingEndsOnHome;
+ mRecentsAnimationController.finishController(endToRecents /* toRecents */,
+ null /* callback */, false /* sendUserLeaveHint */);
+ }
+ }
+
+ @Override
+ public void onRecentsAnimationStart(RecentsAnimationController controller,
+ RecentsAnimationTargets targets) {
+ mRecentsAnimationController = controller;
+ mStateCallback.setState(STATE_TARGET_RECEIVED);
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled(HashMap thumbnailDatas) {
+ mRecentsAnimationController = null;
+ }
+
+ private void endRemoteAnimation() {
+ onDragEnd(Float.MIN_VALUE);
+ }
+
+ @Override
+ public void onConsumerAboutToBeSwitched() {
+ mStateCallback.setState(STATE_HANDLER_INVALIDATED);
+ }
+
+ @Override
+ public boolean allowInterceptByParent() {
+ return !mDragStarted;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
new file mode 100644
index 0000000000..dbe260ac65
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarStashInputConsumer.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.inputconsumers;
+
+import static com.android.launcher3.Utilities.squaredHypot;
+
+import android.content.Context;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.quickstep.InputConsumer;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+/**
+ * Listens for a long press, and cancels the current gesture if that causes Taskbar to be unstashed.
+ */
+public class TaskbarStashInputConsumer extends DelegateInputConsumer {
+
+ private final TaskbarActivityContext mTaskbarActivityContext;
+ private final GestureDetector mLongPressDetector;
+ private final float mSquaredTouchSlop;
+
+ private float mDownX, mDownY;
+ private boolean mCanceledUnstashHint;
+
+ public TaskbarStashInputConsumer(Context context, InputConsumer delegate,
+ InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) {
+ super(delegate, inputMonitor);
+ mTaskbarActivityContext = taskbarActivityContext;
+ mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
+
+ mLongPressDetector = new GestureDetector(context, new SimpleOnGestureListener() {
+ @Override
+ public void onLongPress(MotionEvent motionEvent) {
+ onLongPressDetected(motionEvent);
+ }
+ });
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_TASKBAR_STASH | mDelegate.getType();
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent ev) {
+ mLongPressDetector.onTouchEvent(ev);
+ if (mState != STATE_ACTIVE) {
+ mDelegate.onMotionEvent(ev);
+
+ if (mTaskbarActivityContext != null) {
+ final float x = ev.getRawX();
+ final float y = ev.getRawY();
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDownX = x;
+ mDownY = y;
+ mTaskbarActivityContext.startTaskbarUnstashHint(
+ /* animateForward = */ true);
+ mCanceledUnstashHint = false;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (!mCanceledUnstashHint
+ && squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop) {
+ mTaskbarActivityContext.startTaskbarUnstashHint(
+ /* animateForward = */ false);
+ mCanceledUnstashHint = true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ if (!mCanceledUnstashHint) {
+ mTaskbarActivityContext.startTaskbarUnstashHint(
+ /* animateForward = */ false);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private void onLongPressDetected(MotionEvent motionEvent) {
+ if (mTaskbarActivityContext != null
+ && mTaskbarActivityContext.onLongPressToUnstashTaskbar()) {
+ setActive(motionEvent);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 4472bdcf73..1c3e784308 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -15,11 +15,32 @@
*/
package com.android.quickstep.interaction;
+import static com.android.launcher3.Utilities.mapBoundToRange;
+import static com.android.launcher3.Utilities.mapRange;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.animation.Animator;
import android.app.Activity;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
+import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.PointF;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader.TileMode;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
import android.util.Log;
import android.view.View;
import android.view.View.AccessibilityDelegate;
@@ -29,9 +50,16 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
+import androidx.core.graphics.ColorUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.util.TISBindHelper;
+
+import com.airbnb.lottie.LottieAnimationView;
import java.net.URISyntaxException;
@@ -47,10 +75,27 @@ public class AllSetActivity extends Activity {
private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "suwColorAccentDark";
private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "suwColorAccentLight";
+ private static final float HINT_BOTTOM_FACTOR = 1 - .94f;
+
+ private TISBindHelper mTISBindHelper;
+ private TISBinder mBinder;
+
+ private final AnimatedFloat mSwipeProgress = new AnimatedFloat(this::onSwipeProgressUpdate);
+ private BgDrawable mBackground;
+ private View mContentView;
+ private float mSwipeUpShift;
+
+ @Nullable private Vibrator mVibrator;
+ private LottieAnimationView mAnimatedBackground;
+ private Animator.AnimatorListener mBackgroundAnimatorListener;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_allset);
+ findViewById(R.id.root_view).setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
int mode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
boolean isDarkTheme = mode == Configuration.UI_MODE_NIGHT_YES;
@@ -60,6 +105,11 @@ public class AllSetActivity extends Activity {
((ImageView) findViewById(R.id.icon)).getDrawable().mutate().setTint(accentColor);
+ mBackground = new BgDrawable(this);
+ findViewById(R.id.root_view).setBackground(mBackground);
+ mContentView = findViewById(R.id.content_view);
+ mSwipeUpShift = getResources().getDimension(R.dimen.allset_swipe_up_shift);
+
TextView tv = findViewById(R.id.navigation_settings);
tv.setTextColor(accentColor);
tv.setOnClickListener(v -> {
@@ -73,6 +123,120 @@ public class AllSetActivity extends Activity {
});
findViewById(R.id.hint).setAccessibilityDelegate(new SkipButtonAccessibilityDelegate());
+ mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
+
+ mVibrator = getSystemService(Vibrator.class);
+ mAnimatedBackground = findViewById(R.id.animated_background);
+ startBackgroundAnimation();
+ }
+
+ private void startBackgroundAnimation() {
+ if (Utilities.ATLEAST_S && mVibrator != null && mVibrator.areAllPrimitivesSupported(
+ VibrationEffect.Composition.PRIMITIVE_THUD)) {
+ if (mBackgroundAnimatorListener == null) {
+ mBackgroundAnimatorListener =
+ new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mVibrator.vibrate(getVibrationEffect());
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ mVibrator.vibrate(getVibrationEffect());
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mVibrator.cancel();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mVibrator.cancel();
+ }
+ };
+ }
+ mAnimatedBackground.addAnimatorListener(mBackgroundAnimatorListener);
+ }
+ mAnimatedBackground.playAnimation();
+ }
+
+ /**
+ * Sets up the vibration effect for the next round of animation. The parameters vary between
+ * different illustrations.
+ */
+ private VibrationEffect getVibrationEffect() {
+ return VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_THUD, 1.0f, 50)
+ .compose();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (mBinder != null) {
+ mBinder.getTaskbarManager().setSetupUIVisible(true);
+ mBinder.setSwipeUpProxy(this::createSwipeUpProxy);
+ }
+ }
+
+ private void onTISConnected(TISBinder binder) {
+ mBinder = binder;
+ mBinder.getTaskbarManager().setSetupUIVisible(isResumed());
+ mBinder.setSwipeUpProxy(isResumed() ? this::createSwipeUpProxy : null);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ clearBinderOverride();
+ if (mSwipeProgress.value >= 1) {
+ finishAndRemoveTask();
+ }
+ }
+
+ private void clearBinderOverride() {
+ if (mBinder != null) {
+ mBinder.getTaskbarManager().setSetupUIVisible(false);
+ mBinder.setSwipeUpProxy(null);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mTISBindHelper.onDestroy();
+ clearBinderOverride();
+ if (mBackgroundAnimatorListener != null) {
+ mAnimatedBackground.removeAnimatorListener(mBackgroundAnimatorListener);
+ }
+ }
+
+ private AnimatedFloat createSwipeUpProxy(GestureState state) {
+ if (!state.getHomeIntent().getComponent().getPackageName().equals(getPackageName())) {
+ return null;
+ }
+ RunningTaskInfo rti = state.getRunningTask();
+ if (rti == null || !rti.topActivity.equals(getComponentName())) {
+ return null;
+ }
+ mSwipeProgress.updateValue(0);
+ return mSwipeProgress;
+ }
+
+ private void onSwipeProgressUpdate() {
+ mBackground.setProgress(mSwipeProgress.value);
+ float alpha = Utilities.mapBoundToRange(mSwipeProgress.value, 0, HINT_BOTTOM_FACTOR,
+ 1, 0, LINEAR);
+ mContentView.setAlpha(alpha);
+ mContentView.setTranslationY((alpha - 1) * mSwipeUpShift);
+
+ if (alpha == 0f) {
+ mAnimatedBackground.pauseAnimation();
+ } else if (!mAnimatedBackground.isAnimating()) {
+ mAnimatedBackground.resumeAnimation();
+ }
}
/**
@@ -99,4 +263,79 @@ public class AllSetActivity extends Activity {
return super.performAccessibilityAction(host, action, args);
}
}
+
+ private static class BgDrawable extends Drawable {
+
+ private static final float START_SIZE_FACTOR = .5f;
+ private static final float END_SIZE_FACTOR = 2;
+ private static final float GRADIENT_END_PROGRESS = .5f;
+
+ private final Paint mPaint = new Paint();
+ private final RadialGradient mMaskGrad;
+ private final Matrix mMatrix = new Matrix();
+
+ private final ColorMatrix mColorMatrix = new ColorMatrix();
+ private final ColorMatrixColorFilter mColorFilter =
+ new ColorMatrixColorFilter(mColorMatrix);
+
+ private final int mColor;
+ private float mProgress = 0;
+
+ BgDrawable(Context context) {
+ mColor = context.getColor(R.color.all_set_page_background);
+ mMaskGrad = new RadialGradient(0, 0, 1,
+ new int[] {ColorUtils.setAlphaComponent(mColor, 0), mColor},
+ new float[]{0, 1}, TileMode.CLAMP);
+
+ mPaint.setShader(mMaskGrad);
+ mPaint.setColorFilter(mColorFilter);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (mProgress <= 0) {
+ canvas.drawColor(mColor);
+ return;
+ }
+
+ // Update the progress to half the size only.
+ float progress = mapBoundToRange(mProgress,
+ 0, GRADIENT_END_PROGRESS, 0, 1, LINEAR);
+ Rect bounds = getBounds();
+ float x = bounds.exactCenterX();
+ float height = bounds.height();
+
+ float size = PointF.length(x, height);
+ float radius = size * mapRange(progress, START_SIZE_FACTOR, END_SIZE_FACTOR);
+ float y = mapRange(progress, height + radius , height / 2);
+ mMatrix.setTranslate(x, y);
+ mMatrix.postScale(radius, radius, x, y);
+ mMaskGrad.setLocalMatrix(mMatrix);
+
+ // Change the alpha-addition-component (index 19) so that every pixel is updated
+ // accordingly
+ mColorMatrix.getArray()[19] = mapBoundToRange(mProgress, 0, 1, 0, -255, LINEAR);
+ mColorFilter.setColorMatrix(mColorMatrix);
+
+ canvas.drawPaint(mPaint);
+ }
+
+ public void setProgress(float progress) {
+ if (mProgress != progress) {
+ mProgress = progress;
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int i) { }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) { }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
new file mode 100644
index 0000000000..53ad138b6a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.interaction;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.cardview.widget.CardView;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.launcher3.R;
+
+import java.util.ArrayList;
+
+/**
+ * Helper View for the gesture tutorial mock previous app task view.
+ *
+ * This helper class allows animating from a single-row layout to a two-row layout as seen in
+ * large screen devices.
+ */
+public class AnimatedTaskView extends ConstraintLayout {
+
+ private View mFullTaskView;
+ private CardView mTopTaskView;
+ private CardView mBottomTaskView;
+
+ private ViewOutlineProvider mTaskViewOutlineProvider = null;
+ private final Rect mTaskViewAnimatedRect = new Rect();
+ private float mTaskViewAnimatedRadius;
+
+ public AnimatedTaskView(@NonNull Context context) {
+ super(context);
+ }
+
+ public AnimatedTaskView(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AnimatedTaskView(
+ @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public AnimatedTaskView(
+ @NonNull Context context,
+ @Nullable AttributeSet attrs,
+ int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mFullTaskView = findViewById(R.id.full_task_view);
+ mTopTaskView = findViewById(R.id.top_task_view);
+ mBottomTaskView = findViewById(R.id.bottom_task_view);
+
+ setToSingleRowLayout(false);
+ }
+
+ AnimatorSet createAnimationToMultiRowLayout() {
+ if (mTaskViewOutlineProvider == null) {
+ // This is an illegal state.
+ return null;
+ }
+ Outline startOutline = new Outline();
+ mTaskViewOutlineProvider.getOutline(this, startOutline);
+ Rect outlineStartRect = new Rect();
+ startOutline.getRect(outlineStartRect);
+ int endRectBottom = mTopTaskView.getHeight();
+ float outlineStartRadius = startOutline.getRadius();
+ float outlineEndRadius = getContext().getResources().getDimensionPixelSize(
+ R.dimen.gesture_tutorial_small_task_view_corner_radius);
+
+ ValueAnimator outlineAnimator = ValueAnimator.ofFloat(0f, 1f);
+ outlineAnimator.addUpdateListener(valueAnimator -> {
+ float progress = (float) valueAnimator.getAnimatedValue();
+ mTaskViewAnimatedRect.bottom = (int) (outlineStartRect.bottom
+ + progress * (endRectBottom - outlineStartRect.bottom));
+ mTaskViewAnimatedRadius = outlineStartRadius
+ + progress * (outlineEndRadius - outlineStartRadius);
+ mFullTaskView.invalidateOutline();
+ });
+ outlineAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+
+ mTaskViewAnimatedRect.set(outlineStartRect);
+ mTaskViewAnimatedRadius = outlineStartRadius;
+
+ mFullTaskView.setClipToOutline(true);
+ mFullTaskView.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(mTaskViewAnimatedRect, mTaskViewAnimatedRadius);
+ }
+ });
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mFullTaskView.setOutlineProvider(mTaskViewOutlineProvider);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ mFullTaskView.setOutlineProvider(mTaskViewOutlineProvider);
+ }
+ });
+
+ ArrayList animations = new ArrayList<>();
+ animations.add(ObjectAnimator.ofFloat(
+ mBottomTaskView, View.TRANSLATION_X, -mBottomTaskView.getWidth(), 0));
+ animations.add(outlineAnimator);
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(animations);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ setToSingleRowLayout(true);
+
+ setPadding(0, outlineStartRect.top, 0, getHeight() - outlineStartRect.bottom);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ setToMultiRowLayout();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ setToMultiRowLayout();
+ }
+ });
+
+ return animatorSet;
+ }
+
+ void setToSingleRowLayout(boolean forAnimation) {
+ mFullTaskView.setVisibility(VISIBLE);
+ mTopTaskView.setVisibility(INVISIBLE);
+ mBottomTaskView.setVisibility(forAnimation ? VISIBLE : INVISIBLE);
+ }
+
+ void setToMultiRowLayout() {
+ mFullTaskView.setVisibility(INVISIBLE);
+ mTopTaskView.setVisibility(VISIBLE);
+ mBottomTaskView.setVisibility(VISIBLE);
+ }
+
+ void setFakeTaskViewFillColor(@ColorInt int colorResId) {
+ mFullTaskView.setBackgroundColor(colorResId);
+ mTopTaskView.setCardBackgroundColor(colorResId);
+ mBottomTaskView.setCardBackgroundColor(colorResId);
+ }
+
+ @Override
+ public void setClipToOutline(boolean clipToOutline) {
+ mFullTaskView.setClipToOutline(clipToOutline);
+ }
+
+ @Override
+ public void setOutlineProvider(ViewOutlineProvider provider) {
+ mTaskViewOutlineProvider = provider;
+ mFullTaskView.setOutlineProvider(mTaskViewOutlineProvider);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskbarView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskbarView.java
new file mode 100644
index 0000000000..e8cc45b97b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskbarView.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.interaction;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.launcher3.R;
+
+import java.util.ArrayList;
+
+
+/**
+ * Helper View for the gesture tutorial mock taskbar view.
+ *
+ * This helper class allows animating this mock taskview to and from a mock hotseat and the bottom
+ * of the screen.
+ */
+public class AnimatedTaskbarView extends ConstraintLayout {
+
+ private View mBackground;
+ private View mIconContainer;
+ private View mIcon1;
+ private View mIcon2;
+ private View mIcon3;
+ private View mIcon4;
+ private View mIcon5;
+ private View mIcon6;
+
+ @Nullable private Animator mRunningAnimator;
+
+ public AnimatedTaskbarView(@NonNull Context context) {
+ super(context);
+ }
+
+ public AnimatedTaskbarView(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AnimatedTaskbarView(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public AnimatedTaskbarView(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mBackground = findViewById(R.id.taskbar_background);
+ mIconContainer = findViewById(R.id.icon_container);
+ mIcon1 = findViewById(R.id.taskbar_icon_1);
+ mIcon2 = findViewById(R.id.taskbar_icon_2);
+ mIcon3 = findViewById(R.id.taskbar_icon_3);
+ mIcon4 = findViewById(R.id.taskbar_icon_4);
+ mIcon5 = findViewById(R.id.taskbar_icon_5);
+ mIcon6 = findViewById(R.id.taskbar_icon_6);
+ }
+
+ /**
+ * Animates this fake taskbar's disappearance into the given hotseat view.
+ */
+ public void animateDisappearanceToHotseat(ViewGroup hotseat) {
+ ArrayList animators = new ArrayList<>();
+ int hotseatTop = hotseat.getTop();
+
+ animators.add(ObjectAnimator.ofFloat(
+ mBackground, View.TRANSLATION_Y, 0, mBackground.getHeight()));
+ animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 1f, 0f));
+ animators.add(createIconDisappearanceToHotseatAnimator(
+ mIcon1, hotseat.findViewById(R.id.hotseat_icon_1), hotseatTop));
+ animators.add(createIconDisappearanceToHotseatAnimator(
+ mIcon2, hotseat.findViewById(R.id.hotseat_icon_2), hotseatTop));
+ animators.add(createIconDisappearanceToHotseatAnimator(
+ mIcon3, hotseat.findViewById(R.id.hotseat_icon_3), hotseatTop));
+ animators.add(createIconDisappearanceToHotseatAnimator(
+ mIcon4, hotseat.findViewById(R.id.hotseat_icon_4), hotseatTop));
+ animators.add(createIconDisappearanceToHotseatAnimator(
+ mIcon5, hotseat.findViewById(R.id.hotseat_icon_5), hotseatTop));
+ animators.add(createIconDisappearanceToHotseatAnimator(
+ mIcon6, hotseat.findViewById(R.id.hotseat_icon_6), hotseatTop));
+
+ AnimatorSet animatorSet = new AnimatorSet();
+
+ animatorSet.playTogether(animators);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ setVisibility(INVISIBLE);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ setVisibility(VISIBLE);
+ }
+ });
+
+ start(animatorSet);
+ }
+
+ /**
+ * Animates this fake taskbar's appearance from the given hotseat view.
+ */
+ public void animateAppearanceFromHotseat(ViewGroup hotseat) {
+ ArrayList animators = new ArrayList<>();
+ int hotseatTop = hotseat.getTop();
+
+ animators.add(ObjectAnimator.ofFloat(
+ mBackground, View.TRANSLATION_Y, mBackground.getHeight(), 0));
+ animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 0f, 1f));
+ animators.add(createIconAppearanceFromHotseatAnimator(
+ mIcon1, hotseat.findViewById(R.id.hotseat_icon_1), hotseatTop));
+ animators.add(createIconAppearanceFromHotseatAnimator(
+ mIcon2, hotseat.findViewById(R.id.hotseat_icon_2), hotseatTop));
+ animators.add(createIconAppearanceFromHotseatAnimator(
+ mIcon3, hotseat.findViewById(R.id.hotseat_icon_3), hotseatTop));
+ animators.add(createIconAppearanceFromHotseatAnimator(
+ mIcon4, hotseat.findViewById(R.id.hotseat_icon_4), hotseatTop));
+ animators.add(createIconAppearanceFromHotseatAnimator(
+ mIcon5, hotseat.findViewById(R.id.hotseat_icon_5), hotseatTop));
+ animators.add(createIconAppearanceFromHotseatAnimator(
+ mIcon6, hotseat.findViewById(R.id.hotseat_icon_6), hotseatTop));
+
+ AnimatorSet animatorSet = new AnimatorSet();
+
+ animatorSet.playTogether(animators);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ setVisibility(VISIBLE);
+ }
+ });
+
+ start(animatorSet);
+ }
+
+ /**
+ * Animates this fake taskbar's disappearance to the bottom of the screen.
+ */
+ public void animateDisappearanceToBottom() {
+ ArrayList animators = new ArrayList<>();
+
+ animators.add(ObjectAnimator.ofFloat(
+ mBackground, View.TRANSLATION_Y, 0, mBackground.getHeight()));
+ animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 1f, 0f));
+ animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_X, 1f, 0f));
+ animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_Y, 1f, 0f));
+
+ initializeIconContainerPivot();
+
+ AnimatorSet animatorSet = new AnimatorSet();
+
+ animatorSet.playTogether(animators);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ setVisibility(INVISIBLE);
+ resetIconContainerPivot();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ resetIconContainerPivot();
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ setVisibility(VISIBLE);
+ }
+ });
+
+ start(animatorSet);
+ }
+
+ /**
+ * Animates this fake taskbar's appearance from the bottom of the screen.
+ */
+ public void animateAppearanceFromBottom() {
+ ArrayList animators = new ArrayList<>();
+
+ animators.add(ObjectAnimator.ofFloat(
+ mBackground, View.TRANSLATION_Y, mBackground.getHeight(), 0));
+ animators.add(ObjectAnimator.ofFloat(mBackground, View.ALPHA, 0f, 1f));
+ animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_X, 0f, 1f));
+ animators.add(ObjectAnimator.ofFloat(mIconContainer, View.SCALE_Y, 0f, 1f));
+
+ initializeIconContainerPivot();
+
+ AnimatorSet animatorSet = new AnimatorSet();
+
+ animatorSet.playTogether(animators);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ setVisibility(VISIBLE);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ resetIconContainerPivot();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ resetIconContainerPivot();
+ }
+ });
+
+ start(animatorSet);
+ }
+
+ private void initializeIconContainerPivot() {
+ mIconContainer.setPivotX(getWidth() / 2f);
+ mIconContainer.setPivotY(getHeight() * 0.8f);
+ }
+
+ private void resetIconContainerPivot() {
+ mIconContainer.resetPivot();
+ mIconContainer.setScaleX(1f);
+ mIconContainer.setScaleY(1f);
+ }
+
+ private void start(Animator animator) {
+ if (mRunningAnimator != null) {
+ mRunningAnimator.cancel();
+ }
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ mRunningAnimator = null;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mRunningAnimator = null;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mRunningAnimator = animator;
+ }
+ });
+
+ animator.start();
+ }
+
+ private Animator createIconDisappearanceToHotseatAnimator(
+ View taskbarIcon, View hotseatIcon, int hotseatTop) {
+ ArrayList animators = new ArrayList<>();
+
+ animators.add(ObjectAnimator.ofFloat(
+ taskbarIcon,
+ View.TRANSLATION_Y,
+ 0,
+ (hotseatTop + hotseatIcon.getTop()) - (getTop() + taskbarIcon.getTop())));
+ animators.add(ObjectAnimator.ofFloat(
+ taskbarIcon, View.TRANSLATION_X, 0, hotseatIcon.getLeft() - taskbarIcon.getLeft()));
+ animators.add(ObjectAnimator.ofFloat(
+ taskbarIcon,
+ View.SCALE_X,
+ 1f,
+ (float) hotseatIcon.getWidth() / (float) taskbarIcon.getWidth()));
+ animators.add(ObjectAnimator.ofFloat(
+ taskbarIcon,
+ View.SCALE_Y,
+ 1f,
+ (float) hotseatIcon.getHeight() / (float) taskbarIcon.getHeight()));
+ animators.add(ObjectAnimator.ofFloat(taskbarIcon, View.ALPHA, 1f, 0f));
+
+ AnimatorSet animatorSet = new AnimatorSet();
+
+ animatorSet.playTogether(animators);
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ taskbarIcon.setVisibility(INVISIBLE);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ taskbarIcon.setVisibility(VISIBLE);
+ }
+ });
+
+ return animatorSet;
+ }
+
+ private Animator createIconAppearanceFromHotseatAnimator(
+ View taskbarIcon, View hotseatIcon, int hotseatTop) {
+ ArrayList